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

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.