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