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