diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index bc63a3ddc2..f9f3d3d17e 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -832,8 +832,9 @@ int virNetworkIpDefNetmask(const virNetworkIpDef *def,
static int
virSocketAddrRangeParseXML(const char *networkName,
- xmlNodePtr node,
- virSocketAddrRangePtr range)
+ virNetworkIpDefPtr ipdef,
+ xmlNodePtr node,
+ virSocketAddrRangePtr range)
{
@@ -859,7 +860,8 @@ virSocketAddrRangeParseXML(const char *networkName,
goto cleanup;
/* do a sanity check of the range */
- if (virSocketAddrGetRange(&range->start, &range->end) < 0) {
+ if (virSocketAddrGetRange(&range->start, &range->end, &ipdef->address,
+ virNetworkIpDefPrefix(ipdef)) < 0) {
virReportError(VIR_ERR_XML_ERROR,
_("Invalid dhcp range '%s' to '%s' in network '%s'"),
start, end, networkName);
@@ -1009,8 +1011,8 @@ virNetworkDHCPDefParseXML(const char *networkName,
if (VIR_REALLOC_N(def->ranges, def->nranges + 1) < 0)
return -1;
- if (virSocketAddrRangeParseXML(networkName, cur,
- &def->ranges[def->nranges]) < 0) {
+ if (virSocketAddrRangeParseXML(networkName, def, cur,
+ &def->ranges[def->nranges]) < 0) {
return -1;
}
def->nranges++;
@@ -3608,7 +3610,7 @@ virNetworkDefUpdateIPDHCPRange(virNetworkDefPtr def,
goto cleanup;
}
- if (virSocketAddrRangeParseXML(def->name, ctxt->node, &range) < 0)
+ if (virSocketAddrRangeParseXML(def->name, ipdef, ctxt->node, &range) < 0)
goto cleanup;
/* check if an entry with same name/address/ip already exists */
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index f438c0b49b..5caa6b944f 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -1193,7 +1193,9 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
VIR_FREE(saddr);
VIR_FREE(eaddr);
nbleases += virSocketAddrGetRange(&ipdef->ranges[r].start,
- &ipdef->ranges[r].end);
+ &ipdef->ranges[r].end,
+ &ipdef->address,
+ virNetworkIpDefPrefix(ipdef));
}
/*
diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c
index 67ed330da8..bab8608cf8 100644
--- a/src/util/virsocketaddr.c
+++ b/src/util/virsocketaddr.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2014 Red Hat, Inc.
+ * Copyright (C) 2009-2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -605,31 +605,69 @@ int virSocketAddrCheckNetmask(virSocketAddrPtr addr1, virSocketAddrPtr addr2,
* virSocketGetRange:
* @start: start of an IP range
* @end: end of an IP range
+ * @network: IP address of network that should completely contain this range
+ * @prefix: prefix of the network
*
- * Check the order of the 2 addresses and compute the range, this
- * will return 1 for identical addresses. Errors can come from incompatible
- * addresses type, excessive range (>= 2^^16) where the two addresses are
- * unrelated or inverted start and end.
+ * Check the order of the 2 addresses and compute the range, this will
+ * return 1 for identical addresses. Errors can come from incompatible
+ * addresses type, excessive range (>= 2^^16) where the two addresses
+ * are unrelated, inverted start and end, or a range that is not
+ * within network/prefix.
*
* Returns the size of the range or -1 in case of failure
*/
-int virSocketAddrGetRange(virSocketAddrPtr start, virSocketAddrPtr end)
+int
+virSocketAddrGetRange(virSocketAddrPtr start, virSocketAddrPtr end,
+ virSocketAddrPtr network, int prefix)
{
int ret = 0;
size_t i;
+ virSocketAddr netmask;
- if ((start == NULL) || (end == NULL))
- return -1;
- if (start->data.stor.ss_family != end->data.stor.ss_family)
+ if (start == NULL || end == NULL || network == NULL)
return -1;
- if (start->data.stor.ss_family == AF_INET) {
+ if (VIR_SOCKET_ADDR_FAMILY(start) != VIR_SOCKET_ADDR_FAMILY(end) ||
+ VIR_SOCKET_ADDR_FAMILY(start) != VIR_SOCKET_ADDR_FAMILY(network))
+ return -1;
+
+ if (prefix < 0 ||
+ virSocketAddrPrefixToNetmask(prefix, &netmask, VIR_SOCKET_ADDR_FAMILY(network)) < 0)
+ return -1;
+
+ /* both start and end of range need to be in the same network as
+ * "network"
+ */
+ if (virSocketAddrCheckNetmask(start, network, &netmask) <= 0 ||
+ virSocketAddrCheckNetmask(end, network, &netmask) <= 0)
+ return -1;
+
+ if (VIR_SOCKET_ADDR_IS_FAMILY(start, AF_INET)) {
virSocketAddrIPv4 t1, t2;
+ virSocketAddr netaddr, broadcast;
+
+ if (virSocketAddrBroadcast(network, &netmask, &broadcast) < 0 ||
+ virSocketAddrMask(network, &netmask, &netaddr) < 0)
+ return -1;
+
+ /* Don't allow the start of the range to be the network
+ * address (usually "...0") or the end of the range to be the
+ * broadcast address (usually "...255"). (the opposite also
+ * isn't allowed, but checking for that is implicit in all the
+ * other combined checks) (IPv6 doesn't have broadcast and
+ * network addresses, so this check is only done for IPv4)
+ */
+ if (virSocketAddrEqual(start, &netaddr) ||
+ virSocketAddrEqual(end, &broadcast))
+ return -1;
if ((virSocketAddrGetIPv4Addr(start, &t1) < 0) ||
(virSocketAddrGetIPv4Addr(end, &t2) < 0))
return -1;
+ /* legacy check that everything except the last two bytes are
+ * the same
+ */
for (i = 0; i < 2; i++) {
if (t1[i] != t2[i])
return -1;
@@ -638,13 +676,16 @@ int virSocketAddrGetRange(virSocketAddrPtr start, virSocketAddrPtr end)
if (ret < 0)
return -1;
ret++;
- } else if (start->data.stor.ss_family == AF_INET6) {
+ } else if (VIR_SOCKET_ADDR_IS_FAMILY(start, AF_INET6)) {
virSocketAddrIPv6 t1, t2;
if ((virSocketAddrGetIPv6Addr(start, &t1) < 0) ||
(virSocketAddrGetIPv6Addr(end, &t2) < 0))
return -1;
+ /* legacy check that everything except the last two bytes are
+ * the same
+ */
for (i = 0; i < 7; i++) {
if (t1[i] != t2[i])
return -1;
diff --git a/src/util/virsocketaddr.h b/src/util/virsocketaddr.h
index 99ab46f038..9e2680a4d2 100644
--- a/src/util/virsocketaddr.h
+++ b/src/util/virsocketaddr.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2013 Red Hat, Inc.
+ * Copyright (C) 2009-2013, 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -96,7 +96,9 @@ int virSocketAddrSetPort(virSocketAddrPtr addr, int port);
int virSocketAddrGetPort(virSocketAddrPtr addr);
int virSocketAddrGetRange(virSocketAddrPtr start,
- virSocketAddrPtr end);
+ virSocketAddrPtr end,
+ virSocketAddrPtr network,
+ int prefix);
int virSocketAddrIsNetmask(virSocketAddrPtr netmask);
diff --git a/tests/networkxml2xmlupdatein/dhcp-range-10.xml b/tests/networkxml2xmlupdatein/dhcp-range-10.xml
new file mode 100644
index 0000000000..ed775c8a42
--- /dev/null
+++ b/tests/networkxml2xmlupdatein/dhcp-range-10.xml
@@ -0,0 +1 @@
+
diff --git a/tests/networkxml2xmlupdatein/dhcp-range.xml b/tests/networkxml2xmlupdatein/dhcp-range.xml
index ed775c8a42..d5e283c45b 100644
--- a/tests/networkxml2xmlupdatein/dhcp-range.xml
+++ b/tests/networkxml2xmlupdatein/dhcp-range.xml
@@ -1 +1 @@
-
+
diff --git a/tests/networkxml2xmlupdateout/dhcp6host-routed-network-another-range.xml b/tests/networkxml2xmlupdateout/dhcp6host-routed-network-another-range.xml
index ee6eb7a27c..4a1360d769 100644
--- a/tests/networkxml2xmlupdateout/dhcp6host-routed-network-another-range.xml
+++ b/tests/networkxml2xmlupdateout/dhcp6host-routed-network-another-range.xml
@@ -8,7 +8,7 @@
-
+
diff --git a/tests/networkxml2xmlupdateout/dhcp6host-routed-network-range.xml b/tests/networkxml2xmlupdateout/dhcp6host-routed-network-range.xml
index ee6eb7a27c..4a1360d769 100644
--- a/tests/networkxml2xmlupdateout/dhcp6host-routed-network-range.xml
+++ b/tests/networkxml2xmlupdateout/dhcp6host-routed-network-range.xml
@@ -8,7 +8,7 @@
-
+
diff --git a/tests/networkxml2xmlupdatetest.c b/tests/networkxml2xmlupdatetest.c
index af697bb568..024137858e 100644
--- a/tests/networkxml2xmlupdatetest.c
+++ b/tests/networkxml2xmlupdatetest.c
@@ -202,6 +202,11 @@ mymain(void)
"dhcp6host-routed-network-range",
VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST,
0);
+ DO_TEST_INDEX_FAIL("add-dhcp-range-outside-net",
+ "dhcp-range-10",
+ "dhcp6host-routed-network",
+ VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST,
+ 0);
DO_TEST_INDEX("append-dhcp-range",
"dhcp-range",
"dhcp6host-routed-network",
diff --git a/tests/sockettest.c b/tests/sockettest.c
index 086c0eacaf..292edb6100 100644
--- a/tests/sockettest.c
+++ b/tests/sockettest.c
@@ -1,7 +1,7 @@
/*
* sockettest.c: Testing for src/util/network.c APIs
*
- * Copyright (C) 2010-2011, 2014 Red Hat, Inc.
+ * Copyright (C) 2010-2011, 2014, 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -86,17 +86,22 @@ static int testFormatHelper(const void *opaque)
}
-static int testRange(const char *saddrstr, const char *eaddrstr, int size, bool pass)
+static int
+testRange(const char *saddrstr, const char *eaddrstr,
+ const char *netstr, int prefix, int size, bool pass)
{
virSocketAddr saddr;
virSocketAddr eaddr;
+ virSocketAddr netaddr;
if (virSocketAddrParse(&saddr, saddrstr, AF_UNSPEC) < 0)
return -1;
if (virSocketAddrParse(&eaddr, eaddrstr, AF_UNSPEC) < 0)
return -1;
+ if (virSocketAddrParse(&netaddr, netstr, AF_UNSPEC) < 0)
+ return -1;
- int gotsize = virSocketAddrGetRange(&saddr, &eaddr);
+ int gotsize = virSocketAddrGetRange(&saddr, &eaddr, &netaddr, prefix);
VIR_DEBUG("Size want %d vs got %d", size, gotsize);
if (pass) {
/* fail if virSocketAddrGetRange returns failure, or unexpected size */
@@ -107,16 +112,23 @@ static int testRange(const char *saddrstr, const char *eaddrstr, int size, bool
}
}
+
struct testRangeData {
const char *saddr;
const char *eaddr;
+ const char *netaddr;
+ int prefix;
int size;
bool pass;
};
+
+
static int testRangeHelper(const void *opaque)
{
const struct testRangeData *data = opaque;
- return testRange(data->saddr, data->eaddr, data->size, data->pass);
+ return testRange(data->saddr, data->eaddr,
+ data->netaddr, data->prefix,
+ data->size, data->pass);
}
@@ -289,10 +301,12 @@ mymain(void)
ret = -1; \
} while (0)
-#define DO_TEST_RANGE(saddr, eaddr, size, pass) \
+#define DO_TEST_RANGE(saddr, eaddr, netaddr, prefix, size, pass) \
do { \
- struct testRangeData data = { saddr, eaddr, size, pass }; \
- if (virtTestRun("Test range " saddr " -> " eaddr " size " #size, \
+ struct testRangeData data \
+ = { saddr, eaddr, netaddr, prefix, size, pass }; \
+ if (virtTestRun("Test range " saddr " -> " eaddr "(" netaddr \
+ "/" #prefix") size " #size, \
testRangeHelper, &data) < 0) \
ret = -1; \
} while (0)
@@ -359,17 +373,22 @@ mymain(void)
DO_TEST_PARSE_AND_FORMAT("::1", AF_UNIX, false);
DO_TEST_PARSE_AND_FORMAT("::ffff", AF_UNSPEC, true);
- DO_TEST_RANGE("192.168.122.1", "192.168.122.1", 1, true);
- DO_TEST_RANGE("192.168.122.1", "192.168.122.20", 20, true);
- DO_TEST_RANGE("192.168.122.0", "192.168.122.255", 256, true);
- DO_TEST_RANGE("192.168.122.20", "192.168.122.1", -1, false);
- DO_TEST_RANGE("10.0.0.1", "192.168.122.20", -1, false);
- DO_TEST_RANGE("192.168.122.20", "10.0.0.1", -1, false);
+ DO_TEST_RANGE("192.168.122.1", "192.168.122.1", "192.168.122.1", 24, 1, true);
+ DO_TEST_RANGE("192.168.122.1", "192.168.122.20", "192.168.122.22", 24, 20, true);
+ DO_TEST_RANGE("192.168.122.0", "192.168.122.254", "192.168.122.1", 24, -1, false);
+ DO_TEST_RANGE("192.168.122.1", "192.168.122.255", "192.168.122.1", 24, -1, false);
+ DO_TEST_RANGE("192.168.122.0", "192.168.122.255", "192.168.122.1", 16, 256, true);
+ DO_TEST_RANGE("192.168.122.20", "192.168.122.1", "192.168.122.1", 24, -1, false);
+ DO_TEST_RANGE("10.0.0.1", "192.168.122.20", "192.168.122.1", 24, -1, false);
+ DO_TEST_RANGE("192.168.122.20", "10.0.0.1", "192.168.122.1", 24, -1, false);
+ DO_TEST_RANGE("172.16.0.50", "172.16.0.254", "1.2.3.4", 8, -1, false);
+ DO_TEST_RANGE("192.168.122.1", "192.168.123.20", "192.168.122.22", 24, -1, false);
+ DO_TEST_RANGE("192.168.122.1", "192.168.123.20", "192.168.122.22", 23, 276, true);
- DO_TEST_RANGE("2000::1", "2000::1", 1, true);
- DO_TEST_RANGE("2000::1", "2000::2", 2, true);
- DO_TEST_RANGE("2000::2", "2000::1", -1, false);
- DO_TEST_RANGE("2000::1", "9001::1", -1, false);
+ DO_TEST_RANGE("2000::1", "2000::1", "2000::1", 64, 1, true);
+ DO_TEST_RANGE("2000::1", "2000::2", "2000::1", 64, 2, true);
+ DO_TEST_RANGE("2000::2", "2000::1", "2000::1", 64, -1, false);
+ DO_TEST_RANGE("2000::1", "9001::1", "2000::1", 64, -1, false);
DO_TEST_NETMASK("192.168.122.1", "192.168.122.2",
"255.255.255.0", true);