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. */ 12static void 13help(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", 26IPTABLES_VERSION); 27} 28 29static void 30help_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", 42IPTABLES_VERSION); 43} 44 45static 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 54static char * 55proto_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 71static unsigned int 72parse_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 91static void 92parse_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. */ 132static void 133init(struct ip6t_entry_match *m, unsigned int *nfcache) 134{ 135} 136 137static const char * 138check_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 */ 154static int 155parse(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 204static int 205parse_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. */ 251static void 252final_check(unsigned int flags) 253{ 254 if (!flags) 255 exit_error(PARAMETER_PROBLEM, "multiport expection an option"); 256} 257 258static char * 259port_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 269static void 270print_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. */ 281static void 282print(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 317static void 318print_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. */ 361static 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 388static 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 423static 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 437static 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 453void 454_init(void) 455{ 456 register_match6(&multiport); 457 register_match6(&multiport_v1); 458} 459