1 /* Shared library add-on to iptables to add multiple TCP port support. */
9 #include <libiptc/libiptc.h>
10 #include <libiptc/libip6tc.h>
11 /* To ensure that iptables compiles with an old kernel */
12 #include "../include/linux/netfilter/xt_multiport.h"
14 /* Function which prints out usage message. */
15 static void multiport_help(void)
18 "multiport match options:\n"
19 " --source-ports port[,port,port...]\n"
21 " match source port(s)\n"
22 " --destination-ports port[,port,port...]\n"
24 " match destination port(s)\n"
25 " --ports port[,port,port]\n"
26 " match both source and destination port(s)\n"
27 " NOTE: this kernel does not support port ranges in multiport.\n");
30 static void multiport_help_v1(void)
33 "multiport match options:\n"
34 " --source-ports [!] port[,port:port,port...]\n"
36 " match source port(s)\n"
37 " --destination-ports [!] port[,port:port,port...]\n"
39 " match destination port(s)\n"
40 " --ports [!] port[,port:port,port]\n"
41 " match both source and destination port(s)\n");
44 static const struct option multiport_opts[] = {
45 { "source-ports", 1, NULL, '1' },
46 { "sports", 1, NULL, '1' }, /* synonym */
47 { "destination-ports", 1, NULL, '2' },
48 { "dports", 1, NULL, '2' }, /* synonym */
49 { "ports", 1, NULL, '3' },
54 proto_to_name(u_int8_t proto)
73 parse_multi_ports(const char *portstring, u_int16_t *ports, const char *proto)
75 char *buffer, *cp, *next;
78 buffer = strdup(portstring);
79 if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed");
81 for (cp=buffer, i=0; cp && i<XT_MULTI_PORTS; cp=next,i++)
84 if (next) *next++='\0';
85 ports[i] = parse_port(cp, proto);
87 if (cp) exit_error(PARAMETER_PROBLEM, "too many ports specified");
93 parse_multi_ports_v1(const char *portstring,
94 struct xt_multiport_v1 *multiinfo,
97 char *buffer, *cp, *next, *range;
101 buffer = strdup(portstring);
102 if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed");
104 for (i=0; i<XT_MULTI_PORTS; i++)
105 multiinfo->pflags[i] = 0;
107 for (cp=buffer, i=0; cp && i<XT_MULTI_PORTS; cp=next, i++) {
108 next=strchr(cp, ',');
109 if (next) *next++='\0';
110 range = strchr(cp, ':');
112 if (i == XT_MULTI_PORTS-1)
113 exit_error(PARAMETER_PROBLEM,
114 "too many ports specified");
117 multiinfo->ports[i] = parse_port(cp, proto);
119 multiinfo->pflags[i] = 1;
120 multiinfo->ports[++i] = parse_port(range, proto);
121 if (multiinfo->ports[i-1] >= multiinfo->ports[i])
122 exit_error(PARAMETER_PROBLEM,
123 "invalid portrange specified");
127 multiinfo->count = i;
128 if (cp) exit_error(PARAMETER_PROBLEM, "too many ports specified");
133 check_proto(u_int16_t pnum, u_int8_t invflags)
137 if (invflags & XT_INV_PROTO)
138 exit_error(PARAMETER_PROBLEM,
139 "multiport only works with TCP, UDP, UDPLITE, SCTP and DCCP");
141 if ((proto = proto_to_name(pnum)) != NULL)
144 exit_error(PARAMETER_PROBLEM,
145 "multiport needs `-p tcp', `-p udp', `-p udplite', "
146 "`-p sctp' or `-p dccp'");
148 exit_error(PARAMETER_PROBLEM,
149 "multiport only works with TCP, UDP, UDPLITE, SCTP and DCCP");
152 /* Function which parses command options; returns true if it
155 __multiport_parse(int c, char **argv, int invert, unsigned int *flags,
156 struct xt_entry_match **match, u_int16_t pnum,
160 struct xt_multiport *multiinfo
161 = (struct xt_multiport *)(*match)->data;
165 check_inverse(argv[optind-1], &invert, &optind, 0);
166 proto = check_proto(pnum, invflags);
167 multiinfo->count = parse_multi_ports(argv[optind-1],
168 multiinfo->ports, proto);
169 multiinfo->flags = XT_MULTIPORT_SOURCE;
173 check_inverse(argv[optind-1], &invert, &optind, 0);
174 proto = check_proto(pnum, invflags);
175 multiinfo->count = parse_multi_ports(argv[optind-1],
176 multiinfo->ports, proto);
177 multiinfo->flags = XT_MULTIPORT_DESTINATION;
181 check_inverse(argv[optind-1], &invert, &optind, 0);
182 proto = check_proto(pnum, invflags);
183 multiinfo->count = parse_multi_ports(argv[optind-1],
184 multiinfo->ports, proto);
185 multiinfo->flags = XT_MULTIPORT_EITHER;
193 exit_error(PARAMETER_PROBLEM,
194 "multiport does not support invert");
197 exit_error(PARAMETER_PROBLEM,
198 "multiport can only have one option");
204 multiport_parse(int c, char **argv, int invert, unsigned int *flags,
205 const void *e, struct xt_entry_match **match)
207 const struct ipt_entry *entry = e;
208 return __multiport_parse(c, argv, invert, flags, match,
209 entry->ip.proto, entry->ip.invflags);
213 multiport_parse6(int c, char **argv, int invert, unsigned int *flags,
214 const void *e, struct xt_entry_match **match)
216 const struct ip6t_entry *entry = (const struct ip6t_entry *)e;
217 return __multiport_parse(c, argv, invert, flags, match,
218 entry->ipv6.proto, entry->ipv6.invflags);
222 __multiport_parse_v1(int c, char **argv, int invert, unsigned int *flags,
223 struct xt_entry_match **match, u_int16_t pnum,
227 struct xt_multiport_v1 *multiinfo
228 = (struct xt_multiport_v1 *)(*match)->data;
232 check_inverse(argv[optind-1], &invert, &optind, 0);
233 proto = check_proto(pnum, invflags);
234 parse_multi_ports_v1(argv[optind-1], multiinfo, proto);
235 multiinfo->flags = XT_MULTIPORT_SOURCE;
239 check_inverse(argv[optind-1], &invert, &optind, 0);
240 proto = check_proto(pnum, invflags);
241 parse_multi_ports_v1(argv[optind-1], multiinfo, proto);
242 multiinfo->flags = XT_MULTIPORT_DESTINATION;
246 check_inverse(argv[optind-1], &invert, &optind, 0);
247 proto = check_proto(pnum, invflags);
248 parse_multi_ports_v1(argv[optind-1], multiinfo, proto);
249 multiinfo->flags = XT_MULTIPORT_EITHER;
257 multiinfo->invert = 1;
260 exit_error(PARAMETER_PROBLEM,
261 "multiport can only have one option");
267 multiport_parse_v1(int c, char **argv, int invert, unsigned int *flags,
268 const void *e, struct xt_entry_match **match)
270 const struct ipt_entry *entry = e;
271 return __multiport_parse_v1(c, argv, invert, flags, match,
272 entry->ip.proto, entry->ip.invflags);
276 multiport_parse6_v1(int c, char **argv, int invert, unsigned int *flags,
277 const void *e, struct xt_entry_match **match)
279 const struct ip6t_entry *entry = (const struct ip6t_entry *)e;
280 return __multiport_parse_v1(c, argv, invert, flags, match,
281 entry->ipv6.proto, entry->ipv6.invflags);
284 /* Final check; must specify something. */
285 static void multiport_check(unsigned int flags)
288 exit_error(PARAMETER_PROBLEM, "multiport expection an option");
292 port_to_service(int port, u_int8_t proto)
294 struct servent *service;
296 if ((service = getservbyport(htons(port), proto_to_name(proto))))
297 return service->s_name;
303 print_port(u_int16_t port, u_int8_t protocol, int numeric)
307 if (numeric || (service = port_to_service(port, protocol)) == NULL)
310 printf("%s", service);
313 /* Prints out the matchinfo. */
315 __multiport_print(const struct xt_entry_match *match, int numeric,
318 const struct xt_multiport *multiinfo
319 = (const struct xt_multiport *)match->data;
322 printf("multiport ");
324 switch (multiinfo->flags) {
325 case XT_MULTIPORT_SOURCE:
329 case XT_MULTIPORT_DESTINATION:
333 case XT_MULTIPORT_EITHER:
342 for (i=0; i < multiinfo->count; i++) {
343 printf("%s", i ? "," : "");
344 print_port(multiinfo->ports[i], proto, numeric);
349 static void multiport_print(const void *ip_void,
350 const struct xt_entry_match *match, int numeric)
352 const struct ipt_ip *ip = ip_void;
353 __multiport_print(match, numeric, ip->proto);
356 static void multiport_print6(const void *ip_void,
357 const struct xt_entry_match *match, int numeric)
359 const struct ip6t_ip6 *ip = (const struct ip6t_ip6 *)ip_void;
360 __multiport_print(match, numeric, ip->proto);
363 static void __multiport_print_v1(const struct xt_entry_match *match,
364 int numeric, u_int16_t proto)
366 const struct xt_multiport_v1 *multiinfo
367 = (const struct xt_multiport_v1 *)match->data;
370 printf("multiport ");
372 switch (multiinfo->flags) {
373 case XT_MULTIPORT_SOURCE:
377 case XT_MULTIPORT_DESTINATION:
381 case XT_MULTIPORT_EITHER:
390 if (multiinfo->invert)
393 for (i=0; i < multiinfo->count; i++) {
394 printf("%s", i ? "," : "");
395 print_port(multiinfo->ports[i], proto, numeric);
396 if (multiinfo->pflags[i]) {
398 print_port(multiinfo->ports[++i], proto, numeric);
404 static void multiport_print_v1(const void *ip_void,
405 const struct xt_entry_match *match, int numeric)
407 const struct ipt_ip *ip = ip_void;
408 __multiport_print_v1(match, numeric, ip->proto);
411 static void multiport_print6_v1(const void *ip_void,
412 const struct xt_entry_match *match, int numeric)
414 const struct ip6t_ip6 *ip = (const struct ip6t_ip6 *)ip_void;
415 __multiport_print_v1(match, numeric, ip->proto);
418 /* Saves the union ipt_matchinfo in parsable form to stdout. */
419 static void __multiport_save(const struct xt_entry_match *match,
422 const struct xt_multiport *multiinfo
423 = (const struct xt_multiport *)match->data;
426 switch (multiinfo->flags) {
427 case XT_MULTIPORT_SOURCE:
431 case XT_MULTIPORT_DESTINATION:
435 case XT_MULTIPORT_EITHER:
440 for (i=0; i < multiinfo->count; i++) {
441 printf("%s", i ? "," : "");
442 print_port(multiinfo->ports[i], proto, 1);
447 static void multiport_save(const void *ip_void,
448 const struct xt_entry_match *match)
450 const struct ipt_ip *ip = ip_void;
451 __multiport_save(match, ip->proto);
454 static void multiport_save6(const void *ip_void,
455 const struct xt_entry_match *match)
457 const struct ip6t_ip6 *ip = (const struct ip6t_ip6 *)ip_void;
458 __multiport_save(match, ip->proto);
461 static void __multiport_save_v1(const struct xt_entry_match *match,
464 const struct xt_multiport_v1 *multiinfo
465 = (const struct xt_multiport_v1 *)match->data;
468 switch (multiinfo->flags) {
469 case XT_MULTIPORT_SOURCE:
473 case XT_MULTIPORT_DESTINATION:
477 case XT_MULTIPORT_EITHER:
482 if (multiinfo->invert)
485 for (i=0; i < multiinfo->count; i++) {
486 printf("%s", i ? "," : "");
487 print_port(multiinfo->ports[i], proto, 1);
488 if (multiinfo->pflags[i]) {
490 print_port(multiinfo->ports[++i], proto, 1);
496 static void multiport_save_v1(const void *ip_void,
497 const struct xt_entry_match *match)
499 const struct ipt_ip *ip = ip_void;
500 __multiport_save_v1(match, ip->proto);
503 static void multiport_save6_v1(const void *ip_void,
504 const struct xt_entry_match *match)
506 const struct ip6t_ip6 *ip = (const struct ip6t_ip6 *)ip_void;
507 __multiport_save_v1(match, ip->proto);
510 static struct xtables_match multiport_match = {
514 .version = XTABLES_VERSION,
515 .size = XT_ALIGN(sizeof(struct xt_multiport)),
516 .userspacesize = XT_ALIGN(sizeof(struct xt_multiport)),
517 .help = multiport_help,
518 .parse = multiport_parse,
519 .final_check = multiport_check,
520 .print = multiport_print,
521 .save = multiport_save,
522 .extra_opts = multiport_opts,
525 static struct xtables_match multiport_match6 = {
529 .version = XTABLES_VERSION,
530 .size = XT_ALIGN(sizeof(struct xt_multiport)),
531 .userspacesize = XT_ALIGN(sizeof(struct xt_multiport)),
532 .help = multiport_help,
533 .parse = multiport_parse6,
534 .final_check = multiport_check,
535 .print = multiport_print6,
536 .save = multiport_save6,
537 .extra_opts = multiport_opts,
540 static struct xtables_match multiport_match_v1 = {
543 .version = XTABLES_VERSION,
545 .size = XT_ALIGN(sizeof(struct xt_multiport_v1)),
546 .userspacesize = XT_ALIGN(sizeof(struct xt_multiport_v1)),
547 .help = multiport_help_v1,
548 .parse = multiport_parse_v1,
549 .final_check = multiport_check,
550 .print = multiport_print_v1,
551 .save = multiport_save_v1,
552 .extra_opts = multiport_opts,
555 static struct xtables_match multiport_match6_v1 = {
558 .version = XTABLES_VERSION,
560 .size = XT_ALIGN(sizeof(struct xt_multiport_v1)),
561 .userspacesize = XT_ALIGN(sizeof(struct xt_multiport_v1)),
562 .help = multiport_help_v1,
563 .parse = multiport_parse6_v1,
564 .final_check = multiport_check,
565 .print = multiport_print6_v1,
566 .save = multiport_save6_v1,
567 .extra_opts = multiport_opts,
573 xtables_register_match(&multiport_match);
574 xtables_register_match(&multiport_match6);
575 xtables_register_match(&multiport_match_v1);
576 xtables_register_match(&multiport_match6_v1);