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