Home | History | Annotate | Download | only in extensions
      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. */
     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 
     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 *
     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
     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
    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 	uint16_t m;
    112 
    113 	buffer = strdup(portstring);
    114 	if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
    115 
    116 	for (i=0; i<XT_MULTI_PORTS; i++)
    117 		multiinfo->pflags[i] = 0;
    118 
    119 	for (cp=buffer, i=0; cp && i<XT_MULTI_PORTS; cp=next, i++) {
    120 		next=strchr(cp, ',');
    121  		if (next) *next++='\0';
    122 		range = strchr(cp, ':');
    123 		if (range) {
    124 			if (i == XT_MULTI_PORTS-1)
    125 				xtables_error(PARAMETER_PROBLEM,
    126 					   "too many ports specified");
    127 			*range++ = '\0';
    128 		}
    129 		multiinfo->ports[i] = xtables_parse_port(cp, proto);
    130 		if (range) {
    131 			multiinfo->pflags[i] = 1;
    132 			multiinfo->ports[++i] = xtables_parse_port(range, proto);
    133 			if (multiinfo->ports[i-1] >= multiinfo->ports[i])
    134 				xtables_error(PARAMETER_PROBLEM,
    135 					   "invalid portrange specified");
    136 			m <<= 1;
    137 		}
    138  	}
    139 	multiinfo->count = i;
    140 	if (cp) xtables_error(PARAMETER_PROBLEM, "too many ports specified");
    141  	free(buffer);
    142 }
    143 
    144 static const char *
    145 check_proto(uint16_t pnum, uint8_t invflags)
    146 {
    147 	const char *proto;
    148 
    149 	if (invflags & XT_INV_PROTO)
    150 		xtables_error(PARAMETER_PROBLEM,
    151 			   "multiport only works with TCP, UDP, UDPLITE, SCTP and DCCP");
    152 
    153 	if ((proto = proto_to_name(pnum)) != NULL)
    154 		return proto;
    155 	else if (!pnum)
    156 		xtables_error(PARAMETER_PROBLEM,
    157 			   "multiport needs `-p tcp', `-p udp', `-p udplite', "
    158 			   "`-p sctp' or `-p dccp'");
    159 	else
    160 		xtables_error(PARAMETER_PROBLEM,
    161 			   "multiport only works with TCP, UDP, UDPLITE, SCTP and DCCP");
    162 }
    163 
    164 static void __multiport_parse(struct xt_option_call *cb, uint16_t pnum,
    165 			      uint8_t invflags)
    166 {
    167 	const char *proto;
    168 	struct xt_multiport *multiinfo = cb->data;
    169 
    170 	xtables_option_parse(cb);
    171 	switch (cb->entry->id) {
    172 	case O_SOURCE_PORTS:
    173 		proto = check_proto(pnum, invflags);
    174 		multiinfo->count = parse_multi_ports(cb->arg,
    175 						     multiinfo->ports, proto);
    176 		multiinfo->flags = XT_MULTIPORT_SOURCE;
    177 		break;
    178 	case O_DEST_PORTS:
    179 		proto = check_proto(pnum, invflags);
    180 		multiinfo->count = parse_multi_ports(cb->arg,
    181 						     multiinfo->ports, proto);
    182 		multiinfo->flags = XT_MULTIPORT_DESTINATION;
    183 		break;
    184 	case O_SD_PORTS:
    185 		proto = check_proto(pnum, invflags);
    186 		multiinfo->count = parse_multi_ports(cb->arg,
    187 						     multiinfo->ports, proto);
    188 		multiinfo->flags = XT_MULTIPORT_EITHER;
    189 		break;
    190 	}
    191 	if (cb->invert)
    192 		xtables_error(PARAMETER_PROBLEM,
    193 			   "multiport.0 does not support invert");
    194 }
    195 
    196 static void multiport_parse(struct xt_option_call *cb)
    197 {
    198 	const struct ipt_entry *entry = cb->xt_entry;
    199 	return __multiport_parse(cb,
    200 	       entry->ip.proto, entry->ip.invflags);
    201 }
    202 
    203 static void multiport_parse6(struct xt_option_call *cb)
    204 {
    205 	const struct ip6t_entry *entry = cb->xt_entry;
    206 	return __multiport_parse(cb,
    207 	       entry->ipv6.proto, entry->ipv6.invflags);
    208 }
    209 
    210 static void __multiport_parse_v1(struct xt_option_call *cb, uint16_t pnum,
    211 				 uint8_t invflags)
    212 {
    213 	const char *proto;
    214 	struct xt_multiport_v1 *multiinfo = cb->data;
    215 
    216 	xtables_option_parse(cb);
    217 	switch (cb->entry->id) {
    218 	case O_SOURCE_PORTS:
    219 		proto = check_proto(pnum, invflags);
    220 		parse_multi_ports_v1(cb->arg, multiinfo, proto);
    221 		multiinfo->flags = XT_MULTIPORT_SOURCE;
    222 		break;
    223 	case O_DEST_PORTS:
    224 		proto = check_proto(pnum, invflags);
    225 		parse_multi_ports_v1(cb->arg, multiinfo, proto);
    226 		multiinfo->flags = XT_MULTIPORT_DESTINATION;
    227 		break;
    228 	case O_SD_PORTS:
    229 		proto = check_proto(pnum, invflags);
    230 		parse_multi_ports_v1(cb->arg, multiinfo, proto);
    231 		multiinfo->flags = XT_MULTIPORT_EITHER;
    232 		break;
    233 	}
    234 	if (cb->invert)
    235 		multiinfo->invert = 1;
    236 }
    237 
    238 static void multiport_parse_v1(struct xt_option_call *cb)
    239 {
    240 	const struct ipt_entry *entry = cb->xt_entry;
    241 	return __multiport_parse_v1(cb,
    242 	       entry->ip.proto, entry->ip.invflags);
    243 }
    244 
    245 static void multiport_parse6_v1(struct xt_option_call *cb)
    246 {
    247 	const struct ip6t_entry *entry = cb->xt_entry;
    248 	return __multiport_parse_v1(cb,
    249 	       entry->ipv6.proto, entry->ipv6.invflags);
    250 }
    251 
    252 static void multiport_check(struct xt_fcheck_call *cb)
    253 {
    254 	if (cb->xflags == 0)
    255 		xtables_error(PARAMETER_PROBLEM, "multiport expection an option");
    256 }
    257 
    258 static const char *
    259 port_to_service(int port, uint8_t proto)
    260 {
    261 	const struct servent *service;
    262 
    263 	if ((service = getservbyport(htons(port), proto_to_name(proto))))
    264 		return service->s_name;
    265 
    266 	return NULL;
    267 }
    268 
    269 static void
    270 print_port(uint16_t port, uint8_t protocol, int numeric)
    271 {
    272 	const char *service;
    273 
    274 	if (numeric || (service = port_to_service(port, protocol)) == NULL)
    275 		printf("%u", port);
    276 	else
    277 		printf("%s", service);
    278 }
    279 
    280 static void
    281 __multiport_print(const struct xt_entry_match *match, int numeric,
    282                   uint16_t proto)
    283 {
    284 	const struct xt_multiport *multiinfo
    285 		= (const struct xt_multiport *)match->data;
    286 	unsigned int i;
    287 
    288 	printf(" multiport ");
    289 
    290 	switch (multiinfo->flags) {
    291 	case XT_MULTIPORT_SOURCE:
    292 		printf("sports ");
    293 		break;
    294 
    295 	case XT_MULTIPORT_DESTINATION:
    296 		printf("dports ");
    297 		break;
    298 
    299 	case XT_MULTIPORT_EITHER:
    300 		printf("ports ");
    301 		break;
    302 
    303 	default:
    304 		printf("ERROR ");
    305 		break;
    306 	}
    307 
    308 	for (i=0; i < multiinfo->count; i++) {
    309 		printf("%s", i ? "," : "");
    310 		print_port(multiinfo->ports[i], proto, numeric);
    311 	}
    312 }
    313 
    314 static void multiport_print(const void *ip_void,
    315                             const struct xt_entry_match *match, int numeric)
    316 {
    317 	const struct ipt_ip *ip = ip_void;
    318 	__multiport_print(match, numeric, ip->proto);
    319 }
    320 
    321 static void multiport_print6(const void *ip_void,
    322                              const struct xt_entry_match *match, int numeric)
    323 {
    324 	const struct ip6t_ip6 *ip = ip_void;
    325 	__multiport_print(match, numeric, ip->proto);
    326 }
    327 
    328 static void __multiport_print_v1(const struct xt_entry_match *match,
    329                                  int numeric, uint16_t proto)
    330 {
    331 	const struct xt_multiport_v1 *multiinfo
    332 		= (const struct xt_multiport_v1 *)match->data;
    333 	unsigned int i;
    334 
    335 	printf(" multiport ");
    336 
    337 	switch (multiinfo->flags) {
    338 	case XT_MULTIPORT_SOURCE:
    339 		printf("sports ");
    340 		break;
    341 
    342 	case XT_MULTIPORT_DESTINATION:
    343 		printf("dports ");
    344 		break;
    345 
    346 	case XT_MULTIPORT_EITHER:
    347 		printf("ports ");
    348 		break;
    349 
    350 	default:
    351 		printf("ERROR ");
    352 		break;
    353 	}
    354 
    355 	if (multiinfo->invert)
    356 		printf(" !");
    357 
    358 	for (i=0; i < multiinfo->count; i++) {
    359 		printf("%s", i ? "," : "");
    360 		print_port(multiinfo->ports[i], proto, numeric);
    361 		if (multiinfo->pflags[i]) {
    362 			printf(":");
    363 			print_port(multiinfo->ports[++i], proto, numeric);
    364 		}
    365 	}
    366 }
    367 
    368 static void multiport_print_v1(const void *ip_void,
    369                                const struct xt_entry_match *match, int numeric)
    370 {
    371 	const struct ipt_ip *ip = ip_void;
    372 	__multiport_print_v1(match, numeric, ip->proto);
    373 }
    374 
    375 static void multiport_print6_v1(const void *ip_void,
    376                                 const struct xt_entry_match *match, int numeric)
    377 {
    378 	const struct ip6t_ip6 *ip = ip_void;
    379 	__multiport_print_v1(match, numeric, ip->proto);
    380 }
    381 
    382 static void __multiport_save(const struct xt_entry_match *match,
    383                              uint16_t proto)
    384 {
    385 	const struct xt_multiport *multiinfo
    386 		= (const struct xt_multiport *)match->data;
    387 	unsigned int i;
    388 
    389 	switch (multiinfo->flags) {
    390 	case XT_MULTIPORT_SOURCE:
    391 		printf(" --sports ");
    392 		break;
    393 
    394 	case XT_MULTIPORT_DESTINATION:
    395 		printf(" --dports ");
    396 		break;
    397 
    398 	case XT_MULTIPORT_EITHER:
    399 		printf(" --ports ");
    400 		break;
    401 	}
    402 
    403 	for (i=0; i < multiinfo->count; i++) {
    404 		printf("%s", i ? "," : "");
    405 		print_port(multiinfo->ports[i], proto, 1);
    406 	}
    407 }
    408 
    409 static void multiport_save(const void *ip_void,
    410                            const struct xt_entry_match *match)
    411 {
    412 	const struct ipt_ip *ip = ip_void;
    413 	__multiport_save(match, ip->proto);
    414 }
    415 
    416 static void multiport_save6(const void *ip_void,
    417                             const struct xt_entry_match *match)
    418 {
    419 	const struct ip6t_ip6 *ip = ip_void;
    420 	__multiport_save(match, ip->proto);
    421 }
    422 
    423 static void __multiport_save_v1(const struct xt_entry_match *match,
    424                                 uint16_t proto)
    425 {
    426 	const struct xt_multiport_v1 *multiinfo
    427 		= (const struct xt_multiport_v1 *)match->data;
    428 	unsigned int i;
    429 
    430 	if (multiinfo->invert)
    431 		printf(" !");
    432 
    433 	switch (multiinfo->flags) {
    434 	case XT_MULTIPORT_SOURCE:
    435 		printf(" --sports ");
    436 		break;
    437 
    438 	case XT_MULTIPORT_DESTINATION:
    439 		printf(" --dports ");
    440 		break;
    441 
    442 	case XT_MULTIPORT_EITHER:
    443 		printf(" --ports ");
    444 		break;
    445 	}
    446 
    447 	for (i=0; i < multiinfo->count; i++) {
    448 		printf("%s", i ? "," : "");
    449 		print_port(multiinfo->ports[i], proto, 1);
    450 		if (multiinfo->pflags[i]) {
    451 			printf(":");
    452 			print_port(multiinfo->ports[++i], proto, 1);
    453 		}
    454 	}
    455 }
    456 
    457 static void multiport_save_v1(const void *ip_void,
    458                               const struct xt_entry_match *match)
    459 {
    460 	const struct ipt_ip *ip = ip_void;
    461 	__multiport_save_v1(match, ip->proto);
    462 }
    463 
    464 static void multiport_save6_v1(const void *ip_void,
    465                                const struct xt_entry_match *match)
    466 {
    467 	const struct ip6t_ip6 *ip = ip_void;
    468 	__multiport_save_v1(match, ip->proto);
    469 }
    470 
    471 static struct xtables_match multiport_mt_reg[] = {
    472 	{
    473 		.family        = NFPROTO_IPV4,
    474 		.name          = "multiport",
    475 		.revision      = 0,
    476 		.version       = XTABLES_VERSION,
    477 		.size          = XT_ALIGN(sizeof(struct xt_multiport)),
    478 		.userspacesize = XT_ALIGN(sizeof(struct xt_multiport)),
    479 		.help          = multiport_help,
    480 		.x6_parse      = multiport_parse,
    481 		.x6_fcheck     = multiport_check,
    482 		.print         = multiport_print,
    483 		.save          = multiport_save,
    484 		.x6_options    = multiport_opts,
    485 	},
    486 	{
    487 		.family        = NFPROTO_IPV6,
    488 		.name          = "multiport",
    489 		.revision      = 0,
    490 		.version       = XTABLES_VERSION,
    491 		.size          = XT_ALIGN(sizeof(struct xt_multiport)),
    492 		.userspacesize = XT_ALIGN(sizeof(struct xt_multiport)),
    493 		.help          = multiport_help,
    494 		.x6_parse      = multiport_parse6,
    495 		.x6_fcheck     = multiport_check,
    496 		.print         = multiport_print6,
    497 		.save          = multiport_save6,
    498 		.x6_options    = multiport_opts,
    499 	},
    500 	{
    501 		.family        = NFPROTO_IPV4,
    502 		.name          = "multiport",
    503 		.version       = XTABLES_VERSION,
    504 		.revision      = 1,
    505 		.size          = XT_ALIGN(sizeof(struct xt_multiport_v1)),
    506 		.userspacesize = XT_ALIGN(sizeof(struct xt_multiport_v1)),
    507 		.help          = multiport_help_v1,
    508 		.x6_parse      = multiport_parse_v1,
    509 		.x6_fcheck     = multiport_check,
    510 		.print         = multiport_print_v1,
    511 		.save          = multiport_save_v1,
    512 		.x6_options    = multiport_opts,
    513 	},
    514 	{
    515 		.family        = NFPROTO_IPV6,
    516 		.name          = "multiport",
    517 		.version       = XTABLES_VERSION,
    518 		.revision      = 1,
    519 		.size          = XT_ALIGN(sizeof(struct xt_multiport_v1)),
    520 		.userspacesize = XT_ALIGN(sizeof(struct xt_multiport_v1)),
    521 		.help          = multiport_help_v1,
    522 		.x6_parse      = multiport_parse6_v1,
    523 		.x6_fcheck     = multiport_check,
    524 		.print         = multiport_print6_v1,
    525 		.save          = multiport_save6_v1,
    526 		.x6_options    = multiport_opts,
    527 	},
    528 };
    529 
    530 void
    531 _init(void)
    532 {
    533 	xtables_register_matches(multiport_mt_reg, ARRAY_SIZE(multiport_mt_reg));
    534 }
    535