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 <libiptc/libxtc.h>
37 #ifndef NO_SHARED_LIBS
43 #ifndef PROC_SYS_MODPROBE
44 #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
49 /* the path to command to load kernel module */
50 const char *modprobe_program
= NULL
;
52 /* Keeping track of external matches and targets: linked lists. */
53 struct xtables_match
*xtables_matches
;
54 struct xtables_target
*xtables_targets
;
56 void *fw_calloc(size_t count
, size_t size
)
60 if ((p
= calloc(count
, size
)) == NULL
) {
61 perror("ip[6]tables: calloc failed");
68 void *fw_malloc(size_t size
)
72 if ((p
= malloc(size
)) == NULL
) {
73 perror("ip[6]tables: malloc failed");
80 static char *get_modprobe(void)
85 #define PROCFILE_BUFSIZ 1024
86 procfile
= open(PROC_SYS_MODPROBE
, O_RDONLY
);
90 ret
= (char *) malloc(PROCFILE_BUFSIZ
);
92 memset(ret
, 0, PROCFILE_BUFSIZ
);
93 switch (read(procfile
, ret
, PROCFILE_BUFSIZ
)) {
95 case PROCFILE_BUFSIZ
: goto fail
; /* Partial read. Wierd */
97 if (ret
[strlen(ret
)-1]=='\n')
108 int xtables_insmod(const char *modname
, const char *modprobe
, int quiet
)
114 /* If they don't explicitly set it, read out of kernel */
116 buf
= get_modprobe();
124 argv
[0] = (char *)modprobe
;
125 argv
[1] = (char *)modname
;
133 execv(argv
[0], argv
);
135 /* not usually reached */
140 default: /* parent */
145 if (WIFEXITED(status
) && WEXITSTATUS(status
) == 0)
150 int load_xtables_ko(const char *modprobe
, int quiet
)
152 static int loaded
= 0;
156 ret
= xtables_insmod(afinfo
.kmod
, modprobe
, quiet
);
163 int string_to_number_ll(const char *s
, unsigned long long min
,
164 unsigned long long max
, unsigned long long *ret
)
166 unsigned long long number
;
169 /* Handle hex, octal, etc. */
171 number
= strtoull(s
, &end
, 0);
172 if (*end
== '\0' && end
!= s
) {
173 /* we parsed a number, let's see if we want this */
174 if (errno
!= ERANGE
&& min
<= number
&& (!max
|| number
<= max
)) {
182 int string_to_number_l(const char *s
, unsigned long min
, unsigned long max
,
186 unsigned long long number
;
188 result
= string_to_number_ll(s
, min
, max
, &number
);
189 *ret
= (unsigned long)number
;
194 int string_to_number(const char *s
, unsigned int min
, unsigned int max
,
198 unsigned long number
;
200 result
= string_to_number_l(s
, min
, max
, &number
);
201 *ret
= (unsigned int)number
;
207 * strtonum{,l} - string to number conversion
209 * If @end is NULL, we assume the caller does not want
210 * a case like "15a", so reject it.
212 bool strtonuml(const char *s
, char **end
, unsigned long *value
,
213 unsigned long min
, unsigned long max
)
219 v
= strtoul(s
, &my_end
, 0);
226 if (errno
!= ERANGE
&& min
<= v
&& (max
== 0 || v
<= max
)) {
230 return *my_end
== '\0';
237 bool strtonum(const char *s
, char **end
, unsigned int *value
,
238 unsigned int min
, unsigned int max
)
243 ret
= strtonuml(s
, end
, &v
, min
, max
);
249 int service_to_port(const char *name
, const char *proto
)
251 struct servent
*service
;
253 if ((service
= getservbyname(name
, proto
)) != NULL
)
254 return ntohs((unsigned short) service
->s_port
);
259 u_int16_t
parse_port(const char *port
, const char *proto
)
261 unsigned int portnum
;
263 if ((string_to_number(port
, 0, 65535, &portnum
)) != -1 ||
264 (portnum
= service_to_port(port
, proto
)) != (unsigned)-1)
265 return (u_int16_t
)portnum
;
267 exit_error(PARAMETER_PROBLEM
,
268 "invalid port/service `%s' specified", port
);
271 void parse_interface(const char *arg
, char *vianame
, unsigned char *mask
)
273 int vialen
= strlen(arg
);
276 memset(mask
, 0, IFNAMSIZ
);
277 memset(vianame
, 0, IFNAMSIZ
);
279 if (vialen
+ 1 > IFNAMSIZ
)
280 exit_error(PARAMETER_PROBLEM
,
281 "interface name `%s' must be shorter than IFNAMSIZ"
282 " (%i)", arg
, IFNAMSIZ
-1);
284 strcpy(vianame
, arg
);
285 if ((vialen
== 0) || (vialen
== 1 && vianame
[0] == '+'))
286 memset(mask
, 0, IFNAMSIZ
);
287 else if (vianame
[vialen
- 1] == '+') {
288 memset(mask
, 0xFF, vialen
- 1);
289 memset(mask
+ vialen
- 1, 0, IFNAMSIZ
- vialen
+ 1);
290 /* Don't remove `+' here! -HW */
292 /* Include nul-terminator in match */
293 memset(mask
, 0xFF, vialen
+ 1);
294 memset(mask
+ vialen
+ 1, 0, IFNAMSIZ
- vialen
- 1);
295 for (i
= 0; vianame
[i
]; i
++) {
296 if (vianame
[i
] == ':' ||
300 "Warning: weird character in interface"
301 " `%s' (No aliases, :, ! or *).\n",
309 #ifndef NO_SHARED_LIBS
310 static void *load_extension(const char *search_path
, const char *prefix
,
311 const char *name
, bool is_target
)
313 const char *dir
= search_path
, *next
;
319 next
= strchr(dir
, ':');
321 next
= dir
+ strlen(dir
);
322 snprintf(path
, sizeof(path
), "%.*s/libxt_%s.so",
323 (unsigned int)(next
- dir
), dir
, name
);
325 if (dlopen(path
, RTLD_NOW
) != NULL
) {
326 /* Found library. If it didn't register itself,
327 maybe they specified target as match. */
329 ptr
= find_target(name
, DONT_LOAD
);
331 ptr
= find_match(name
, DONT_LOAD
, NULL
);
332 } else if (stat(path
, &sb
) == 0) {
333 fprintf(stderr
, "%s: %s\n", path
, dlerror());
339 snprintf(path
, sizeof(path
), "%.*s/%s%s.so",
340 (unsigned int)(next
- dir
), dir
, prefix
, name
);
341 if (dlopen(path
, RTLD_NOW
) != NULL
) {
343 ptr
= find_target(name
, DONT_LOAD
);
345 ptr
= find_match(name
, DONT_LOAD
, NULL
);
346 } else if (stat(path
, &sb
) == 0) {
347 fprintf(stderr
, "%s: %s\n", path
, dlerror());
354 } while (*next
!= '\0');
360 struct xtables_match
*find_match(const char *name
, enum xt_tryload tryload
,
361 struct xtables_rule_match
**matches
)
363 struct xtables_match
*ptr
;
364 const char *icmp6
= "icmp6";
366 /* This is ugly as hell. Nonetheless, there is no way of changing
367 * this without hurting backwards compatibility */
368 if ( (strcmp(name
,"icmpv6") == 0) ||
369 (strcmp(name
,"ipv6-icmp") == 0) ||
370 (strcmp(name
,"icmp6") == 0) )
373 for (ptr
= xtables_matches
; ptr
; ptr
= ptr
->next
) {
374 if (strcmp(name
, ptr
->name
) == 0) {
375 struct xtables_match
*clone
;
377 /* First match of this type: */
381 /* Second and subsequent clones */
382 clone
= fw_malloc(sizeof(struct xtables_match
));
383 memcpy(clone
, ptr
, sizeof(struct xtables_match
));
385 /* This is a clone: */
393 #ifndef NO_SHARED_LIBS
394 if (!ptr
&& tryload
!= DONT_LOAD
&& tryload
!= DURING_LOAD
) {
395 ptr
= load_extension(lib_dir
, afinfo
.libprefix
, name
, false);
397 if (ptr
== NULL
&& tryload
== LOAD_MUST_SUCCEED
)
398 exit_error(PARAMETER_PROBLEM
,
399 "Couldn't load match `%s':%s\n",
403 if (ptr
&& !ptr
->loaded
) {
404 if (tryload
!= DONT_LOAD
)
409 if(!ptr
&& (tryload
== LOAD_MUST_SUCCEED
)) {
410 exit_error(PARAMETER_PROBLEM
,
411 "Couldn't find match `%s'\n", name
);
415 if (ptr
&& matches
) {
416 struct xtables_rule_match
**i
;
417 struct xtables_rule_match
*newentry
;
419 newentry
= fw_malloc(sizeof(struct xtables_rule_match
));
421 for (i
= matches
; *i
; i
= &(*i
)->next
) {
422 if (strcmp(name
, (*i
)->match
->name
) == 0)
425 newentry
->match
= ptr
;
426 newentry
->completed
= 0;
427 newentry
->next
= NULL
;
435 struct xtables_target
*find_target(const char *name
, enum xt_tryload tryload
)
437 struct xtables_target
*ptr
;
439 /* Standard target? */
440 if (strcmp(name
, "") == 0
441 || strcmp(name
, XTC_LABEL_ACCEPT
) == 0
442 || strcmp(name
, XTC_LABEL_DROP
) == 0
443 || strcmp(name
, XTC_LABEL_QUEUE
) == 0
444 || strcmp(name
, XTC_LABEL_RETURN
) == 0)
447 for (ptr
= xtables_targets
; ptr
; ptr
= ptr
->next
) {
448 if (strcmp(name
, ptr
->name
) == 0)
452 #ifndef NO_SHARED_LIBS
453 if (!ptr
&& tryload
!= DONT_LOAD
&& tryload
!= DURING_LOAD
) {
454 ptr
= load_extension(lib_dir
, afinfo
.libprefix
, name
, true);
456 if (ptr
== NULL
&& tryload
== LOAD_MUST_SUCCEED
)
457 exit_error(PARAMETER_PROBLEM
,
458 "Couldn't load target `%s':%s\n",
462 if (ptr
&& !ptr
->loaded
) {
463 if (tryload
!= DONT_LOAD
)
468 if(!ptr
&& (tryload
== LOAD_MUST_SUCCEED
)) {
469 exit_error(PARAMETER_PROBLEM
,
470 "Couldn't find target `%s'\n", name
);
480 static int compatible_revision(const char *name
, u_int8_t revision
, int opt
)
482 struct xt_get_revision rev
;
483 socklen_t s
= sizeof(rev
);
486 sockfd
= socket(afinfo
.family
, SOCK_RAW
, IPPROTO_RAW
);
488 if (errno
== EPERM
) {
489 /* revision 0 is always supported. */
491 fprintf(stderr
, "Could not determine whether "
492 "revision %u is supported, "
497 fprintf(stderr
, "Could not open socket to kernel: %s\n",
502 load_xtables_ko(modprobe_program
, 1);
504 strcpy(rev
.name
, name
);
505 rev
.revision
= revision
;
507 max_rev
= getsockopt(sockfd
, afinfo
.ipproto
, opt
, &rev
, &s
);
509 /* Definitely don't support this? */
510 if (errno
== ENOENT
|| errno
== EPROTONOSUPPORT
) {
513 } else if (errno
== ENOPROTOOPT
) {
515 /* Assume only revision 0 support (old kernel) */
516 return (revision
== 0);
518 fprintf(stderr
, "getsockopt failed strangely: %s\n",
528 static int compatible_match_revision(const char *name
, u_int8_t revision
)
530 return compatible_revision(name
, revision
, afinfo
.so_rev_match
);
533 static int compatible_target_revision(const char *name
, u_int8_t revision
)
535 return compatible_revision(name
, revision
, afinfo
.so_rev_target
);
538 void xtables_register_match(struct xtables_match
*me
)
540 struct xtables_match
**i
, *old
;
542 if (strcmp(me
->version
, program_version
) != 0) {
543 fprintf(stderr
, "%s: match `%s' v%s (I'm v%s).\n",
544 program_name
, me
->name
, me
->version
, program_version
);
548 /* Revision field stole a char from name. */
549 if (strlen(me
->name
) >= XT_FUNCTION_MAXNAMELEN
-1) {
550 fprintf(stderr
, "%s: target `%s' has invalid name\n",
551 program_name
, me
->name
);
555 if (me
->family
>= NPROTO
) {
557 "%s: BUG: match %s has invalid protocol family\n",
558 program_name
, me
->name
);
562 /* ignore not interested match */
563 if (me
->family
!= afinfo
.family
&& me
->family
!= AF_UNSPEC
)
566 old
= find_match(me
->name
, DURING_LOAD
, NULL
);
568 if (old
->revision
== me
->revision
&&
569 old
->family
== me
->family
) {
571 "%s: match `%s' already registered.\n",
572 program_name
, me
->name
);
576 /* Now we have two (or more) options, check compatibility. */
577 if (compatible_match_revision(old
->name
, old
->revision
)
578 && old
->revision
> me
->revision
)
581 /* See if new match can be used. */
582 if (!compatible_match_revision(me
->name
, me
->revision
))
585 /* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
586 if (old
->revision
== me
->revision
&& me
->family
== AF_UNSPEC
)
589 /* Delete old one. */
590 for (i
= &xtables_matches
; *i
!=old
; i
= &(*i
)->next
);
594 if (me
->size
!= XT_ALIGN(me
->size
)) {
595 fprintf(stderr
, "%s: match `%s' has invalid size %u.\n",
596 program_name
, me
->name
, (unsigned int)me
->size
);
600 /* Append to list. */
601 for (i
= &xtables_matches
; *i
; i
= &(*i
)->next
);
609 void xtables_register_target(struct xtables_target
*me
)
611 struct xtables_target
*old
;
613 if (strcmp(me
->version
, program_version
) != 0) {
614 fprintf(stderr
, "%s: target `%s' v%s (I'm v%s).\n",
615 program_name
, me
->name
, me
->version
, program_version
);
619 /* Revision field stole a char from name. */
620 if (strlen(me
->name
) >= XT_FUNCTION_MAXNAMELEN
-1) {
621 fprintf(stderr
, "%s: target `%s' has invalid name\n",
622 program_name
, me
->name
);
626 if (me
->family
>= NPROTO
) {
628 "%s: BUG: target %s has invalid protocol family\n",
629 program_name
, me
->name
);
633 /* ignore not interested target */
634 if (me
->family
!= afinfo
.family
&& me
->family
!= AF_UNSPEC
)
637 old
= find_target(me
->name
, DURING_LOAD
);
639 struct xtables_target
**i
;
641 if (old
->revision
== me
->revision
&&
642 old
->family
== me
->family
) {
644 "%s: target `%s' already registered.\n",
645 program_name
, me
->name
);
649 /* Now we have two (or more) options, check compatibility. */
650 if (compatible_target_revision(old
->name
, old
->revision
)
651 && old
->revision
> me
->revision
)
654 /* See if new target can be used. */
655 if (!compatible_target_revision(me
->name
, me
->revision
))
658 /* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */
659 if (old
->revision
== me
->revision
&& me
->family
== AF_UNSPEC
)
662 /* Delete old one. */
663 for (i
= &xtables_targets
; *i
!=old
; i
= &(*i
)->next
);
667 if (me
->size
!= XT_ALIGN(me
->size
)) {
668 fprintf(stderr
, "%s: target `%s' has invalid size %u.\n",
669 program_name
, me
->name
, (unsigned int)me
->size
);
673 /* Prepend to list. */
674 me
->next
= xtables_targets
;
675 xtables_targets
= me
;
680 void param_act(unsigned int status
, const char *p1
, ...)
690 p2
= va_arg(args
, const char *);
691 b
= va_arg(args
, unsigned int);
694 exit_error(PARAMETER_PROBLEM
,
695 "%s: \"%s\" option may only be specified once",
699 p2
= va_arg(args
, const char *);
700 b
= va_arg(args
, unsigned int);
703 exit_error(PARAMETER_PROBLEM
,
704 "%s: \"%s\" option cannot be inverted", p1
, p2
);
707 p2
= va_arg(args
, const char *);
708 p3
= va_arg(args
, const char *);
709 exit_error(PARAMETER_PROBLEM
,
710 "%s: Bad value for \"%s\" option: \"%s\"",
714 b
= va_arg(args
, unsigned int);
717 exit_error(PARAMETER_PROBLEM
,
718 "%s: At most one action is possible", p1
);
721 exit_error(status
, p1
, args
);
728 const char *ipaddr_to_numeric(const struct in_addr
*addrp
)
731 const unsigned char *bytep
= (const void *)&addrp
->s_addr
;
733 sprintf(buf
, "%u.%u.%u.%u", bytep
[0], bytep
[1], bytep
[2], bytep
[3]);
737 static const char *ipaddr_to_host(const struct in_addr
*addr
)
739 struct hostent
*host
;
741 host
= gethostbyaddr(addr
, sizeof(struct in_addr
), AF_INET
);
748 static const char *ipaddr_to_network(const struct in_addr
*addr
)
752 if ((net
= getnetbyaddr(ntohl(addr
->s_addr
), AF_INET
)) != NULL
)
758 const char *ipaddr_to_anyname(const struct in_addr
*addr
)
762 if ((name
= ipaddr_to_host(addr
)) != NULL
||
763 (name
= ipaddr_to_network(addr
)) != NULL
)
766 return ipaddr_to_numeric(addr
);
769 const char *ipmask_to_numeric(const struct in_addr
*mask
)
772 uint32_t maskaddr
, bits
;
775 maskaddr
= ntohl(mask
->s_addr
);
777 if (maskaddr
== 0xFFFFFFFFL
)
778 /* we don't want to see "/32" */
783 while (--i
>= 0 && maskaddr
!= bits
)
786 sprintf(buf
, "/%d", i
);
788 /* mask was not a decent combination of 1's and 0's */
789 sprintf(buf
, "/%s", ipaddr_to_numeric(mask
));
794 static struct in_addr
*__numeric_to_ipaddr(const char *dotted
, bool is_mask
)
796 static struct in_addr addr
;
797 unsigned char *addrp
;
798 unsigned int onebyte
;
799 char buf
[20], *p
, *q
;
802 /* copy dotted string, because we need to modify it */
803 strncpy(buf
, dotted
, sizeof(buf
) - 1);
804 buf
[sizeof(buf
) - 1] = '\0';
805 addrp
= (void *)&addr
.s_addr
;
808 for (i
= 0; i
< 3; ++i
) {
809 if ((q
= strchr(p
, '.')) == NULL
) {
813 /* autocomplete, this is a network address */
814 if (!strtonum(p
, NULL
, &onebyte
, 0, 255))
825 if (!strtonum(p
, NULL
, &onebyte
, 0, 255))
832 /* we have checked 3 bytes, now we check the last one */
833 if (!strtonum(p
, NULL
, &onebyte
, 0, 255))
840 struct in_addr
*numeric_to_ipaddr(const char *dotted
)
842 return __numeric_to_ipaddr(dotted
, false);
845 struct in_addr
*numeric_to_ipmask(const char *dotted
)
847 return __numeric_to_ipaddr(dotted
, true);
850 static struct in_addr
*network_to_ipaddr(const char *name
)
852 static struct in_addr addr
;
855 if ((net
= getnetbyname(name
)) != NULL
) {
856 if (net
->n_addrtype
!= AF_INET
)
858 addr
.s_addr
= htonl(net
->n_net
);
865 static struct in_addr
*host_to_ipaddr(const char *name
, unsigned int *naddr
)
867 struct hostent
*host
;
868 struct in_addr
*addr
;
872 if ((host
= gethostbyname(name
)) != NULL
) {
873 if (host
->h_addrtype
!= AF_INET
||
874 host
->h_length
!= sizeof(struct in_addr
))
877 while (host
->h_addr_list
[*naddr
] != NULL
)
879 addr
= fw_calloc(*naddr
, sizeof(struct in_addr
) * *naddr
);
880 for (i
= 0; i
< *naddr
; i
++)
881 memcpy(&addr
[i
], host
->h_addr_list
[i
],
882 sizeof(struct in_addr
));
889 static struct in_addr
*
890 ipparse_hostnetwork(const char *name
, unsigned int *naddrs
)
892 struct in_addr
*addrptmp
, *addrp
;
894 if ((addrptmp
= numeric_to_ipaddr(name
)) != NULL
||
895 (addrptmp
= network_to_ipaddr(name
)) != NULL
) {
896 addrp
= fw_malloc(sizeof(struct in_addr
));
897 memcpy(addrp
, addrptmp
, sizeof(*addrp
));
901 if ((addrptmp
= host_to_ipaddr(name
, naddrs
)) != NULL
)
904 exit_error(PARAMETER_PROBLEM
, "host/network `%s' not found", name
);
907 static struct in_addr
*parse_ipmask(const char *mask
)
909 static struct in_addr maskaddr
;
910 struct in_addr
*addrp
;
914 /* no mask at all defaults to 32 bits */
915 maskaddr
.s_addr
= 0xFFFFFFFF;
918 if ((addrp
= numeric_to_ipmask(mask
)) != NULL
)
919 /* dotted_to_addr already returns a network byte order addr */
921 if (string_to_number(mask
, 0, 32, &bits
) == -1)
922 exit_error(PARAMETER_PROBLEM
,
923 "invalid mask `%s' specified", mask
);
925 maskaddr
.s_addr
= htonl(0xFFFFFFFF << (32 - bits
));
929 maskaddr
.s_addr
= 0U;
933 void ipparse_hostnetworkmask(const char *name
, struct in_addr
**addrpp
,
934 struct in_addr
*maskp
, unsigned int *naddrs
)
936 unsigned int i
, j
, k
, n
;
937 struct in_addr
*addrp
;
940 strncpy(buf
, name
, sizeof(buf
) - 1);
941 buf
[sizeof(buf
) - 1] = '\0';
942 if ((p
= strrchr(buf
, '/')) != NULL
) {
944 addrp
= parse_ipmask(p
+ 1);
946 addrp
= parse_ipmask(NULL
);
948 memcpy(maskp
, addrp
, sizeof(*maskp
));
950 /* if a null mask is given, the name is ignored, like in "any/0" */
951 if (maskp
->s_addr
== 0U)
952 strcpy(buf
, "0.0.0.0");
954 addrp
= *addrpp
= ipparse_hostnetwork(buf
, naddrs
);
956 for (i
= 0, j
= 0; i
< n
; ++i
) {
957 addrp
[j
++].s_addr
&= maskp
->s_addr
;
958 for (k
= 0; k
< j
- 1; ++k
)
959 if (addrp
[k
].s_addr
== addrp
[j
-1].s_addr
) {
967 const char *ip6addr_to_numeric(const struct in6_addr
*addrp
)
969 /* 0000:0000:0000:0000:0000:000.000.000.000
970 * 0000:0000:0000:0000:0000:0000:0000:0000 */
971 static char buf
[50+1];
972 return inet_ntop(AF_INET6
, addrp
, buf
, sizeof(buf
));
975 static const char *ip6addr_to_host(const struct in6_addr
*addr
)
977 static char hostname
[NI_MAXHOST
];
978 struct sockaddr_in6 saddr
;
981 memset(&saddr
, 0, sizeof(struct sockaddr_in6
));
982 memcpy(&saddr
.sin6_addr
, addr
, sizeof(*addr
));
983 saddr
.sin6_family
= AF_INET6
;
985 err
= getnameinfo((const void *)&saddr
, sizeof(struct sockaddr_in6
),
986 hostname
, sizeof(hostname
) - 1, NULL
, 0, 0);
989 fprintf(stderr
,"IP2Name: %s\n",gai_strerror(err
));
995 fprintf (stderr
, "\naddr2host: %s\n", hostname
);
1000 const char *ip6addr_to_anyname(const struct in6_addr
*addr
)
1004 if ((name
= ip6addr_to_host(addr
)) != NULL
)
1007 return ip6addr_to_numeric(addr
);
1010 static int ip6addr_prefix_length(const struct in6_addr
*k
)
1012 unsigned int bits
= 0;
1013 uint32_t a
, b
, c
, d
;
1015 a
= ntohl(k
->s6_addr32
[0]);
1016 b
= ntohl(k
->s6_addr32
[1]);
1017 c
= ntohl(k
->s6_addr32
[2]);
1018 d
= ntohl(k
->s6_addr32
[3]);
1019 while (a
& 0x80000000U
) {
1029 if (a
!= 0 || b
!= 0 || c
!= 0 || d
!= 0)
1034 const char *ip6mask_to_numeric(const struct in6_addr
*addrp
)
1036 static char buf
[50+2];
1037 int l
= ip6addr_prefix_length(addrp
);
1041 strcat(buf
, ip6addr_to_numeric(addrp
));
1044 sprintf(buf
, "/%d", l
);
1048 struct in6_addr
*numeric_to_ip6addr(const char *num
)
1050 static struct in6_addr ap
;
1053 if ((err
= inet_pton(AF_INET6
, num
, &ap
)) == 1)
1056 fprintf(stderr
, "\nnumeric2addr: %d\n", err
);
1061 static struct in6_addr
*
1062 host_to_ip6addr(const char *name
, unsigned int *naddr
)
1064 static struct in6_addr
*addr
;
1065 struct addrinfo hints
;
1066 struct addrinfo
*res
;
1069 memset(&hints
, 0, sizeof(hints
));
1070 hints
.ai_flags
= AI_CANONNAME
;
1071 hints
.ai_family
= AF_INET6
;
1072 hints
.ai_socktype
= SOCK_RAW
;
1073 hints
.ai_protocol
= IPPROTO_IPV6
;
1074 hints
.ai_next
= NULL
;
1077 if ((err
= getaddrinfo(name
, NULL
, &hints
, &res
)) != 0) {
1079 fprintf(stderr
,"Name2IP: %s\n",gai_strerror(err
));
1083 if (res
->ai_family
!= AF_INET6
||
1084 res
->ai_addrlen
!= sizeof(struct sockaddr_in6
))
1088 fprintf(stderr
, "resolved: len=%d %s ", res
->ai_addrlen
,
1089 ip6addr_to_numeric(&((struct sockaddr_in6
*)res
->ai_addr
)->sin6_addr
));
1091 /* Get the first element of the address-chain */
1092 addr
= fw_malloc(sizeof(struct in6_addr
));
1093 memcpy(addr
, &((const struct sockaddr_in6
*)res
->ai_addr
)->sin6_addr
,
1094 sizeof(struct in6_addr
));
1103 static struct in6_addr
*network_to_ip6addr(const char *name
)
1106 /* TODO: not implemented yet, but the exception breaks the
1107 * name resolvation */
1111 static struct in6_addr
*
1112 ip6parse_hostnetwork(const char *name
, unsigned int *naddrs
)
1114 struct in6_addr
*addrp
, *addrptmp
;
1116 if ((addrptmp
= numeric_to_ip6addr(name
)) != NULL
||
1117 (addrptmp
= network_to_ip6addr(name
)) != NULL
) {
1118 addrp
= fw_malloc(sizeof(struct in6_addr
));
1119 memcpy(addrp
, addrptmp
, sizeof(*addrp
));
1123 if ((addrp
= host_to_ip6addr(name
, naddrs
)) != NULL
)
1126 exit_error(PARAMETER_PROBLEM
, "host/network `%s' not found", name
);
1129 static struct in6_addr
*parse_ip6mask(char *mask
)
1131 static struct in6_addr maskaddr
;
1132 struct in6_addr
*addrp
;
1136 /* no mask at all defaults to 128 bits */
1137 memset(&maskaddr
, 0xff, sizeof maskaddr
);
1140 if ((addrp
= numeric_to_ip6addr(mask
)) != NULL
)
1142 if (string_to_number(mask
, 0, 128, &bits
) == -1)
1143 exit_error(PARAMETER_PROBLEM
,
1144 "invalid mask `%s' specified", mask
);
1146 char *p
= (void *)&maskaddr
;
1147 memset(p
, 0xff, bits
/ 8);
1148 memset(p
+ (bits
/ 8) + 1, 0, (128 - bits
) / 8);
1149 p
[bits
/8] = 0xff << (8 - (bits
& 7));
1153 memset(&maskaddr
, 0, sizeof(maskaddr
));
1157 void ip6parse_hostnetworkmask(const char *name
, struct in6_addr
**addrpp
,
1158 struct in6_addr
*maskp
, unsigned int *naddrs
)
1160 struct in6_addr
*addrp
;
1161 unsigned int i
, j
, k
, n
;
1164 strncpy(buf
, name
, sizeof(buf
) - 1);
1165 buf
[sizeof(buf
)-1] = '\0';
1166 if ((p
= strrchr(buf
, '/')) != NULL
) {
1168 addrp
= parse_ip6mask(p
+ 1);
1170 addrp
= parse_ip6mask(NULL
);
1172 memcpy(maskp
, addrp
, sizeof(*maskp
));
1174 /* if a null mask is given, the name is ignored, like in "any/0" */
1175 if (memcmp(maskp
, &in6addr_any
, sizeof(in6addr_any
)) == 0)
1178 addrp
= *addrpp
= ip6parse_hostnetwork(buf
, naddrs
);
1180 for (i
= 0, j
= 0; i
< n
; ++i
) {
1181 for (k
= 0; k
< 4; ++k
)
1182 addrp
[j
].s6_addr32
[k
] &= maskp
->s6_addr32
[k
];
1184 for (k
= 0; k
< j
- 1; ++k
)
1185 if (IN6_ARE_ADDR_EQUAL(&addrp
[k
], &addrp
[j
- 1])) {
1193 void save_string(const char *value
)
1195 static const char no_quote_chars
[] = "_-0123456789"
1196 "abcdefghijklmnopqrstuvwxyz"
1197 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1198 static const char escape_chars
[] = "\"\\'";
1202 length
= strcspn(value
, no_quote_chars
);
1203 if (length
> 0 && value
[length
] == 0) {
1204 /* no quoting required */
1205 fputs(value
, stdout
);
1208 /* there is at least one dangerous character in the
1209 value, which we have to quote. Write double quotes
1210 around the value and escape special characters with
1214 for (p
= strpbrk(value
, escape_chars
); p
!= NULL
;
1215 p
= strpbrk(value
, escape_chars
)) {
1217 fwrite(value
, 1, p
- value
, stdout
);
1223 /* print the rest and finish the double quoted
1225 fputs(value
, stdout
);