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