ipset-2.2.8-20051203
[iptables.git] / extensions / libipt_ipv4options.c
1 /* Shared library add-on to iptables to add ipv4 options matching support. */
2 #include <stdio.h>
3 #include <netdb.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <getopt.h>
7
8 #include <iptables.h>
9 #include <linux/netfilter_ipv4/ipt_ipv4options.h>
10
11 /* Function which prints out usage message. */
12 static void
13 help(void)
14 {
15         printf(
16 "ipv4options v%s options:\n"
17 "      --ssrr    (match strict source routing flag)\n"
18 "      --lsrr    (match loose  source routing flag)\n"
19 "      --no-srr  (match packets with no source routing)\n\n"
20 "  [!] --rr      (match record route flag)\n\n"
21 "  [!] --ts      (match timestamp flag)\n\n"
22 "  [!] --ra      (match router-alert option)\n\n"
23 "  [!] --any-opt (match any option or no option at all if used with '!')\n",
24 IPTABLES_VERSION);
25 }
26
27 static struct option opts[] = {
28         { "ssrr", 0, 0, '1' },
29         { "lsrr", 0, 0, '2' },
30         { "no-srr", 0, 0, '3'},
31         { "rr", 0, 0, '4'},
32         { "ts", 0, 0, '5'},
33         { "ra", 0, 0, '6'},
34         { "any-opt", 0, 0, '7'},
35         {0}
36 };
37
38 /* Function which parses command options; returns true if it
39    ate an option */
40 static int
41 parse(int c, char **argv, int invert, unsigned int *flags,
42       const struct ipt_entry *entry,
43       unsigned int *nfcache,
44       struct ipt_entry_match **match)
45 {
46         struct ipt_ipv4options_info *info = (struct ipt_ipv4options_info *)(*match)->data;
47
48         switch (c)
49         {
50                 /* strict-source-routing */
51         case '1':
52                 if (invert) 
53                         exit_error(PARAMETER_PROBLEM,
54                                    "ipv4options: unexpected `!' with --ssrr");
55                 if (*flags & IPT_IPV4OPTION_MATCH_SSRR)
56                         exit_error(PARAMETER_PROBLEM,
57                                    "Can't specify --ssrr twice");
58                 if (*flags & IPT_IPV4OPTION_MATCH_LSRR)
59                         exit_error(PARAMETER_PROBLEM,
60                                    "Can't specify --ssrr with --lsrr");
61                 if (*flags & IPT_IPV4OPTION_DONT_MATCH_SRR)
62                         exit_error(PARAMETER_PROBLEM,
63                                    "Can't specify --ssrr with --no-srr");
64
65                 info->options |= IPT_IPV4OPTION_MATCH_SSRR;
66                 *flags |= IPT_IPV4OPTION_MATCH_SSRR;
67                 break;
68
69                 /* loose-source-routing */
70         case '2':
71                 if (invert) 
72                         exit_error(PARAMETER_PROBLEM,
73                                    "ipv4options: unexpected `!' with --lsrr");
74                 if (*flags & IPT_IPV4OPTION_MATCH_SSRR)
75                         exit_error(PARAMETER_PROBLEM,
76                                    "Can't specify --lsrr twice");
77                 if (*flags & IPT_IPV4OPTION_MATCH_LSRR)
78                         exit_error(PARAMETER_PROBLEM,
79                                    "Can't specify --lsrr with --ssrr");
80                 if (*flags & IPT_IPV4OPTION_DONT_MATCH_SRR)
81                         exit_error(PARAMETER_PROBLEM,
82                                    "Can't specify --lsrr with --no-srr");
83                 info->options |= IPT_IPV4OPTION_MATCH_LSRR;
84                 *flags |= IPT_IPV4OPTION_MATCH_LSRR;
85                 break;
86
87                 /* no-source-routing */
88         case '3':
89                 if (invert) 
90                         exit_error(PARAMETER_PROBLEM,
91                                            "ipv4options: unexpected `!' with --no-srr");
92                 if (*flags & IPT_IPV4OPTION_DONT_MATCH_SRR)
93                         exit_error(PARAMETER_PROBLEM,
94                                    "Can't specify --no-srr twice");
95                 if (*flags & IPT_IPV4OPTION_MATCH_SSRR)
96                         exit_error(PARAMETER_PROBLEM,
97                                    "Can't specify --no-srr with --ssrr");
98                 if (*flags & IPT_IPV4OPTION_MATCH_LSRR)
99                         exit_error(PARAMETER_PROBLEM,
100                                    "Can't specify --no-srr with --lsrr");
101                 info->options |= IPT_IPV4OPTION_DONT_MATCH_SRR;
102                 *flags |= IPT_IPV4OPTION_DONT_MATCH_SRR;
103                 break;
104
105                 /* record-route */
106         case '4':
107                 if ((!invert) && (*flags & IPT_IPV4OPTION_MATCH_RR))
108                         exit_error(PARAMETER_PROBLEM,
109                                    "Can't specify --rr twice"); 
110                 if (invert && (*flags & IPT_IPV4OPTION_DONT_MATCH_RR))
111                         exit_error(PARAMETER_PROBLEM,
112                                    "Can't specify ! --rr twice");
113                 if ((!invert) && (*flags & IPT_IPV4OPTION_DONT_MATCH_RR))
114                         exit_error(PARAMETER_PROBLEM,
115                                    "Can't specify --rr with ! --rr");
116                 if (invert && (*flags & IPT_IPV4OPTION_MATCH_RR))
117                         exit_error(PARAMETER_PROBLEM,
118                                    "Can't specify ! --rr with --rr");
119                 if (invert) {
120                         info->options |= IPT_IPV4OPTION_DONT_MATCH_RR;
121                         *flags |= IPT_IPV4OPTION_DONT_MATCH_RR;
122                 }
123                 else {
124                         info->options |= IPT_IPV4OPTION_MATCH_RR;
125                         *flags |= IPT_IPV4OPTION_MATCH_RR;
126                 }
127                 break;
128
129                 /* timestamp */
130         case '5':
131                 if ((!invert) && (*flags & IPT_IPV4OPTION_MATCH_TIMESTAMP))
132                         exit_error(PARAMETER_PROBLEM,
133                                    "Can't specify --ts twice"); 
134                 if (invert && (*flags & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP))
135                         exit_error(PARAMETER_PROBLEM,
136                                    "Can't specify ! --ts twice");
137                 if ((!invert) && (*flags & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP))
138                         exit_error(PARAMETER_PROBLEM,
139                                    "Can't specify --ts with ! --ts");
140                 if (invert && (*flags & IPT_IPV4OPTION_MATCH_TIMESTAMP))
141                         exit_error(PARAMETER_PROBLEM,
142                                    "Can't specify ! --ts with --ts");
143                 if (invert) {
144                         info->options |= IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP;
145                         *flags |= IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP;
146                 }
147                 else {
148                         info->options |= IPT_IPV4OPTION_MATCH_TIMESTAMP;
149                         *flags |= IPT_IPV4OPTION_MATCH_TIMESTAMP;
150                 }
151                 break;
152
153                 /* router-alert  */
154         case '6':
155                 if ((!invert) && (*flags & IPT_IPV4OPTION_MATCH_ROUTER_ALERT))
156                         exit_error(PARAMETER_PROBLEM,
157                                    "Can't specify --ra twice"); 
158                 if (invert && (*flags & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT))
159                         exit_error(PARAMETER_PROBLEM,
160                                    "Can't specify ! --rr twice");
161                 if ((!invert) && (*flags & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT))
162                         exit_error(PARAMETER_PROBLEM,
163                                    "Can't specify --ra with ! --ra");
164                 if (invert && (*flags & IPT_IPV4OPTION_MATCH_ROUTER_ALERT))
165                         exit_error(PARAMETER_PROBLEM,
166                                    "Can't specify ! --ra with --ra");
167                 if (invert) {
168                         info->options |= IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT;
169                         *flags |= IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT;
170                 }
171                 else {
172                         info->options |= IPT_IPV4OPTION_MATCH_ROUTER_ALERT;
173                         *flags |= IPT_IPV4OPTION_MATCH_ROUTER_ALERT;
174                 }
175                 break;
176
177                 /* any option */
178         case '7' :
179                 if ((!invert) && (*flags & IPT_IPV4OPTION_MATCH_ANY_OPT))
180                         exit_error(PARAMETER_PROBLEM,
181                                    "Can't specify --any-opt twice");
182                 if (invert && (*flags & IPT_IPV4OPTION_MATCH_ANY_OPT))
183                         exit_error(PARAMETER_PROBLEM,
184                                    "Can't specify ! --any-opt with --any-opt");
185                 if (invert && (*flags & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT))
186                         exit_error(PARAMETER_PROBLEM,
187                                    "Can't specify ! --any-opt twice");
188                 if ((!invert) &&
189                     ((*flags & IPT_IPV4OPTION_DONT_MATCH_SRR)       ||
190                      (*flags & IPT_IPV4OPTION_DONT_MATCH_RR)        ||
191                      (*flags & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) ||
192                      (*flags & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT)))
193                         exit_error(PARAMETER_PROBLEM,
194                                    "Can't specify --any-opt with any other negative ipv4options match");
195                 if (invert &&
196                     ((*flags & IPT_IPV4OPTION_MATCH_LSRR)      ||
197                      (*flags & IPT_IPV4OPTION_MATCH_SSRR)      ||
198                      (*flags & IPT_IPV4OPTION_MATCH_RR)        ||
199                      (*flags & IPT_IPV4OPTION_MATCH_TIMESTAMP) ||
200                      (*flags & IPT_IPV4OPTION_MATCH_ROUTER_ALERT)))
201                         exit_error(PARAMETER_PROBLEM,
202                                    "Can't specify ! --any-opt with any other positive ipv4options match");
203                 if (invert) {
204                         info->options |= IPT_IPV4OPTION_DONT_MATCH_ANY_OPT;
205                         *flags |= IPT_IPV4OPTION_DONT_MATCH_ANY_OPT;    
206                 }
207                 else {
208                         info->options |= IPT_IPV4OPTION_MATCH_ANY_OPT;
209                         *flags |= IPT_IPV4OPTION_MATCH_ANY_OPT;
210                 }
211                 break;
212
213         default:
214                 return 0;
215         }
216         return 1;
217 }
218
219 static void
220 final_check(unsigned int flags)
221 {
222         if (flags == 0)
223                 exit_error(PARAMETER_PROBLEM,
224                            "ipv4options match: you must specify some parameters. See iptables -m ipv4options --help for help.'");
225 }
226
227 /* Prints out the matchinfo. */
228 static void
229 print(const struct ipt_ip *ip,
230       const struct ipt_entry_match *match,
231       int numeric)
232 {
233         struct ipt_ipv4options_info *info = ((struct ipt_ipv4options_info *)match->data);
234
235         printf(" IPV4OPTS");
236         if (info->options & IPT_IPV4OPTION_MATCH_SSRR)
237                 printf(" SSRR");
238         else if (info->options & IPT_IPV4OPTION_MATCH_LSRR)
239                 printf(" LSRR");
240         else if (info->options & IPT_IPV4OPTION_DONT_MATCH_SRR)
241                 printf(" !SRR");
242         if (info->options & IPT_IPV4OPTION_MATCH_RR)
243                 printf(" RR");
244         else if (info->options & IPT_IPV4OPTION_DONT_MATCH_RR)
245                 printf(" !RR");
246         if (info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP)
247                 printf(" TS");
248         else if (info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP)
249                 printf(" !TS");
250         if (info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT)
251                 printf(" RA");
252         else if (info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT)
253                 printf(" !RA");
254         if (info->options & IPT_IPV4OPTION_MATCH_ANY_OPT)
255                 printf(" ANYOPT ");
256         else if (info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)
257                 printf(" NOOPT");
258
259         printf(" ");
260 }
261
262 /* Saves the data in parsable form to stdout. */
263 static void
264 save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
265 {
266         struct ipt_ipv4options_info *info = ((struct ipt_ipv4options_info *)match->data);
267
268         if (info->options & IPT_IPV4OPTION_MATCH_SSRR)
269                 printf(" --ssrr");
270         else if (info->options & IPT_IPV4OPTION_MATCH_LSRR)
271                 printf(" --lsrr");
272         else if (info->options & IPT_IPV4OPTION_DONT_MATCH_SRR)
273                 printf(" --no-srr");
274         if (info->options & IPT_IPV4OPTION_MATCH_RR)
275                 printf(" --rr");
276         else if (info->options & IPT_IPV4OPTION_DONT_MATCH_RR)
277                 printf(" ! --rr");
278         if (info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP)
279                 printf(" --ts");
280         else if (info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP)
281                 printf(" ! --ts");
282         if (info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT)
283                 printf(" --ra");
284         else if (info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT)
285                 printf(" ! --ra");
286         if (info->options & IPT_IPV4OPTION_MATCH_ANY_OPT)
287                 printf(" --any-opt");
288         if (info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)
289                 printf(" ! --any-opt");
290
291         printf(" ");
292 }
293
294 static struct iptables_match ipv4options_struct = { 
295         .next           = NULL,
296         .name           = "ipv4options",
297         .version        = IPTABLES_VERSION,
298         .size           = IPT_ALIGN(sizeof(struct ipt_ipv4options_info)),
299         .userspacesize  = IPT_ALIGN(sizeof(struct ipt_ipv4options_info)),
300         .help           = &help,
301         .parse          = &parse,
302         .final_check    = &final_check,
303         .print          = &print,
304         .save           = &save,
305         .extra_opts     = opts
306 };
307
308 void _init(void)
309 {
310         register_match(&ipv4options_struct);
311 }