Use libvirt's existing ipv6/ipv4 parser/printer rather than self-written ones

This patch changes the network filtering code to use libvirt's existing
IPv4 and IPv6 address parsers/printers rather than my self-written ones.

I am introducing a new function in network.c that counts the number of
bits in a netmask and ensures that the given address is indeed a netmask,
return -1 on error or values of 0-32 for IPv4 addresses and 0-128 for
IPv6 addresses. I then based the function checking for valid netmask
on invoking this function.
This commit is contained in:
Stefan Berger 2010-03-30 11:18:04 -04:00
parent bc2102104f
commit 0e0f6021ce
5 changed files with 142 additions and 269 deletions

View File

@ -473,22 +473,6 @@ checkValidMask(unsigned char *data, int len)
}
/* check for a valid IPv4 mask */
static bool
checkIPv4Mask(enum attrDatatype datatype ATTRIBUTE_UNUSED, void *maskptr,
virNWFilterRuleDefPtr nwf ATTRIBUTE_UNUSED)
{
return checkValidMask(maskptr, 4);
}
static bool
checkIPv6Mask(enum attrDatatype datatype ATTRIBUTE_UNUSED, void *maskptr,
virNWFilterRuleDefPtr nwf ATTRIBUTE_UNUSED)
{
return checkValidMask(maskptr, 16);
}
static bool
checkMACMask(enum attrDatatype datatype ATTRIBUTE_UNUSED,
void *macMask,
@ -498,16 +482,6 @@ checkMACMask(enum attrDatatype datatype ATTRIBUTE_UNUSED,
}
static int getMaskNumBits(const unsigned char *mask, int len) {
int i = 0;
while (i < (len << 3)) {
if (!(mask[i>>3] & (0x80 >> (i & 3))))
break;
i++;
}
return i;
}
/*
* supported arp opcode -- see 'ebtables -h arp' for the naming
*/
@ -1227,21 +1201,8 @@ static bool
virNWIPv4AddressParser(const char *input,
nwIPAddressPtr output)
{
int i;
char *endptr;
const char *n = input;
long int d;
for (i = 0; i < 4; i++) {
d = strtol(n, &endptr, 10);
if (d < 0 || d > 255 ||
(endptr - n > 3 ) ||
(i <= 2 && *endptr != '.' ) ||
(i == 3 && *endptr != '\0'))
if (virSocketParseIpv4Addr(input, &output->addr) == -1)
return 0;
output->addr.ipv4Addr[i] = (unsigned char)d;
n = endptr + 1;
}
return 1;
}
@ -1250,81 +1211,8 @@ static bool
virNWIPv6AddressParser(const char *input,
nwIPAddressPtr output)
{
int i, j, pos;
uint16_t n;
int shiftpos = -1;
char prevchar;
char base;
memset(output, 0x0, sizeof(*output));
output->isIPv6 = 1;
pos = 0;
i = 0;
while (i < 8) {
j = 0;
n = 0;
while (1) {
prevchar = input[pos++];
if (prevchar == ':' || prevchar == 0) {
if (j > 0) {
output->addr.ipv6Addr[i * 2 + 0] = n >> 8;
output->addr.ipv6Addr[i * 2 + 1] = n;
i++;
}
break;
}
if (j >= 4)
if (virSocketParseIpv6Addr(input, &output->addr) == -1)
return 0;
if (prevchar >= '0' && prevchar <= '9')
base = '0';
else if (prevchar >= 'a' && prevchar <= 'f')
base = 'a' - 10;
else if (prevchar >= 'A' && prevchar <= 'F')
base = 'A' - 10;
else
return 0;
n <<= 4;
n |= (prevchar - base);
j++;
}
if (prevchar == 0)
break;
if (input[pos] == ':') {
pos ++;
// sequence of zeros
if (prevchar != ':')
return 0;
if (shiftpos != -1)
return 0;
shiftpos = i;
}
}
if (shiftpos != -1) {
if (i >= 7)
return 0;
i--;
j = 0;
while (i >= shiftpos) {
output->addr.ipv6Addr[15 - (j*2) - 1] =
output->addr.ipv6Addr[i * 2 + 0];
output->addr.ipv6Addr[15 - (j*2) - 0] =
output->addr.ipv6Addr[i * 2 + 1];
output->addr.ipv6Addr[i * 2 + 0] = 0;
output->addr.ipv6Addr[i * 2 + 1] = 0;
i--;
j++;
}
}
return 1;
}
@ -1442,11 +1330,10 @@ virNWFilterRuleDetailsParse(virConnectPtr conn ATTRIBUTE_UNUSED,
} else
rc = -1;
} else {
if (checkIPv4Mask(datatype,
ipaddr.addr.ipv4Addr, nwf))
*(uint8_t *)storage_ptr =
getMaskNumBits(ipaddr.addr.ipv4Addr,
sizeof(ipaddr.addr.ipv4Addr));
int_val = virSocketGetNumNetmaskBits(
&ipaddr.addr);
if (int_val >= 0)
*(uint8_t *)storage_ptr = int_val;
else
rc = -1;
found = 1;
@ -1497,11 +1384,10 @@ virNWFilterRuleDetailsParse(virConnectPtr conn ATTRIBUTE_UNUSED,
} else
rc = -1;
} else {
if (checkIPv6Mask(datatype,
ipaddr.addr.ipv6Addr, nwf))
*(uint8_t *)storage_ptr =
getMaskNumBits(ipaddr.addr.ipv6Addr,
sizeof(ipaddr.addr.ipv6Addr));
int_val = virSocketGetNumNetmaskBits(
&ipaddr.addr);
if (int_val >= 0)
*(uint8_t *)storage_ptr = int_val;
else
rc = -1;
found = 1;
@ -2571,43 +2457,12 @@ virNWFilterPoolObjDeleteDef(virConnectPtr conn,
static void
virNWIPAddressFormat(virBufferPtr buf, nwIPAddressPtr ipaddr)
{
if (!ipaddr->isIPv6) {
virBufferVSprintf(buf, "%d.%d.%d.%d",
ipaddr->addr.ipv4Addr[0],
ipaddr->addr.ipv4Addr[1],
ipaddr->addr.ipv4Addr[2],
ipaddr->addr.ipv4Addr[3]);
} else {
int i;
int dcshown = 0, in_dc = 0;
unsigned short n;
while (i < 8) {
n = (ipaddr->addr.ipv6Addr[i * 2 + 0] << 8) |
ipaddr->addr.ipv6Addr[i * 2 + 1];
if (n == 0) {
if (!dcshown) {
in_dc = 1;
if (i == 0)
virBufferAddLit(buf, ":");
dcshown = 1;
}
if (in_dc) {
i++;
continue;
}
}
if (in_dc) {
dcshown = 1;
virBufferAddLit(buf, ":");
in_dc = 0;
}
i++;
virBufferVSprintf(buf, "%x", n);
if (i < 8)
virBufferAddLit(buf, ":");
}
if (in_dc)
virBufferAddLit(buf, ":");
virSocketAddrPtr addr = &ipaddr->addr;
char *output = virSocketFormatAddr(addr);
if (output) {
virBufferVSprintf(buf, "%s", output);
VIR_FREE(output);
}
}

View File

@ -33,6 +33,8 @@
# include "util.h"
# include "hash.h"
# include "xml.h"
# include "network.h"
/**
* Chain suffix size is:
@ -85,11 +87,7 @@ struct _nwMACAddress {
typedef struct _nwIPAddress nwIPAddress;
typedef nwIPAddress *nwIPAddressPtr;
struct _nwIPAddress {
int isIPv6;
union {
unsigned char ipv4Addr[4];
unsigned char ipv6Addr[16];
} addr;
virSocketAddr addr;
};

View File

@ -144,7 +144,7 @@ printDataType(virConnectPtr conn,
nwItemDescPtr item)
{
int done;
int i, pos, s;
char *data;
if (printVar(conn, vars, buf, bufsize, item, &done))
return 1;
@ -154,30 +154,38 @@ printDataType(virConnectPtr conn,
switch (item->datatype) {
case DATATYPE_IPADDR:
if (snprintf(buf, bufsize, "%d.%d.%d.%d",
item->u.ipaddr.addr.ipv4Addr[0],
item->u.ipaddr.addr.ipv4Addr[1],
item->u.ipaddr.addr.ipv4Addr[2],
item->u.ipaddr.addr.ipv4Addr[3]) >= bufsize) {
virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
_("Buffer too small for IP address"));
data = virSocketFormatAddr(&item->u.ipaddr.addr);
if (!data) {
virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
_("internal IPv4 address representation "
"is bad"));
return 1;
}
if (snprintf(buf, bufsize, "%s", data) >= bufsize) {
virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
_("buffer too small for IP address"));
VIR_FREE(data);
return 1;
}
VIR_FREE(data);
break;
case DATATYPE_IPV6ADDR:
pos = 0;
for (i = 0; i < 16; i++) {
s = snprintf(&buf[pos], bufsize - pos, "%x%s",
(unsigned int)item->u.ipaddr.addr.ipv6Addr[i],
((i & 1) && (i < 15)) ? ":" : "" );
if (s >= bufsize - pos) {
virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
_("Buffer too small for IPv6 address"));
data = virSocketFormatAddr(&item->u.ipaddr.addr);
if (!data) {
virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
_("internal IPv6 address representation "
"is bad"));
return 1;
}
pos += s;
if (snprintf(buf, bufsize, "%s", data) >= bufsize) {
virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
_("buffer too small for IPv6 address"));
VIR_FREE(data);
return 1;
}
VIR_FREE(data);
break;
case DATATYPE_MACADDR:

View File

@ -219,88 +219,10 @@ virSocketGetPort(virSocketAddrPtr addr) {
* Returns 0 in case of success and -1 in case of error
*/
int virSocketAddrIsNetmask(virSocketAddrPtr netmask) {
int i;
if (netmask == NULL)
return(-1);
if (netmask->stor.ss_family == AF_INET) {
virIPv4Addr tm;
unsigned char tmp;
int ok = 0;
if (getIPv4Addr(netmask, &tm) < 0)
return(-1);
for (i = 0;i < 4;i++) {
if (tm[i] != 0)
break;
}
if (i >= 4)
return(0);
tmp = 0xFF;
do {
if (tm[i] == tmp) {
ok = 1;
break;
}
tmp <<= 1;
} while (tmp != 0);
if (ok == 0)
return(-1);
i++;
if (i >= 4)
return(0);
for (;i < 4;i++) {
if (tm[i] != 0xFF)
return(-1);
}
} else if (netmask->stor.ss_family == AF_INET6) {
virIPv6Addr tm;
unsigned short tmp;
int ok = 0;
/*
* Hum, on IPv6 people use prefixes instead of netmask
*/
if (getIPv6Addr(netmask, &tm) < 0)
return(-1);
for (i = 0;i < 8;i++) {
if (tm[i] != 0)
break;
}
if (i >= 8)
return(0);
tmp = 0xFFFF;
do {
if (tm[i] == tmp) {
ok = 1;
break;
}
tmp <<= 1;
} while (tmp != 0);
if (ok == 0)
return(-1);
i++;
if (i >= 8)
return(0);
for (;i < 8;i++) {
if (tm[i] != 0xFFFF)
return(-1);
}
} else {
return(-1);
}
return(0);
int n = virSocketGetNumNetmaskBits(netmask);
if (n < 0)
return -1;
return 0;
}
/**
@ -415,3 +337,90 @@ int virSocketGetRange(virSocketAddrPtr start, virSocketAddrPtr end) {
}
return(ret);
}
/**
* virGetNumNetmaskBits
* @netmask: the presumed netmask
*
* Get the number of netmask bits in a netmask.
*
* Returns the number of bits in the netmask or -1 if an error occurred
* or the netmask is invalid.
*/
int virSocketGetNumNetmaskBits(const virSocketAddrPtr netmask)
{
int i, j;
int c = 0;
if (netmask->stor.ss_family == AF_INET) {
virIPv4Addr tm;
uint8_t bit;
if (getIPv4Addr(netmask, &tm) < 0)
return -1;
for (i = 0; i < 4; i++)
if (tm[i] == 0xff)
c += 8;
else
break;
if (c == 8 * 4)
return c;
j = i << 3;
while (j < (8 * 4)) {
bit = 1 << (7 - (j & 7));
if ((tm[j >> 3] & bit)) {
c++;
} else
break;
j++;
}
while (j < (8 * 4)) {
bit = 1 << (7 - (j & 7));
if ((tm[j >> 3] & bit))
return -1;
j++;
}
return c;
} else if (netmask->stor.ss_family == AF_INET6) {
virIPv6Addr tm;
uint16_t bit;
if (getIPv6Addr(netmask, &tm) < 0)
return -1;
for (i = 0; i < 8; i++)
if (tm[i] == 0xffff)
c += 16;
else
break;
if (c == 16 * 8)
return c;
j = i << 4;
while (j < (16 * 8)) {
bit = 1 << (15 - (j & 0xf));
if ((tm[j >> 4] & bit)) {
c++;
} else
break;
j++;
}
while (j < (16 * 8)) {
bit = 1 << (15 - (j & 0xf));
if ((tm[j >> 4]) & bit)
return -1;
j++;
}
return c;
}
return -1;
}

View File

@ -48,4 +48,7 @@ int virSocketAddrIsNetmask(virSocketAddrPtr netmask);
int virSocketCheckNetmask (virSocketAddrPtr addr1,
virSocketAddrPtr addr2,
virSocketAddrPtr netmask);
int virSocketGetNumNetmaskBits(const virSocketAddrPtr netmask);
#endif /* __VIR_NETWORK_H__ */