• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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