static int
virSocketAddrRangeParseXML(const char *networkName,
- xmlNodePtr node,
- virSocketAddrRangePtr range)
+ virNetworkIpDefPtr ipdef,
+ xmlNodePtr node,
+ virSocketAddrRangePtr range)
{
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);
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++;
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 */
/*
- * 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
* 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 || network == NULL)
+ return -1;
+
+ if (VIR_SOCKET_ADDR_FAMILY(start) != VIR_SOCKET_ADDR_FAMILY(end) ||
+ VIR_SOCKET_ADDR_FAMILY(start) != VIR_SOCKET_ADDR_FAMILY(network))
+ return -1;
- if ((start == NULL) || (end == NULL))
+ if (prefix < 0 ||
+ virSocketAddrPrefixToNetmask(prefix, &netmask, VIR_SOCKET_ADDR_FAMILY(network)) < 0)
return -1;
- if (start->data.stor.ss_family != end->data.stor.ss_family)
+
+ /* 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 (start->data.stor.ss_family == AF_INET) {
+ 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;
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;
/*
* 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
}
-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 */
}
}
+
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);
}
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)
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("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("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", "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);