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