[libvirt] [PATCH 1/3] network: validate DHCP ranges are completely within defined network
Laine Stump
laine at laine.org
Fri May 29 19:06:35 UTC 2015
On 05/29/2015 12:30 PM, John Ferlan wrote:
>
> On 05/26/2015 03:48 PM, Laine Stump wrote:
>> virSocketAddrGetRange() has been updated to take the network address
>> and prefix, and now checks that both the start and end of the range
>> are within that network, thus validating that the entire range of
>> addresses is in the network. For IPv4, it also checks that ranges to
>> not start with the "network address" of the subnet, nor end with the
>> broadcast address of the subnet (this check doesn't apply to IPv6,
>> since IPv6 doesn't have a broadcast or network address)
>>
>> Negative tests have been added to the network update and socket tests
>> to verify that bad ranges properly generate an error.
>>
>> This resolves: https://bugzilla.redhat.com/show_bug.cgi?id=985653
>> ---
>> src/conf/network_conf.c | 14 ++---
>> src/network/bridge_driver.c | 4 +-
>> src/util/virsocketaddr.c | 61 ++++++++++++++++++----
>> src/util/virsocketaddr.h | 6 ++-
>> tests/networkxml2xmlupdatein/dhcp-range-10.xml | 1 +
>> tests/networkxml2xmlupdatein/dhcp-range.xml | 2 +-
>> .../dhcp6host-routed-network-another-range.xml | 2 +-
>> .../dhcp6host-routed-network-range.xml | 2 +-
>> tests/networkxml2xmlupdatetest.c | 5 ++
>> tests/sockettest.c | 55 ++++++++++++-------
>> 10 files changed, 112 insertions(+), 40 deletions(-)
>> create mode 100644 tests/networkxml2xmlupdatein/dhcp-range-10.xml
>>
>> diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
>> index bc63a3d..f9f3d3d 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 4b53475..e08a316 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 67ed330..0edf345 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 || 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(start, network, &netmask) <= 0)
> Should I assume this is a cut-n-paste (eg, the second call should use
> end not start)...
Yep.
>
> Side note - seems there's no "FAIL" test for this condition -
> considering we passed the tests with the check this way...
Yeah, there is a test where the end address is outside the subnet:
> + DO_TEST_RANGE("192.168.122.20", "10.0.0.1", "192.168.122.1", 24, -1, false);
But that one fails anyway, because the end address is lower than the
start address.
Thankfully I was waiting until after release to push . I'll change the
offending "start" to "end", and add this test:
DO_TEST_RANGE("192.168.122.20", "192.168.123.1", "192.168.122.1", 24,
-1, false);
Thanks for your eagle eye!
More information about the libvir-list
mailing list