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>
36 #ifndef NO_SHARED_LIBS
42 #ifndef PROC_SYS_MODPROBE
43 #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
48 /* the path to command to load kernel module */
49 const char *modprobe_program = NULL;
51 /* Keeping track of external matches and targets: linked lists. */
52 struct xtables_match *xtables_matches;
53 struct xtables_target *xtables_targets;
55 void *fw_calloc(size_t count, size_t size)
59 if ((p = calloc(count, size)) == NULL) {
60 perror("ip[6]tables: calloc failed");
67 void *fw_malloc(size_t size)
71 if ((p = malloc(size)) == NULL) {
72 perror("ip[6]tables: malloc failed");
79 static char *get_modprobe(void)
84 #define PROCFILE_BUFSIZ 1024
85 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
89 ret = (char *) malloc(PROCFILE_BUFSIZ);
91 memset(ret, 0, PROCFILE_BUFSIZ);
92 switch (read(procfile, ret, PROCFILE_BUFSIZ)) {
94 case PROCFILE_BUFSIZ: goto fail; /* Partial read. Wierd */
96 if (ret[strlen(ret)-1]=='\n')
107 int xtables_insmod(const char *modname, const char *modprobe, int quiet)
113 /* If they don't explicitly set it, read out of kernel */
115 buf = get_modprobe();
123 argv[0] = (char *)modprobe;
124 argv[1] = (char *)modname;
132 execv(argv[0], argv);
134 /* not usually reached */
139 default: /* parent */
144 if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
149 int load_xtables_ko(const char *modprobe, int quiet)
151 static int loaded = 0;
155 ret = xtables_insmod(afinfo.kmod, modprobe, quiet);
162 int string_to_number_ll(const char *s, unsigned long long min,
163 unsigned long long max, unsigned long long *ret)
165 unsigned long long number;
168 /* Handle hex, octal, etc. */
170 number = strtoull(s, &end, 0);
171 if (*end == '\0' && end != s) {
172 /* we parsed a number, let's see if we want this */
173 if (errno != ERANGE && min <= number && (!max || number <= max)) {
181 int string_to_number_l(const char *s, unsigned long min, unsigned long max,
185 unsigned long long number;
187 result = string_to_number_ll(s, min, max, &number);
188 *ret = (unsigned long)number;
193 int string_to_number(const char *s, unsigned int min, unsigned int max,
197 unsigned long number;
199 result = string_to_number_l(s, min, max, &number);
200 *ret = (unsigned int)number;
206 * strtonum{,l} - string to number conversion
208 * If @end is NULL, we assume the caller does not want
209 * a case like "15a", so reject it.
211 bool strtonuml(const char *s, char **end, unsigned long *value,
212 unsigned long min, unsigned long max)
218 v = strtoul(s, &my_end, 0);
225 if (errno != ERANGE && min <= v && (max == 0 || v <= max)) {
229 return *my_end == '\0';
236 bool strtonum(const char *s, char **end, unsigned int *value,
237 unsigned int min, unsigned int max)
242 ret = strtonuml(s, end, &v, min, max);
248 int service_to_port(const char *name, const char *proto)
250 struct servent *service;
252 if ((service = getservbyname(name, proto)) != NULL)
253 return ntohs((unsigned short) service->s_port);
258 u_int16_t parse_port(const char *port, const char *proto)
260 unsigned int portnum;
262 if ((string_to_number(port, 0, 65535, &portnum)) != -1 ||
263 (portnum = service_to_port(port, proto)) != (unsigned)-1)
264 return (u_int16_t)portnum;
266 exit_error(PARAMETER_PROBLEM,
267 "invalid port/service `%s' specified", port);
270 void parse_interface(const char *arg, char *vianame, unsigned char *mask)
272 int vialen = strlen(arg);
275 memset(mask, 0, IFNAMSIZ);
276 memset(vianame, 0, IFNAMSIZ);
278 if (vialen + 1 > IFNAMSIZ)
279 exit_error(PARAMETER_PROBLEM,
280 "interface name `%s' must be shorter than IFNAMSIZ"
281 " (%i)", arg, IFNAMSIZ-1);
283 strcpy(vianame, arg);
284 if ((vialen == 0) || (vialen == 1 && vianame[0] == '+'))
285 memset(mask, 0, IFNAMSIZ);
286 else if (vianame[vialen - 1] == '+') {
287 memset(mask, 0xFF, vialen - 1);
288 memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1);
289 /* Don't remove `+' here! -HW */
291 /* Include nul-terminator in match */
292 memset(mask, 0xFF, vialen + 1);
293 memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1);
294 for (i = 0; vianame[i]; i++) {
295 if (vianame[i] == ':' ||
299 "Warning: weird character in interface"
300 " `%s' (No aliases, :, ! or *).\n",
308 #ifndef NO_SHARED_LIBS
309 static void *load_extension(const char *search_path, const char *prefix,
310 const char *name, bool is_target)
312 const char *dir = search_path, *next;
318 next = strchr(dir, ':');
320 next = dir + strlen(dir);
321 snprintf(path, sizeof(path), "%.*s/libxt_%s.so",
322 (unsigned int)(next - dir), dir, name);
324 if (dlopen(path, RTLD_NOW) != NULL) {
325 /* Found library. If it didn't register itself,
326 maybe they specified target as match. */
328 ptr = find_target(name, DONT_LOAD);
330 ptr = find_match(name, DONT_LOAD, NULL);
331 } else if (stat(path, &sb) == 0) {
332 fprintf(stderr, "%s: %s\n", path, dlerror());
338 snprintf(path, sizeof(path), "%.*s/%s%s.so",
339 (unsigned int)(next - dir), dir, prefix, name);
340 if (dlopen(path, RTLD_NOW) != NULL) {
342 ptr = find_target(name, DONT_LOAD);
344 ptr = find_match(name, DONT_LOAD, NULL);
345 } else if (stat(path, &sb) == 0) {
346 fprintf(stderr, "%s: %s\n", path, dlerror());
353 } while (*next != '\0');
359 struct xtables_match *find_match(const char *name, enum xt_tryload tryload,
360 struct xtables_rule_match **matches)
362 struct xtables_match *ptr;
363 const char *icmp6 = "icmp6";
365 /* This is ugly as hell. Nonetheless, there is no way of changing
366 * this without hurting backwards compatibility */
367 if ( (strcmp(name,"icmpv6") == 0) ||
368 (strcmp(name,"ipv6-icmp") == 0) ||
369 (strcmp(name,"icmp6") == 0) )
372 for (ptr = xtables_matches; ptr; ptr = ptr->next) {
373 if (strcmp(name, ptr->name) == 0) {
374 struct xtables_match *clone;
376 /* First match of this type: */
380 /* Second and subsequent clones */
381 clone = fw_malloc(sizeof(struct xtables_match));
382 memcpy(clone, ptr, sizeof(struct xtables_match));
384 /* This is a clone: */
392 #ifndef NO_SHARED_LIBS
393 if (!ptr && tryload != DONT_LOAD && tryload != DURING_LOAD) {
394 ptr = load_extension(lib_dir, afinfo.libprefix, name, false);
396 if (ptr == NULL && tryload == LOAD_MUST_SUCCEED)
397 exit_error(PARAMETER_PROBLEM,
398 "Couldn't load match `%s':%s\n",
402 if (ptr && !ptr->loaded) {
403 if (tryload != DONT_LOAD)
408 if(!ptr && (tryload == LOAD_MUST_SUCCEED)) {
409 exit_error(PARAMETER_PROBLEM,
410 "Couldn't find match `%s'\n", name);
414 if (ptr && matches) {
415 struct xtables_rule_match **i;
416 struct xtables_rule_match *newentry;
418 newentry = fw_malloc(sizeof(struct xtables_rule_match));
420 for (i = matches; *i; i = &(*i)->next) {
421 if (strcmp(name, (*i)->match->name) == 0)
424 newentry->match = ptr;
425 newentry->completed = 0;
426 newentry->next = NULL;
434 struct xtables_target *find_target(const char *name, enum xt_tryload tryload)
436 struct xtables_target *ptr;
438 /* Standard target? */
439 if (strcmp(name, "") == 0
440 || strcmp(name, XTC_LABEL_ACCEPT) == 0
441 || strcmp(name, XTC_LABEL_DROP) == 0
442 || strcmp(name, XTC_LABEL_QUEUE) == 0
443 || strcmp(name, XTC_LABEL_RETURN) == 0)
446 for (ptr = xtables_targets; ptr; ptr = ptr->next) {
447 if (strcmp(name, ptr->name) == 0)
451 #ifndef NO_SHARED_LIBS
452 if (!ptr && tryload != DONT_LOAD && tryload != DURING_LOAD) {
453 ptr = load_extension(lib_dir, afinfo.libprefix, name, true);
455 if (ptr == NULL && tryload == LOAD_MUST_SUCCEED)
456 exit_error(PARAMETER_PROBLEM,
457 "Couldn't load target `%s':%s\n",
461 if (ptr && !ptr->loaded) {
462 if (tryload != DONT_LOAD)
467 if(!ptr && (tryload == LOAD_MUST_SUCCEED)) {
468 exit_error(PARAMETER_PROBLEM,
469 "Couldn't find target `%s'\n", name);
479 static int compatible_revision(const char *name, u_int8_t revision, int opt)
481 struct xt_get_revision rev;
482 socklen_t s = sizeof(rev);
485 sockfd = socket(afinfo.family, SOCK_RAW, IPPROTO_RAW);
487 if (errno == EPERM) {
488 /* revision 0 is always supported. */
490 fprintf(stderr, "Could not determine whether "
491 "revision %u is supported, "
496 fprintf(stderr, "Could not open socket to kernel: %s\n",
501 load_xtables_ko(modprobe_program, 1);
503 strcpy(rev.name, name);
504 rev.revision = revision;
506 max_rev = getsockopt(sockfd, afinfo.ipproto, opt, &rev, &s);
508 /* Definitely don't support this? */
509 if (errno == ENOENT || errno == EPROTONOSUPPORT) {
512 } else if (errno == ENOPROTOOPT) {
514 /* Assume only revision 0 support (old kernel) */
515 return (revision == 0);
517 fprintf(stderr, "getsockopt failed strangely: %s\n",
527 static int compatible_match_revision(const char *name, u_int8_t revision)
529 return compatible_revision(name, revision, afinfo.so_rev_match);
532 static int compatible_target_revision(const char *name, u_int8_t revision)
534 return compatible_revision(name, revision, afinfo.so_rev_target);
537 void xtables_register_match(struct xtables_match *me)
539 struct xtables_match **i, *old;
541 if (strcmp(me->version, program_version) != 0) {
542 fprintf(stderr, "%s: match `%s' v%s (I'm v%s).\n",
543 program_name, me->name, me->version, program_version);
547 /* Revision field stole a char from name. */
548 if (strlen(me->name) >= XT_FUNCTION_MAXNAMELEN-1) {
549 fprintf(stderr, "%s: target `%s' has invalid name\n",
550 program_name, me->name);
554 if (me->family >= NPROTO) {
556 "%s: BUG: match %s has invalid protocol family\n",
557 program_name, me->name);
561 /* ignore not interested match */
562 if (me->family != afinfo.family && me->family != AF_UNSPEC)
565 old = find_match(me->name, DURING_LOAD, NULL);
567 if (old->revision == me->revision &&
568 old->family == me->family) {
570 "%s: match `%s' already registered.\n",
571 program_name, me->name);
575 /* Now we have two (or more) options, check compatibility. */
576 if (compatible_match_revision(old->name, old->revision)
577 && old->revision > me->revision)
580 /* See if new match can be used. */
581 if (!compatible_match_revision(me->name, me->revision))
584 /* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
585 if (old->revision == me->revision && me->family == AF_UNSPEC)
588 /* Delete old one. */
589 for (i = &xtables_matches; *i!=old; i = &(*i)->next);
593 if (me->size != XT_ALIGN(me->size)) {
594 fprintf(stderr, "%s: match `%s' has invalid size %u.\n",
595 program_name, me->name, (unsigned int)me->size);
599 /* Append to list. */
600 for (i = &xtables_matches; *i; i = &(*i)->next);
608 void xtables_register_target(struct xtables_target *me)
610 struct xtables_target *old;
612 if (strcmp(me->version, program_version) != 0) {
613 fprintf(stderr, "%s: target `%s' v%s (I'm v%s).\n",
614 program_name, me->name, me->version, program_version);
618 /* Revision field stole a char from name. */
619 if (strlen(me->name) >= XT_FUNCTION_MAXNAMELEN-1) {
620 fprintf(stderr, "%s: target `%s' has invalid name\n",
621 program_name, me->name);
625 if (me->family >= NPROTO) {
627 "%s: BUG: target %s has invalid protocol family\n",
628 program_name, me->name);
632 /* ignore not interested target */
633 if (me->family != afinfo.family && me->family != AF_UNSPEC)
636 old = find_target(me->name, DURING_LOAD);
638 struct xtables_target **i;
640 if (old->revision == me->revision &&
641 old->family == me->family) {
643 "%s: target `%s' already registered.\n",
644 program_name, me->name);
648 /* Now we have two (or more) options, check compatibility. */
649 if (compatible_target_revision(old->name, old->revision)
650 && old->revision > me->revision)
653 /* See if new target can be used. */
654 if (!compatible_target_revision(me->name, me->revision))
657 /* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
658 if (old->revision == me->revision && me->family == AF_UNSPEC)
661 /* Delete old one. */
662 for (i = &xtables_targets; *i!=old; i = &(*i)->next);
666 if (me->size != XT_ALIGN(me->size)) {
667 fprintf(stderr, "%s: target `%s' has invalid size %u.\n",
668 program_name, me->name, (unsigned int)me->size);
672 /* Prepend to list. */
673 me->next = xtables_targets;
674 xtables_targets = me;
679 void param_act(unsigned int status, const char *p1, ...)
689 p2 = va_arg(args, const char *);
690 b = va_arg(args, unsigned int);
693 exit_error(PARAMETER_PROBLEM,
694 "%s: \"%s\" option may only be specified once",
698 p2 = va_arg(args, const char *);
699 b = va_arg(args, unsigned int);
702 exit_error(PARAMETER_PROBLEM,
703 "%s: \"%s\" option cannot be inverted", p1, p2);
706 p2 = va_arg(args, const char *);
707 p3 = va_arg(args, const char *);
708 exit_error(PARAMETER_PROBLEM,
709 "%s: Bad value for \"%s\" option: \"%s\"",
713 b = va_arg(args, unsigned int);
716 exit_error(PARAMETER_PROBLEM,
717 "%s: At most one action is possible", p1);
720 exit_error(status, p1, args);
727 const char *ipaddr_to_numeric(const struct in_addr *addrp)
730 const unsigned char *bytep = (const void *)&addrp->s_addr;
732 sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
736 static const char *ipaddr_to_host(const struct in_addr *addr)
738 struct hostent *host;
740 host = gethostbyaddr(addr, sizeof(struct in_addr), AF_INET);
747 static const char *ipaddr_to_network(const struct in_addr *addr)
751 if ((net = getnetbyaddr(ntohl(addr->s_addr), AF_INET)) != NULL)
757 const char *ipaddr_to_anyname(const struct in_addr *addr)
761 if ((name = ipaddr_to_host(addr)) != NULL ||
762 (name = ipaddr_to_network(addr)) != NULL)
765 return ipaddr_to_numeric(addr);
768 const char *ipmask_to_numeric(const struct in_addr *mask)
771 uint32_t maskaddr, bits;
774 maskaddr = ntohl(mask->s_addr);
776 if (maskaddr == 0xFFFFFFFFL)
777 /* we don't want to see "/32" */
782 while (--i >= 0 && maskaddr != bits)
785 sprintf(buf, "/%d", i);
787 /* mask was not a decent combination of 1's and 0's */
788 sprintf(buf, "/%s", ipaddr_to_numeric(mask));
793 static struct in_addr *__numeric_to_ipaddr(const char *dotted, bool is_mask)
795 static struct in_addr addr;
796 unsigned char *addrp;
797 unsigned int onebyte;
798 char buf[20], *p, *q;
801 /* copy dotted string, because we need to modify it */
802 strncpy(buf, dotted, sizeof(buf) - 1);
803 buf[sizeof(buf) - 1] = '\0';
804 addrp = (void *)&addr.s_addr;
807 for (i = 0; i < 3; ++i) {
808 if ((q = strchr(p, '.')) == NULL) {
812 /* autocomplete, this is a network address */
813 if (!strtonum(p, NULL, &onebyte, 0, 255))
824 if (!strtonum(p, NULL, &onebyte, 0, 255))
831 /* we have checked 3 bytes, now we check the last one */
832 if (!strtonum(p, NULL, &onebyte, 0, 255))
839 struct in_addr *numeric_to_ipaddr(const char *dotted)
841 return __numeric_to_ipaddr(dotted, false);
844 struct in_addr *numeric_to_ipmask(const char *dotted)
846 return __numeric_to_ipaddr(dotted, true);
849 static struct in_addr *network_to_ipaddr(const char *name)
851 static struct in_addr addr;
854 if ((net = getnetbyname(name)) != NULL) {
855 if (net->n_addrtype != AF_INET)
857 addr.s_addr = htonl(net->n_net);
864 static struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)
866 struct hostent *host;
867 struct in_addr *addr;
871 if ((host = gethostbyname(name)) != NULL) {
872 if (host->h_addrtype != AF_INET ||
873 host->h_length != sizeof(struct in_addr))
876 while (host->h_addr_list[*naddr] != NULL)
878 addr = fw_calloc(*naddr, sizeof(struct in_addr) * *naddr);
879 for (i = 0; i < *naddr; i++)
880 memcpy(&addr[i], host->h_addr_list[i],
881 sizeof(struct in_addr));
888 static struct in_addr *
889 ipparse_hostnetwork(const char *name, unsigned int *naddrs)
891 struct in_addr *addrptmp, *addrp;
893 if ((addrptmp = numeric_to_ipaddr(name)) != NULL ||
894 (addrptmp = network_to_ipaddr(name)) != NULL) {
895 addrp = fw_malloc(sizeof(struct in_addr));
896 memcpy(addrp, addrptmp, sizeof(*addrp));
900 if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)
903 exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", name);
906 static struct in_addr *parse_ipmask(const char *mask)
908 static struct in_addr maskaddr;
909 struct in_addr *addrp;
913 /* no mask at all defaults to 32 bits */
914 maskaddr.s_addr = 0xFFFFFFFF;
917 if ((addrp = numeric_to_ipmask(mask)) != NULL)
918 /* dotted_to_addr already returns a network byte order addr */
920 if (string_to_number(mask, 0, 32, &bits) == -1)
921 exit_error(PARAMETER_PROBLEM,
922 "invalid mask `%s' specified", mask);
924 maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
928 maskaddr.s_addr = 0U;
932 void ipparse_hostnetworkmask(const char *name, struct in_addr **addrpp,
933 struct in_addr *maskp, unsigned int *naddrs)
935 unsigned int i, j, k, n;
936 struct in_addr *addrp;
939 strncpy(buf, name, sizeof(buf) - 1);
940 buf[sizeof(buf) - 1] = '\0';
941 if ((p = strrchr(buf, '/')) != NULL) {
943 addrp = parse_ipmask(p + 1);
945 addrp = parse_ipmask(NULL);
947 memcpy(maskp, addrp, sizeof(*maskp));
949 /* if a null mask is given, the name is ignored, like in "any/0" */
950 if (maskp->s_addr == 0U)
951 strcpy(buf, "0.0.0.0");
953 addrp = *addrpp = ipparse_hostnetwork(buf, naddrs);
955 for (i = 0, j = 0; i < n; ++i) {
956 addrp[j++].s_addr &= maskp->s_addr;
957 for (k = 0; k < j - 1; ++k)
958 if (addrp[k].s_addr == addrp[j-1].s_addr) {
966 const char *ip6addr_to_numeric(const struct in6_addr *addrp)
968 /* 0000:0000:0000:0000:0000:000.000.000.000
969 * 0000:0000:0000:0000:0000:0000:0000:0000 */
970 static char buf[50+1];
971 return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
974 static const char *ip6addr_to_host(const struct in6_addr *addr)
976 static char hostname[NI_MAXHOST];
977 struct sockaddr_in6 saddr;
980 memset(&saddr, 0, sizeof(struct sockaddr_in6));
981 memcpy(&saddr.sin6_addr, addr, sizeof(*addr));
982 saddr.sin6_family = AF_INET6;
984 err = getnameinfo((const void *)&saddr, sizeof(struct sockaddr_in6),
985 hostname, sizeof(hostname) - 1, NULL, 0, 0);
988 fprintf(stderr,"IP2Name: %s\n",gai_strerror(err));
994 fprintf (stderr, "\naddr2host: %s\n", hostname);
999 const char *ip6addr_to_anyname(const struct in6_addr *addr)
1003 if ((name = ip6addr_to_host(addr)) != NULL)
1006 return ip6addr_to_numeric(addr);
1009 static int ip6addr_prefix_length(const struct in6_addr *k)
1011 unsigned int bits = 0;
1012 uint32_t a, b, c, d;
1014 a = ntohl(k->s6_addr32[0]);
1015 b = ntohl(k->s6_addr32[1]);
1016 c = ntohl(k->s6_addr32[2]);
1017 d = ntohl(k->s6_addr32[3]);
1018 while (a & 0x80000000U) {
1028 if (a != 0 || b != 0 || c != 0 || d != 0)
1033 const char *ip6mask_to_numeric(const struct in6_addr *addrp)
1035 static char buf[50+2];
1036 int l = ip6addr_prefix_length(addrp);
1040 strcat(buf, ip6addr_to_numeric(addrp));
1043 sprintf(buf, "/%d", l);
1047 struct in6_addr *numeric_to_ip6addr(const char *num)
1049 static struct in6_addr ap;
1052 if ((err = inet_pton(AF_INET6, num, &ap)) == 1)
1055 fprintf(stderr, "\nnumeric2addr: %d\n", err);
1060 static struct in6_addr *
1061 host_to_ip6addr(const char *name, unsigned int *naddr)
1063 static struct in6_addr *addr;
1064 struct addrinfo hints;
1065 struct addrinfo *res;
1068 memset(&hints, 0, sizeof(hints));
1069 hints.ai_flags = AI_CANONNAME;
1070 hints.ai_family = AF_INET6;
1071 hints.ai_socktype = SOCK_RAW;
1072 hints.ai_protocol = IPPROTO_IPV6;
1073 hints.ai_next = NULL;
1076 if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) {
1078 fprintf(stderr,"Name2IP: %s\n",gai_strerror(err));
1082 if (res->ai_family != AF_INET6 ||
1083 res->ai_addrlen != sizeof(struct sockaddr_in6))
1087 fprintf(stderr, "resolved: len=%d %s ", res->ai_addrlen,
1088 ip6addr_to_numeric(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr));
1090 /* Get the first element of the address-chain */
1091 addr = fw_malloc(sizeof(struct in6_addr));
1092 memcpy(addr, &((const struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
1093 sizeof(struct in6_addr));
1102 static struct in6_addr *network_to_ip6addr(const char *name)
1105 /* TODO: not implemented yet, but the exception breaks the
1106 * name resolvation */
1110 static struct in6_addr *
1111 ip6parse_hostnetwork(const char *name, unsigned int *naddrs)
1113 struct in6_addr *addrp, *addrptmp;
1115 if ((addrptmp = numeric_to_ip6addr(name)) != NULL ||
1116 (addrptmp = network_to_ip6addr(name)) != NULL) {
1117 addrp = fw_malloc(sizeof(struct in6_addr));
1118 memcpy(addrp, addrptmp, sizeof(*addrp));
1122 if ((addrp = host_to_ip6addr(name, naddrs)) != NULL)
1125 exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", name);
1128 static struct in6_addr *parse_ip6mask(char *mask)
1130 static struct in6_addr maskaddr;
1131 struct in6_addr *addrp;
1135 /* no mask at all defaults to 128 bits */
1136 memset(&maskaddr, 0xff, sizeof maskaddr);
1139 if ((addrp = numeric_to_ip6addr(mask)) != NULL)
1141 if (string_to_number(mask, 0, 128, &bits) == -1)
1142 exit_error(PARAMETER_PROBLEM,
1143 "invalid mask `%s' specified", mask);
1145 char *p = (void *)&maskaddr;
1146 memset(p, 0xff, bits / 8);
1147 memset(p + (bits / 8) + 1, 0, (128 - bits) / 8);
1148 p[bits/8] = 0xff << (8 - (bits & 7));
1152 memset(&maskaddr, 0, sizeof(maskaddr));
1156 void ip6parse_hostnetworkmask(const char *name, struct in6_addr **addrpp,
1157 struct in6_addr *maskp, unsigned int *naddrs)
1159 struct in6_addr *addrp;
1160 unsigned int i, j, k, n;
1163 strncpy(buf, name, sizeof(buf) - 1);
1164 buf[sizeof(buf)-1] = '\0';
1165 if ((p = strrchr(buf, '/')) != NULL) {
1167 addrp = parse_ip6mask(p + 1);
1169 addrp = parse_ip6mask(NULL);
1171 memcpy(maskp, addrp, sizeof(*maskp));
1173 /* if a null mask is given, the name is ignored, like in "any/0" */
1174 if (memcmp(maskp, &in6addr_any, sizeof(in6addr_any)) == 0)
1177 addrp = *addrpp = ip6parse_hostnetwork(buf, naddrs);
1179 for (i = 0, j = 0; i < n; ++i) {
1180 for (k = 0; k < 4; ++k)
1181 addrp[j].s6_addr32[k] &= maskp->s6_addr32[k];
1183 for (k = 0; k < j - 1; ++k)
1184 if (IN6_ARE_ADDR_EQUAL(&addrp[k], &addrp[j - 1])) {
1192 void save_string(const char *value)
1194 static const char no_quote_chars[] = "_-0123456789"
1195 "abcdefghijklmnopqrstuvwxyz"
1196 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1197 static const char escape_chars[] = "\"\\'";
1201 length = strcspn(value, no_quote_chars);
1202 if (length > 0 && value[length] == 0) {
1203 /* no quoting required */
1204 fputs(value, stdout);
1207 /* there is at least one dangerous character in the
1208 value, which we have to quote. Write double quotes
1209 around the value and escape special characters with
1213 for (p = strpbrk(value, escape_chars); p != NULL;
1214 p = strpbrk(value, escape_chars)) {
1216 fwrite(value, 1, p - value, stdout);
1222 /* print the rest and finish the double quoted
1224 fputs(value, stdout);