IPv6: add DHCPv6 support

The DHCP version is determined according to the first IP address that
appears in the configuration file.  Caveat; counters are of native long
type.  Since IPv6 address space has 2^128 addresses, they are subject to
overflow.

[Sami Kerola:  This commit also fixed a percent sorting bug, which has
been broken always.  See changes ret_percent() for the fix.]

CC: LI Zimu <lzm@cernet.edu.cn>
CC: Xing Li <xing@cernet.edu.cn>
Reviewed-by: Sami Kerola <kerolasa@iki.fi>
Signed-off-by: Cheer Xiao <xiaqqaix@gmail.com>
This commit is contained in:
Cheer Xiao 2012-12-02 19:38:26 +00:00 committed by Sami Kerola
parent 71bcee14e9
commit a57d399643
8 changed files with 267 additions and 119 deletions

View file

@ -45,6 +45,78 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
int parse_ipaddr(const char *restrict src, union ipaddr_t *restrict dst)
{
int rv;
if (dhcp_version == VERSION_UNKNOWN) {
struct in_addr addr;
struct in6_addr addr6;
if (inet_aton(src, &addr) == 1) {
dhcp_version = VERSION_4;
} else if (inet_pton(AF_INET6, src, &addr6) == 1) {
dhcp_version = VERSION_6;
} else {
return 0;
}
}
if (dhcp_version == VERSION_6) {
struct in6_addr addr;
rv = inet_pton(AF_INET6, src, &addr);
memcpy(&dst->v6, addr.s6_addr, sizeof(addr.s6_addr));
} else {
struct in_addr addr;
rv = inet_aton(src, &addr);
dst->v4 = ntohl(addr.s_addr);
}
return rv == 1;
}
void copy_ipaddr(union ipaddr_t *restrict dst,
const union ipaddr_t *restrict src)
{
if (dhcp_version == VERSION_6) {
memcpy(&dst->v6, &src->v6, sizeof(src->v6));
} else {
dst->v4 = src->v4;
}
}
const char *ntop_ipaddr(const union ipaddr_t *ip)
{
static char
buffer[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
if (dhcp_version == VERSION_6) {
struct in6_addr addr;
memcpy(addr.s6_addr, ip->v6, sizeof(addr.s6_addr));
return inet_ntop(AF_INET6, &addr, buffer, sizeof(buffer));
} else {
struct in_addr addr;
addr.s_addr = htonl(ip->v4);
return inet_ntop(AF_INET, &addr, buffer, sizeof(buffer));
}
}
unsigned long get_range_size(const struct range_t *r)
{
if (dhcp_version == VERSION_6) {
unsigned long size = 0;
int i;
/* When calculating the size of an IPv6 range overflow may
* occur. In that case only the last LONG_BIT bits are
* preserved, thus we just skip the first (16 - LONG_BIT)
* bits... */
for (i = LONG_BIT / 8 < 16 ? 16 - LONG_BIT / 8 : 0; i < 16; i++) {
size <<= 8;
size += (int)r->last_ip.v6[i] - (int)r->first_ip.v6[i];
}
fprintf(stderr, "\n");
return size + 1;
} else {
return r->last_ip.v4 - r->first_ip.v4 + 1;
}
}
int
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)