fix for f12, gcc4.4
[iptables.git] / extensions / libip6t_multiport.c
1 /* Shared library add-on to iptables to add multiple TCP port support. */
2 #include <stdio.h>
3 #include <netdb.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <getopt.h>
7 #include <ip6tables.h>
8 /* To ensure that iptables compiles with an old kernel */
9 #include "../include/linux/netfilter_ipv6/ip6t_multiport.h"
10
11 /* Function which prints out usage message. */
12 static void
13 help(void)
14 {
15         printf(
16 "multiport v%s options:\n"
17 " --source-ports port[,port,port...]\n"
18 " --sports ...\n"
19 "                               match source port(s)\n"
20 " --destination-ports port[,port,port...]\n"
21 " --dports ...\n"
22 "                               match destination port(s)\n"
23 " --ports port[,port,port]\n"
24 "                               match both source and destination port(s)\n"
25 " NOTE: this kernel does not support port ranges in multiport.\n",
26 IPTABLES_VERSION);
27 }
28
29 static void
30 help_v1(void)
31 {
32         printf(
33 "multiport v%s options:\n"
34 " --source-ports [!] port[,port:port,port...]\n"
35 " --sports ...\n"
36 "                               match source port(s)\n"
37 " --destination-ports [!] port[,port:port,port...]\n"
38 " --dports ...\n"
39 "                               match destination port(s)\n"
40 " --ports [!] port[,port:port,port]\n"
41 "                               match both source and destination port(s)\n",
42 IPTABLES_VERSION);
43 }
44
45 static struct option opts[] = {
46         { "source-ports", 1, 0, '1' },
47         { "sports", 1, 0, '1' }, /* synonym */
48         { "destination-ports", 1, 0, '2' },
49         { "dports", 1, 0, '2' }, /* synonym */
50         { "ports", 1, 0, '3' },
51         {0}
52 };
53
54 static char *
55 proto_to_name(u_int8_t proto)
56 {
57         switch (proto) {
58         case IPPROTO_TCP:
59                 return "tcp";
60         case IPPROTO_UDP:
61                 return "udp";
62         case IPPROTO_SCTP:
63                 return "sctp";
64         case IPPROTO_DCCP:
65                 return "dccp";
66         default:
67                 return NULL;
68         }
69 }
70
71 static unsigned int
72 parse_multi_ports(const char *portstring, u_int16_t *ports, const char *proto)
73 {
74         char *buffer, *cp, *next;
75         unsigned int i;
76
77         buffer = strdup(portstring);
78         if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed");
79
80         for (cp=buffer, i=0; cp && i<IP6T_MULTI_PORTS; cp=next,i++)
81         {
82                 next=strchr(cp, ',');
83                 if (next) *next++='\0';
84                 ports[i] = parse_port(cp, proto);
85         }
86         if (cp) exit_error(PARAMETER_PROBLEM, "too many ports specified");
87         free(buffer);
88         return i;
89 }
90
91 static void
92 parse_multi_ports_v1(const char *portstring, 
93                      struct ip6t_multiport_v1 *multiinfo,
94                      const char *proto)
95 {
96         char *buffer, *cp, *next, *range;
97         unsigned int i;
98         u_int16_t m;
99
100         buffer = strdup(portstring);
101         if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed");
102
103         for (i=0; i<IP6T_MULTI_PORTS; i++)
104                 multiinfo->pflags[i] = 0;
105  
106         for (cp=buffer, i=0; cp && i<IP6T_MULTI_PORTS; cp=next, i++) {
107                 next=strchr(cp, ',');
108                 if (next) *next++='\0';
109                 range = strchr(cp, ':');
110                 if (range) {
111                         if (i == IP6T_MULTI_PORTS-1)
112                                 exit_error(PARAMETER_PROBLEM,
113                                            "too many ports specified");
114                         *range++ = '\0';
115                 }
116                 multiinfo->ports[i] = parse_port(cp, proto);
117                 if (range) {
118                         multiinfo->pflags[i] = 1;
119                         multiinfo->ports[++i] = parse_port(range, proto);
120                         if (multiinfo->ports[i-1] >= multiinfo->ports[i])
121                                 exit_error(PARAMETER_PROBLEM,
122                                            "invalid portrange specified");
123                         m <<= 1;
124                 }
125         }
126         multiinfo->count = i;
127         if (cp) exit_error(PARAMETER_PROBLEM, "too many ports specified");
128         free(buffer);
129 }
130
131 /* Initialize the match. */
132 static void
133 init(struct ip6t_entry_match *m, unsigned int *nfcache)
134 {
135 }
136
137 static const char *
138 check_proto(const struct ip6t_entry *entry)
139 {
140         char *proto;
141
142         if ((proto = proto_to_name(entry->ipv6.proto)) != NULL)
143                 return proto;
144         else if (!entry->ipv6.proto)
145                 exit_error(PARAMETER_PROBLEM,
146                            "multiport needs `-p tcp', `-p udp', `-p sctp' or `-p dccp'");
147         else
148                 exit_error(PARAMETER_PROBLEM,
149                            "multiport only works with TCP, UDP, SCTP and DCCP");
150 }
151
152 /* Function which parses command options; returns true if it
153    ate an option */
154 static int
155 parse(int c, char **argv, int invert, unsigned int *flags,
156       const struct ip6t_entry *entry,
157       unsigned int *nfcache,
158       struct ip6t_entry_match **match)
159 {
160         const char *proto;
161         struct ip6t_multiport *multiinfo
162                 = (struct ip6t_multiport *)(*match)->data;
163
164         switch (c) {
165         case '1':
166                 check_inverse(argv[optind-1], &invert, &optind, 0);
167                 proto = check_proto(entry);
168                 multiinfo->count = parse_multi_ports(argv[optind-1],
169                                                      multiinfo->ports, proto);
170                 multiinfo->flags = IP6T_MULTIPORT_SOURCE;
171                 break;
172
173         case '2':
174                 check_inverse(argv[optind-1], &invert, &optind, 0);
175                 proto = check_proto(entry);
176                 multiinfo->count = parse_multi_ports(argv[optind-1],
177                                                      multiinfo->ports, proto);
178                 multiinfo->flags = IP6T_MULTIPORT_DESTINATION;
179                 break;
180
181         case '3':
182                 check_inverse(argv[optind-1], &invert, &optind, 0);
183                 proto = check_proto(entry);
184                 multiinfo->count = parse_multi_ports(argv[optind-1],
185                                                      multiinfo->ports, proto);
186                 multiinfo->flags = IP6T_MULTIPORT_EITHER;
187                 break;
188
189         default:
190                 return 0;
191         }
192
193         if (invert)
194                 exit_error(PARAMETER_PROBLEM,
195                            "multiport does not support invert");
196
197         if (*flags)
198                 exit_error(PARAMETER_PROBLEM,
199                            "multiport can only have one option");
200         *flags = 1;
201         return 1;
202 }
203
204 static int
205 parse_v1(int c, char **argv, int invert, unsigned int *flags,
206          const struct ip6t_entry *entry,
207          unsigned int *nfcache,
208          struct ip6t_entry_match **match)
209 {
210         const char *proto;
211         struct ip6t_multiport_v1 *multiinfo
212                 = (struct ip6t_multiport_v1 *)(*match)->data;
213
214         switch (c) {
215         case '1':
216                 check_inverse(argv[optind-1], &invert, &optind, 0);
217                 proto = check_proto(entry);
218                 parse_multi_ports_v1(argv[optind-1], multiinfo, proto);
219                 multiinfo->flags = IP6T_MULTIPORT_SOURCE;
220                 break;
221
222         case '2':
223                 check_inverse(argv[optind-1], &invert, &optind, 0);
224                 proto = check_proto(entry);
225                 parse_multi_ports_v1(argv[optind-1], multiinfo, proto);
226                 multiinfo->flags = IP6T_MULTIPORT_DESTINATION;
227                 break;
228
229         case '3':
230                 check_inverse(argv[optind-1], &invert, &optind, 0);
231                 proto = check_proto(entry);
232                 parse_multi_ports_v1(argv[optind-1], multiinfo, proto);
233                 multiinfo->flags = IP6T_MULTIPORT_EITHER;
234                 break;
235
236         default:
237                 return 0;
238         }
239
240         if (invert)
241                 multiinfo->invert = 1;
242
243         if (*flags)
244                 exit_error(PARAMETER_PROBLEM,
245                            "multiport can only have one option");
246         *flags = 1;
247         return 1;
248 }
249
250 /* Final check; must specify something. */
251 static void
252 final_check(unsigned int flags)
253 {
254         if (!flags)
255                 exit_error(PARAMETER_PROBLEM, "multiport expection an option");
256 }
257
258 static char *
259 port_to_service(int port, u_int8_t proto)
260 {
261         struct servent *service;
262
263         if ((service = getservbyport(htons(port), proto_to_name(proto))))
264                 return service->s_name;
265
266         return NULL;
267 }
268
269 static void
270 print_port(u_int16_t port, u_int8_t protocol, int numeric)
271 {
272         char *service;
273
274         if (numeric || (service = port_to_service(port, protocol)) == NULL)
275                 printf("%u", port);
276         else
277                 printf("%s", service);
278 }
279
280 /* Prints out the matchinfo. */
281 static void
282 print(const struct ip6t_ip6 *ip,
283       const struct ip6t_entry_match *match,
284       int numeric)
285 {
286         const struct ip6t_multiport *multiinfo
287                 = (const struct ip6t_multiport *)match->data;
288         unsigned int i;
289
290         printf("multiport ");
291
292         switch (multiinfo->flags) {
293         case IP6T_MULTIPORT_SOURCE:
294                 printf("sports ");
295                 break;
296
297         case IP6T_MULTIPORT_DESTINATION:
298                 printf("dports ");
299                 break;
300
301         case IP6T_MULTIPORT_EITHER:
302                 printf("ports ");
303                 break;
304
305         default:
306                 printf("ERROR ");
307                 break;
308         }
309
310         for (i=0; i < multiinfo->count; i++) {
311                 printf("%s", i ? "," : "");
312                 print_port(multiinfo->ports[i], ip->proto, numeric);
313         }
314         printf(" ");
315 }
316
317 static void
318 print_v1(const struct ip6t_ip6 *ip,
319          const struct ip6t_entry_match *match,
320          int numeric)
321 {
322         const struct ip6t_multiport_v1 *multiinfo
323                 = (const struct ip6t_multiport_v1 *)match->data;
324         unsigned int i;
325
326         printf("multiport ");
327
328         switch (multiinfo->flags) {
329         case IP6T_MULTIPORT_SOURCE:
330                 printf("sports ");
331                 break;
332
333         case IP6T_MULTIPORT_DESTINATION:
334                 printf("dports ");
335                 break;
336
337         case IP6T_MULTIPORT_EITHER:
338                 printf("ports ");
339                 break;
340
341         default:
342                 printf("ERROR ");
343                 break;
344         }
345
346         if (multiinfo->invert)
347                 printf("! ");
348
349         for (i=0; i < multiinfo->count; i++) {
350                 printf("%s", i ? "," : "");
351                 print_port(multiinfo->ports[i], ip->proto, numeric);
352                 if (multiinfo->pflags[i]) {
353                         printf(":");
354                         print_port(multiinfo->ports[++i], ip->proto, numeric);
355                 }
356         }
357         printf(" ");
358 }
359
360 /* Saves the union ip6t_matchinfo in parsable form to stdout. */
361 static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match)
362 {
363         const struct ip6t_multiport *multiinfo
364                 = (const struct ip6t_multiport *)match->data;
365         unsigned int i;
366
367         switch (multiinfo->flags) {
368         case IP6T_MULTIPORT_SOURCE:
369                 printf("--sports ");
370                 break;
371
372         case IP6T_MULTIPORT_DESTINATION:
373                 printf("--dports ");
374                 break;
375
376         case IP6T_MULTIPORT_EITHER:
377                 printf("--ports ");
378                 break;
379         }
380
381         for (i=0; i < multiinfo->count; i++) {
382                 printf("%s", i ? "," : "");
383                 print_port(multiinfo->ports[i], ip->proto, 1);
384         }
385         printf(" ");
386 }
387
388 static void save_v1(const struct ip6t_ip6 *ip, 
389                     const struct ip6t_entry_match *match)
390 {
391         const struct ip6t_multiport_v1 *multiinfo
392                 = (const struct ip6t_multiport_v1 *)match->data;
393         unsigned int i;
394
395         switch (multiinfo->flags) {
396         case IP6T_MULTIPORT_SOURCE:
397                 printf("--sports ");
398                 break;
399
400         case IP6T_MULTIPORT_DESTINATION:
401                 printf("--dports ");
402                 break;
403
404         case IP6T_MULTIPORT_EITHER:
405                 printf("--ports ");
406                 break;
407         }
408
409         if (multiinfo->invert)
410                 printf("! ");
411
412         for (i=0; i < multiinfo->count; i++) {
413                 printf("%s", i ? "," : "");
414                 print_port(multiinfo->ports[i], ip->proto, 1);
415                 if (multiinfo->pflags[i]) {
416                         printf(":");
417                         print_port(multiinfo->ports[++i], ip->proto, 1);
418                 }
419         }
420         printf(" ");
421 }
422
423 static struct ip6tables_match multiport = {
424         .name           = "multiport",
425         .version        = IPTABLES_VERSION,
426         .size           = IP6T_ALIGN(sizeof(struct ip6t_multiport)),
427         .userspacesize  = IP6T_ALIGN(sizeof(struct ip6t_multiport)),
428         .help           = &help,
429         .init           = &init,
430         .parse          = &parse,
431         .final_check    = &final_check,
432         .print          = &print,
433         .save           = &save,
434         .extra_opts     = opts,
435 };
436
437 static struct ip6tables_match multiport_v1 = { 
438         .next           = NULL,
439         .name           = "multiport",
440         .revision       = 1,
441         .version        = IPTABLES_VERSION,
442         .size           = IP6T_ALIGN(sizeof(struct ip6t_multiport_v1)),
443         .userspacesize  = IP6T_ALIGN(sizeof(struct ip6t_multiport_v1)),
444         .help           = &help_v1,
445         .init           = &init,
446         .parse          = &parse_v1,
447         .final_check    = &final_check,
448         .print          = &print_v1,
449         .save           = &save_v1,
450         .extra_opts     = opts
451 };
452
453 void
454 _init(void)
455 {
456         register_match6(&multiport);
457         register_match6(&multiport_v1);
458 }