2 * (C) 2000-2006 by the netfilter coreteam <coreteam@netfilter.org>:
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.
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.
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.
28 #include <sys/socket.h>
30 #include <sys/types.h>
32 #include <arpa/inet.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>
40 #ifndef NO_SHARED_LIBS
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)
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
56 #ifndef PROC_SYS_MODPROBE
57 #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
60 void basic_exit_err(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
62 struct xtables_globals *xt_params = NULL;
64 void basic_exit_err(enum xtables_exittype status, const char *msg, ...)
69 fprintf(stderr, "%s v%s: ", xt_params->program_name, xt_params->program_version);
70 vfprintf(stderr, msg, args);
72 fprintf(stderr, "\n");
77 void xtables_free_opts(int reset_offset)
79 if (xt_params->opts != xt_params->orig_opts) {
80 free(xt_params->opts);
81 xt_params->opts = xt_params->orig_opts;
83 xt_params->option_offset = 0;
87 struct option *xtables_merge_options(struct option *oldopts,
88 const struct option *newopts,
89 unsigned int *option_offset)
91 unsigned int num_old, num_new, i;
97 for (num_old = 0; oldopts[num_old].name; num_old++) ;
98 for (num_new = 0; newopts[num_new].name; num_new++) ;
100 xt_params->option_offset += 256;
101 *option_offset = xt_params->option_offset;
103 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
106 memcpy(merge, oldopts, num_old * sizeof(struct option));
107 xtables_free_opts(0); /* Release any old options merged */
108 for (i = 0; i < num_new; i++) {
109 merge[num_old + i] = newopts[i];
110 merge[num_old + i].val += *option_offset;
112 memset(merge + num_old + num_new, 0, sizeof(struct option));
118 * xtables_afinfo - protocol family dependent information
119 * @kmod: kernel module basename (e.g. "ip_tables")
120 * @libprefix: prefix of .so library name (e.g. "libipt_")
121 * @family: nfproto family
122 * @ipproto: used by setsockopt (e.g. IPPROTO_IP)
123 * @so_rev_match: optname to check revision support of match
124 * @so_rev_target: optname to check revision support of target
126 struct xtables_afinfo {
128 const char *libprefix;
135 static const struct xtables_afinfo afinfo_ipv4 = {
137 .libprefix = "libipt_",
138 .family = NFPROTO_IPV4,
139 .ipproto = IPPROTO_IP,
140 .so_rev_match = IPT_SO_GET_REVISION_MATCH,
141 .so_rev_target = IPT_SO_GET_REVISION_TARGET,
144 static const struct xtables_afinfo afinfo_ipv6 = {
145 .kmod = "ip6_tables",
146 .libprefix = "libip6t_",
147 .family = NFPROTO_IPV6,
148 .ipproto = IPPROTO_IPV6,
149 .so_rev_match = IP6T_SO_GET_REVISION_MATCH,
150 .so_rev_target = IP6T_SO_GET_REVISION_TARGET,
153 static const struct xtables_afinfo *afinfo;
155 /* Search path for Xtables .so files */
156 static const char *xtables_libdir;
158 /* the path to command to load kernel module */
159 const char *xtables_modprobe_program;
161 /* Keeping track of external matches and targets: linked lists. */
162 struct xtables_match *xtables_matches;
163 struct xtables_target *xtables_targets;
165 void xtables_init(void)
167 xtables_libdir = getenv("XTABLES_LIBDIR");
168 if (xtables_libdir != NULL)
170 xtables_libdir = getenv("IPTABLES_LIB_DIR");
171 if (xtables_libdir != NULL) {
172 fprintf(stderr, "IPTABLES_LIB_DIR is deprecated, "
173 "use XTABLES_LIBDIR.\n");
177 * Well yes, IP6TABLES_LIB_DIR is of lower priority over
178 * IPTABLES_LIB_DIR since this moved to libxtables; I think that is ok
179 * for these env vars are deprecated anyhow, and in light of the
180 * (shared) libxt_*.so files, makes less sense to have
181 * IPTABLES_LIB_DIR != IP6TABLES_LIB_DIR.
183 xtables_libdir = getenv("IP6TABLES_LIB_DIR");
184 if (xtables_libdir != NULL) {
185 fprintf(stderr, "IP6TABLES_LIB_DIR is deprecated, "
186 "use XTABLES_LIBDIR.\n");
189 xtables_libdir = XTABLES_LIBDIR;
192 void xtables_set_nfproto(uint8_t nfproto)
196 afinfo = &afinfo_ipv4;
199 afinfo = &afinfo_ipv6;
202 fprintf(stderr, "libxtables: unhandled NFPROTO in %s\n",
208 * xtables_set_params - set the global parameters used by xtables
209 * @xtp: input xtables_globals structure
211 * The app is expected to pass a valid xtables_globals data-filled
213 * @xtp cannot be NULL
215 * Returns -1 on failure to set and 0 on success
217 int xtables_set_params(struct xtables_globals *xtp)
220 fprintf(stderr, "%s: Illegal global params\n",__func__);
226 if (!xt_params->exit_err)
227 xt_params->exit_err = basic_exit_err;
232 int xtables_init_all(struct xtables_globals *xtp, uint8_t nfproto)
235 xtables_set_nfproto(nfproto);
236 return xtables_set_params(xtp);
240 * xtables_*alloc - wrappers that exit on failure
242 void *xtables_calloc(size_t count, size_t size)
246 if ((p = calloc(count, size)) == NULL) {
247 perror("ip[6]tables: calloc failed");
254 void *xtables_malloc(size_t size)
258 if ((p = malloc(size)) == NULL) {
259 perror("ip[6]tables: malloc failed");
266 void *xtables_realloc(void *ptr, size_t size)
270 if ((p = realloc(ptr, size)) == NULL) {
271 perror("ip[6]tables: realloc failed");
278 static char *get_modprobe(void)
283 #define PROCFILE_BUFSIZ 1024
284 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
288 ret = (char *) malloc(PROCFILE_BUFSIZ);
290 memset(ret, 0, PROCFILE_BUFSIZ);
291 switch (read(procfile, ret, PROCFILE_BUFSIZ)) {
293 case PROCFILE_BUFSIZ: goto fail; /* Partial read. Wierd */
295 if (ret[strlen(ret)-1]=='\n')
296 ret[strlen(ret)-1]=0;
306 int xtables_insmod(const char *modname, const char *modprobe, bool quiet)
312 /* If they don't explicitly set it, read out of kernel */
314 buf = get_modprobe();
321 * Need to flush the buffer, or the child may output it again
322 * when switching the program thru execv.
328 argv[0] = (char *)modprobe;
329 argv[1] = (char *)modname;
337 execv(argv[0], argv);
339 /* not usually reached */
344 default: /* parent */
349 if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
354 int xtables_load_ko(const char *modprobe, bool quiet)
356 static bool loaded = false;
360 ret = xtables_insmod(afinfo->kmod, modprobe, quiet);
368 * xtables_strtou{i,l} - string to number conversion
370 * @end: like strtoul's "end" pointer
371 * @value: pointer for result
372 * @min: minimum accepted value
373 * @max: maximum accepted value
375 * If @end is NULL, we assume the caller wants a "strict strtoul", and hence
377 * In either case, the value obtained is compared for min-max compliance.
378 * Base is always 0, i.e. autodetect depending on @s.
380 * Returns true/false whether number was accepted. On failure, *value has
381 * undefined contents.
383 bool xtables_strtoul(const char *s, char **end, unsigned long *value,
384 unsigned long min, unsigned long max)
390 v = strtoul(s, &my_end, 0);
397 if (errno != ERANGE && min <= v && (max == 0 || v <= max)) {
401 return *my_end == '\0';
408 bool xtables_strtoui(const char *s, char **end, unsigned int *value,
409 unsigned int min, unsigned int max)
414 ret = xtables_strtoul(s, end, &v, min, max);
420 int xtables_service_to_port(const char *name, const char *proto)
422 struct servent *service;
424 if ((service = getservbyname(name, proto)) != NULL)
425 return ntohs((unsigned short) service->s_port);
430 u_int16_t xtables_parse_port(const char *port, const char *proto)
432 unsigned int portnum;
434 if (xtables_strtoui(port, NULL, &portnum, 0, UINT16_MAX) ||
435 (portnum = xtables_service_to_port(port, proto)) != (unsigned)-1)
438 xt_params->exit_err(PARAMETER_PROBLEM,
439 "invalid port/service `%s' specified", port);
442 void xtables_parse_interface(const char *arg, char *vianame,
445 unsigned int vialen = strlen(arg);
448 memset(mask, 0, IFNAMSIZ);
449 memset(vianame, 0, IFNAMSIZ);
451 if (vialen + 1 > IFNAMSIZ)
452 xt_params->exit_err(PARAMETER_PROBLEM,
453 "interface name `%s' must be shorter than IFNAMSIZ"
454 " (%i)", arg, IFNAMSIZ-1);
456 strcpy(vianame, arg);
458 memset(mask, 0, IFNAMSIZ);
459 else if (vianame[vialen - 1] == '+') {
460 memset(mask, 0xFF, vialen - 1);
461 memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1);
462 /* Don't remove `+' here! -HW */
464 /* Include nul-terminator in match */
465 memset(mask, 0xFF, vialen + 1);
466 memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1);
467 for (i = 0; vianame[i]; i++) {
468 if (vianame[i] == '/' ||
471 "Warning: weird character in interface"
472 " `%s' ('/' and ' ' are not allowed by the kernel).\n",
480 #ifndef NO_SHARED_LIBS
481 static void *load_extension(const char *search_path, const char *prefix,
482 const char *name, bool is_target)
484 const char *dir = search_path, *next;
490 next = strchr(dir, ':');
492 next = dir + strlen(dir);
493 snprintf(path, sizeof(path), "%.*s/libxt_%s.so",
494 (unsigned int)(next - dir), dir, name);
496 if (dlopen(path, RTLD_NOW) != NULL) {
497 /* Found library. If it didn't register itself,
498 maybe they specified target as match. */
500 ptr = xtables_find_target(name, XTF_DONT_LOAD);
502 ptr = xtables_find_match(name,
503 XTF_DONT_LOAD, NULL);
504 } else if (stat(path, &sb) == 0) {
505 fprintf(stderr, "%s: %s\n", path, dlerror());
511 snprintf(path, sizeof(path), "%.*s/%s%s.so",
512 (unsigned int)(next - dir), dir, prefix, name);
513 if (dlopen(path, RTLD_NOW) != NULL) {
515 ptr = xtables_find_target(name, XTF_DONT_LOAD);
517 ptr = xtables_find_match(name,
518 XTF_DONT_LOAD, NULL);
519 } else if (stat(path, &sb) == 0) {
520 fprintf(stderr, "%s: %s\n", path, dlerror());
527 } while (*next != '\0');
533 struct xtables_match *
534 xtables_find_match(const char *name, enum xtables_tryload tryload,
535 struct xtables_rule_match **matches)
537 struct xtables_match *ptr;
538 const char *icmp6 = "icmp6";
540 if (strlen(name) >= XT_EXTENSION_MAXNAMELEN)
541 xtables_error(PARAMETER_PROBLEM,
542 "Invalid match name \"%s\" (%u chars max)",
543 name, XT_EXTENSION_MAXNAMELEN - 1);
545 /* This is ugly as hell. Nonetheless, there is no way of changing
546 * this without hurting backwards compatibility */
547 if ( (strcmp(name,"icmpv6") == 0) ||
548 (strcmp(name,"ipv6-icmp") == 0) ||
549 (strcmp(name,"icmp6") == 0) )
552 for (ptr = xtables_matches; ptr; ptr = ptr->next) {
553 if (strcmp(name, ptr->name) == 0) {
554 struct xtables_match *clone;
556 /* First match of this type: */
560 /* Second and subsequent clones */
561 clone = xtables_malloc(sizeof(struct xtables_match));
562 memcpy(clone, ptr, sizeof(struct xtables_match));
564 /* This is a clone: */
572 #ifndef NO_SHARED_LIBS
573 if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
574 ptr = load_extension(xtables_libdir, afinfo->libprefix,
577 if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
578 xt_params->exit_err(PARAMETER_PROBLEM,
579 "Couldn't load match `%s':%s\n",
583 if (ptr && !ptr->loaded) {
584 if (tryload != XTF_DONT_LOAD)
589 if(!ptr && (tryload == XTF_LOAD_MUST_SUCCEED)) {
590 xt_params->exit_err(PARAMETER_PROBLEM,
591 "Couldn't find match `%s'\n", name);
595 if (ptr && matches) {
596 struct xtables_rule_match **i;
597 struct xtables_rule_match *newentry;
599 newentry = xtables_malloc(sizeof(struct xtables_rule_match));
601 for (i = matches; *i; i = &(*i)->next) {
602 if (strcmp(name, (*i)->match->name) == 0)
603 (*i)->completed = true;
605 newentry->match = ptr;
606 newentry->completed = false;
607 newentry->next = NULL;
614 struct xtables_target *
615 xtables_find_target(const char *name, enum xtables_tryload tryload)
617 struct xtables_target *ptr;
619 /* Standard target? */
620 if (strcmp(name, "") == 0
621 || strcmp(name, XTC_LABEL_ACCEPT) == 0
622 || strcmp(name, XTC_LABEL_DROP) == 0
623 || strcmp(name, XTC_LABEL_QUEUE) == 0
624 || strcmp(name, XTC_LABEL_RETURN) == 0)
627 for (ptr = xtables_targets; ptr; ptr = ptr->next) {
628 if (strcmp(name, ptr->name) == 0)
632 #ifndef NO_SHARED_LIBS
633 if (!ptr && tryload != XTF_DONT_LOAD && tryload != XTF_DURING_LOAD) {
634 ptr = load_extension(xtables_libdir, afinfo->libprefix,
637 if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED)
638 xt_params->exit_err(PARAMETER_PROBLEM,
639 "Couldn't load target `%s':%s\n",
643 if (ptr && !ptr->loaded) {
644 if (tryload != XTF_DONT_LOAD)
649 if (ptr == NULL && tryload == XTF_LOAD_MUST_SUCCEED) {
650 xt_params->exit_err(PARAMETER_PROBLEM,
651 "Couldn't find target `%s'\n", name);
661 static int compatible_revision(const char *name, u_int8_t revision, int opt)
663 struct xt_get_revision rev;
664 socklen_t s = sizeof(rev);
667 sockfd = socket(afinfo->family, SOCK_RAW, IPPROTO_RAW);
669 if (errno == EPERM) {
670 /* revision 0 is always supported. */
672 fprintf(stderr, "Could not determine whether "
673 "revision %u is supported, "
678 fprintf(stderr, "Could not open socket to kernel: %s\n",
683 xtables_load_ko(xtables_modprobe_program, true);
685 strcpy(rev.name, name);
686 rev.revision = revision;
688 max_rev = getsockopt(sockfd, afinfo->ipproto, opt, &rev, &s);
690 /* Definitely don't support this? */
691 if (errno == ENOENT || errno == EPROTONOSUPPORT) {
694 } else if (errno == ENOPROTOOPT) {
696 /* Assume only revision 0 support (old kernel) */
697 return (revision == 0);
699 fprintf(stderr, "getsockopt failed strangely: %s\n",
709 static int compatible_match_revision(const char *name, u_int8_t revision)
711 return compatible_revision(name, revision, afinfo->so_rev_match);
714 static int compatible_target_revision(const char *name, u_int8_t revision)
716 return compatible_revision(name, revision, afinfo->so_rev_target);
719 void xtables_register_match(struct xtables_match *me)
721 struct xtables_match **i, *old;
723 if (me->version == NULL) {
724 fprintf(stderr, "%s: match %s<%u> is missing a version\n",
725 xt_params->program_name, me->name, me->revision);
728 if (strcmp(me->version, XTABLES_VERSION) != 0) {
729 fprintf(stderr, "%s: match \"%s\" has version \"%s\", "
730 "but \"%s\" is required.\n",
731 xt_params->program_name, me->name,
732 me->version, XTABLES_VERSION);
736 if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
737 fprintf(stderr, "%s: target `%s' has invalid name\n",
738 xt_params->program_name, me->name);
742 if (me->family >= NPROTO) {
744 "%s: BUG: match %s has invalid protocol family\n",
745 xt_params->program_name, me->name);
749 /* ignore not interested match */
750 if (me->family != afinfo->family && me->family != AF_UNSPEC)
753 old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL);
755 if (old->revision == me->revision &&
756 old->family == me->family) {
758 "%s: match `%s' already registered.\n",
759 xt_params->program_name, me->name);
763 /* Now we have two (or more) options, check compatibility. */
764 if (compatible_match_revision(old->name, old->revision)
765 && old->revision > me->revision)
768 /* See if new match can be used. */
769 if (!compatible_match_revision(me->name, me->revision))
772 /* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
773 if (old->revision == me->revision && me->family == AF_UNSPEC)
776 /* Delete old one. */
777 for (i = &xtables_matches; *i!=old; i = &(*i)->next);
781 if (me->size != XT_ALIGN(me->size)) {
782 fprintf(stderr, "%s: match `%s' has invalid size %u.\n",
783 xt_params->program_name, me->name,
784 (unsigned int)me->size);
788 /* Append to list. */
789 for (i = &xtables_matches; *i; i = &(*i)->next);
797 void xtables_register_matches(struct xtables_match *match, unsigned int n)
800 xtables_register_match(&match[--n]);
804 void xtables_register_target(struct xtables_target *me)
806 struct xtables_target *old;
808 if (me->version == NULL) {
809 fprintf(stderr, "%s: target %s<%u> is missing a version\n",
810 xt_params->program_name, me->name, me->revision);
813 if (strcmp(me->version, XTABLES_VERSION) != 0) {
814 fprintf(stderr, "%s: target \"%s\" has version \"%s\", "
815 "but \"%s\" is required.\n",
816 xt_params->program_name, me->name,
817 me->version, XTABLES_VERSION);
821 if (strlen(me->name) >= XT_EXTENSION_MAXNAMELEN) {
822 fprintf(stderr, "%s: target `%s' has invalid name\n",
823 xt_params->program_name, me->name);
827 if (me->family >= NPROTO) {
829 "%s: BUG: target %s has invalid protocol family\n",
830 xt_params->program_name, me->name);
834 /* ignore not interested target */
835 if (me->family != afinfo->family && me->family != AF_UNSPEC)
838 old = xtables_find_target(me->name, XTF_DURING_LOAD);
840 struct xtables_target **i;
842 if (old->revision == me->revision &&
843 old->family == me->family) {
845 "%s: target `%s' already registered.\n",
846 xt_params->program_name, me->name);
850 /* Now we have two (or more) options, check compatibility. */
851 if (compatible_target_revision(old->name, old->revision)
852 && old->revision > me->revision)
855 /* See if new target can be used. */
856 if (!compatible_target_revision(me->name, me->revision))
859 /* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
860 if (old->revision == me->revision && me->family == AF_UNSPEC)
863 /* Delete old one. */
864 for (i = &xtables_targets; *i!=old; i = &(*i)->next);
868 if (me->size != XT_ALIGN(me->size)) {
869 fprintf(stderr, "%s: target `%s' has invalid size %u.\n",
870 xt_params->program_name, me->name,
871 (unsigned int)me->size);
875 /* Prepend to list. */
876 me->next = xtables_targets;
877 xtables_targets = me;
882 void xtables_register_targets(struct xtables_target *target, unsigned int n)
885 xtables_register_target(&target[--n]);
890 * xtables_param_act - act on condition
891 * @status: a constant from enum xtables_exittype
893 * %XTF_ONLY_ONCE: print error message that option may only be used once.
894 * @p1: module name (e.g. "mark")
895 * @p2(...): option in conflict (e.g. "--mark")
896 * @p3(...): condition to match on (see extensions/ for examples)
898 * %XTF_NO_INVERT: option does not support inversion
900 * @p2: option in conflict
901 * @p3: condition to match on
903 * %XTF_BAD_VALUE: bad value for option
905 * @p2: option with which the problem occured (e.g. "--mark")
906 * @p3: string the user passed in (e.g. "99999999999999")
908 * %XTF_ONE_ACTION: two mutually exclusive actions have been specified
911 * Displays an error message and exits the program.
913 void xtables_param_act(unsigned int status, const char *p1, ...)
923 p2 = va_arg(args, const char *);
924 b = va_arg(args, unsigned int);
927 xt_params->exit_err(PARAMETER_PROBLEM,
928 "%s: \"%s\" option may only be specified once",
932 p2 = va_arg(args, const char *);
933 b = va_arg(args, unsigned int);
936 xt_params->exit_err(PARAMETER_PROBLEM,
937 "%s: \"%s\" option cannot be inverted", p1, p2);
940 p2 = va_arg(args, const char *);
941 p3 = va_arg(args, const char *);
942 xt_params->exit_err(PARAMETER_PROBLEM,
943 "%s: Bad value for \"%s\" option: \"%s\"",
947 b = va_arg(args, unsigned int);
950 xt_params->exit_err(PARAMETER_PROBLEM,
951 "%s: At most one action is possible", p1);
954 xt_params->exit_err(status, p1, args);
961 const char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
964 const unsigned char *bytep = (const void *)&addrp->s_addr;
966 sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
970 static const char *ipaddr_to_host(const struct in_addr *addr)
972 struct hostent *host;
974 host = gethostbyaddr(addr, sizeof(struct in_addr), AF_INET);
981 static const char *ipaddr_to_network(const struct in_addr *addr)
985 if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL)
991 const char *xtables_ipaddr_to_anyname(const struct in_addr *addr)
995 if ((name = ipaddr_to_host(addr)) != NULL ||
996 (name = ipaddr_to_network(addr)) != NULL)
999 return xtables_ipaddr_to_numeric(addr);
1002 const char *xtables_ipmask_to_numeric(const struct in_addr *mask)
1004 static char buf[20];
1005 uint32_t maskaddr, bits;
1008 maskaddr = ntohl(mask->s_addr);
1010 if (maskaddr == 0xFFFFFFFFL)
1011 /* we don't want to see "/32" */
1016 while (--i >= 0 && maskaddr != bits)
1019 sprintf(buf, "/%d", i);
1021 /* mask was not a decent combination of 1's and 0's */
1022 sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask));
1027 static struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask)
1029 static struct in_addr addr;
1030 unsigned char *addrp;
1031 unsigned int onebyte;
1032 char buf[20], *p, *q;
1035 /* copy dotted string, because we need to modify it */
1036 strncpy(buf, dotted, sizeof(buf) - 1);
1037 buf[sizeof(buf) - 1] = '\0';
1038 addrp = (void *)&addr.s_addr;
1041 for (i = 0; i < 3; ++i) {
1042 if ((q = strchr(p, '.')) == NULL) {
1046 /* autocomplete, this is a network address */
1047 if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1058 if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1065 /* we have checked 3 bytes, now we check the last one */
1066 if (!xtables_strtoui(p, NULL, &onebyte, 0, UINT8_MAX))
1073 struct in_addr *xtables_numeric_to_ipaddr(const char *dotted)
1075 return __numeric_to_ipaddr(dotted, false);
1078 struct in_addr *xtables_numeric_to_ipmask(const char *dotted)
1080 return __numeric_to_ipaddr(dotted, true);
1083 static struct in_addr *network_to_ipaddr(const char *name)
1085 static struct in_addr addr;
1088 if ((net = getnetbyname(name)) != NULL) {
1089 if (net->n_addrtype != AF_INET)
1091 addr.s_addr = htonl(net->n_net);
1098 static struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
1100 struct hostent *host;
1101 struct in_addr *addr;
1105 if ((host = gethostbyname(name)) != NULL) {
1106 if (host->h_addrtype != AF_INET ||
1107 host->h_length != sizeof(struct in_addr))
1110 while (host->h_addr_list[*naddr] != NULL)
1112 addr = xtables_calloc(*naddr, sizeof(struct in_addr) * *naddr);
1113 for (i = 0; i < *naddr; i++)
1114 memcpy(&addr[i], host->h_addr_list[i],
1115 sizeof(struct in_addr));
1122 static struct in_addr *
1123 ipparse_hostnetwork(const char *name, unsigned int *naddrs)
1125 struct in_addr *addrptmp, *addrp;
1127 if ((addrptmp = xtables_numeric_to_ipaddr(name)) != NULL ||
1128 (addrptmp = network_to_ipaddr(name)) != NULL) {
1129 addrp = xtables_malloc(sizeof(struct in_addr));
1130 memcpy(addrp, addrptmp, sizeof(*addrp));
1134 if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)
1137 xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1140 static struct in_addr *parse_ipmask(const char *mask)
1142 static struct in_addr maskaddr;
1143 struct in_addr *addrp;
1147 /* no mask at all defaults to 32 bits */
1148 maskaddr.s_addr = 0xFFFFFFFF;
1151 if ((addrp = xtables_numeric_to_ipmask(mask)) != NULL)
1152 /* dotted_to_addr already returns a network byte order addr */
1154 if (!xtables_strtoui(mask, NULL, &bits, 0, 32))
1155 xt_params->exit_err(PARAMETER_PROBLEM,
1156 "invalid mask `%s' specified", mask);
1158 maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
1162 maskaddr.s_addr = 0U;
1166 void xtables_ipparse_multiple(const char *name, struct in_addr **addrpp,
1167 struct in_addr **maskpp, unsigned int *naddrs)
1169 struct in_addr *addrp;
1171 unsigned int len, i, j, n, count = 1;
1172 const char *loop = name;
1174 while ((loop = strchr(loop, ',')) != NULL) {
1176 ++loop; /* skip ',' */
1179 *addrpp = xtables_malloc(sizeof(struct in_addr) * count);
1180 *maskpp = xtables_malloc(sizeof(struct in_addr) * count);
1184 for (i = 0; i < count; ++i) {
1191 p = strchr(loop, ',');
1196 if (len == 0 || sizeof(buf) - 1 < len)
1199 strncpy(buf, loop, len);
1202 if ((p = strrchr(buf, '/')) != NULL) {
1204 addrp = parse_ipmask(p + 1);
1206 addrp = parse_ipmask(NULL);
1208 memcpy(*maskpp + i, addrp, sizeof(*addrp));
1210 /* if a null mask is given, the name is ignored, like in "any/0" */
1211 if ((*maskpp + i)->s_addr == 0)
1213 * A bit pointless to process multiple addresses
1216 strcpy(buf, "0.0.0.0");
1218 addrp = ipparse_hostnetwork(buf, &n);
1221 *addrpp = xtables_realloc(*addrpp,
1222 sizeof(struct in_addr) * count);
1223 *maskpp = xtables_realloc(*maskpp,
1224 sizeof(struct in_addr) * count);
1225 for (j = 0; j < n; ++j)
1226 /* for each new addr */
1227 memcpy(*addrpp + i + j, addrp + j,
1229 for (j = 1; j < n; ++j)
1230 /* for each new mask */
1231 memcpy(*maskpp + i + j, *maskpp + i,
1235 memcpy(*addrpp + i, addrp, sizeof(*addrp));
1237 /* free what ipparse_hostnetwork had allocated: */
1241 for (i = 0; i < n; ++i)
1242 (*addrpp+i)->s_addr &= (*maskpp+i)->s_addr;
1247 * xtables_ipparse_any - transform arbitrary name to in_addr
1249 * Possible inputs (pseudo regex):
1250 * m{^($hostname|$networkname|$ipaddr)(/$mask)?}
1251 * "1.2.3.4/5", "1.2.3.4", "hostname", "networkname"
1253 void xtables_ipparse_any(const char *name, struct in_addr **addrpp,
1254 struct in_addr *maskp, unsigned int *naddrs)
1256 unsigned int i, j, k, n;
1257 struct in_addr *addrp;
1260 strncpy(buf, name, sizeof(buf) - 1);
1261 buf[sizeof(buf) - 1] = '\0';
1262 if ((p = strrchr(buf, '/')) != NULL) {
1264 addrp = parse_ipmask(p + 1);
1266 addrp = parse_ipmask(NULL);
1268 memcpy(maskp, addrp, sizeof(*maskp));
1270 /* if a null mask is given, the name is ignored, like in "any/0" */
1271 if (maskp->s_addr == 0U)
1272 strcpy(buf, "0.0.0.0");
1274 addrp = *addrpp = ipparse_hostnetwork(buf, naddrs);
1276 for (i = 0, j = 0; i < n; ++i) {
1277 addrp[j++].s_addr &= maskp->s_addr;
1278 for (k = 0; k < j - 1; ++k)
1279 if (addrp[k].s_addr == addrp[j-1].s_addr) {
1287 const char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp)
1289 /* 0000:0000:0000:0000:0000:000.000.000.000
1290 * 0000:0000:0000:0000:0000:0000:0000:0000 */
1291 static char buf[50+1];
1292 return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
1295 static const char *ip6addr_to_host(const struct in6_addr *addr)
1297 static char hostname[NI_MAXHOST];
1298 struct sockaddr_in6 saddr;
1301 memset(&saddr, 0, sizeof(struct sockaddr_in6));
1302 memcpy(&saddr.sin6_addr, addr, sizeof(*addr));
1303 saddr.sin6_family = AF_INET6;
1305 err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6),
1306 hostname, sizeof(hostname) - 1, NULL, 0, 0);
1309 fprintf(stderr,"IP2Name: %s\n",gai_strerror(err));
1315 fprintf (stderr, "\naddr2host: %s\n", hostname);
1320 const char *xtables_ip6addr_to_anyname(const struct in6_addr *addr)
1324 if ((name = ip6addr_to_host(addr)) != NULL)
1327 return xtables_ip6addr_to_numeric(addr);
1330 static int ip6addr_prefix_length(const struct in6_addr *k)
1332 unsigned int bits = 0;
1333 uint32_t a, b, c, d;
1335 a = ntohl(k->s6_addr32[0]);
1336 b = ntohl(k->s6_addr32[1]);
1337 c = ntohl(k->s6_addr32[2]);
1338 d = ntohl(k->s6_addr32[3]);
1339 while (a & 0x80000000U) {
1349 if (a != 0 || b != 0 || c != 0 || d != 0)
1354 const char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
1356 static char buf[50+2];
1357 int l = ip6addr_prefix_length(addrp);
1361 strcat(buf, xtables_ip6addr_to_numeric(addrp));
1364 sprintf(buf, "/%d", l);
1368 struct in6_addr *xtables_numeric_to_ip6addr(const char *num)
1370 static struct in6_addr ap;
1373 if ((err = inet_pton(AF_INET6, num, &ap)) == 1)
1376 fprintf(stderr, "\nnumeric2addr: %d\n", err);
1381 static struct in6_addr *
1382 host_to_ip6addr(const char *name, unsigned int *naddr)
1384 static struct in6_addr *addr;
1385 struct addrinfo hints;
1386 struct addrinfo *res;
1389 memset(&hints, 0, sizeof(hints));
1390 hints.ai_flags = AI_CANONNAME;
1391 hints.ai_family = AF_INET6;
1392 hints.ai_socktype = SOCK_RAW;
1393 hints.ai_protocol = IPPROTO_IPV6;
1394 hints.ai_next = NULL;
1397 if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) {
1399 fprintf(stderr,"Name2IP: %s\n",gai_strerror(err));
1403 if (res->ai_family != AF_INET6 ||
1404 res->ai_addrlen != sizeof(struct sockaddr_in6))
1408 fprintf(stderr, "resolved: len=%d %s ", res->ai_addrlen,
1409 xtables_ip6addr_to_numeric(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr));
1411 /* Get the first element of the address-chain */
1412 addr = xtables_malloc(sizeof(struct in6_addr));
1413 memcpy(addr, &((const struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
1414 sizeof(struct in6_addr));
1423 static struct in6_addr *network_to_ip6addr(const char *name)
1426 /* TODO: not implemented yet, but the exception breaks the
1427 * name resolvation */
1431 static struct in6_addr *
1432 ip6parse_hostnetwork(const char *name, unsigned int *naddrs)
1434 struct in6_addr *addrp, *addrptmp;
1436 if ((addrptmp = xtables_numeric_to_ip6addr(name)) != NULL ||
1437 (addrptmp = network_to_ip6addr(name)) != NULL) {
1438 addrp = xtables_malloc(sizeof(struct in6_addr));
1439 memcpy(addrp, addrptmp, sizeof(*addrp));
1443 if ((addrp = host_to_ip6addr(name, naddrs)) != NULL)
1446 xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1449 static struct in6_addr *parse_ip6mask(char *mask)
1451 static struct in6_addr maskaddr;
1452 struct in6_addr *addrp;
1456 /* no mask at all defaults to 128 bits */
1457 memset(&maskaddr, 0xff, sizeof maskaddr);
1460 if ((addrp = xtables_numeric_to_ip6addr(mask)) != NULL)
1462 if (!xtables_strtoui(mask, NULL, &bits, 0, 128))
1463 xt_params->exit_err(PARAMETER_PROBLEM,
1464 "invalid mask `%s' specified", mask);
1466 char *p = (void *)&maskaddr;
1467 memset(p, 0xff, bits / 8);
1468 memset(p + (bits / 8) + 1, 0, (128 - bits) / 8);
1469 p[bits/8] = 0xff << (8 - (bits & 7));
1473 memset(&maskaddr, 0, sizeof(maskaddr));
1478 xtables_ip6parse_multiple(const char *name, struct in6_addr **addrpp,
1479 struct in6_addr **maskpp, unsigned int *naddrs)
1481 static const struct in6_addr zero_addr;
1482 struct in6_addr *addrp;
1484 unsigned int len, i, j, n, count = 1;
1485 const char *loop = name;
1487 while ((loop = strchr(loop, ',')) != NULL) {
1489 ++loop; /* skip ',' */
1492 *addrpp = xtables_malloc(sizeof(struct in6_addr) * count);
1493 *maskpp = xtables_malloc(sizeof(struct in6_addr) * count);
1497 for (i = 0; i < count /*NB: count can grow*/; ++i) {
1504 p = strchr(loop, ',');
1509 if (len == 0 || sizeof(buf) - 1 < len)
1512 strncpy(buf, loop, len);
1515 if ((p = strrchr(buf, '/')) != NULL) {
1517 addrp = parse_ip6mask(p + 1);
1519 addrp = parse_ip6mask(NULL);
1521 memcpy(*maskpp + i, addrp, sizeof(*addrp));
1523 /* if a null mask is given, the name is ignored, like in "any/0" */
1524 if (memcmp(*maskpp + i, &zero_addr, sizeof(zero_addr)) == 0)
1527 addrp = ip6parse_hostnetwork(buf, &n);
1528 /* ip6parse_hostnetwork only ever returns one IP
1529 address (it exits if the resolution fails).
1530 Therefore, n will always be 1 here. Leaving the
1531 code below in anyway in case ip6parse_hostnetwork
1532 is improved some day to behave like
1533 ipparse_hostnetwork: */
1536 *addrpp = xtables_realloc(*addrpp,
1537 sizeof(struct in6_addr) * count);
1538 *maskpp = xtables_realloc(*maskpp,
1539 sizeof(struct in6_addr) * count);
1540 for (j = 0; j < n; ++j)
1541 /* for each new addr */
1542 memcpy(*addrpp + i + j, addrp + j,
1544 for (j = 1; j < n; ++j)
1545 /* for each new mask */
1546 memcpy(*maskpp + i + j, *maskpp + i,
1550 memcpy(*addrpp + i, addrp, sizeof(*addrp));
1552 /* free what ip6parse_hostnetwork had allocated: */
1556 for (i = 0; i < n; ++i)
1557 for (j = 0; j < 4; ++j)
1558 (*addrpp+i)->s6_addr32[j] &= (*maskpp+i)->s6_addr32[j];
1561 void xtables_ip6parse_any(const char *name, struct in6_addr **addrpp,
1562 struct in6_addr *maskp, unsigned int *naddrs)
1564 static const struct in6_addr zero_addr;
1565 struct in6_addr *addrp;
1566 unsigned int i, j, k, n;
1569 strncpy(buf, name, sizeof(buf) - 1);
1570 buf[sizeof(buf)-1] = '\0';
1571 if ((p = strrchr(buf, '/')) != NULL) {
1573 addrp = parse_ip6mask(p + 1);
1575 addrp = parse_ip6mask(NULL);
1577 memcpy(maskp, addrp, sizeof(*maskp));
1579 /* if a null mask is given, the name is ignored, like in "any/0" */
1580 if (memcmp(maskp, &zero_addr, sizeof(zero_addr)) == 0)
1583 addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs);
1585 for (i = 0, j = 0; i < n; ++i) {
1586 for (k = 0; k < 4; ++k)
1587 addrp[j].s6_addr32[k] &= maskp->s6_addr32[k];
1589 for (k = 0; k < j - 1; ++k)
1590 if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) {
1598 void xtables_save_string(const char *value)
1600 static const char no_quote_chars[] = "_-0123456789"
1601 "abcdefghijklmnopqrstuvwxyz"
1602 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1603 static const char escape_chars[] = "\"\\'";
1607 length = strcspn(value, no_quote_chars);
1608 if (length > 0 && value[length] == 0) {
1609 /* no quoting required */
1610 fputs(value, stdout);
1613 /* there is at least one dangerous character in the
1614 value, which we have to quote. Write double quotes
1615 around the value and escape special characters with
1619 for (p = strpbrk(value, escape_chars); p != NULL;
1620 p = strpbrk(value, escape_chars)) {
1622 fwrite(value, 1, p - value, stdout);
1628 /* print the rest and finish the double quoted
1630 fputs(value, stdout);
1636 * Check for option-intrapositional negation.
1637 * Do not use in new code.
1639 int xtables_check_inverse(const char option[], int *invert,
1640 int *my_optind, int argc, char **argv)
1642 if (option == NULL || strcmp(option, "!") != 0)
1645 fprintf(stderr, "Using intrapositioned negation "
1646 "(`--option ! this`) is deprecated in favor of "
1647 "extrapositioned (`! --option this`).\n");
1650 xt_params->exit_err(PARAMETER_PROBLEM,
1651 "Multiple `!' flags not allowed");
1653 if (my_optind != NULL) {
1654 optarg = argv[*my_optind];
1656 if (argc && *my_optind > argc)
1657 xt_params->exit_err(PARAMETER_PROBLEM,
1658 "no argument following `!'");
1664 const struct xtables_pprot xtables_chain_protos[] = {
1665 {"tcp", IPPROTO_TCP},
1666 {"sctp", IPPROTO_SCTP},
1667 {"udp", IPPROTO_UDP},
1668 {"udplite", IPPROTO_UDPLITE},
1669 {"icmp", IPPROTO_ICMP},
1670 {"icmpv6", IPPROTO_ICMPV6},
1671 {"ipv6-icmp", IPPROTO_ICMPV6},
1672 {"esp", IPPROTO_ESP},
1674 {"ipv6-mh", IPPROTO_MH},
1681 xtables_parse_protocol(const char *s)
1685 if (!xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX)) {
1686 struct protoent *pent;
1688 /* first deal with the special case of 'all' to prevent
1689 * people from being able to redefine 'all' in nsswitch
1690 * and/or provoke expensive [not working] ldap/nis/...
1692 if (!strcmp(s, "all"))
1695 if ((pent = getprotobyname(s)))
1696 proto = pent->p_proto;
1699 for (i = 0; i < ARRAY_SIZE(xtables_chain_protos); ++i) {
1700 if (xtables_chain_protos[i].name == NULL)
1703 if (strcmp(s, xtables_chain_protos[i].name) == 0) {
1704 proto = xtables_chain_protos[i].num;
1708 if (i == ARRAY_SIZE(xtables_chain_protos))
1709 xt_params->exit_err(PARAMETER_PROBLEM,
1710 "unknown protocol `%s' specified",