iptables-1.3.2-20050720
[iptables.git] / extensions / libip6t_nth.c
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 <ip6tables.h>
22 #include <linux/netfilter_ipv6/ip6_tables.h>
23 #include <linux/netfilter_ipv6/ip6t_nth.h>
24
25
26 /* Function which prints out usage message. */
27 static void
28 help(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",
42 IPTABLES_VERSION, IP6T_NTH_NUM_COUNTERS-1);
43 }
44
45 static 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 IP6T_NTH_OPT_EVERY      0x01
54 #define IP6T_NTH_OPT_NOT_EVERY  0x02
55 #define IP6T_NTH_OPT_START      0x04
56 #define IP6T_NTH_OPT_COUNTER     0x08
57 #define IP6T_NTH_OPT_PACKET      0x10
58
59 /* Function which parses command options; returns true if it
60    ate an option */
61 static int
62 parse(int c, char **argv, int invert, unsigned int *flags,
63       const struct ip6t_entry *entry,
64       unsigned int *nfcache,
65       struct ip6t_entry_match **match)
66 {
67         struct ip6t_nth_info *nthinfo = (struct ip6t_nth_info *)(*match)->data;
68         unsigned int num;
69
70         switch (c) {
71         case '1':
72                 /* check for common mistakes... */
73                 if ((!invert) && (*flags & IP6T_NTH_OPT_EVERY))
74                         exit_error(PARAMETER_PROBLEM,
75                                    "Can't specify --every twice");
76                 if (invert && (*flags & IP6T_NTH_OPT_NOT_EVERY))
77                         exit_error(PARAMETER_PROBLEM,
78                                    "Can't specify ! --every twice");
79                 if ((!invert) && (*flags & IP6T_NTH_OPT_NOT_EVERY))
80                         exit_error(PARAMETER_PROBLEM,
81                                    "Can't specify --every with ! --every");
82                 if (invert && (*flags & IP6T_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 & IP6T_NTH_OPT_EVERY))
97                 {
98                         nthinfo->counter = 0;
99                 }
100                 if (invert)
101                 {
102                         *flags |= IP6T_NTH_OPT_NOT_EVERY;
103                         nthinfo->not = 1;
104                 }
105                 else
106                 {
107                         *flags |= IP6T_NTH_OPT_EVERY;
108                         nthinfo->not = 0;
109                 }
110                 break;
111         case '2':
112                 /* check for common mistakes... */
113                 if (!((*flags & IP6T_NTH_OPT_EVERY) ||
114                       (*flags & IP6T_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 & IP6T_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 |= IP6T_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 & IP6T_NTH_OPT_COUNTER)
135                         exit_error(PARAMETER_PROBLEM,
136                                    "Can't specify --counter twice");
137                 if (string_to_number(optarg, 0, IP6T_NTH_NUM_COUNTERS-1, &num) == -1)
138                         exit_error(PARAMETER_PROBLEM,
139                                    "bad --counter `%s', must between 0 and %u", optarg, IP6T_NTH_NUM_COUNTERS-1);
140                 /* assign the values */
141                 *flags |= IP6T_NTH_OPT_COUNTER;
142                 nthinfo->counter = num;
143                 break;
144         case '4':
145                 /* check for common mistakes... */
146                 if (!((*flags & IP6T_NTH_OPT_EVERY) ||
147                       (*flags & IP6T_NTH_OPT_NOT_EVERY)))
148                         exit_error(PARAMETER_PROBLEM,
149                                    "Can't specify --packet before --every");
150                 if ((*flags & IP6T_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 & IP6T_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 |= IP6T_NTH_OPT_PACKET;
163                 nthinfo->packet = num;
164                 break;
165         default:
166                 return 0;
167         }
168         return 1;
169 }
170
171 /* Final check; nothing. */
172 static void final_check(unsigned int flags)
173 {
174 }
175
176 /* Prints out the targinfo. */
177 static void
178 print(const struct ip6t_ip6 *ip,
179       const struct ip6t_entry_match *match,
180       int numeric)
181 {
182         const struct ip6t_nth_info *nthinfo
183                 = (const struct ip6t_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 ip6t_targinfo in parsable form to stdout. */
197 static void
198 save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match)
199 {
200         const struct ip6t_nth_info *nthinfo
201                 = (const struct ip6t_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
213 struct ip6tables_match nth = {
214         .name           = "nth",
215         .version        = IPTABLES_VERSION,
216         .size           = IP6T_ALIGN(sizeof(struct ip6t_nth_info)),
217         .userspacesize  = IP6T_ALIGN(sizeof(struct ip6t_nth_info)),
218         .help           = &help,
219         .parse          = &parse,
220         .final_check    = &final_check,
221         .print          = &print,
222         .save           = &save,
223         .extra_opts     = opts,
224 };
225
226 void _init(void)
227 {
228         register_match6(&nth);
229 }