1/* 2 Shared library add-on to iptables to add match support for every Nth packet 3 4 This file is distributed under the terms of the GNU General Public 5 License (GPL). Copies of the GPL can be obtained from: 6 ftp://prep.ai.mit.edu/pub/gnu/GPL 7 8 2001-07-17 Fabrice MARIE <fabrice@netfilter.org> : initial development. 9 2001-09-20 Richard Wagner (rwagner@cloudnet.com) 10 * added support for multiple counters 11 * added support for matching on individual packets 12 in the counter cycle 13*/ 14 15#include <stdio.h> 16#include <netdb.h> 17#include <string.h> 18#include <stdlib.h> 19#include <syslog.h> 20#include <getopt.h> 21#include <iptables.h> 22#include <linux/netfilter_ipv4/ip_tables.h> 23#include <linux/netfilter_ipv4/ipt_nth.h> 24 25 26/* Function which prints out usage message. */ 27static void 28help(void) 29{ 30 printf( 31"nth v%s options:\n" 32" --every Nth Match every Nth packet\n" 33" [--counter num ] Use counter 0-%u (default:0)\n" 34" [--start num ] Initialize the counter at the number 'num'\n" 35" instead of 0. Must be between 0 and Nth-1\n" 36" [--packet num ] Match on 'num' packet. Must be between 0\n" 37" and Nth-1.\n\n" 38" If --packet is used for a counter than\n" 39" there must be Nth number of --packet\n" 40" rules, covering all values between 0 and\n" 41" Nth-1 inclusively.\n", 42IPTABLES_VERSION, IPT_NTH_NUM_COUNTERS-1); 43} 44 45static struct option opts[] = { 46 { "every", 1, 0, '1' }, 47 { "start", 1, 0, '2' }, 48 { "counter", 1, 0, '3' }, 49 { "packet", 1, 0, '4' }, 50 { 0 } 51}; 52 53#define IPT_NTH_OPT_EVERY 0x01 54#define IPT_NTH_OPT_NOT_EVERY 0x02 55#define IPT_NTH_OPT_START 0x04 56#define IPT_NTH_OPT_COUNTER 0x08 57#define IPT_NTH_OPT_PACKET 0x10 58 59/* Function which parses command options; returns true if it 60 ate an option */ 61static int 62parse(int c, char **argv, int invert, unsigned int *flags, 63 const struct ipt_entry *entry, 64 unsigned int *nfcache, 65 struct ipt_entry_match **match) 66{ 67 struct ipt_nth_info *nthinfo = (struct ipt_nth_info *)(*match)->data; 68 unsigned int num; 69 70 switch (c) { 71 case '1': 72 /* check for common mistakes... */ 73 if ((!invert) && (*flags & IPT_NTH_OPT_EVERY)) 74 exit_error(PARAMETER_PROBLEM, 75 "Can't specify --every twice"); 76 if (invert && (*flags & IPT_NTH_OPT_NOT_EVERY)) 77 exit_error(PARAMETER_PROBLEM, 78 "Can't specify ! --every twice"); 79 if ((!invert) && (*flags & IPT_NTH_OPT_NOT_EVERY)) 80 exit_error(PARAMETER_PROBLEM, 81 "Can't specify --every with ! --every"); 82 if (invert && (*flags & IPT_NTH_OPT_EVERY)) 83 exit_error(PARAMETER_PROBLEM, 84 "Can't specify ! --every with --every"); 85 86 /* Remember, this function will interpret a leading 0 to be 87 Octal, a leading 0x to be hexdecimal... */ 88 if (string_to_number(optarg, 2, 100, &num) == -1 || num < 2) 89 exit_error(PARAMETER_PROBLEM, 90 "bad --every `%s', must be between 2 and 100", optarg); 91 92 /* assign the values */ 93 nthinfo->every = num-1; 94 nthinfo->startat = 0; 95 nthinfo->packet = 0xFF; 96 if(!(*flags & IPT_NTH_OPT_EVERY)) 97 { 98 nthinfo->counter = 0; 99 } 100 if (invert) 101 { 102 *flags |= IPT_NTH_OPT_NOT_EVERY; 103 nthinfo->not = 1; 104 } 105 else 106 { 107 *flags |= IPT_NTH_OPT_EVERY; 108 nthinfo->not = 0; 109 } 110 break; 111 case '2': 112 /* check for common mistakes... */ 113 if (!((*flags & IPT_NTH_OPT_EVERY) || 114 (*flags & IPT_NTH_OPT_NOT_EVERY))) 115 exit_error(PARAMETER_PROBLEM, 116 "Can't specify --start before --every"); 117 if (invert) 118 exit_error(PARAMETER_PROBLEM, 119 "Can't specify with ! --start"); 120 if (*flags & IPT_NTH_OPT_START) 121 exit_error(PARAMETER_PROBLEM, 122 "Can't specify --start twice"); 123 if (string_to_number(optarg, 0, nthinfo->every, &num) == -1) 124 exit_error(PARAMETER_PROBLEM, 125 "bad --start `%s', must between 0 and %u", optarg, nthinfo->every); 126 *flags |= IPT_NTH_OPT_START; 127 nthinfo->startat = num; 128 break; 129 case '3': 130 /* check for common mistakes... */ 131 if (invert) 132 exit_error(PARAMETER_PROBLEM, 133 "Can't specify with ! --counter"); 134 if (*flags & IPT_NTH_OPT_COUNTER) 135 exit_error(PARAMETER_PROBLEM, 136 "Can't specify --counter twice"); 137 if (string_to_number(optarg, 0, IPT_NTH_NUM_COUNTERS-1, &num) == -1) 138 exit_error(PARAMETER_PROBLEM, 139 "bad --counter `%s', must between 0 and %u", optarg, IPT_NTH_NUM_COUNTERS-1); 140 /* assign the values */ 141 *flags |= IPT_NTH_OPT_COUNTER; 142 nthinfo->counter = num; 143 break; 144 case '4': 145 /* check for common mistakes... */ 146 if (!((*flags & IPT_NTH_OPT_EVERY) || 147 (*flags & IPT_NTH_OPT_NOT_EVERY))) 148 exit_error(PARAMETER_PROBLEM, 149 "Can't specify --packet before --every"); 150 if ((*flags & IPT_NTH_OPT_NOT_EVERY)) 151 exit_error(PARAMETER_PROBLEM, 152 "Can't specify --packet with ! --every"); 153 if (invert) 154 exit_error(PARAMETER_PROBLEM, 155 "Can't specify with ! --packet"); 156 if (*flags & IPT_NTH_OPT_PACKET) 157 exit_error(PARAMETER_PROBLEM, 158 "Can't specify --packet twice"); 159 if (string_to_number(optarg, 0, nthinfo->every, &num) == -1) 160 exit_error(PARAMETER_PROBLEM, 161 "bad --packet `%s', must between 0 and %u", optarg, nthinfo->every); 162 *flags |= IPT_NTH_OPT_PACKET; 163 nthinfo->packet = num; 164 break; 165 default: 166 return 0; 167 } 168 return 1; 169} 170 171/* Final check; nothing. */ 172static void final_check(unsigned int flags) 173{ 174} 175 176/* Prints out the targinfo. */ 177static void 178print(const struct ipt_ip *ip, 179 const struct ipt_entry_match *match, 180 int numeric) 181{ 182 const struct ipt_nth_info *nthinfo 183 = (const struct ipt_nth_info *)match->data; 184 185 if (nthinfo->not == 1) 186 printf(" !"); 187 printf("every %uth ", (nthinfo->every +1)); 188 if (nthinfo->counter != 0) 189 printf("counter #%u ", (nthinfo->counter)); 190 if (nthinfo->packet != 0xFF) 191 printf("packet #%u ", nthinfo->packet); 192 if (nthinfo->startat != 0) 193 printf("start at %u ", nthinfo->startat); 194} 195 196/* Saves the union ipt_targinfo in parsable form to stdout. */ 197static void 198save(const struct ipt_ip *ip, const struct ipt_entry_match *match) 199{ 200 const struct ipt_nth_info *nthinfo 201 = (const struct ipt_nth_info *)match->data; 202 203 if (nthinfo->not == 1) 204 printf("! "); 205 printf("--every %u ", (nthinfo->every +1)); 206 printf("--counter %u ", (nthinfo->counter)); 207 if (nthinfo->startat != 0) 208 printf("--start %u ", nthinfo->startat ); 209 if (nthinfo->packet != 0xFF) 210 printf("--packet %u ", nthinfo->packet ); 211} 212 213static struct iptables_match nth = { 214 .next = NULL, 215 .name = "nth", 216 .version = IPTABLES_VERSION, 217 .size = IPT_ALIGN(sizeof(struct ipt_nth_info)), 218 .userspacesize = IPT_ALIGN(sizeof(struct ipt_nth_info)), 219 .help = &help, 220 .parse = &parse, 221 .final_check = &final_check, 222 .print = &print, 223 .save = &save, 224 .extra_opts = opts 225}; 226 227void _init(void) 228{ 229 register_match(&nth); 230} 231