1/* Shared library add-on to iptables to add multiple TCP port support. */ 2#include <stdio.h> 3#include <netdb.h> 4#include <string.h> 5#include <stdlib.h> 6#include <getopt.h> 7#include <ip6tables.h> 8/* To ensure that iptables compiles with an old kernel */ 9#include "../include/linux/netfilter_ipv6/ip6t_multiport.h" 10 11/* Function which prints out usage message. */ 12#if 0 13static void 14help(void) 15{ 16 printf( 17"multiport v%s options:\n" 18" --source-ports port[,port,port...]\n" 19" --sports ...\n" 20" match source port(s)\n" 21" --destination-ports port[,port,port...]\n" 22" --dports ...\n" 23" match destination port(s)\n" 24" --ports port[,port,port]\n" 25" match both source and destination port(s)\n" 26" NOTE: this kernel does not support port ranges in multiport.\n", 27IPTABLES_VERSION); 28} 29#endif 30 31static void 32help_v1(void) 33{ 34 printf( 35"multiport v%s options:\n" 36" --source-ports [!] port[,port:port,port...]\n" 37" --sports ...\n" 38" match source port(s)\n" 39" --destination-ports [!] port[,port:port,port...]\n" 40" --dports ...\n" 41" match destination port(s)\n" 42" --ports [!] port[,port:port,port]\n" 43" match both source and destination port(s)\n", 44IPTABLES_VERSION); 45} 46 47static struct option opts[] = { 48 { "source-ports", 1, 0, '1' }, 49 { "sports", 1, 0, '1' }, /* synonym */ 50 { "destination-ports", 1, 0, '2' }, 51 { "dports", 1, 0, '2' }, /* synonym */ 52 { "ports", 1, 0, '3' }, 53 {0} 54}; 55 56static char * 57proto_to_name(u_int8_t proto) 58{ 59 switch (proto) { 60 case IPPROTO_TCP: 61 return "tcp"; 62 case IPPROTO_UDP: 63 return "udp"; 64 case IPPROTO_SCTP: 65 return "sctp"; 66 case IPPROTO_DCCP: 67 return "dccp"; 68 default: 69 return NULL; 70 } 71} 72 73#if 0 74static unsigned int 75parse_multi_ports(const char *portstring, u_int16_t *ports, const char *proto) 76{ 77 char *buffer, *cp, *next; 78 unsigned int i; 79 80 buffer = strdup(portstring); 81 if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed"); 82 83 for (cp=buffer, i=0; cp && i<IP6T_MULTI_PORTS; cp=next,i++) 84 { 85 next=strchr(cp, ','); 86 if (next) *next++='\0'; 87 ports[i] = parse_port(cp, proto); 88 } 89 if (cp) exit_error(PARAMETER_PROBLEM, "too many ports specified"); 90 free(buffer); 91 return i; 92} 93#endif 94 95static void 96parse_multi_ports_v1(const char *portstring, 97 struct ip6t_multiport_v1 *multiinfo, 98 const char *proto) 99{ 100 char *buffer, *cp, *next, *range; 101 unsigned int i; 102 u_int16_t m; 103 104 buffer = strdup(portstring); 105 if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed"); 106 107 for (i=0; i<IP6T_MULTI_PORTS; i++) 108 multiinfo->pflags[i] = 0; 109 110 for (cp=buffer, i=0; cp && i<IP6T_MULTI_PORTS; cp=next, i++) { 111 next=strchr(cp, ','); 112 if (next) *next++='\0'; 113 range = strchr(cp, ':'); 114 if (range) { 115 if (i == IP6T_MULTI_PORTS-1) 116 exit_error(PARAMETER_PROBLEM, 117 "too many ports specified"); 118 *range++ = '\0'; 119 } 120 multiinfo->ports[i] = parse_port(cp, proto); 121 if (range) { 122 multiinfo->pflags[i] = 1; 123 multiinfo->ports[++i] = parse_port(range, proto); 124 if (multiinfo->ports[i-1] >= multiinfo->ports[i]) 125 exit_error(PARAMETER_PROBLEM, 126 "invalid portrange specified"); 127 m <<= 1; 128 } 129 } 130 multiinfo->count = i; 131 if (cp) exit_error(PARAMETER_PROBLEM, "too many ports specified"); 132 free(buffer); 133} 134 135/* Initialize the match. */ 136static void 137init(struct ip6t_entry_match *m, unsigned int *nfcache) 138{ 139} 140 141static const char * 142check_proto(const struct ip6t_entry *entry) 143{ 144 char *proto; 145 146 if ((proto = proto_to_name(entry->ipv6.proto)) != NULL) 147 return proto; 148 else if (!entry->ipv6.proto) 149 exit_error(PARAMETER_PROBLEM, 150 "multiport needs `-p tcp', `-p udp', `-p sctp' or `-p dccp'"); 151 else 152 exit_error(PARAMETER_PROBLEM, 153 "multiport only works with TCP, UDP, SCTP and DCCP"); 154} 155 156/* Function which parses command options; returns true if it 157 ate an option */ 158#if 0 159static int 160parse(int c, char **argv, int invert, unsigned int *flags, 161 const struct ip6t_entry *entry, 162 unsigned int *nfcache, 163 struct ip6t_entry_match **match) 164{ 165 const char *proto; 166 struct ip6t_multiport *multiinfo 167 = (struct ip6t_multiport *)(*match)->data; 168 169 switch (c) { 170 case '1': 171 check_inverse(argv[optind-1], &invert, &optind, 0); 172 proto = check_proto(entry); 173 multiinfo->count = parse_multi_ports(argv[optind-1], 174 multiinfo->ports, proto); 175 multiinfo->flags = IP6T_MULTIPORT_SOURCE; 176 break; 177 178 case '2': 179 check_inverse(argv[optind-1], &invert, &optind, 0); 180 proto = check_proto(entry); 181 multiinfo->count = parse_multi_ports(argv[optind-1], 182 multiinfo->ports, proto); 183 multiinfo->flags = IP6T_MULTIPORT_DESTINATION; 184 break; 185 186 case '3': 187 check_inverse(argv[optind-1], &invert, &optind, 0); 188 proto = check_proto(entry); 189 multiinfo->count = parse_multi_ports(argv[optind-1], 190 multiinfo->ports, proto); 191 multiinfo->flags = IP6T_MULTIPORT_EITHER; 192 break; 193 194 default: 195 return 0; 196 } 197 198 if (invert) 199 exit_error(PARAMETER_PROBLEM, 200 "multiport does not support invert"); 201 202 if (*flags) 203 exit_error(PARAMETER_PROBLEM, 204 "multiport can only have one option"); 205 *flags = 1; 206 return 1; 207} 208#endif 209 210static int 211parse_v1(int c, char **argv, int invert, unsigned int *flags, 212 const struct ip6t_entry *entry, 213 unsigned int *nfcache, 214 struct ip6t_entry_match **match) 215{ 216 const char *proto; 217 struct ip6t_multiport_v1 *multiinfo 218 = (struct ip6t_multiport_v1 *)(*match)->data; 219 220 switch (c) { 221 case '1': 222 check_inverse(argv[optind-1], &invert, &optind, 0); 223 proto = check_proto(entry); 224 parse_multi_ports_v1(argv[optind-1], multiinfo, proto); 225 multiinfo->flags = IP6T_MULTIPORT_SOURCE; 226 break; 227 228 case '2': 229 check_inverse(argv[optind-1], &invert, &optind, 0); 230 proto = check_proto(entry); 231 parse_multi_ports_v1(argv[optind-1], multiinfo, proto); 232 multiinfo->flags = IP6T_MULTIPORT_DESTINATION; 233 break; 234 235 case '3': 236 check_inverse(argv[optind-1], &invert, &optind, 0); 237 proto = check_proto(entry); 238 parse_multi_ports_v1(argv[optind-1], multiinfo, proto); 239 multiinfo->flags = IP6T_MULTIPORT_EITHER; 240 break; 241 242 default: 243 return 0; 244 } 245 246 if (invert) 247 multiinfo->invert = 1; 248 249 if (*flags) 250 exit_error(PARAMETER_PROBLEM, 251 "multiport can only have one option"); 252 *flags = 1; 253 return 1; 254} 255 256/* Final check; must specify something. */ 257static void 258final_check(unsigned int flags) 259{ 260 if (!flags) 261 exit_error(PARAMETER_PROBLEM, "multiport expection an option"); 262} 263 264static char * 265port_to_service(int port, u_int8_t proto) 266{ 267 struct servent *service; 268 269 if ((service = getservbyport(htons(port), proto_to_name(proto)))) 270 return service->s_name; 271 272 return NULL; 273} 274 275static void 276print_port(u_int16_t port, u_int8_t protocol, int numeric) 277{ 278 char *service; 279 280 if (numeric || (service = port_to_service(port, protocol)) == NULL) 281 printf("%u", port); 282 else 283 printf("%s", service); 284} 285 286/* Prints out the matchinfo. */ 287#if 0 288static void 289print(const struct ip6t_ip6 *ip, 290 const struct ip6t_entry_match *match, 291 int numeric) 292{ 293 const struct ip6t_multiport *multiinfo 294 = (const struct ip6t_multiport *)match->data; 295 unsigned int i; 296 297 printf("multiport "); 298 299 switch (multiinfo->flags) { 300 case IP6T_MULTIPORT_SOURCE: 301 printf("sports "); 302 break; 303 304 case IP6T_MULTIPORT_DESTINATION: 305 printf("dports "); 306 break; 307 308 case IP6T_MULTIPORT_EITHER: 309 printf("ports "); 310 break; 311 312 default: 313 printf("ERROR "); 314 break; 315 } 316 317 for (i=0; i < multiinfo->count; i++) { 318 printf("%s", i ? "," : ""); 319 print_port(multiinfo->ports[i], ip->proto, numeric); 320 } 321 printf(" "); 322} 323#endif 324 325static void 326print_v1(const struct ip6t_ip6 *ip, 327 const struct ip6t_entry_match *match, 328 int numeric) 329{ 330 const struct ip6t_multiport_v1 *multiinfo 331 = (const struct ip6t_multiport_v1 *)match->data; 332 unsigned int i; 333 334 printf("multiport "); 335 336 switch (multiinfo->flags) { 337 case IP6T_MULTIPORT_SOURCE: 338 printf("sports "); 339 break; 340 341 case IP6T_MULTIPORT_DESTINATION: 342 printf("dports "); 343 break; 344 345 case IP6T_MULTIPORT_EITHER: 346 printf("ports "); 347 break; 348 349 default: 350 printf("ERROR "); 351 break; 352 } 353 354 if (multiinfo->invert) 355 printf("! "); 356 357 for (i=0; i < multiinfo->count; i++) { 358 printf("%s", i ? "," : ""); 359 print_port(multiinfo->ports[i], ip->proto, numeric); 360 if (multiinfo->pflags[i]) { 361 printf(":"); 362 print_port(multiinfo->ports[++i], ip->proto, numeric); 363 } 364 } 365 printf(" "); 366} 367 368/* Saves the union ip6t_matchinfo in parsable form to stdout. */ 369#if 0 370static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match) 371{ 372 const struct ip6t_multiport *multiinfo 373 = (const struct ip6t_multiport *)match->data; 374 unsigned int i; 375 376 switch (multiinfo->flags) { 377 case IP6T_MULTIPORT_SOURCE: 378 printf("--sports "); 379 break; 380 381 case IP6T_MULTIPORT_DESTINATION: 382 printf("--dports "); 383 break; 384 385 case IP6T_MULTIPORT_EITHER: 386 printf("--ports "); 387 break; 388 } 389 390 for (i=0; i < multiinfo->count; i++) { 391 printf("%s", i ? "," : ""); 392 print_port(multiinfo->ports[i], ip->proto, 1); 393 } 394 printf(" "); 395} 396#endif 397 398static void save_v1(const struct ip6t_ip6 *ip, 399 const struct ip6t_entry_match *match) 400{ 401 const struct ip6t_multiport_v1 *multiinfo 402 = (const struct ip6t_multiport_v1 *)match->data; 403 unsigned int i; 404 405 switch (multiinfo->flags) { 406 case IP6T_MULTIPORT_SOURCE: 407 printf("--sports "); 408 break; 409 410 case IP6T_MULTIPORT_DESTINATION: 411 printf("--dports "); 412 break; 413 414 case IP6T_MULTIPORT_EITHER: 415 printf("--ports "); 416 break; 417 } 418 419 if (multiinfo->invert) 420 printf("! "); 421 422 for (i=0; i < multiinfo->count; i++) { 423 printf("%s", i ? "," : ""); 424 print_port(multiinfo->ports[i], ip->proto, 1); 425 if (multiinfo->pflags[i]) { 426 printf(":"); 427 print_port(multiinfo->ports[++i], ip->proto, 1); 428 } 429 } 430 printf(" "); 431} 432 433#if 0 434static struct ip6tables_match multiport = { 435 .name = "multiport", 436 .version = IPTABLES_VERSION, 437 .size = IP6T_ALIGN(sizeof(struct ip6t_multiport)), 438 .userspacesize = IP6T_ALIGN(sizeof(struct ip6t_multiport)), 439 .help = &help, 440 .init = &init, 441 .parse = &parse, 442 .final_check = &final_check, 443 .print = &print, 444 .save = &save, 445 .extra_opts = opts, 446}; 447#endif 448 449static struct ip6tables_match multiport_v1 = { 450 .next = NULL, 451 .name = "multiport", 452 .revision = 1, 453 .version = IPTABLES_VERSION, 454 .size = IP6T_ALIGN(sizeof(struct ip6t_multiport_v1)), 455 .userspacesize = IP6T_ALIGN(sizeof(struct ip6t_multiport_v1)), 456 .help = &help_v1, 457 .init = &init, 458 .parse = &parse_v1, 459 .final_check = &final_check, 460 .print = &print_v1, 461 .save = &save_v1, 462 .extra_opts = opts 463}; 464 465void 466_init(void) 467{ 468#if 0 469 register_match6(&multiport); 470#endif 471 register_match6(&multiport_v1); 472} 473