diff options
author | Bart De Schuymer <bdschuym@pandora.be> | 2008-02-21 21:32:25 +0000 |
---|---|---|
committer | Bart De Schuymer <bdschuym@pandora.be> | 2008-02-21 21:32:25 +0000 |
commit | 005837ee38584e53460a985a2932b23d03a51c3c (patch) | |
tree | 08f633141c94aef8000ead38ed6305244415f2a0 /useful_functions.c | |
parent | fbdebad3b9e87de6d983a96fd27620727c37027a (diff) | |
download | ebtables-005837ee38584e53460a985a2932b23d03a51c3c.tar.gz ebtables-005837ee38584e53460a985a2932b23d03a51c3c.tar.bz2 ebtables-005837ee38584e53460a985a2932b23d03a51c3c.zip |
Kuo-Lang Tseng et al: add ipv6 support
Diffstat (limited to 'useful_functions.c')
-rw-r--r-- | useful_functions.c | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/useful_functions.c b/useful_functions.c index 131851a..1634f22 100644 --- a/useful_functions.c +++ b/useful_functions.c @@ -29,6 +29,10 @@ #include <string.h> #include <stdlib.h> #include <getopt.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> const unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0}; const unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0}; @@ -244,6 +248,7 @@ void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk) *addr = *addr & *msk; } + /* Transform the ip mask into a string ready for output. */ char *ebt_mask_to_dotted(uint32_t mask) { @@ -276,3 +281,134 @@ char *ebt_mask_to_dotted(uint32_t mask) return buf; } + +/* Most of the following code is derived from iptables */ +static void +in6addrcpy(struct in6_addr *dst, struct in6_addr *src) +{ + memcpy(dst, src, sizeof(struct in6_addr)); +} + +int string_to_number_ll(const char *s, unsigned long long min, + unsigned long long max, unsigned long long *ret) +{ + unsigned long long number; + char *end; + + /* Handle hex, octal, etc. */ + errno = 0; + number = strtoull(s, &end, 0); + if (*end == '\0' && end != s) { + /* we parsed a number, let's see if we want this */ + if (errno != ERANGE && min <= number && (!max || number <= max)) { + *ret = number; + return 0; + } + } + return -1; +} + +int string_to_number_l(const char *s, unsigned long min, unsigned long max, + unsigned long *ret) +{ + int result; + unsigned long long number; + + result = string_to_number_ll(s, min, max, &number); + *ret = (unsigned long)number; + + return result; +} + +int string_to_number(const char *s, unsigned int min, unsigned int max, + unsigned int *ret) +{ + int result; + unsigned long number; + + result = string_to_number_l(s, min, max, &number); + *ret = (unsigned int)number; + + return result; +} + +static struct in6_addr * +numeric_to_addr(const char *num) +{ + static struct in6_addr ap; + int err; + if ((err=inet_pton(AF_INET6, num, &ap)) == 1) + return ≈ + return (struct in6_addr *)NULL; +} + +static struct in6_addr * +parse_ip6_mask(char *mask) +{ + static struct in6_addr maskaddr; + struct in6_addr *addrp; + unsigned int bits; + + if (mask == NULL) { + /* no mask at all defaults to 128 bits */ + memset(&maskaddr, 0xff, sizeof maskaddr); + return &maskaddr; + } + if ((addrp = numeric_to_addr(mask)) != NULL) + return addrp; + if (string_to_number(mask, 0, 128, &bits) == -1) + ebt_print_error("Invalid IPv6 Mask '%s' specified", mask); + if (bits != 0) { + char *p = (char *)&maskaddr; + memset(p, 0xff, bits / 8); + memset(p + (bits / 8) + 1, 0, (128 - bits) / 8); + p[bits / 8] = 0xff << (8 - (bits & 7)); + return &maskaddr; + } + + memset(&maskaddr, 0, sizeof maskaddr); + return &maskaddr; +} + +/* Set the ipv6 mask and address. Callers should check ebt_errormsg[0]. + * The string pointed to by address can be altered. */ +void ebt_parse_ip6_address(char *address, struct in6_addr *addr, + struct in6_addr *msk) +{ + struct in6_addr *tmp_addr; + char buf[256]; + char *p; + int i; + int err; + + strncpy(buf, address, sizeof(buf) - 1); + /* first the mask */ + buf[sizeof(buf) - 1] = '\0'; + if ((p = strrchr(buf, '/')) != NULL) { + *p = '\0'; + tmp_addr = parse_ip6_mask(p + 1); + } else + tmp_addr = parse_ip6_mask(NULL); + in6addrcpy(msk, tmp_addr); + + /* if a null mask is given, the name is ignored, like in "any/0" */ + if (!memcmp(msk, &in6addr_any, sizeof(in6addr_any))) + strcpy(buf, "::"); + + if ((err=inet_pton(AF_INET6, buf, addr)) < 1) { + ebt_print_error("Invalid IPv6 Address '%s' specified", buf); + return; + } + + for (i = 0; i < 4; i++) + addr->in6_u.u6_addr32[i] &= msk->in6_u.u6_addr32[i]; +} + +/* Transform the ip6 addr into a string ready for output. */ +char *ebt_ip6_to_numeric(const struct in6_addr *addrp) +{ + /* 0000:0000:0000:0000:0000:000.000.000.000 + * 0000:0000:0000:0000:0000:0000:0000:0000 */ + static char buf[50+1]; + return (char *)inet_ntop(AF_INET6, addrp, buf, sizeof(buf)); +} |