xtables.c revision 94aa2ea67d7b8a669e8541f094661a1dc89722a3
1/* 2 * (C) 2000-2006 by the netfilter coreteam <coreteam@netfilter.org>: 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 */ 18 19#include <errno.h> 20#include <fcntl.h> 21#include <netdb.h> 22#include <stdarg.h> 23#include <stdbool.h> 24#include <stdio.h> 25#include <stdlib.h> 26#include <string.h> 27#include <unistd.h> 28#include <sys/socket.h> 29#include <sys/stat.h> 30#include <sys/types.h> 31#include <sys/wait.h> 32#include <arpa/inet.h> 33 34#include <xtables.h> 35#include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */ 36#include <linux/netfilter_ipv4/ip_tables.h> 37#include <linux/netfilter_ipv6/ip6_tables.h> 38#include <libiptc/libxtc.h> 39 40#ifndef NO_SHARED_LIBS 41#include <dlfcn.h> 42#endif 43#ifndef IPT_SO_GET_REVISION_MATCH /* Old kernel source. */ 44# define IPT_SO_GET_REVISION_MATCH (IPT_BASE_CTL + 2) 45# define IPT_SO_GET_REVISION_TARGET (IPT_BASE_CTL + 3) 46#endif 47#ifndef IP6T_SO_GET_REVISION_MATCH /* Old kernel source. */ 48# define IP6T_SO_GET_REVISION_MATCH 68 49# define IP6T_SO_GET_REVISION_TARGET 69 50#endif 51#include <getopt.h> 52 53 54#define NPROTO 255 55 56#ifndef PROC_SYS_MODPROBE 57#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe" 58#endif 59 60void basic_exit_err(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); 61 62struct xtables_globals *xt_params = NULL; 63 64void basic_exit_err(enum xtables_exittype status, const char *msg, ...) 65{ 66 va_list args; 67 68 va_start(args, msg); 69 fprintf(stderr, "%s v%s: ", xt_params->program_name, xt_params->program_version); 70 vfprintf(stderr, msg, args); 71 va_end(args); 72 fprintf(stderr, "\n"); 73 exit(status); 74} 75 76 77void xtables_free_opts(int reset_offset) 78{ 79 if (xt_params->opts != xt_params->orig_opts) { 80 free(xt_params->opts); 81 xt_params->opts = xt_params->orig_opts; 82 if (reset_offset) 83 xt_params->option_offset = 0; 84 } 85} 86 87struct option *xtables_merge_options(struct option *oldopts, 88 const struct option *newopts, 89 unsigned int *option_offset) 90{ 91 unsigned int num_old, num_new, i; 92 struct option *merge; 93 94 if (newopts == NULL) 95 return oldopts; 96 97 for (num_old = 0; oldopts[num_old].name; num_old++) ; 98 for (num_new = 0; newopts[num_new].name; num_new++) ; 99 100 xt_params->option_offset += 256; 101 *option_offset = xt_params->option_offset; 102 103 merge = malloc(sizeof(struct option) * (num_new + num_old + 1)); 104 if (merge == NULL) 105 return NULL; 106 memcpy(merge, oldopts, num_old * sizeof(struct option)); 107 xtables_free_opts(0); /* Release any old options merged */ 108 for (i = 0; i < num_new; i++) { 109 merge[num_old + i] = newopts[i]; 110 merge[num_old + i].val += *option_offset; 111 } 112 memset(merge + num_old + num_new, 0, sizeof(struct option)); 113 114 return merge; 115} 116 117void xtables_set_revision(char *name, u_int8_t revision) 118{ 119 /* Old kernel sources don't have ".revision" field, 120 * but we stole a byte from name. */ 121 name[XT_FUNCTION_MAXNAMELEN - 2] = '\0'; 122 name[XT_FUNCTION_MAXNAMELEN - 1] = revision; 123} 124 125/** 126 * xtables_afinfo - protocol family dependent information 127 * @kmod: kernel module basename (e.g. "ip_tables") 128 * @libprefix: prefix of .so library name (e.g. "libipt_") 129 * @family: nfproto family 130 * @ipproto: used by setsockopt (e.g. IPPROTO_IP) 131 * @so_rev_match: optname to check revision support of match 132 * @so_rev_target: optname to check revision support of target 133 */ 134struct xtables_afinfo { 135 const char *kmod; 136 const char *libprefix; 137 uint8_t family; 138 uint8_t ipproto; 139 int so_rev_match; 140 int so_rev_target; 141}; 142 143static const struct xtables_afinfo afinfo_ipv4 = { 144 .kmod = "ip_tables", 145 .libprefix = "libipt_", 146 .family = NFPROTO_IPV4, 147 .ipproto = IPPROTO_IP, 148 .so_rev_match = IPT_SO_GET_REVISION_MATCH, 149 .so_rev_target = IPT_SO_GET_REVISION_TARGET, 150}; 151 152static const struct xtables_afinfo afinfo_ipv6 = { 153 .kmod = "ip6_tables", 154 .libprefix = "libip6t_", 155 .family = NFPROTO_IPV6, 156 .ipproto = IPPROTO_IPV6, 157 .so_rev_match = IP6T_SO_GET_REVISION_MATCH, 158 .so_rev_target = IP6T_SO_GET_REVISION_TARGET, 159}; 160 161static const struct xtables_afinfo *afinfo; 162 163/* Search path for Xtables .so files */ 164static const char *xtables_libdir; 165 166/* the path to command to load kernel module */ 167const char *xtables_modprobe_program; 168 169/* Keeping track of external matches and targets: linked lists. */ 170struct xtables_match *xtables_matches; 171struct xtables_target *xtables_targets; 172 173void xtables_init(void) 174{ 175 xtables_libdir = getenv("XTABLES_LIBDIR"); 176 if (xtables_libdir != NULL) 177 return; 178 xtables_libdir = getenv("IPTABLES_LIB_DIR"); 179 if (xtables_libdir != NULL) { 180 fprintf(stderr, "IPTABLES_LIB_DIR is deprecated, " 181 "use XTABLES_LIBDIR.\n"); 182 return; 183 } 184 /* 185 * Well yes, IP6TABLES_LIB_DIR is of lower priority over 186 * IPTABLES_LIB_DIR since this moved to libxtables; I think that is ok 187 * for these env vars are deprecated anyhow, and in light of the 188 * (shared) libxt_*.so files, makes less sense to have 189 * IPTABLES_LIB_DIR != IP6TABLES_LIB_DIR. 190 */ 191 xtables_libdir = getenv("IP6TABLES_LIB_DIR"); 192 if (xtables_libdir != NULL) { 193 fprintf(stderr, "IP6TABLES_LIB_DIR is deprecated, " 194 "use XTABLES_LIBDIR.\n"); 195 return; 196 } 197 xtables_libdir = XTABLES_LIBDIR; 198} 199 200void xtables_set_nfproto(uint8_t nfproto) 201{ 202 switch (nfproto) { 203 case NFPROTO_IPV4: 204 afinfo = &afinfo_ipv4; 205 break; 206 case NFPROTO_IPV6: 207 afinfo = &afinfo_ipv6; 208 break; 209 default: 210 fprintf(stderr, "libxtables: unhandled NFPROTO in %s\n", 211 __func__); 212 } 213} 214 215/** 216 * xtables_set_params - set the global parameters used by xtables 217 * @xtp: input xtables_globals structure 218 * 219 * The app is expected to pass a valid xtables_globals data-filled 220 * with proper values 221 * @xtp cannot be NULL 222 * 223 * Returns -1 on failure to set and 0 on success 224 */ 225int xtables_set_params(struct xtables_globals *xtp) 226{ 227 if (!xtp) { 228 fprintf(stderr, "%s: Illegal global params\n",__func__); 229 return -1; 230 } 231 232 xt_params = xtp; 233 234 if (!xt_params->exit_err) 235 xt_params->exit_err = basic_exit_err; 236 237 return 0; 238} 239 240int xtables_init_all(struct xtables_globals *xtp, uint8_t nfproto) 241{ 242 xtables_init(); 243 xtables_set_nfproto(nfproto); 244 return xtables_set_params(xtp); 245} 246 247/** 248 * xtables_*alloc - wrappers that exit on failure 249 */ 250void *xtables_calloc(size_t count, size_t size) 251{ 252 void *p; 253 254 if ((p = calloc(count, size)) == NULL) { 255 perror("ip[6]tables: calloc failed"); 256 exit(1); 257 } 258 259 return p; 260} 261 262void *xtables_malloc(size_t size) 263{ 264 void *p; 265 266 if ((p = malloc(size)) == NULL) { 267 perror("ip[6]tables: malloc failed"); 268 exit(1); 269 } 270 271 return p; 272} 273 274void *xtables_realloc(void *ptr, size_t size) 275{ 276 void *p; 277 278 if ((p = realloc(ptr, size)) == NULL) { 279 perror("ip[6]tables: realloc failed"); 280 exit(1); 281 } 282 283 return p; 284} 285 286static char *get_modprobe(void) 287{ 288 int procfile; 289 char *ret; 290 291#define PROCFILE_BUFSIZ 1024 292 procfile = open(PROC_SYS_MODPROBE, O_RDONLY); 293 if (procfile < 0) 294 return NULL; 295 296 ret = (char *) malloc(PROCFILE_BUFSIZ); 297 if (ret) { 298 memset(ret, 0, PROCFILE_BUFSIZ); 299 switch (read(procfile, ret, PROCFILE_BUFSIZ)) { 300 case -1: goto fail; 301 case PROCFILE_BUFSIZ: goto fail; /* Partial read. Wierd */ 302 } 303 if (ret[strlen(ret)-1]=='\n') 304 ret[strlen(ret)-1]=0; 305 close(procfile); 306 return ret; 307 } 308 fail: 309 free(ret); 310 close(procfile); 311 return NULL; 312} 313 314int xtables_insmod(const char *modname, const char *modprobe, bool quiet) 315{ 316 char *buf = NULL; 317 char *argv[4]; 318 int status; 319 320 /* If they don't explicitly set it, read out of kernel */ 321 if (!modprobe) { 322 buf = get_modprobe(); 323 if (!buf) 324 return -1; 325 modprobe = buf; 326 } 327 328 /* 329 * Need to flush the buffer, or the child may output it again 330 * when switching the program thru execv. 331 */ 332 fflush(stdout); 333 334 switch (vfork()) { 335 case 0: 336 argv[0] = (char *)modprobe; 337 argv[1] = (char *)modname; 338 if (quiet) { 339 argv[2] = "-q"; 340 argv[3] = NULL; 341 } else { 342 argv[2] = NULL; 343 argv[3] = NULL; 344 } 345 execv(argv[0], argv); 346 347 /* not usually reached */ 348 exit(1); 349 case -1: 350 return -1; 351 352 default: /* parent */ 353 wait(&status); 354 } 355 356 free(buf); 357 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) 358 return 0; 359 return -1; 360} 361 362int xtables_load_ko(const char *modprobe, bool quiet) 363{ 364 static bool loaded = false; 365 static int ret = -1; 366 367 if (!loaded) { 368 ret = xtables_insmod(afinfo->kmod, modprobe, quiet); 369 loaded = (ret == 0); 370 } 371 372 return ret; 373} 374 375/** 376 * xtables_strtou{i,l} - string to number conversion 377 * @s: input string 378 * @end: like strtoul's "end" pointer 379 * @value: pointer for result 380 * @min: minimum accepted value 381 * @max: maximum accepted value 382 * 383 * If @end is NULL, we assume the caller wants a "strict strtoul", and hence 384 * "15a" is rejected. 385 * In either case, the value obtained is compared for min-max compliance. 386 * Base is always 0, i.e. autodetect depending on @s. 387 * 388 * Returns true/false whether number was accepted. On failure, *value has 389 * undefined contents. 390 */ 391bool xtables_strtoul(const char *s, char **end, unsigned long *value, 392 unsigned long min, unsigned long max) 393{ 394 unsigned long v; 395 char *my_end; 396 397 errno = 0; 398 v = strtoul(s, &my_end, 0); 399 400 if (my_end == s) 401 return false; 402 if (end != NULL) 403 *end = my_end; 404 405 if (errno != ERANGE && min <= v && (max == 0 || v <= max)) { 406 if (value != NULL) 407 *value = v; 408 if (end == NULL) 409 return *my_end == '\0'; 410 return true; 411 } 412 413 return false; 414} 415 416bool xtables_strtoui(const char *s, char **end, unsigned int *value, 417 unsigned int min, unsigned int max) 418{ 419 unsigned long v; 420 bool ret; 421 422 ret = xtables_strtoul(s, end, &v, min, max); 423 if (value != NULL) 424 *value = v; 425 return ret; 426} 427 428int xtables_service_to_port(const char *name, const char *proto) 429{ 430 struct servent *service; 431 432 if ((service = getservbyname(name, proto)) != NULL) 433 return ntohs((unsigned short) service->s_port); 434 435 return -1; 436} 437 438u_int16_t xtables_parse_port(const char *port, const char *proto) 439{ 440 unsigned int portnum; 441 442 if (xtables_strtoui(port, NULL, &portnum, 0, UINT16_MAX) || 443 (portnum = xtables_service_to_port(port, proto)) != (unsigned)-1) 444 return portnum; 445 446 xt_params->exit_err(PARAMETER_PROBLEM, 447 "invalid port/service `%s' specified", port); 448} 449 450void xtables_parse_interface(const char *arg, char *vianame, 451 unsigned char *mask) 452{ 453 int vialen = strlen(arg); 454 unsigned int i; 455 456 memset(mask, 0, IFNAMSIZ); 457 memset(vianame, 0, IFNAMSIZ); 458 459 if (vialen + 1 > IFNAMSIZ) 460 xt_params->exit_err(PARAMETER_PROBLEM, 461 "interface name `%s' must be shorter than IFNAMSIZ" 462 " (%i)", arg, IFNAMSIZ-1); 463 464 strcpy(vianame, arg); 465 if ((vialen == 0) || (vialen == 1 && vianame[0] == '+')) 466 memset(mask, 0, IFNAMSIZ); 467 else if (vianame[vialen - 1] == '+') { 468 memset(mask, 0xFF, vialen - 1); 469 memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1); 470 /* Don't remove `+' here! -HW */ 471 } else { 472 /* Include nul-terminator in match */ 473 memset(mask, 0xFF, vialen + 1); 474 memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1); 475 for (i = 0; vianame[i]; i++) { 476 if (vianame[i] == ':' || 477 vianame[i] == '!' || 478 vianame[i] == '*') { 479 fprintf(stderr, 480 "Warning: weird character in interface" 481 " `%s' (No aliases, :, ! or *).\n", 482 vianame); 483 break; 484 } 485 } 486 } 487} 488 489#ifndef NO_SHARED_LIBS 490static void *load_extension(const char *search_path, const char *prefix, 491 const char *name, bool is_target) 492{ 493 const char *dir = search_path, *next; 494 void *ptr = NULL; 495 struct stat sb; 496 char path[256]; 497 498 do { 499 next = strchr(dir, ':'); 500 if (next == NULL) 501 next = dir + strlen(dir); 502 snprintf(path, sizeof(path), "%.*s/libxt_%s.so", 503 (unsigned int)(next - dir), dir, name); 504 505 if (dlopen(path, RTLD_NOW) != NULL) { 506 /* Found library. If it didn't register itself, 507 maybe they specified target as match. */ 508 if (is_target) 509 ptr = xtables_find_target(name, XTF_DONT_LOAD); 510 else 511 ptr = xtables_find_match(name, 512 XTF_DONT_LOAD, NULL); 513 } else if (stat(path, &sb) == 0) { 514 fprintf(stderr, "%s: %s\n", path, dlerror()); 515 } 516 517 if (ptr != NULL) 518 return ptr; 519 520 snprintf(path, sizeof(path), "%.*s/%s%s.so", 521 (unsigned int)(next - dir), dir, prefix, name); 522 if (dlopen(path, RTLD_NOW) != NULL) { 523 if (is_target) 524 ptr = xtables_find_target(name, XTF_DONT_LOAD); 525 else 526 ptr = xtables_find_match(name, 527 XTF_DONT_LOAD, NULL); 528 } else if (stat(path, &sb) == 0) { 529 fprintf(stderr, "%s: %s\n", path, dlerror()); 530 } 531 532 if (ptr != NULL) 533 return ptr; 534 535 dir = next + 1; 536 } while (*next != '\0'); 537 538 return NULL; 539} 540#endif 541 542struct xtables_match * 543xtables_find_match(const char *name, enum xtables_tryload tryload, 544 struct xtables_rule_match **matches) 545{ 546 struct xtables_match *ptr; 547 const char *icmp6 = "icmp6"; 548 549 /* This is ugly as hell. Nonetheless, there is no way of changing 550 * this without hurting backwards compatibility */ 551 if ( (strcmp(name,"icmpv6") == 0) || 552 (strcmp(name,"ipv6-icmp") == 0) || 553 (strcmp(name,"icmp6") == 0) ) 554 name = icmp6; 555 556 for (ptr = xtables_matches; ptr; ptr = ptr->next) { 557 if (strcmp(name, ptr->name) == 0) { 558 struct xtables_match *clone; 559 560 /* First match of this type: */ 561 if (ptr->m == NULL) 562 break; 563 564 /* Second and subsequent clones */ 565 clone = xtables_malloc(sizeof(struct xtables_match)); 566 memcpy(clone, ptr, sizeof(struct xtables_match)); 567 clone->mflags = 0; 568 /* This is a clone: */ 569 clone->next = clone; 570 571 ptr = clone; 572 break; 573 } 574 } 575 576#ifndef NO_SHARED_LIBS 577 if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) { 578 ptr = load_extension(xtables_libdir, afinfo->libprefix, 579 name, false); 580 581 if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED) 582 xt_params->exit_err(PARAMETER_PROBLEM, 583 "Couldn't load match `%s':%s\n", 584 name, dlerror()); 585 } 586#else 587 if (ptr && !ptr->loaded) { 588 if (tryload != XTF_DONT_LOAD) 589 ptr->loaded = 1; 590 else 591 ptr = NULL; 592 } 593 if(!ptr && (tryload == XTF_LOAD_MUST_SUCCEED)) { 594 xt_params->exit_err(PARAMETER_PROBLEM, 595 "Couldn't find match `%s'\n", name); 596 } 597#endif 598 599 if (ptr && matches) { 600 struct xtables_rule_match **i; 601 struct xtables_rule_match *newentry; 602 603 newentry = xtables_malloc(sizeof(struct xtables_rule_match)); 604 605 for (i = matches; *i; i = &(*i)->next) { 606 if (strcmp(name, (*i)->match->name) == 0) 607 (*i)->completed = true; 608 } 609 newentry->match = ptr; 610 newentry->completed = false; 611 newentry->next = NULL; 612 *i = newentry; 613 } 614 615 return ptr; 616} 617 618struct xtables_target * 619xtables_find_target(const char *name, enum xtables_tryload tryload) 620{ 621 struct xtables_target *ptr; 622 623 /* Standard target? */ 624 if (strcmp(name, "") == 0 625 || strcmp(name, XTC_LABEL_ACCEPT) == 0 626 || strcmp(name, XTC_LABEL_DROP) == 0 627 || strcmp(name, XTC_LABEL_QUEUE) == 0 628 || strcmp(name, XTC_LABEL_RETURN) == 0) 629 name = "standard"; 630 631 for (ptr = xtables_targets; ptr; ptr = ptr->next) { 632 if (strcmp(name, ptr->name) == 0) 633 break; 634 } 635 636#ifndef NO_SHARED_LIBS 637 if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) { 638 ptr = load_extension(xtables_libdir, afinfo->libprefix, 639 name, true); 640 641 if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED) 642 xt_params->exit_err(PARAMETER_PROBLEM, 643 "Couldn't load target `%s':%s\n", 644 name, dlerror()); 645 } 646#else 647 if (ptr && !ptr->loaded) { 648 if (tryload != XTF_DONT_LOAD) 649 ptr->loaded = 1; 650 else 651 ptr = NULL; 652 } 653 if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED) { 654 xt_params->exit_err(PARAMETER_PROBLEM, 655 "Couldn't find target `%s'\n", name); 656 } 657#endif 658 659 if (ptr) 660 ptr->used = 1; 661 662 return ptr; 663} 664 665static int compatible_revision(const char *name, u_int8_t revision, int opt) 666{ 667 struct xt_get_revision rev; 668 socklen_t s = sizeof(rev); 669 int max_rev, sockfd; 670 671 sockfd = socket(afinfo->family, SOCK_RAW, IPPROTO_RAW); 672 if (sockfd < 0) { 673 if (errno == EPERM) { 674 /* revision 0 is always supported. */ 675 if (revision != 0) 676 fprintf(stderr, "Could not determine whether " 677 "revision %u is supported, " 678 "assuming it is.\n", 679 revision); 680 return 1; 681 } 682 fprintf(stderr, "Could not open socket to kernel: %s\n", 683 strerror(errno)); 684 exit(1); 685 } 686 687 xtables_load_ko(xtables_modprobe_program, true); 688 689 strcpy(rev.name, name); 690 rev.revision = revision; 691 692 max_rev = getsockopt(sockfd, afinfo->ipproto, opt, &rev, &s); 693 if (max_rev < 0) { 694 /* Definitely don't support this? */ 695 if (errno == ENOENT || errno == EPROTONOSUPPORT) { 696 close(sockfd); 697 return 0; 698 } else if (errno == ENOPROTOOPT) { 699 close(sockfd); 700 /* Assume only revision 0 support (old kernel) */ 701 return (revision == 0); 702 } else { 703 fprintf(stderr, "getsockopt failed strangely: %s\n", 704 strerror(errno)); 705 exit(1); 706 } 707 } 708 close(sockfd); 709 return 1; 710} 711 712 713static int compatible_match_revision(const char *name, u_int8_t revision) 714{ 715 return compatible_revision(name, revision, afinfo->so_rev_match); 716} 717 718static int compatible_target_revision(const char *name, u_int8_t revision) 719{ 720 return compatible_revision(name, revision, afinfo->so_rev_target); 721} 722 723void xtables_register_match(struct xtables_match *me) 724{ 725 struct xtables_match **i, *old; 726 727 if (me->version == NULL) { 728 fprintf(stderr, "%s: match %s<%u> is missing a version\n", 729 xt_params->program_name, me->name, me->revision); 730 exit(1); 731 } 732 if (strcmp(me->version, XTABLES_VERSION) != 0) { 733 fprintf(stderr, "%s: match \"%s\" has version \"%s\", " 734 "but \"%s\" is required.\n", 735 xt_params->program_name, me->name, 736 me->version, XTABLES_VERSION); 737 exit(1); 738 } 739 740 /* Revision field stole a char from name. */ 741 if (strlen(me->name) >= XT_FUNCTION_MAXNAMELEN-1) { 742 fprintf(stderr, "%s: target `%s' has invalid name\n", 743 xt_params->program_name, me->name); 744 exit(1); 745 } 746 747 if (me->family >= NPROTO) { 748 fprintf(stderr, 749 "%s: BUG: match %s has invalid protocol family\n", 750 xt_params->program_name, me->name); 751 exit(1); 752 } 753 754 /* ignore not interested match */ 755 if (me->family != afinfo->family && me->family != AF_UNSPEC) 756 return; 757 758 old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL); 759 if (old) { 760 if (old->revision == me->revision && 761 old->family == me->family) { 762 fprintf(stderr, 763 "%s: match `%s' already registered.\n", 764 xt_params->program_name, me->name); 765 exit(1); 766 } 767 768 /* Now we have two (or more) options, check compatibility. */ 769 if (compatible_match_revision(old->name, old->revision) 770 && old->revision > me->revision) 771 return; 772 773 /* See if new match can be used. */ 774 if (!compatible_match_revision(me->name, me->revision)) 775 return; 776 777 /* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */ 778 if (old->revision == me->revision && me->family == AF_UNSPEC) 779 return; 780 781 /* Delete old one. */ 782 for (i = &xtables_matches; *i!=old; i = &(*i)->next); 783 *i = old->next; 784 } 785 786 if (me->size != XT_ALIGN(me->size)) { 787 fprintf(stderr, "%s: match `%s' has invalid size %u.\n", 788 xt_params->program_name, me->name, 789 (unsigned int)me->size); 790 exit(1); 791 } 792 793 /* Append to list. */ 794 for (i = &xtables_matches; *i; i = &(*i)->next); 795 me->next = NULL; 796 *i = me; 797 798 me->m = NULL; 799 me->mflags = 0; 800} 801 802void xtables_register_matches(struct xtables_match *match, unsigned int n) 803{ 804 do { 805 xtables_register_match(&match[--n]); 806 } while (n > 0); 807} 808 809void xtables_register_target(struct xtables_target *me) 810{ 811 struct xtables_target *old; 812 813 if (me->version == NULL) { 814 fprintf(stderr, "%s: target %s<%u> is missing a version\n", 815 xt_params->program_name, me->name, me->revision); 816 exit(1); 817 } 818 if (strcmp(me->version, XTABLES_VERSION) != 0) { 819 fprintf(stderr, "%s: target \"%s\" has version \"%s\", " 820 "but \"%s\" is required.\n", 821 xt_params->program_name, me->name, 822 me->version, XTABLES_VERSION); 823 exit(1); 824 } 825 826 /* Revision field stole a char from name. */ 827 if (strlen(me->name) >= XT_FUNCTION_MAXNAMELEN-1) { 828 fprintf(stderr, "%s: target `%s' has invalid name\n", 829 xt_params->program_name, me->name); 830 exit(1); 831 } 832 833 if (me->family >= NPROTO) { 834 fprintf(stderr, 835 "%s: BUG: target %s has invalid protocol family\n", 836 xt_params->program_name, me->name); 837 exit(1); 838 } 839 840 /* ignore not interested target */ 841 if (me->family != afinfo->family && me->family != AF_UNSPEC) 842 return; 843 844 old = xtables_find_target(me->name, XTF_DURING_LOAD); 845 if (old) { 846 struct xtables_target **i; 847 848 if (old->revision == me->revision && 849 old->family == me->family) { 850 fprintf(stderr, 851 "%s: target `%s' already registered.\n", 852 xt_params->program_name, me->name); 853 exit(1); 854 } 855 856 /* Now we have two (or more) options, check compatibility. */ 857 if (compatible_target_revision(old->name, old->revision) 858 && old->revision > me->revision) 859 return; 860 861 /* See if new target can be used. */ 862 if (!compatible_target_revision(me->name, me->revision)) 863 return; 864 865 /* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */ 866 if (old->revision == me->revision && me->family == AF_UNSPEC) 867 return; 868 869 /* Delete old one. */ 870 for (i = &xtables_targets; *i!=old; i = &(*i)->next); 871 *i = old->next; 872 } 873 874 if (me->size != XT_ALIGN(me->size)) { 875 fprintf(stderr, "%s: target `%s' has invalid size %u.\n", 876 xt_params->program_name, me->name, 877 (unsigned int)me->size); 878 exit(1); 879 } 880 881 /* Prepend to list. */ 882 me->next = xtables_targets; 883 xtables_targets = me; 884 me->t = NULL; 885 me->tflags = 0; 886} 887 888void xtables_register_targets(struct xtables_target *target, unsigned int n) 889{ 890 do { 891 xtables_register_target(&target[--n]); 892 } while (n > 0); 893} 894 895/** 896 * xtables_param_act - act on condition 897 * @status: a constant from enum xtables_exittype 898 * 899 * %XTF_ONLY_ONCE: print error message that option may only be used once. 900 * @p1: module name (e.g. "mark") 901 * @p2(...): option in conflict (e.g. "--mark") 902 * @p3(...): condition to match on (see extensions/ for examples) 903 * 904 * %XTF_NO_INVERT: option does not support inversion 905 * @p1: module name 906 * @p2: option in conflict 907 * @p3: condition to match on 908 * 909 * %XTF_BAD_VALUE: bad value for option 910 * @p1: module name 911 * @p2: option with which the problem occured (e.g. "--mark") 912 * @p3: string the user passed in (e.g. "99999999999999") 913 * 914 * %XTF_ONE_ACTION: two mutually exclusive actions have been specified 915 * @p1: module name 916 * 917 * Displays an error message and exits the program. 918 */ 919void xtables_param_act(unsigned int status, const char *p1, ...) 920{ 921 const char *p2, *p3; 922 va_list args; 923 bool b; 924 925 va_start(args, p1); 926 927 switch (status) { 928 case XTF_ONLY_ONCE: 929 p2 = va_arg(args, const char *); 930 b = va_arg(args, unsigned int); 931 if (!b) 932 return; 933 xt_params->exit_err(PARAMETER_PROBLEM, 934 "%s: \"%s\" option may only be specified once", 935 p1, p2); 936 break; 937 case XTF_NO_INVERT: 938 p2 = va_arg(args, const char *); 939 b = va_arg(args, unsigned int); 940 if (!b) 941 return; 942 xt_params->exit_err(PARAMETER_PROBLEM, 943 "%s: \"%s\" option cannot be inverted", p1, p2); 944 break; 945 case XTF_BAD_VALUE: 946 p2 = va_arg(args, const char *); 947 p3 = va_arg(args, const char *); 948 xt_params->exit_err(PARAMETER_PROBLEM, 949 "%s: Bad value for \"%s\" option: \"%s\"", 950 p1, p2, p3); 951 break; 952 case XTF_ONE_ACTION: 953 b = va_arg(args, unsigned int); 954 if (!b) 955 return; 956 xt_params->exit_err(PARAMETER_PROBLEM, 957 "%s: At most one action is possible", p1); 958 break; 959 default: 960 xt_params->exit_err(status, p1, args); 961 break; 962 } 963 964 va_end(args); 965} 966 967const char *xtables_ipaddr_to_numeric(const struct in_addr *addrp) 968{ 969 static char buf[20]; 970 const unsigned char *bytep = (const void *)&addrp->s_addr; 971 972 sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]); 973 return buf; 974} 975 976static const char *ipaddr_to_host(const struct in_addr *addr) 977{ 978 struct hostent *host; 979 980 host = gethostbyaddr(addr, sizeof(struct in_addr), AF_INET); 981 if (host == NULL) 982 return NULL; 983 984 return host->h_name; 985} 986 987static const char *ipaddr_to_network(const struct in_addr *addr) 988{ 989 struct netent *net; 990 991 if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL) 992 return net->n_name; 993 994 return NULL; 995} 996 997const char *xtables_ipaddr_to_anyname(const struct in_addr *addr) 998{ 999 const char *name; 1000 1001 if ((name = ipaddr_to_host(addr)) != NULL || 1002 (name = ipaddr_to_network(addr)) != NULL) 1003 return name; 1004 1005 return xtables_ipaddr_to_numeric(addr); 1006} 1007 1008const char *xtables_ipmask_to_numeric(const struct in_addr *mask) 1009{ 1010 static char buf[20]; 1011 uint32_t maskaddr, bits; 1012 int i; 1013 1014 maskaddr = ntohl(mask->s_addr); 1015 1016 if (maskaddr == 0xFFFFFFFFL) 1017 /* we don't want to see "/32" */ 1018 return ""; 1019 1020 i = 32; 1021 bits = 0xFFFFFFFEL; 1022 while (--i >= 0 && maskaddr != bits) 1023 bits <<= 1; 1024 if (i >= 0) 1025 sprintf(buf, "/%d", i); 1026 else 1027 /* mask was not a decent combination of 1's and 0's */ 1028 sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask)); 1029 1030 return buf; 1031} 1032 1033static struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask) 1034{ 1035 static struct in_addr addr; 1036 unsigned char *addrp; 1037 unsigned int onebyte; 1038 char buf[20], *p, *q; 1039 int i; 1040 1041 /* copy dotted string, because we need to modify it */ 1042 strncpy(buf, dotted, sizeof(buf) - 1); 1043 buf[sizeof(buf) - 1] = '\0'; 1044 addrp = (void *)&addr.s_addr; 1045 1046 p = buf; 1047 for (i = 0; i < 3; ++i) { 1048 if ((q = strchr(p, '.')) == NULL) { 1049 if (is_mask) 1050 return NULL; 1051 1052 /* autocomplete, this is a network address */ 1053 if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX)) 1054 return NULL; 1055 1056 addrp[i] = onebyte; 1057 while (i < 3) 1058 addrp[++i] = 0; 1059 1060 return &addr; 1061 } 1062 1063 *q = '\0'; 1064 if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX)) 1065 return NULL; 1066 1067 addrp[i] = onebyte; 1068 p = q + 1; 1069 } 1070 1071 /* we have checked 3 bytes, now we check the last one */ 1072 if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX)) 1073 return NULL; 1074 1075 addrp[3] = onebyte; 1076 return &addr; 1077} 1078 1079struct in_addr *xtables_numeric_to_ipaddr(const char *dotted) 1080{ 1081 return __numeric_to_ipaddr(dotted, false); 1082} 1083 1084struct in_addr *xtables_numeric_to_ipmask(const char *dotted) 1085{ 1086 return __numeric_to_ipaddr(dotted, true); 1087} 1088 1089static struct in_addr *network_to_ipaddr(const char *name) 1090{ 1091 static struct in_addr addr; 1092 struct netent *net; 1093 1094 if ((net = getnetbyname(name)) != NULL) { 1095 if (net->n_addrtype != AF_INET) 1096 return NULL; 1097 addr.s_addr = htonl(net->n_net); 1098 return &addr; 1099 } 1100 1101 return NULL; 1102} 1103 1104static struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr) 1105{ 1106 struct hostent *host; 1107 struct in_addr *addr; 1108 unsigned int i; 1109 1110 *naddr = 0; 1111 if ((host = gethostbyname(name)) != NULL) { 1112 if (host->h_addrtype != AF_INET || 1113 host->h_length != sizeof(struct in_addr)) 1114 return NULL; 1115 1116 while (host->h_addr_list[*naddr] != NULL) 1117 ++*naddr; 1118 addr = xtables_calloc(*naddr, sizeof(struct in_addr) * *naddr); 1119 for (i = 0; i < *naddr; i++) 1120 memcpy(&addr[i], host->h_addr_list[i], 1121 sizeof(struct in_addr)); 1122 return addr; 1123 } 1124 1125 return NULL; 1126} 1127 1128static struct in_addr * 1129ipparse_hostnetwork(const char *name, unsigned int *naddrs) 1130{ 1131 struct in_addr *addrptmp, *addrp; 1132 1133 if ((addrptmp = xtables_numeric_to_ipaddr(name)) != NULL || 1134 (addrptmp = network_to_ipaddr(name)) != NULL) { 1135 addrp = xtables_malloc(sizeof(struct in_addr)); 1136 memcpy(addrp, addrptmp, sizeof(*addrp)); 1137 *naddrs = 1; 1138 return addrp; 1139 } 1140 if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL) 1141 return addrptmp; 1142 1143 xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name); 1144} 1145 1146static struct in_addr *parse_ipmask(const char *mask) 1147{ 1148 static struct in_addr maskaddr; 1149 struct in_addr *addrp; 1150 unsigned int bits; 1151 1152 if (mask == NULL) { 1153 /* no mask at all defaults to 32 bits */ 1154 maskaddr.s_addr = 0xFFFFFFFF; 1155 return &maskaddr; 1156 } 1157 if ((addrp = xtables_numeric_to_ipmask(mask)) != NULL) 1158 /* dotted_to_addr already returns a network byte order addr */ 1159 return addrp; 1160 if (!xtables_strtoui(mask, NULL, &bits, 0, 32)) 1161 xt_params->exit_err(PARAMETER_PROBLEM, 1162 "invalid mask `%s' specified", mask); 1163 if (bits != 0) { 1164 maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits)); 1165 return &maskaddr; 1166 } 1167 1168 maskaddr.s_addr = 0U; 1169 return &maskaddr; 1170} 1171 1172void xtables_ipparse_multiple(const char *name, struct in_addr **addrpp, 1173 struct in_addr **maskpp, unsigned int *naddrs) 1174{ 1175 struct in_addr *addrp; 1176 char buf[256], *p; 1177 unsigned int len, i, j, n, count = 1; 1178 const char *loop = name; 1179 1180 while ((loop = strchr(loop, ',')) != NULL) { 1181 ++count; 1182 ++loop; /* skip ',' */ 1183 } 1184 1185 *addrpp = xtables_malloc(sizeof(struct in_addr) * count); 1186 *maskpp = xtables_malloc(sizeof(struct in_addr) * count); 1187 1188 loop = name; 1189 1190 for (i = 0; i < count; ++i) { 1191 if (loop == NULL) 1192 break; 1193 if (*loop == ',') 1194 ++loop; 1195 if (*loop == '\0') 1196 break; 1197 p = strchr(loop, ','); 1198 if (p != NULL) 1199 len = p - loop; 1200 else 1201 len = strlen(loop); 1202 if (len == 0 || sizeof(buf) - 1 < len) 1203 break; 1204 1205 strncpy(buf, loop, len); 1206 buf[len] = '\0'; 1207 loop += len; 1208 if ((p = strrchr(buf, '/')) != NULL) { 1209 *p = '\0'; 1210 addrp = parse_ipmask(p + 1); 1211 } else { 1212 addrp = parse_ipmask(NULL); 1213 } 1214 memcpy(*maskpp + i, addrp, sizeof(*addrp)); 1215 1216 /* if a null mask is given, the name is ignored, like in "any/0" */ 1217 if ((*maskpp + i)->s_addr == 0) 1218 /* 1219 * A bit pointless to process multiple addresses 1220 * in this case... 1221 */ 1222 strcpy(buf, "0.0.0.0"); 1223 1224 addrp = ipparse_hostnetwork(buf, &n); 1225 if (n > 1) { 1226 count += n - 1; 1227 *addrpp = xtables_realloc(*addrpp, 1228 sizeof(struct in_addr) * count); 1229 *maskpp = xtables_realloc(*maskpp, 1230 sizeof(struct in_addr) * count); 1231 for (j = 0; j < n; ++j) 1232 /* for each new addr */ 1233 memcpy(*addrpp + i + j, addrp + j, 1234 sizeof(*addrp)); 1235 for (j = 1; j < n; ++j) 1236 /* for each new mask */ 1237 memcpy(*maskpp + i + j, *maskpp + i, 1238 sizeof(*addrp)); 1239 i += n - 1; 1240 } else { 1241 memcpy(*addrpp + i, addrp, sizeof(*addrp)); 1242 } 1243 /* free what ipparse_hostnetwork had allocated: */ 1244 free(addrp); 1245 } 1246 *naddrs = count; 1247 for (i = 0; i < n; ++i) 1248 (*addrpp+i)->s_addr &= (*maskpp+i)->s_addr; 1249} 1250 1251 1252/** 1253 * xtables_ipparse_any - transform arbitrary name to in_addr 1254 * 1255 * Possible inputs (pseudo regex): 1256 * m{^($hostname|$networkname|$ipaddr)(/$mask)?} 1257 * "1.2.3.4/5", "1.2.3.4", "hostname", "networkname" 1258 */ 1259void xtables_ipparse_any(const char *name, struct in_addr **addrpp, 1260 struct in_addr *maskp, unsigned int *naddrs) 1261{ 1262 unsigned int i, j, k, n; 1263 struct in_addr *addrp; 1264 char buf[256], *p; 1265 1266 strncpy(buf, name, sizeof(buf) - 1); 1267 buf[sizeof(buf) - 1] = '\0'; 1268 if ((p = strrchr(buf, '/')) != NULL) { 1269 *p = '\0'; 1270 addrp = parse_ipmask(p + 1); 1271 } else { 1272 addrp = parse_ipmask(NULL); 1273 } 1274 memcpy(maskp, addrp, sizeof(*maskp)); 1275 1276 /* if a null mask is given, the name is ignored, like in "any/0" */ 1277 if (maskp->s_addr == 0U) 1278 strcpy(buf, "0.0.0.0"); 1279 1280 addrp = *addrpp = ipparse_hostnetwork(buf, naddrs); 1281 n = *naddrs; 1282 for (i = 0, j = 0; i < n; ++i) { 1283 addrp[j++].s_addr &= maskp->s_addr; 1284 for (k = 0; k < j - 1; ++k) 1285 if (addrp[k].s_addr == addrp[j-1].s_addr) { 1286 --*naddrs; 1287 --j; 1288 break; 1289 } 1290 } 1291} 1292 1293const char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp) 1294{ 1295 /* 0000:0000:0000:0000:0000:000.000.000.000 1296 * 0000:0000:0000:0000:0000:0000:0000:0000 */ 1297 static char buf[50+1]; 1298 return inet_ntop(AF_INET6, addrp, buf, sizeof(buf)); 1299} 1300 1301static const char *ip6addr_to_host(const struct in6_addr *addr) 1302{ 1303 static char hostname[NI_MAXHOST]; 1304 struct sockaddr_in6 saddr; 1305 int err; 1306 1307 memset(&saddr, 0, sizeof(struct sockaddr_in6)); 1308 memcpy(&saddr.sin6_addr, addr, sizeof(*addr)); 1309 saddr.sin6_family = AF_INET6; 1310 1311 err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6), 1312 hostname, sizeof(hostname) - 1, NULL, 0, 0); 1313 if (err != 0) { 1314#ifdef DEBUG 1315 fprintf(stderr,"IP2Name: %s\n",gai_strerror(err)); 1316#endif 1317 return NULL; 1318 } 1319 1320#ifdef DEBUG 1321 fprintf (stderr, "\naddr2host: %s\n", hostname); 1322#endif 1323 return hostname; 1324} 1325 1326const char *xtables_ip6addr_to_anyname(const struct in6_addr *addr) 1327{ 1328 const char *name; 1329 1330 if ((name = ip6addr_to_host(addr)) != NULL) 1331 return name; 1332 1333 return xtables_ip6addr_to_numeric(addr); 1334} 1335 1336static int ip6addr_prefix_length(const struct in6_addr *k) 1337{ 1338 unsigned int bits = 0; 1339 uint32_t a, b, c, d; 1340 1341 a = ntohl(k->s6_addr32[0]); 1342 b = ntohl(k->s6_addr32[1]); 1343 c = ntohl(k->s6_addr32[2]); 1344 d = ntohl(k->s6_addr32[3]); 1345 while (a & 0x80000000U) { 1346 ++bits; 1347 a <<= 1; 1348 a |= (b >> 31) & 1; 1349 b <<= 1; 1350 b |= (c >> 31) & 1; 1351 c <<= 1; 1352 c |= (d >> 31) & 1; 1353 d <<= 1; 1354 } 1355 if (a != 0 || b != 0 || c != 0 || d != 0) 1356 return -1; 1357 return bits; 1358} 1359 1360const char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp) 1361{ 1362 static char buf[50+2]; 1363 int l = ip6addr_prefix_length(addrp); 1364 1365 if (l == -1) { 1366 strcpy(buf, "/"); 1367 strcat(buf, xtables_ip6addr_to_numeric(addrp)); 1368 return buf; 1369 } 1370 sprintf(buf, "/%d", l); 1371 return buf; 1372} 1373 1374struct in6_addr *xtables_numeric_to_ip6addr(const char *num) 1375{ 1376 static struct in6_addr ap; 1377 int err; 1378 1379 if ((err = inet_pton(AF_INET6, num, &ap)) == 1) 1380 return ≈ 1381#ifdef DEBUG 1382 fprintf(stderr, "\nnumeric2addr: %d\n", err); 1383#endif 1384 return NULL; 1385} 1386 1387static struct in6_addr * 1388host_to_ip6addr(const char *name, unsigned int *naddr) 1389{ 1390 static struct in6_addr *addr; 1391 struct addrinfo hints; 1392 struct addrinfo *res; 1393 int err; 1394 1395 memset(&hints, 0, sizeof(hints)); 1396 hints.ai_flags = AI_CANONNAME; 1397 hints.ai_family = AF_INET6; 1398 hints.ai_socktype = SOCK_RAW; 1399 hints.ai_protocol = IPPROTO_IPV6; 1400 hints.ai_next = NULL; 1401 1402 *naddr = 0; 1403 if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) { 1404#ifdef DEBUG 1405 fprintf(stderr,"Name2IP: %s\n",gai_strerror(err)); 1406#endif 1407 return NULL; 1408 } else { 1409 if (res->ai_family != AF_INET6 || 1410 res->ai_addrlen != sizeof(struct sockaddr_in6)) 1411 return NULL; 1412 1413#ifdef DEBUG 1414 fprintf(stderr, "resolved: len=%d %s ", res->ai_addrlen, 1415 ip6addr_to_numeric(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr)); 1416#endif 1417 /* Get the first element of the address-chain */ 1418 addr = xtables_malloc(sizeof(struct in6_addr)); 1419 memcpy(addr, &((const struct sockaddr_in6 *)res->ai_addr)->sin6_addr, 1420 sizeof(struct in6_addr)); 1421 freeaddrinfo(res); 1422 *naddr = 1; 1423 return addr; 1424 } 1425 1426 return NULL; 1427} 1428 1429static struct in6_addr *network_to_ip6addr(const char *name) 1430{ 1431 /* abort();*/ 1432 /* TODO: not implemented yet, but the exception breaks the 1433 * name resolvation */ 1434 return NULL; 1435} 1436 1437static struct in6_addr * 1438ip6parse_hostnetwork(const char *name, unsigned int *naddrs) 1439{ 1440 struct in6_addr *addrp, *addrptmp; 1441 1442 if ((addrptmp = xtables_numeric_to_ip6addr(name)) != NULL || 1443 (addrptmp = network_to_ip6addr(name)) != NULL) { 1444 addrp = xtables_malloc(sizeof(struct in6_addr)); 1445 memcpy(addrp, addrptmp, sizeof(*addrp)); 1446 *naddrs = 1; 1447 return addrp; 1448 } 1449 if ((addrp = host_to_ip6addr(name, naddrs)) != NULL) 1450 return addrp; 1451 1452 xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name); 1453} 1454 1455static struct in6_addr *parse_ip6mask(char *mask) 1456{ 1457 static struct in6_addr maskaddr; 1458 struct in6_addr *addrp; 1459 unsigned int bits; 1460 1461 if (mask == NULL) { 1462 /* no mask at all defaults to 128 bits */ 1463 memset(&maskaddr, 0xff, sizeof maskaddr); 1464 return &maskaddr; 1465 } 1466 if ((addrp = xtables_numeric_to_ip6addr(mask)) != NULL) 1467 return addrp; 1468 if (!xtables_strtoui(mask, NULL, &bits, 0, 128)) 1469 xt_params->exit_err(PARAMETER_PROBLEM, 1470 "invalid mask `%s' specified", mask); 1471 if (bits != 0) { 1472 char *p = (void *)&maskaddr; 1473 memset(p, 0xff, bits / 8); 1474 memset(p + (bits / 8) + 1, 0, (128 - bits) / 8); 1475 p[bits/8] = 0xff << (8 - (bits & 7)); 1476 return &maskaddr; 1477 } 1478 1479 memset(&maskaddr, 0, sizeof(maskaddr)); 1480 return &maskaddr; 1481} 1482 1483void 1484xtables_ip6parse_multiple(const char *name, struct in6_addr **addrpp, 1485 struct in6_addr **maskpp, unsigned int *naddrs) 1486{ 1487 struct in6_addr *addrp; 1488 char buf[256], *p; 1489 unsigned int len, i, j, n, count = 1; 1490 const char *loop = name; 1491 1492 while ((loop = strchr(loop, ',')) != NULL) { 1493 ++count; 1494 ++loop; /* skip ',' */ 1495 } 1496 1497 *addrpp = xtables_malloc(sizeof(struct in6_addr) * count); 1498 *maskpp = xtables_malloc(sizeof(struct in6_addr) * count); 1499 1500 loop = name; 1501 1502 for (i = 0; i < count /*NB: count can grow*/; ++i) { 1503 if (loop == NULL) 1504 break; 1505 if (*loop == ',') 1506 ++loop; 1507 if (*loop == '\0') 1508 break; 1509 p = strchr(loop, ','); 1510 if (p != NULL) 1511 len = p - loop; 1512 else 1513 len = strlen(loop); 1514 if (len == 0 || sizeof(buf) - 1 < len) 1515 break; 1516 1517 strncpy(buf, loop, len); 1518 buf[len] = '\0'; 1519 loop += len; 1520 if ((p = strrchr(buf, '/')) != NULL) { 1521 *p = '\0'; 1522 addrp = parse_ip6mask(p + 1); 1523 } else { 1524 addrp = parse_ip6mask(NULL); 1525 } 1526 memcpy(*maskpp + i, addrp, sizeof(*addrp)); 1527 1528 /* if a null mask is given, the name is ignored, like in "any/0" */ 1529 if (memcmp(*maskpp + i, &in6addr_any, sizeof(in6addr_any)) == 0) 1530 strcpy(buf, "::"); 1531 1532 addrp = ip6parse_hostnetwork(buf, &n); 1533 /* ip6parse_hostnetwork only ever returns one IP 1534 address (it exits if the resolution fails). 1535 Therefore, n will always be 1 here. Leaving the 1536 code below in anyway in case ip6parse_hostnetwork 1537 is improved some day to behave like 1538 ipparse_hostnetwork: */ 1539 if (n > 1) { 1540 count += n - 1; 1541 *addrpp = xtables_realloc(*addrpp, 1542 sizeof(struct in6_addr) * count); 1543 *maskpp = xtables_realloc(*maskpp, 1544 sizeof(struct in6_addr) * count); 1545 for (j = 0; j < n; ++j) 1546 /* for each new addr */ 1547 memcpy(*addrpp + i + j, addrp + j, 1548 sizeof(*addrp)); 1549 for (j = 1; j < n; ++j) 1550 /* for each new mask */ 1551 memcpy(*maskpp + i + j, *maskpp + i, 1552 sizeof(*addrp)); 1553 i += n - 1; 1554 } else { 1555 memcpy(*addrpp + i, addrp, sizeof(*addrp)); 1556 } 1557 /* free what ip6parse_hostnetwork had allocated: */ 1558 free(addrp); 1559 } 1560 *naddrs = count; 1561 for (i = 0; i < n; ++i) 1562 for (j = 0; j < 4; ++j) 1563 (*addrpp+i)->s6_addr32[j] &= (*maskpp+i)->s6_addr32[j]; 1564} 1565 1566void xtables_ip6parse_any(const char *name, struct in6_addr **addrpp, 1567 struct in6_addr *maskp, unsigned int *naddrs) 1568{ 1569 static const struct in6_addr zero_addr; 1570 struct in6_addr *addrp; 1571 unsigned int i, j, k, n; 1572 char buf[256], *p; 1573 1574 strncpy(buf, name, sizeof(buf) - 1); 1575 buf[sizeof(buf)-1] = '\0'; 1576 if ((p = strrchr(buf, '/')) != NULL) { 1577 *p = '\0'; 1578 addrp = parse_ip6mask(p + 1); 1579 } else { 1580 addrp = parse_ip6mask(NULL); 1581 } 1582 memcpy(maskp, addrp, sizeof(*maskp)); 1583 1584 /* if a null mask is given, the name is ignored, like in "any/0" */ 1585 if (memcmp(maskp, &zero_addr, sizeof(zero_addr)) == 0) 1586 strcpy(buf, "::"); 1587 1588 addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs); 1589 n = *naddrs; 1590 for (i = 0, j = 0; i < n; ++i) { 1591 for (k = 0; k < 4; ++k) 1592 addrp[j].s6_addr32[k] &= maskp->s6_addr32[k]; 1593 ++j; 1594 for (k = 0; k < j - 1; ++k) 1595 if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) { 1596 --*naddrs; 1597 --j; 1598 break; 1599 } 1600 } 1601} 1602 1603void xtables_save_string(const char *value) 1604{ 1605 static const char no_quote_chars[] = "_-0123456789" 1606 "abcdefghijklmnopqrstuvwxyz" 1607 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 1608 static const char escape_chars[] = "\"\\'"; 1609 size_t length; 1610 const char *p; 1611 1612 length = strcspn(value, no_quote_chars); 1613 if (length > 0 && value[length] == 0) { 1614 /* no quoting required */ 1615 fputs(value, stdout); 1616 putchar(' '); 1617 } else { 1618 /* there is at least one dangerous character in the 1619 value, which we have to quote. Write double quotes 1620 around the value and escape special characters with 1621 a backslash */ 1622 putchar('"'); 1623 1624 for (p = strpbrk(value, escape_chars); p != NULL; 1625 p = strpbrk(value, escape_chars)) { 1626 if (p > value) 1627 fwrite(value, 1, p - value, stdout); 1628 putchar('\\'); 1629 putchar(*p); 1630 value = p + 1; 1631 } 1632 1633 /* print the rest and finish the double quoted 1634 string */ 1635 fputs(value, stdout); 1636 printf("\" "); 1637 } 1638} 1639 1640/** 1641 * Check for option-intrapositional negation. 1642 * Do not use in new code. 1643 */ 1644int xtables_check_inverse(const char option[], int *invert, 1645 int *my_optind, int argc) 1646{ 1647 if (option && strcmp(option, "!") == 0) { 1648 fprintf(stderr, "Using intrapositioned negation " 1649 "(`--option ! this`) is deprecated in favor of " 1650 "extrapositioned (`! --option this`).\n"); 1651 1652 if (*invert) 1653 xt_params->exit_err(PARAMETER_PROBLEM, 1654 "Multiple `!' flags not allowed"); 1655 *invert = true; 1656 if (my_optind != NULL) { 1657 ++*my_optind; 1658 if (argc && *my_optind > argc) 1659 xt_params->exit_err(PARAMETER_PROBLEM, 1660 "no argument following `!'"); 1661 } 1662 1663 return true; 1664 } 1665 return false; 1666} 1667 1668const struct xtables_pprot xtables_chain_protos[] = { 1669 {"tcp", IPPROTO_TCP}, 1670 {"sctp", IPPROTO_SCTP}, 1671 {"udp", IPPROTO_UDP}, 1672 {"udplite", IPPROTO_UDPLITE}, 1673 {"icmp", IPPROTO_ICMP}, 1674 {"icmpv6", IPPROTO_ICMPV6}, 1675 {"ipv6-icmp", IPPROTO_ICMPV6}, 1676 {"esp", IPPROTO_ESP}, 1677 {"ah", IPPROTO_AH}, 1678 {"ipv6-mh", IPPROTO_MH}, 1679 {"mh", IPPROTO_MH}, 1680 {"all", 0}, 1681 {NULL}, 1682}; 1683 1684u_int16_t 1685xtables_parse_protocol(const char *s) 1686{ 1687 unsigned int proto; 1688 1689 if (!xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX)) { 1690 struct protoent *pent; 1691 1692 /* first deal with the special case of 'all' to prevent 1693 * people from being able to redefine 'all' in nsswitch 1694 * and/or provoke expensive [not working] ldap/nis/... 1695 * lookups */ 1696 if (!strcmp(s, "all")) 1697 return 0; 1698 1699 if ((pent = getprotobyname(s))) 1700 proto = pent->p_proto; 1701 else { 1702 unsigned int i; 1703 for (i = 0; i < ARRAY_SIZE(xtables_chain_protos); ++i) { 1704 if (xtables_chain_protos[i].name == NULL) 1705 continue; 1706 1707 if (strcmp(s, xtables_chain_protos[i].name) == 0) { 1708 proto = xtables_chain_protos[i].num; 1709 break; 1710 } 1711 } 1712 if (i == ARRAY_SIZE(xtables_chain_protos)) 1713 xt_params->exit_err(PARAMETER_PROBLEM, 1714 "unknown protocol `%s' specified", 1715 s); 1716 } 1717 } 1718 1719 return proto; 1720} 1721