• 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 = 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