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