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