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