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