iptables-1.2.9-2.3.1.src.rpm
[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 /* Initialize the target. */
54 static void
55 init(struct ip6t_entry_match *m, unsigned int *nfcache)
56 {
57         *nfcache |= NFC_UNKNOWN;
58 }
59
60 #define IP6T_NTH_OPT_EVERY      0x01
61 #define IP6T_NTH_OPT_NOT_EVERY  0x02
62 #define IP6T_NTH_OPT_START      0x04
63 #define IP6T_NTH_OPT_COUNTER     0x08
64 #define IP6T_NTH_OPT_PACKET      0x10
65
66 /* Function which parses command options; returns true if it
67    ate an option */
68 static int
69 parse(int c, char **argv, int invert, unsigned int *flags,
70       const struct ip6t_entry *entry,
71       unsigned int *nfcache,
72       struct ip6t_entry_match **match)
73 {
74         struct ip6t_nth_info *nthinfo = (struct ip6t_nth_info *)(*match)->data;
75         unsigned int num;
76
77         switch (c) {
78         case '1':
79                 /* check for common mistakes... */
80                 if ((!invert) && (*flags & IP6T_NTH_OPT_EVERY))
81                         exit_error(PARAMETER_PROBLEM,
82                                    "Can't specify --every twice");
83                 if (invert && (*flags & IP6T_NTH_OPT_NOT_EVERY))
84                         exit_error(PARAMETER_PROBLEM,
85                                    "Can't specify ! --every twice");
86                 if ((!invert) && (*flags & IP6T_NTH_OPT_NOT_EVERY))
87                         exit_error(PARAMETER_PROBLEM,
88                                    "Can't specify --every with ! --every");
89                 if (invert && (*flags & IP6T_NTH_OPT_EVERY))
90                         exit_error(PARAMETER_PROBLEM,
91                                    "Can't specify ! --every with --every");
92
93                 /* Remember, this function will interpret a leading 0 to be 
94                    Octal, a leading 0x to be hexdecimal... */
95                 if (string_to_number(optarg, 2, 100, &num) == -1 || num < 2)
96                         exit_error(PARAMETER_PROBLEM,
97                                    "bad --every `%s', must be between 2 and 100", optarg);
98
99                 /* assign the values */
100                 nthinfo->every = num-1;
101                 nthinfo->startat = 0;
102                 nthinfo->packet = 0xFF;
103                 if(!(*flags & IP6T_NTH_OPT_EVERY))
104                 {
105                         nthinfo->counter = 0;
106                 }
107                 if (invert)
108                 {
109                         *flags |= IP6T_NTH_OPT_NOT_EVERY;
110                         nthinfo->not = 1;
111                 }
112                 else
113                 {
114                         *flags |= IP6T_NTH_OPT_EVERY;
115                         nthinfo->not = 0;
116                 }
117                 break;
118         case '2':
119                 /* check for common mistakes... */
120                 if (!((*flags & IP6T_NTH_OPT_EVERY) ||
121                       (*flags & IP6T_NTH_OPT_NOT_EVERY)))
122                         exit_error(PARAMETER_PROBLEM,
123                                    "Can't specify --start before --every");
124                 if (invert)
125                         exit_error(PARAMETER_PROBLEM,
126                                    "Can't specify with ! --start");
127                 if (*flags & IP6T_NTH_OPT_START)
128                         exit_error(PARAMETER_PROBLEM,
129                                    "Can't specify --start twice");
130                 if (string_to_number(optarg, 0, nthinfo->every, &num) == -1)
131                         exit_error(PARAMETER_PROBLEM,
132                                    "bad --start `%s', must between 0 and %u", optarg, nthinfo->every);
133                 *flags |= IP6T_NTH_OPT_START;
134                 nthinfo->startat = num;
135                 break;
136         case '3':
137                 /* check for common mistakes... */
138                 if (invert)
139                         exit_error(PARAMETER_PROBLEM,
140                                    "Can't specify with ! --counter");
141                 if (*flags & IP6T_NTH_OPT_COUNTER)
142                         exit_error(PARAMETER_PROBLEM,
143                                    "Can't specify --counter twice");
144                 if (string_to_number(optarg, 0, IP6T_NTH_NUM_COUNTERS-1, &num) == -1)
145                         exit_error(PARAMETER_PROBLEM,
146                                    "bad --counter `%s', must between 0 and %u", optarg, IP6T_NTH_NUM_COUNTERS-1);
147                 /* assign the values */
148                 *flags |= IP6T_NTH_OPT_COUNTER;
149                 nthinfo->counter = num;
150                 break;
151         case '4':
152                 /* check for common mistakes... */
153                 if (!((*flags & IP6T_NTH_OPT_EVERY) ||
154                       (*flags & IP6T_NTH_OPT_NOT_EVERY)))
155                         exit_error(PARAMETER_PROBLEM,
156                                    "Can't specify --packet before --every");
157                 if ((*flags & IP6T_NTH_OPT_NOT_EVERY))
158                         exit_error(PARAMETER_PROBLEM,
159                                    "Can't specify --packet with ! --every");
160                 if (invert)
161                         exit_error(PARAMETER_PROBLEM,
162                                    "Can't specify with ! --packet");
163                 if (*flags & IP6T_NTH_OPT_PACKET)
164                         exit_error(PARAMETER_PROBLEM,
165                                    "Can't specify --packet twice");
166                 if (string_to_number(optarg, 0, nthinfo->every, &num) == -1)
167                         exit_error(PARAMETER_PROBLEM,
168                                    "bad --packet `%s', must between 0 and %u", optarg, nthinfo->every);
169                 *flags |= IP6T_NTH_OPT_PACKET;
170                 nthinfo->packet = num;
171                 break;
172         default:
173                 return 0;
174         }
175         return 1;
176 }
177
178 /* Final check; nothing. */
179 static void final_check(unsigned int flags)
180 {
181 }
182
183 /* Prints out the targinfo. */
184 static void
185 print(const struct ip6t_ip6 *ip,
186       const struct ip6t_entry_match *match,
187       int numeric)
188 {
189         const struct ip6t_nth_info *nthinfo
190                 = (const struct ip6t_nth_info *)match->data;
191
192         if (nthinfo->not == 1)
193                 printf(" !");
194         printf("every %uth ", (nthinfo->every +1));
195         if (nthinfo->counter != 0) 
196                 printf("counter #%u ", (nthinfo->counter));
197         if (nthinfo->packet != 0xFF)
198                 printf("packet #%u ", nthinfo->packet);
199         if (nthinfo->startat != 0)
200                 printf("start at %u ", nthinfo->startat);
201 }
202
203 /* Saves the union ip6t_targinfo in parsable form to stdout. */
204 static void
205 save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match)
206 {
207         const struct ip6t_nth_info *nthinfo
208                 = (const struct ip6t_nth_info *)match->data;
209
210         if (nthinfo->not == 1)
211                 printf("! ");
212         printf("--every %u ", (nthinfo->every +1));
213         printf("--counter %u ", (nthinfo->counter));
214         if (nthinfo->startat != 0)
215                 printf("--start %u ", nthinfo->startat );
216         if (nthinfo->packet != 0xFF)
217                 printf("--packet %u ", nthinfo->packet );
218 }
219
220 struct ip6tables_match nth
221 = { NULL,
222     "nth",
223     IPTABLES_VERSION,
224     IP6T_ALIGN(sizeof(struct ip6t_nth_info)),
225     IP6T_ALIGN(sizeof(struct ip6t_nth_info)),
226     &help,
227     &init,
228     &parse,
229     &final_check,
230     &print,
231     &save,
232     opts
233 };
234
235 void _init(void)
236 {
237         register_match6(&nth);
238 }