getdata: add cidr range support

This makes 'range6 123::/45' style cidr notation to be understood as address
range.  Earlier ranges that used cidr failed to parse completely.

Reported-by: Jeff Bailey <jeffrey.bailey@bt.com>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
This commit is contained in:
Sami Kerola 2017-09-17 00:03:06 +01:00
parent 48d0629881
commit bb0fa9adae
No known key found for this signature in database
GPG key ID: A9553245FDE9B739
13 changed files with 175 additions and 5 deletions

1
THANKS
View file

@ -41,3 +41,4 @@ Ivanov Ivan
Manuel Hachtkemper
Klaus Slott
Boris Lytochkin
Jeff Bailey

View file

@ -238,6 +238,8 @@ extern int parse_ipaddr_init(const char *restrict src,
extern int parse_ipaddr_v4(const char *restrict src, union ipaddr_t *restrict dst);
extern int parse_ipaddr_v6(const char *restrict src, union ipaddr_t *restrict dst);
extern void parse_cidr(struct range_t *range_p, const char *word);
extern void (*copy_ipaddr) (union ipaddr_t *restrict dst, const union ipaddr_t *restrict src);
extern void copy_ipaddr_init(union ipaddr_t *restrict dst,
const union ipaddr_t *restrict src);

View file

@ -339,13 +339,19 @@ void parse_config(int is_include, const char *restrict config_file,
/* printf ("range 2nd ip: %s\n", word); */
range_p = ranges + num_ranges;
argument = ITS_NOTHING_INTERESTING;
parse_ipaddr(word, &addr);
if (one_ip_range == 1) {
if (strchr(word, '/')) {
parse_cidr(range_p, word);
one_ip_range = 0;
copy_ipaddr(&range_p->first_ip, &addr);
} else {
/* not cidr */
parse_ipaddr(word, &addr);
if (one_ip_range == 1) {
one_ip_range = 0;
copy_ipaddr(&range_p->first_ip, &addr);
}
copy_ipaddr(&range_p->last_ip, &addr);
reorder_last_first(range_p);
}
copy_ipaddr(&range_p->last_ip, &addr);
reorder_last_first(range_p);
newrange:
range_p->count = 0;
range_p->touched = 0;

View file

@ -52,10 +52,15 @@
#include "error.h"
#include "progname.h"
#include "quote.h"
#include "xalloc.h"
#include "dhcpd-pools.h"
#include "defaults.h"
char *(*cidr_last)(union ipaddr_t *restrict addr, const int mask);
static char *cidr_last_v4(union ipaddr_t *restrict addr, const int mask);
static char *cidr_last_v6(union ipaddr_t *restrict addr, const int mask);
/*! \brief Set function pointers depending on IP version.
* \param ip IP version.
*/
@ -73,6 +78,7 @@ void set_ipv_functions(int version)
leasecomp = leasecomp_v4;
ntop_ipaddr = ntop_ipaddr_v4;
parse_ipaddr = parse_ipaddr_v4;
cidr_last = cidr_last_v4;
xstrstr = xstrstr_v4;
break;
@ -86,6 +92,7 @@ void set_ipv_functions(int version)
leasecomp = leasecomp_v6;
ntop_ipaddr = ntop_ipaddr_v6;
parse_ipaddr = parse_ipaddr_v6;
cidr_last = cidr_last_v6;
xstrstr = xstrstr_v6;
break;
@ -99,6 +106,7 @@ void set_ipv_functions(int version)
leasecomp = leasecomp_init;
ntop_ipaddr = ntop_ipaddr_init;
parse_ipaddr = parse_ipaddr_init;
cidr_last = NULL;
xstrstr = xstrstr_init;
break;
@ -148,6 +156,92 @@ int parse_ipaddr_v6(const char *restrict src, union ipaddr_t *restrict dst)
return rv == 1;
}
static int strtol_mask(const char *str)
{
long num;
char *end = NULL;
errno = 0;
if (str == NULL || *str == '\0')
goto err;
num = strtol(str, &end, 10);
if (errno || str == end || (end && *end))
goto err;
if (num < 0 || 128 < num)
goto err;
return (int)num;
err:
return -1;
}
static char *cidr_last_v4(union ipaddr_t *restrict addr, const int mask)
{
union ipaddr_t last_ip;
uint32_t netmask;
const char *ip;
if (mask)
netmask = (1U << (32 - mask)) - 1;
else
netmask = 0;
last_ip.v4 = addr->v4 | netmask;
ip = ntop_ipaddr(&last_ip);
return xstrdup(ip);
}
static char *cidr_last_v6(union ipaddr_t *restrict addr, const int mask)
{
union ipaddr_t bitmask;
int i, j;
char ip[128];
memset(&bitmask, 0x0, sizeof(bitmask));
for (i = mask, j = 0; i > 0; i -= 8, j++) {
if (i >= 8)
bitmask.v6[j] = 0xff;
else
bitmask.v6[j] = (unsigned char)(0xffU << (8 - i));
}
for (i = 0; i < (int)sizeof(bitmask); i++)
addr->v6[i] |= ~bitmask.v6[i];
inet_ntop(AF_INET6, addr, ip, sizeof(ip));
return xstrdup(ip);
}
void parse_cidr(struct range_t *range_p, const char *word)
{
char *divider;
int mask;
union ipaddr_t addr;
char *last;
/* determine cidr */
divider = strchr(word, '/');
*divider++ = '\0';
mask = strtol_mask(divider);
if (mask < 0)
error(EXIT_FAILURE, 0, "cidr %s invalid mask %s", word,
divider);
if (config.ip_version == IPvUNKNOWN) {
if (!strchr(word, ':'))
set_ipv_functions(IPv4);
else
set_ipv_functions(IPv6);
}
/* start of the range is easy */
parse_ipaddr(word, &addr);
copy_ipaddr(&range_p->first_ip, &addr);
/* end of the range depends cidr size */
last = cidr_last(&addr, mask);
parse_ipaddr(last, &addr);
copy_ipaddr(&range_p->last_ip, &addr);
free(last);
}
/*! \brief Copy IP address to union.
*
* \param dst Destination for a binary IP address.

View file

@ -20,6 +20,8 @@ TESTS = \
tests/leading0 \
tests/one-ip \
tests/one-line \
tests/range4 \
tests/range6 \
tests/same-twice \
tests/simple \
tests/sorts \

31
tests/confs/range4 Normal file
View file

@ -0,0 +1,31 @@
shared-network example1 {
subnet 10.0.0.0 netmask 255.255.255.0 {
pool {
range 10.0.0.0/27;
}
}
subnet 10.1.0.0 netmask 255.255.255.0 {
pool {
range 10.1.0.1/27;
}
}
}
shared-network example2 {
subnet 10.2.0.0 netmask 255.255.255.0 {
pool {
range 10.2.0.1/28;
}
}
subnet 10.3.0.0 netmask 255.255.255.0 {
pool {
range 10.3.0.1/29;
}
}
}
subnet 10.4.0.0 netmask 255.255.255.0 {
pool {
range 10.4.0.1/32;
}
}

4
tests/confs/range6 Normal file
View file

@ -0,0 +1,4 @@
subnet6 dead:abba:1000::/56 {
range6 dead:abba:1000::/56;
prefix6 dead:abba:1000:0100:: dead:abba:1000:ff00::/56;
}

16
tests/expected/range4 Normal file
View file

@ -0,0 +1,16 @@
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc
example1 10.0.0.0 - 10.0.0.31 32 12 37.500 0 12 37.500
example1 10.1.0.1 - 10.1.0.31 31 10 32.258 0 10 32.258
example2 10.2.0.1 - 10.2.0.15 15 8 53.333 0 8 53.333
example2 10.3.0.1 - 10.3.0.7 7 7 100.000 0 7 100.000
All networks 10.4.0.1 - 10.4.0.1 1 1 100.000 0 1 100.000
Shared networks:
name max cur percent touch t+c t+c perc
example1 63 22 34.921 0 22 34.921
example2 22 15 68.182 0 15 68.182
Sum of all ranges:
name max cur percent touch t+c t+c perc
All networks 86 38 44.186 0 38 44.186

10
tests/expected/range6 Normal file
View file

@ -0,0 +1,10 @@
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc
All networks dead:abba:1000:: - dead:abba:1000:ff:ffff:ffff:ffff:ffff 4.72237e+21 2 0.000 1 3 0.000
Shared networks:
name max cur percent touch t+c t+c perc
Sum of all ranges:
name max cur percent touch t+c t+c perc
All networks 4.72237e+21 2 0.000 1 3 0.000

1
tests/leases/range4 Symbolic link
View file

@ -0,0 +1 @@
complete

1
tests/leases/range6 Symbolic link
View file

@ -0,0 +1 @@
v6

1
tests/range4 Symbolic link
View file

@ -0,0 +1 @@
test.sh

1
tests/range6 Symbolic link
View file

@ -0,0 +1 @@
test.sh