1 #include <stdio.h>
2 #include <netdb.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <xtables.h>
6 #include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */
7 #include <linux/netfilter_ipv4/ip_tables.h>
8 #include <linux/netfilter_ipv6/ip6_tables.h>
9 #include <linux/netfilter/xt_multiport.h>
10
11 enum {
12 O_SOURCE_PORTS = 0,
13 O_DEST_PORTS,
14 O_SD_PORTS,
15 F_SOURCE_PORTS = 1 << O_SOURCE_PORTS,
16 F_DEST_PORTS = 1 << O_DEST_PORTS,
17 F_SD_PORTS = 1 << O_SD_PORTS,
18 F_ANY = F_SOURCE_PORTS | F_DEST_PORTS | F_SD_PORTS,
19 };
20
21 /* Function which prints out usage message. */
multiport_help(void)22 static void multiport_help(void)
23 {
24 printf(
25 "multiport match options:\n"
26 " --source-ports port[,port,port...]\n"
27 " --sports ...\n"
28 " match source port(s)\n"
29 " --destination-ports port[,port,port...]\n"
30 " --dports ...\n"
31 " match destination port(s)\n"
32 " --ports port[,port,port]\n"
33 " match both source and destination port(s)\n"
34 " NOTE: this kernel does not support port ranges in multiport.\n");
35 }
36
multiport_help_v1(void)37 static void multiport_help_v1(void)
38 {
39 printf(
40 "multiport match options:\n"
41 "[!] --source-ports port[,port:port,port...]\n"
42 " --sports ...\n"
43 " match source port(s)\n"
44 "[!] --destination-ports port[,port:port,port...]\n"
45 " --dports ...\n"
46 " match destination port(s)\n"
47 "[!] --ports port[,port:port,port]\n"
48 " match both source and destination port(s)\n");
49 }
50
51 static const struct xt_option_entry multiport_opts[] = {
52 {.name = "source-ports", .id = O_SOURCE_PORTS, .type = XTTYPE_STRING,
53 .excl = F_ANY, .flags = XTOPT_INVERT},
54 {.name = "sports", .id = O_SOURCE_PORTS, .type = XTTYPE_STRING,
55 .excl = F_ANY, .flags = XTOPT_INVERT},
56 {.name = "destination-ports", .id = O_DEST_PORTS,
57 .type = XTTYPE_STRING, .excl = F_ANY, .flags = XTOPT_INVERT},
58 {.name = "dports", .id = O_DEST_PORTS, .type = XTTYPE_STRING,
59 .excl = F_ANY, .flags = XTOPT_INVERT},
60 {.name = "ports", .id = O_SD_PORTS, .type = XTTYPE_STRING,
61 .excl = F_ANY, .flags = XTOPT_INVERT},
62 XTOPT_TABLEEND,
63 };
64
65 static const char *
proto_to_name(uint8_t proto)66 proto_to_name(uint8_t proto)
67 {
68 switch (proto) {
69 case IPPROTO_TCP:
70 return "tcp";
71 case IPPROTO_UDP:
72 return "udp";
73 case IPPROTO_UDPLITE:
74 return "udplite";
75 case IPPROTO_SCTP:
76 return "sctp";
77 case IPPROTO_DCCP:
78 return "dccp";
79 default:
80 return NULL;
81 }
82 }
83
84 static unsigned int
parse_multi_ports(const char * portstring,uint16_t * ports,const char * proto)85 parse_multi_ports(const char *portstring, uint16_t *ports, const char *proto)
86 {
87 char *buffer, *cp, *next;
88 unsigned int i;
89
90 buffer = strdup(portstring);
91 if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
92
93 for (cp=buffer, i=0; cp && i<XT_MULTI_PORTS; cp=next,i++)
94 {
95 next=strchr(cp, ',');
96 if (next) *next++='\0';
97 ports[i] = xtables_parse_port(cp, proto);
98 }
99 if (cp) xtables_error(PARAMETER_PROBLEM, "too many ports specified");
100 free(buffer);
101 return i;
102 }
103
104 static void
parse_multi_ports_v1(const char * portstring,struct xt_multiport_v1 * multiinfo,const char * proto)105 parse_multi_ports_v1(const char *portstring,
106 struct xt_multiport_v1 *multiinfo,
107 const char *proto)
108 {
109 char *buffer, *cp, *next, *range;
110 unsigned int i;
111
112 buffer = strdup(portstring);
113 if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
114
115 for (i=0; i<XT_MULTI_PORTS; i++)
116 multiinfo->pflags[i] = 0;
117
118 for (cp=buffer, i=0; cp && i<XT_MULTI_PORTS; cp=next, i++) {
119 next=strchr(cp, ',');
120 if (next) *next++='\0';
121 range = strchr(cp, ':');
122 if (range) {
123 if (i == XT_MULTI_PORTS-1)
124 xtables_error(PARAMETER_PROBLEM,
125 "too many ports specified");
126 *range++ = '\0';
127 }
128 multiinfo->ports[i] = xtables_parse_port(cp, proto);
129 if (range) {
130 multiinfo->pflags[i] = 1;
131 multiinfo->ports[++i] = xtables_parse_port(range, proto);
132 if (multiinfo->ports[i-1] >= multiinfo->ports[i])
133 xtables_error(PARAMETER_PROBLEM,
134 "invalid portrange specified");
135 }
136 }
137 multiinfo->count = i;
138 if (cp) xtables_error(PARAMETER_PROBLEM, "too many ports specified");
139 free(buffer);
140 }
141
142 static const char *
check_proto(uint16_t pnum,uint8_t invflags)143 check_proto(uint16_t pnum, uint8_t invflags)
144 {
145 const char *proto;
146
147 if (invflags & XT_INV_PROTO)
148 xtables_error(PARAMETER_PROBLEM,
149 "multiport only works with TCP, UDP, UDPLITE, SCTP and DCCP");
150
151 if ((proto = proto_to_name(pnum)) != NULL)
152 return proto;
153 else if (!pnum)
154 xtables_error(PARAMETER_PROBLEM,
155 "multiport needs `-p tcp', `-p udp', `-p udplite', "
156 "`-p sctp' or `-p dccp'");
157 else
158 xtables_error(PARAMETER_PROBLEM,
159 "multiport only works with TCP, UDP, UDPLITE, SCTP and DCCP");
160 }
161
__multiport_parse(struct xt_option_call * cb,uint16_t pnum,uint8_t invflags)162 static void __multiport_parse(struct xt_option_call *cb, uint16_t pnum,
163 uint8_t invflags)
164 {
165 const char *proto;
166 struct xt_multiport *multiinfo = cb->data;
167
168 xtables_option_parse(cb);
169 switch (cb->entry->id) {
170 case O_SOURCE_PORTS:
171 proto = check_proto(pnum, invflags);
172 multiinfo->count = parse_multi_ports(cb->arg,
173 multiinfo->ports, proto);
174 multiinfo->flags = XT_MULTIPORT_SOURCE;
175 break;
176 case O_DEST_PORTS:
177 proto = check_proto(pnum, invflags);
178 multiinfo->count = parse_multi_ports(cb->arg,
179 multiinfo->ports, proto);
180 multiinfo->flags = XT_MULTIPORT_DESTINATION;
181 break;
182 case O_SD_PORTS:
183 proto = check_proto(pnum, invflags);
184 multiinfo->count = parse_multi_ports(cb->arg,
185 multiinfo->ports, proto);
186 multiinfo->flags = XT_MULTIPORT_EITHER;
187 break;
188 }
189 if (cb->invert)
190 xtables_error(PARAMETER_PROBLEM,
191 "multiport.0 does not support invert");
192 }
193
multiport_parse(struct xt_option_call * cb)194 static void multiport_parse(struct xt_option_call *cb)
195 {
196 const struct ipt_entry *entry = cb->xt_entry;
197 return __multiport_parse(cb,
198 entry->ip.proto, entry->ip.invflags);
199 }
200
multiport_parse6(struct xt_option_call * cb)201 static void multiport_parse6(struct xt_option_call *cb)
202 {
203 const struct ip6t_entry *entry = cb->xt_entry;
204 return __multiport_parse(cb,
205 entry->ipv6.proto, entry->ipv6.invflags);
206 }
207
__multiport_parse_v1(struct xt_option_call * cb,uint16_t pnum,uint8_t invflags)208 static void __multiport_parse_v1(struct xt_option_call *cb, uint16_t pnum,
209 uint8_t invflags)
210 {
211 const char *proto;
212 struct xt_multiport_v1 *multiinfo = cb->data;
213
214 xtables_option_parse(cb);
215 switch (cb->entry->id) {
216 case O_SOURCE_PORTS:
217 proto = check_proto(pnum, invflags);
218 parse_multi_ports_v1(cb->arg, multiinfo, proto);
219 multiinfo->flags = XT_MULTIPORT_SOURCE;
220 break;
221 case O_DEST_PORTS:
222 proto = check_proto(pnum, invflags);
223 parse_multi_ports_v1(cb->arg, multiinfo, proto);
224 multiinfo->flags = XT_MULTIPORT_DESTINATION;
225 break;
226 case O_SD_PORTS:
227 proto = check_proto(pnum, invflags);
228 parse_multi_ports_v1(cb->arg, multiinfo, proto);
229 multiinfo->flags = XT_MULTIPORT_EITHER;
230 break;
231 }
232 if (cb->invert)
233 multiinfo->invert = 1;
234 }
235
multiport_parse_v1(struct xt_option_call * cb)236 static void multiport_parse_v1(struct xt_option_call *cb)
237 {
238 const struct ipt_entry *entry = cb->xt_entry;
239 return __multiport_parse_v1(cb,
240 entry->ip.proto, entry->ip.invflags);
241 }
242
multiport_parse6_v1(struct xt_option_call * cb)243 static void multiport_parse6_v1(struct xt_option_call *cb)
244 {
245 const struct ip6t_entry *entry = cb->xt_entry;
246 return __multiport_parse_v1(cb,
247 entry->ipv6.proto, entry->ipv6.invflags);
248 }
249
multiport_check(struct xt_fcheck_call * cb)250 static void multiport_check(struct xt_fcheck_call *cb)
251 {
252 if (cb->xflags == 0)
253 xtables_error(PARAMETER_PROBLEM, "multiport expection an option");
254 }
255
256 static const char *
port_to_service(int port,uint8_t proto)257 port_to_service(int port, uint8_t proto)
258 {
259 const struct servent *service;
260
261 if ((service = getservbyport(htons(port), proto_to_name(proto))))
262 return service->s_name;
263
264 return NULL;
265 }
266
267 static void
print_port(uint16_t port,uint8_t protocol,int numeric)268 print_port(uint16_t port, uint8_t protocol, int numeric)
269 {
270 const char *service;
271
272 if (numeric || (service = port_to_service(port, protocol)) == NULL)
273 printf("%u", port);
274 else
275 printf("%s", service);
276 }
277
278 static void
__multiport_print(const struct xt_entry_match * match,int numeric,uint16_t proto)279 __multiport_print(const struct xt_entry_match *match, int numeric,
280 uint16_t proto)
281 {
282 const struct xt_multiport *multiinfo
283 = (const struct xt_multiport *)match->data;
284 unsigned int i;
285
286 printf(" multiport ");
287
288 switch (multiinfo->flags) {
289 case XT_MULTIPORT_SOURCE:
290 printf("sports ");
291 break;
292
293 case XT_MULTIPORT_DESTINATION:
294 printf("dports ");
295 break;
296
297 case XT_MULTIPORT_EITHER:
298 printf("ports ");
299 break;
300
301 default:
302 printf("ERROR ");
303 break;
304 }
305
306 for (i=0; i < multiinfo->count; i++) {
307 printf("%s", i ? "," : "");
308 print_port(multiinfo->ports[i], proto, numeric);
309 }
310 }
311
multiport_print(const void * ip_void,const struct xt_entry_match * match,int numeric)312 static void multiport_print(const void *ip_void,
313 const struct xt_entry_match *match, int numeric)
314 {
315 const struct ipt_ip *ip = ip_void;
316 __multiport_print(match, numeric, ip->proto);
317 }
318
multiport_print6(const void * ip_void,const struct xt_entry_match * match,int numeric)319 static void multiport_print6(const void *ip_void,
320 const struct xt_entry_match *match, int numeric)
321 {
322 const struct ip6t_ip6 *ip = ip_void;
323 __multiport_print(match, numeric, ip->proto);
324 }
325
__multiport_print_v1(const struct xt_entry_match * match,int numeric,uint16_t proto)326 static void __multiport_print_v1(const struct xt_entry_match *match,
327 int numeric, uint16_t proto)
328 {
329 const struct xt_multiport_v1 *multiinfo
330 = (const struct xt_multiport_v1 *)match->data;
331 unsigned int i;
332
333 printf(" multiport ");
334
335 switch (multiinfo->flags) {
336 case XT_MULTIPORT_SOURCE:
337 printf("sports ");
338 break;
339
340 case XT_MULTIPORT_DESTINATION:
341 printf("dports ");
342 break;
343
344 case XT_MULTIPORT_EITHER:
345 printf("ports ");
346 break;
347
348 default:
349 printf("ERROR ");
350 break;
351 }
352
353 if (multiinfo->invert)
354 printf(" !");
355
356 for (i=0; i < multiinfo->count; i++) {
357 printf("%s", i ? "," : "");
358 print_port(multiinfo->ports[i], proto, numeric);
359 if (multiinfo->pflags[i]) {
360 printf(":");
361 print_port(multiinfo->ports[++i], proto, numeric);
362 }
363 }
364 }
365
multiport_print_v1(const void * ip_void,const struct xt_entry_match * match,int numeric)366 static void multiport_print_v1(const void *ip_void,
367 const struct xt_entry_match *match, int numeric)
368 {
369 const struct ipt_ip *ip = ip_void;
370 __multiport_print_v1(match, numeric, ip->proto);
371 }
372
multiport_print6_v1(const void * ip_void,const struct xt_entry_match * match,int numeric)373 static void multiport_print6_v1(const void *ip_void,
374 const struct xt_entry_match *match, int numeric)
375 {
376 const struct ip6t_ip6 *ip = ip_void;
377 __multiport_print_v1(match, numeric, ip->proto);
378 }
379
__multiport_save(const struct xt_entry_match * match,uint16_t proto)380 static void __multiport_save(const struct xt_entry_match *match,
381 uint16_t proto)
382 {
383 const struct xt_multiport *multiinfo
384 = (const struct xt_multiport *)match->data;
385 unsigned int i;
386
387 switch (multiinfo->flags) {
388 case XT_MULTIPORT_SOURCE:
389 printf(" --sports ");
390 break;
391
392 case XT_MULTIPORT_DESTINATION:
393 printf(" --dports ");
394 break;
395
396 case XT_MULTIPORT_EITHER:
397 printf(" --ports ");
398 break;
399 }
400
401 for (i=0; i < multiinfo->count; i++) {
402 printf("%s", i ? "," : "");
403 print_port(multiinfo->ports[i], proto, 1);
404 }
405 }
406
multiport_save(const void * ip_void,const struct xt_entry_match * match)407 static void multiport_save(const void *ip_void,
408 const struct xt_entry_match *match)
409 {
410 const struct ipt_ip *ip = ip_void;
411 __multiport_save(match, ip->proto);
412 }
413
multiport_save6(const void * ip_void,const struct xt_entry_match * match)414 static void multiport_save6(const void *ip_void,
415 const struct xt_entry_match *match)
416 {
417 const struct ip6t_ip6 *ip = ip_void;
418 __multiport_save(match, ip->proto);
419 }
420
__multiport_save_v1(const struct xt_entry_match * match,uint16_t proto)421 static void __multiport_save_v1(const struct xt_entry_match *match,
422 uint16_t proto)
423 {
424 const struct xt_multiport_v1 *multiinfo
425 = (const struct xt_multiport_v1 *)match->data;
426 unsigned int i;
427
428 if (multiinfo->invert)
429 printf(" !");
430
431 switch (multiinfo->flags) {
432 case XT_MULTIPORT_SOURCE:
433 printf(" --sports ");
434 break;
435
436 case XT_MULTIPORT_DESTINATION:
437 printf(" --dports ");
438 break;
439
440 case XT_MULTIPORT_EITHER:
441 printf(" --ports ");
442 break;
443 }
444
445 for (i=0; i < multiinfo->count; i++) {
446 printf("%s", i ? "," : "");
447 print_port(multiinfo->ports[i], proto, 1);
448 if (multiinfo->pflags[i]) {
449 printf(":");
450 print_port(multiinfo->ports[++i], proto, 1);
451 }
452 }
453 }
454
multiport_save_v1(const void * ip_void,const struct xt_entry_match * match)455 static void multiport_save_v1(const void *ip_void,
456 const struct xt_entry_match *match)
457 {
458 const struct ipt_ip *ip = ip_void;
459 __multiport_save_v1(match, ip->proto);
460 }
461
multiport_save6_v1(const void * ip_void,const struct xt_entry_match * match)462 static void multiport_save6_v1(const void *ip_void,
463 const struct xt_entry_match *match)
464 {
465 const struct ip6t_ip6 *ip = ip_void;
466 __multiport_save_v1(match, ip->proto);
467 }
468
__multiport_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)469 static int __multiport_xlate(struct xt_xlate *xl,
470 const struct xt_xlate_mt_params *params)
471 {
472 const struct xt_multiport *multiinfo
473 = (const struct xt_multiport *)params->match->data;
474 unsigned int i;
475
476 switch (multiinfo->flags) {
477 case XT_MULTIPORT_SOURCE:
478 xt_xlate_add(xl, " sport ");
479 break;
480 case XT_MULTIPORT_DESTINATION:
481 xt_xlate_add(xl, " dport ");
482 break;
483 case XT_MULTIPORT_EITHER:
484 return 0;
485 }
486
487 if (multiinfo->count > 1)
488 xt_xlate_add(xl, "{ ");
489
490 for (i = 0; i < multiinfo->count; i++)
491 xt_xlate_add(xl, "%s%u", i ? "," : "", multiinfo->ports[i]);
492
493 if (multiinfo->count > 1)
494 xt_xlate_add(xl, "}");
495
496 return 1;
497 }
498
multiport_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)499 static int multiport_xlate(struct xt_xlate *xl,
500 const struct xt_xlate_mt_params *params)
501 {
502 uint8_t proto = ((const struct ipt_ip *)params->ip)->proto;
503
504 xt_xlate_add(xl, "%s", proto_to_name(proto));
505 return __multiport_xlate(xl, params);
506 }
507
multiport_xlate6(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)508 static int multiport_xlate6(struct xt_xlate *xl,
509 const struct xt_xlate_mt_params *params)
510 {
511 uint8_t proto = ((const struct ip6t_ip6 *)params->ip)->proto;
512
513 xt_xlate_add(xl, "%s", proto_to_name(proto));
514 return __multiport_xlate(xl, params);
515 }
516
__multiport_xlate_v1(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)517 static int __multiport_xlate_v1(struct xt_xlate *xl,
518 const struct xt_xlate_mt_params *params)
519 {
520 const struct xt_multiport_v1 *multiinfo =
521 (const struct xt_multiport_v1 *)params->match->data;
522 unsigned int i;
523
524 switch (multiinfo->flags) {
525 case XT_MULTIPORT_SOURCE:
526 xt_xlate_add(xl, " sport ");
527 break;
528 case XT_MULTIPORT_DESTINATION:
529 xt_xlate_add(xl, " dport ");
530 break;
531 case XT_MULTIPORT_EITHER:
532 return 0;
533 }
534
535 if (multiinfo->invert)
536 xt_xlate_add(xl, "!= ");
537
538 if (multiinfo->count > 2 ||
539 (multiinfo->count > 1 && !multiinfo->pflags[0]))
540 xt_xlate_add(xl, "{ ");
541
542 for (i = 0; i < multiinfo->count; i++) {
543 xt_xlate_add(xl, "%s%u", i ? "," : "", multiinfo->ports[i]);
544 if (multiinfo->pflags[i])
545 xt_xlate_add(xl, "-%u", multiinfo->ports[++i]);
546 }
547
548 if (multiinfo->count > 2 ||
549 (multiinfo->count > 1 && !multiinfo->pflags[0]))
550 xt_xlate_add(xl, "}");
551
552 return 1;
553 }
554
multiport_xlate_v1(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)555 static int multiport_xlate_v1(struct xt_xlate *xl,
556 const struct xt_xlate_mt_params *params)
557 {
558 uint8_t proto = ((const struct ipt_ip *)params->ip)->proto;
559
560 xt_xlate_add(xl, "%s", proto_to_name(proto));
561 return __multiport_xlate_v1(xl, params);
562 }
563
multiport_xlate6_v1(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)564 static int multiport_xlate6_v1(struct xt_xlate *xl,
565 const struct xt_xlate_mt_params *params)
566 {
567 uint8_t proto = ((const struct ip6t_ip6 *)params->ip)->proto;
568
569 xt_xlate_add(xl, "%s", proto_to_name(proto));
570 return __multiport_xlate_v1(xl, params);
571 }
572
573 static struct xtables_match multiport_mt_reg[] = {
574 {
575 .family = NFPROTO_IPV4,
576 .name = "multiport",
577 .revision = 0,
578 .version = XTABLES_VERSION,
579 .size = XT_ALIGN(sizeof(struct xt_multiport)),
580 .userspacesize = XT_ALIGN(sizeof(struct xt_multiport)),
581 .help = multiport_help,
582 .x6_parse = multiport_parse,
583 .x6_fcheck = multiport_check,
584 .print = multiport_print,
585 .save = multiport_save,
586 .x6_options = multiport_opts,
587 .xlate = multiport_xlate,
588 },
589 {
590 .family = NFPROTO_IPV6,
591 .name = "multiport",
592 .revision = 0,
593 .version = XTABLES_VERSION,
594 .size = XT_ALIGN(sizeof(struct xt_multiport)),
595 .userspacesize = XT_ALIGN(sizeof(struct xt_multiport)),
596 .help = multiport_help,
597 .x6_parse = multiport_parse6,
598 .x6_fcheck = multiport_check,
599 .print = multiport_print6,
600 .save = multiport_save6,
601 .x6_options = multiport_opts,
602 .xlate = multiport_xlate6,
603 },
604 {
605 .family = NFPROTO_IPV4,
606 .name = "multiport",
607 .version = XTABLES_VERSION,
608 .revision = 1,
609 .size = XT_ALIGN(sizeof(struct xt_multiport_v1)),
610 .userspacesize = XT_ALIGN(sizeof(struct xt_multiport_v1)),
611 .help = multiport_help_v1,
612 .x6_parse = multiport_parse_v1,
613 .x6_fcheck = multiport_check,
614 .print = multiport_print_v1,
615 .save = multiport_save_v1,
616 .x6_options = multiport_opts,
617 .xlate = multiport_xlate_v1,
618 },
619 {
620 .family = NFPROTO_IPV6,
621 .name = "multiport",
622 .version = XTABLES_VERSION,
623 .revision = 1,
624 .size = XT_ALIGN(sizeof(struct xt_multiport_v1)),
625 .userspacesize = XT_ALIGN(sizeof(struct xt_multiport_v1)),
626 .help = multiport_help_v1,
627 .x6_parse = multiport_parse6_v1,
628 .x6_fcheck = multiport_check,
629 .print = multiport_print6_v1,
630 .save = multiport_save6_v1,
631 .x6_options = multiport_opts,
632 .xlate = multiport_xlate6_v1,
633 },
634 };
635
636 void
_init(void)637 _init(void)
638 {
639 xtables_register_matches(multiport_mt_reg, ARRAY_SIZE(multiport_mt_reg));
640 }
641