[libvirt] [PATCH v3 0/3] network: Add support for local PTR domains

I run a system dnsmasq to be able to forward specific DNS requests to specific servers. And I have it configured for both forward and reverse lookups. Another dnsmasq is started for a virtual network with domain "virt". The system dnsmasq knows it needs to forward any requests for the "virt" domain and corresponding PTR domain to the dnsmasq started by libvirt. The problem is dnsmasq forwards queries for unknown names to the upstream name server (which is the system instance in my case). One can get nice endless loops of DNS requests pretty easily. Forward loops can be avoided by specifying localOnly='yes', but there was no way to avoid reverse lookup loops. And this is what I'm trying to address in the following patches. Version 3: - <ptr> support dropped from this series, it will be implemented separately Patches 1 and 2 from version 2 were already pushed. Version 2: - RNG schema changes and tests Jiri Denemark (3): conf: Make virNetworkIPDefParseXML a little bit saner util: Introduce virSocketAddrPTRDomain network: Add support for local PTR domains docs/formatnetwork.html.in | 21 ++++-- docs/news.html.in | 2 + docs/schemas/network.rng | 3 + src/conf/network_conf.c | 55 +++++++++------- src/conf/network_conf.h | 2 + src/libvirt_private.syms | 1 + src/network/bridge_driver.c | 41 ++++++++++++ src/util/virsocketaddr.c | 85 +++++++++++++++++++++++++ src/util/virsocketaddr.h | 9 +++ tests/networkxml2confdata/ptr-domains-auto.conf | 20 ++++++ tests/networkxml2confdata/ptr-domains-auto.xml | 21 ++++++ tests/networkxml2conftest.c | 1 + 12 files changed, 232 insertions(+), 29 deletions(-) create mode 100644 tests/networkxml2confdata/ptr-domains-auto.conf create mode 100644 tests/networkxml2confdata/ptr-domains-auto.xml -- 2.11.0

Iterating over all child nodes when we only support one instance of each child is pretty weired. And it would even cause memory leaks if more than one <tftp> element was specified. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: ACKed in v2 src/conf/network_conf.c | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index aabf315c9..b6849ceab 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -1501,7 +1501,8 @@ virNetworkIPDefParseXML(const char *networkName, * On failure clear it out, but don't free it. */ - xmlNodePtr cur, save; + xmlNodePtr save; + xmlNodePtr dhcp; char *address = NULL, *netmask = NULL; unsigned long prefix = 0; int prefixRc; @@ -1603,29 +1604,20 @@ virNetworkIPDefParseXML(const char *networkName, goto cleanup; } - cur = node->children; - while (cur != NULL) { - if (cur->type == XML_ELEMENT_NODE && - xmlStrEqual(cur->name, BAD_CAST "dhcp")) { - if (virNetworkDHCPDefParseXML(networkName, cur, def) < 0) - goto cleanup; - } else if (cur->type == XML_ELEMENT_NODE && - xmlStrEqual(cur->name, BAD_CAST "tftp")) { - char *root; + if ((dhcp = virXPathNode("./dhcp[1]", ctxt)) && + virNetworkDHCPDefParseXML(networkName, dhcp, def) < 0) + goto cleanup; - if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Unsupported <tftp> element in an IPv6 element in network '%s'"), - networkName); - goto cleanup; - } - if (!(root = virXMLPropString(cur, "root"))) { - cur = cur->next; - continue; - } - def->tftproot = (char *)root; + if (virXPathNode("./tftp[1]", ctxt)) { + if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Unsupported <tftp> element in an IPv6 element " + "in network '%s'"), + networkName); + goto cleanup; } - cur = cur->next; + + def->tftproot = virXPathString("string(./tftp[1]/@root)", ctxt); } result = 0; -- 2.11.0

On 12/16/2016 01:09 PM, Jiri Denemark wrote:
Iterating over all child nodes when we only support one instance of each child is pretty weired. And it would even cause memory leaks if more
s/weired/weird/ ACK sustained.
than one <tftp> element was specified.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> ---
Notes: ACKed in v2
src/conf/network_conf.c | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-)
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index aabf315c9..b6849ceab 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -1501,7 +1501,8 @@ virNetworkIPDefParseXML(const char *networkName, * On failure clear it out, but don't free it. */
- xmlNodePtr cur, save; + xmlNodePtr save; + xmlNodePtr dhcp; char *address = NULL, *netmask = NULL; unsigned long prefix = 0; int prefixRc; @@ -1603,29 +1604,20 @@ virNetworkIPDefParseXML(const char *networkName, goto cleanup; }
- cur = node->children; - while (cur != NULL) { - if (cur->type == XML_ELEMENT_NODE && - xmlStrEqual(cur->name, BAD_CAST "dhcp")) { - if (virNetworkDHCPDefParseXML(networkName, cur, def) < 0) - goto cleanup; - } else if (cur->type == XML_ELEMENT_NODE && - xmlStrEqual(cur->name, BAD_CAST "tftp")) { - char *root; + if ((dhcp = virXPathNode("./dhcp[1]", ctxt)) && + virNetworkDHCPDefParseXML(networkName, dhcp, def) < 0) + goto cleanup;
- if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Unsupported <tftp> element in an IPv6 element in network '%s'"), - networkName); - goto cleanup; - } - if (!(root = virXMLPropString(cur, "root"))) { - cur = cur->next; - continue; - } - def->tftproot = (char *)root; + if (virXPathNode("./tftp[1]", ctxt)) { + if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Unsupported <tftp> element in an IPv6 element " + "in network '%s'"), + networkName); + goto cleanup; } - cur = cur->next; + + def->tftproot = virXPathString("string(./tftp[1]/@root)", ctxt); }
result = 0;

The API creates PTR domain which corresponds to a given addr/prefix. Both IPv4 and IPv6 addresses are supported, but the prefix must be divisible by 8 for IPv4 and divisible by 4 for IPv6. The generated PTR domain has the following format IPv4: 1.2.3.4.in-addr.arpa IPv6: 0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.ip6.arpa Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: ACKed in v2 src/libvirt_private.syms | 1 + src/util/virsocketaddr.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++ src/util/virsocketaddr.h | 9 +++++ 3 files changed, 95 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 7beebbf27..1391a4282 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2403,6 +2403,7 @@ virSocketAddrParse; virSocketAddrParseIPv4; virSocketAddrParseIPv6; virSocketAddrPrefixToNetmask; +virSocketAddrPTRDomain; virSocketAddrSetIPv4Addr; virSocketAddrSetIPv4AddrNetOrder; virSocketAddrSetIPv6Addr; diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c index 33b1e9e1f..41f75d5c2 100644 --- a/src/util/virsocketaddr.c +++ b/src/util/virsocketaddr.c @@ -27,6 +27,7 @@ #include "virerror.h" #include "virstring.h" #include "viralloc.h" +#include "virbuffer.h" #include <netdb.h> @@ -40,6 +41,8 @@ typedef unsigned char virSocketAddrIPv4[4]; typedef virSocketAddrIPv4 *virSocketAddrIPv4Ptr; typedef unsigned short virSocketAddrIPv6[8]; typedef virSocketAddrIPv6 *virSocketAddrIPv6Ptr; +typedef unsigned char virSocketAddrIPv6Nibbles[32]; +typedef virSocketAddrIPv6Nibbles *virSocketAddrIPv6NibblesPtr; static int virSocketAddrGetIPv4Addr(const virSocketAddr *addr, @@ -78,6 +81,23 @@ virSocketAddrGetIPv6Addr(const virSocketAddr *addr, virSocketAddrIPv6Ptr tab) } static int +virSocketAddrGetIPv6Nibbles(const virSocketAddr *addr, + virSocketAddrIPv6NibblesPtr tab) +{ + size_t i; + + if (!addr || !tab || addr->data.stor.ss_family != AF_INET6) + return -1; + + for (i = 0; i < 16; i++) { + (*tab)[2 * i] = addr->data.inet6.sin6_addr.s6_addr[i] >> 4; + (*tab)[2 * i + 1] = addr->data.inet6.sin6_addr.s6_addr[i] & 0xF; + } + + return 0; +} + +static int virSocketAddrParseInternal(struct addrinfo **res, const char *val, int family, @@ -1118,3 +1138,68 @@ virSocketAddrIsNumericLocalhost(const char *addr) return false; } + + +/** + * virSocketAddrPTRDomain: + * + * Create PTR domain which corresponds to @addr/@prefix. Both IPv4 and IPv6 + * addresses are supported, but @prefix must be divisible by 8 for IPv4 and + * divisible by 4 for IPv6, otherwise -2 will be returned. + * + * Returns -2 if the PTR record cannot be automatically created, + * -1 on error, + * 0 on success. + */ +int +virSocketAddrPTRDomain(const virSocketAddr *addr, + unsigned int prefix, + char **ptr) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + size_t i; + int ret = -1; + + if (VIR_SOCKET_ADDR_IS_FAMILY(addr, AF_INET)) { + virSocketAddrIPv4 ip; + + if (prefix == 0 || prefix >= 32 || prefix % 8 != 0) + goto unsupported; + + if (virSocketAddrGetIPv4Addr(addr, &ip) < 0) + goto cleanup; + + for (i = prefix / 8; i > 0; i--) + virBufferAsprintf(&buf, "%u.", ip[i - 1]); + + virBufferAddLit(&buf, VIR_SOCKET_ADDR_IPV4_ARPA); + } else if (VIR_SOCKET_ADDR_IS_FAMILY(addr, AF_INET6)) { + virSocketAddrIPv6Nibbles ip; + + if (prefix == 0 || prefix >= 128 || prefix % 4 != 0) + goto unsupported; + + if (virSocketAddrGetIPv6Nibbles(addr, &ip) < 0) + goto cleanup; + + for (i = prefix / 4; i > 0; i--) + virBufferAsprintf(&buf, "%x.", ip[i - 1]); + + virBufferAddLit(&buf, VIR_SOCKET_ADDR_IPV6_ARPA); + } else { + goto unsupported; + } + + if (!(*ptr = virBufferContentAndReset(&buf))) + goto cleanup; + + ret = 0; + + cleanup: + virBufferFreeAndReset(&buf); + return ret; + + unsupported: + ret = -2; + goto cleanup; +} diff --git a/src/util/virsocketaddr.h b/src/util/virsocketaddr.h index 7ee993b1a..43a370620 100644 --- a/src/util/virsocketaddr.h +++ b/src/util/virsocketaddr.h @@ -57,6 +57,9 @@ typedef struct { # define VIR_SOCKET_ADDR_IPV4_ALL "0.0.0.0" # define VIR_SOCKET_ADDR_IPV6_ALL "::" +# define VIR_SOCKET_ADDR_IPV4_ARPA "in-addr.arpa" +# define VIR_SOCKET_ADDR_IPV6_ARPA "ip6.arpa" + typedef virSocketAddr *virSocketAddrPtr; typedef struct _virSocketAddrRange virSocketAddrRange; @@ -136,4 +139,10 @@ bool virSocketAddrIsWildcard(const virSocketAddr *addr); int virSocketAddrNumericFamily(const char *address); bool virSocketAddrIsNumericLocalhost(const char *addr); + +int virSocketAddrPTRDomain(const virSocketAddr *addr, + unsigned int prefix, + char **ptr) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3); + #endif /* __VIR_SOCKETADDR_H__ */ -- 2.11.0

On 12/16/2016 01:09 PM, Jiri Denemark wrote:
The API creates PTR domain which corresponds to a given addr/prefix. Both IPv4 and IPv6 addresses are supported, but the prefix must be divisible by 8 for IPv4 and divisible by 4 for IPv6.
The generated PTR domain has the following format
IPv4: 1.2.3.4.in-addr.arpa IPv6: 0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.ip6.arpa
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> ---
Notes: ACKed in v2
And it's *still ACKed in v3. Who'd a thunk it??
src/libvirt_private.syms | 1 + src/util/virsocketaddr.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++ src/util/virsocketaddr.h | 9 +++++ 3 files changed, 95 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 7beebbf27..1391a4282 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2403,6 +2403,7 @@ virSocketAddrParse; virSocketAddrParseIPv4; virSocketAddrParseIPv6; virSocketAddrPrefixToNetmask; +virSocketAddrPTRDomain; virSocketAddrSetIPv4Addr; virSocketAddrSetIPv4AddrNetOrder; virSocketAddrSetIPv6Addr; diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c index 33b1e9e1f..41f75d5c2 100644 --- a/src/util/virsocketaddr.c +++ b/src/util/virsocketaddr.c @@ -27,6 +27,7 @@ #include "virerror.h" #include "virstring.h" #include "viralloc.h" +#include "virbuffer.h"
#include <netdb.h>
@@ -40,6 +41,8 @@ typedef unsigned char virSocketAddrIPv4[4]; typedef virSocketAddrIPv4 *virSocketAddrIPv4Ptr; typedef unsigned short virSocketAddrIPv6[8]; typedef virSocketAddrIPv6 *virSocketAddrIPv6Ptr; +typedef unsigned char virSocketAddrIPv6Nibbles[32]; +typedef virSocketAddrIPv6Nibbles *virSocketAddrIPv6NibblesPtr;
static int virSocketAddrGetIPv4Addr(const virSocketAddr *addr, @@ -78,6 +81,23 @@ virSocketAddrGetIPv6Addr(const virSocketAddr *addr, virSocketAddrIPv6Ptr tab) }
static int +virSocketAddrGetIPv6Nibbles(const virSocketAddr *addr, + virSocketAddrIPv6NibblesPtr tab) +{ + size_t i; + + if (!addr || !tab || addr->data.stor.ss_family != AF_INET6) + return -1; + + for (i = 0; i < 16; i++) { + (*tab)[2 * i] = addr->data.inet6.sin6_addr.s6_addr[i] >> 4; + (*tab)[2 * i + 1] = addr->data.inet6.sin6_addr.s6_addr[i] & 0xF; + } + + return 0; +} + +static int virSocketAddrParseInternal(struct addrinfo **res, const char *val, int family, @@ -1118,3 +1138,68 @@ virSocketAddrIsNumericLocalhost(const char *addr)
return false; } + + +/** + * virSocketAddrPTRDomain: + * + * Create PTR domain which corresponds to @addr/@prefix. Both IPv4 and IPv6 + * addresses are supported, but @prefix must be divisible by 8 for IPv4 and + * divisible by 4 for IPv6, otherwise -2 will be returned. + * + * Returns -2 if the PTR record cannot be automatically created, + * -1 on error, + * 0 on success. + */ +int +virSocketAddrPTRDomain(const virSocketAddr *addr, + unsigned int prefix, + char **ptr) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + size_t i; + int ret = -1; + + if (VIR_SOCKET_ADDR_IS_FAMILY(addr, AF_INET)) { + virSocketAddrIPv4 ip; + + if (prefix == 0 || prefix >= 32 || prefix % 8 != 0) + goto unsupported; + + if (virSocketAddrGetIPv4Addr(addr, &ip) < 0) + goto cleanup; + + for (i = prefix / 8; i > 0; i--) + virBufferAsprintf(&buf, "%u.", ip[i - 1]); + + virBufferAddLit(&buf, VIR_SOCKET_ADDR_IPV4_ARPA); + } else if (VIR_SOCKET_ADDR_IS_FAMILY(addr, AF_INET6)) { + virSocketAddrIPv6Nibbles ip; + + if (prefix == 0 || prefix >= 128 || prefix % 4 != 0) + goto unsupported; + + if (virSocketAddrGetIPv6Nibbles(addr, &ip) < 0) + goto cleanup; + + for (i = prefix / 4; i > 0; i--) + virBufferAsprintf(&buf, "%x.", ip[i - 1]); + + virBufferAddLit(&buf, VIR_SOCKET_ADDR_IPV6_ARPA); + } else { + goto unsupported; + } + + if (!(*ptr = virBufferContentAndReset(&buf))) + goto cleanup; + + ret = 0; + + cleanup: + virBufferFreeAndReset(&buf); + return ret; + + unsupported: + ret = -2; + goto cleanup; +} diff --git a/src/util/virsocketaddr.h b/src/util/virsocketaddr.h index 7ee993b1a..43a370620 100644 --- a/src/util/virsocketaddr.h +++ b/src/util/virsocketaddr.h @@ -57,6 +57,9 @@ typedef struct { # define VIR_SOCKET_ADDR_IPV4_ALL "0.0.0.0" # define VIR_SOCKET_ADDR_IPV6_ALL "::"
+# define VIR_SOCKET_ADDR_IPV4_ARPA "in-addr.arpa" +# define VIR_SOCKET_ADDR_IPV6_ARPA "ip6.arpa" + typedef virSocketAddr *virSocketAddrPtr;
typedef struct _virSocketAddrRange virSocketAddrRange; @@ -136,4 +139,10 @@ bool virSocketAddrIsWildcard(const virSocketAddr *addr); int virSocketAddrNumericFamily(const char *address);
bool virSocketAddrIsNumericLocalhost(const char *addr); + +int virSocketAddrPTRDomain(const virSocketAddr *addr, + unsigned int prefix, + char **ptr) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3); + #endif /* __VIR_SOCKETADDR_H__ */

Similarly to localOnly DNS domain, localPtr attribute can be used to tell the DNS server not to forward reverse lookups for unknown IPs which belong to the virtual network. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 3: - <ptr> was removed from this patch and will be implemented separately - NEWS item Version 2: - RNG schema and tests docs/formatnetwork.html.in | 21 ++++++++----- docs/news.html.in | 2 ++ docs/schemas/network.rng | 3 ++ src/conf/network_conf.c | 19 ++++++++++++ src/conf/network_conf.h | 2 ++ src/network/bridge_driver.c | 41 +++++++++++++++++++++++++ tests/networkxml2confdata/ptr-domains-auto.conf | 20 ++++++++++++ tests/networkxml2confdata/ptr-domains-auto.xml | 21 +++++++++++++ tests/networkxml2conftest.c | 1 + 9 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 tests/networkxml2confdata/ptr-domains-auto.conf create mode 100644 tests/networkxml2confdata/ptr-domains-auto.xml diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in index 9cf940052..390aa2e0d 100644 --- a/docs/formatnetwork.html.in +++ b/docs/formatnetwork.html.in @@ -855,14 +855,14 @@ <hostname>myhostalias</hostname> </host> </dns> -<ip address="192.168.122.1" netmask="255.255.255.0"> +<ip address="192.168.122.1" netmask="255.255.255.0" localPtr="yes"> <dhcp> <range start="192.168.122.100" end="192.168.122.254"/> <host mac="00:16:3e:77:e2:ed" name="foo.example.com" ip="192.168.122.10"/> <host mac="00:16:3e:3e:a9:1a" name="bar.example.com" ip="192.168.122.11"/> </dhcp> </ip> -<ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64"/> +<ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64" localPtr="yes"/> <route family="ipv6" address="2001:db9:ca1:1::" prefix="64" gateway="2001:db8:ca2:2::2"/> </pre> @@ -983,11 +983,18 @@ to specify the type of address — <code>ipv4</code> or <code>ipv6</code>; if no <code>family</code> is given, <code>ipv4</code> is assumed. More than one address of each family can - be defined for a network. The <code>ip</code> element is supported - <span class="since">since 0.3.0</span>. IPv6, multiple addresses on a - single network, <code>family</code>, and <code>prefix</code> are - supported <span class="since">since 0.8.7</span>. The <code>ip</code> - element may contain the following elements: + be defined for a network. The optional <code>localPtr</code> attribute + (<span class="since">since 3.0.0</span>) configures the DNS server not + to forward any reverse DNS requests for IP addresses from the network + configured by the <code>address</code> and + <code>netmask</code>/<code>prefix</code> attributes. For some unusual + network prefixes (not divisible by 8 for IPv4 or not divisible by 4 for + IPv6) libvirt may be unable to compute the PTR domain automatically. + The <code>ip</code> element is supported <span class="since">since + 0.3.0</span>. IPv6, multiple addresses on a single network, + <code>family</code>, and <code>prefix</code> are supported + <span class="since">since 0.8.7</span>. The <code>ip</code> element may + contain the following elements: <dl> <dt><code>tftp</code></dt> diff --git a/docs/news.html.in b/docs/news.html.in index 80ac304cd..5a34674f1 100644 --- a/docs/news.html.in +++ b/docs/news.html.in @@ -16,6 +16,8 @@ <ul> <li><strong>New features</strong> <ul> + <li>New localPtr attribute for "ip" element in network XML + </li> <li>qemu: Support QEMU group I/O throttling<br/> Add the capability to allow group I/O throttling via a new domain <disk> <iotune> subelement "group_name" diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng index 986119596..8f0a61b5b 100644 --- a/docs/schemas/network.rng +++ b/docs/schemas/network.rng @@ -339,6 +339,9 @@ <optional> <attribute name="family"><ref name="addr-family"/></attribute> </optional> + <optional> + <attribute name="localPtr"><ref name="virYesNo"/></attribute> + </optional> <interleave> <optional> <element name="tftp"> diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index b6849ceab..86ce311ee 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -1507,6 +1507,7 @@ virNetworkIPDefParseXML(const char *networkName, unsigned long prefix = 0; int prefixRc; int result = -1; + char *localPtr = NULL; save = ctxt->node; ctxt->node = node; @@ -1549,6 +1550,17 @@ virNetworkIPDefParseXML(const char *networkName, else def->prefix = prefix; + localPtr = virXPathString("string(./@localPtr)", ctxt); + if (localPtr) { + def->localPTR = virTristateBoolTypeFromString(localPtr); + if (def->localPTR <= 0) { + virReportError(VIR_ERR_XML_ERROR, + _("Invalid localPtr value '%s' in network '%s'"), + localPtr, networkName); + goto cleanup; + } + } + /* validate address, etc. for each family */ if ((def->family == NULL) || (STREQ(def->family, "ipv4"))) { if (!(VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET) || @@ -1627,6 +1639,7 @@ virNetworkIPDefParseXML(const char *networkName, virNetworkIPDefClear(def); VIR_FREE(address); VIR_FREE(netmask); + VIR_FREE(localPtr); ctxt->node = save; return result; @@ -2652,6 +2665,12 @@ virNetworkIPDefFormat(virBufferPtr buf, } if (def->prefix > 0) virBufferAsprintf(buf, " prefix='%u'", def->prefix); + + if (def->localPTR) { + virBufferAsprintf(buf, " localPtr='%s'", + virTristateBoolTypeToString(def->localPTR)); + } + virBufferAddLit(buf, ">\n"); virBufferAdjustIndent(buf, 2); diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h index 09e091616..b5c9ea24e 100644 --- a/src/conf/network_conf.h +++ b/src/conf/network_conf.h @@ -162,6 +162,8 @@ struct _virNetworkIPDef { unsigned int prefix; /* ipv6 - only prefix allowed */ virSocketAddr netmask; /* ipv4 - either netmask or prefix specified */ + int localPTR; /* virTristateBool */ + size_t nranges; /* Zero or more dhcp ranges */ virSocketAddrRangePtr ranges; diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index ae1589d8c..f9022d43c 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -994,6 +994,43 @@ networkBuildDnsmasqHostsList(dnsmasqContext *dctx, } +static int +networkDnsmasqConfLocalPTRs(virBufferPtr buf, + virNetworkDefPtr def) +{ + virNetworkIPDefPtr ip; + size_t i; + char *ptr = NULL; + int rc; + + for (i = 0; i < def->nips; i++) { + ip = def->ips + i; + + if (ip->localPTR != VIR_TRISTATE_BOOL_YES) + continue; + + if ((rc = virSocketAddrPTRDomain(&ip->address, + virNetworkIPDefPrefix(ip), + &ptr)) < 0) { + if (rc == -2) { + int family = VIR_SOCKET_ADDR_FAMILY(&ip->address); + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("PTR domain for %s network with prefix %u " + "cannot be automatically created"), + (family == AF_INET) ? "IPv4" : "IPv6", + virNetworkIPDefPrefix(ip)); + } + return -1; + } + + virBufferAsprintf(buf, "local=/%s/\n", ptr); + VIR_FREE(ptr); + } + + return 0; +} + + int networkDnsmasqConfContents(virNetworkObjPtr network, const char *pidfile, @@ -1079,6 +1116,10 @@ networkDnsmasqConfContents(virNetworkObjPtr network, network->def->domain); } + if (wantDNS && + networkDnsmasqConfLocalPTRs(&configbuf, network->def) < 0) + goto cleanup; + if (wantDNS && network->def->dns.forwardPlainNames == VIR_TRISTATE_BOOL_NO) { virBufferAddLit(&configbuf, "domain-needed\n"); /* need to specify local=// whether or not a domain is diff --git a/tests/networkxml2confdata/ptr-domains-auto.conf b/tests/networkxml2confdata/ptr-domains-auto.conf new file mode 100644 index 000000000..7f1a393dd --- /dev/null +++ b/tests/networkxml2confdata/ptr-domains-auto.conf @@ -0,0 +1,20 @@ +##WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE +##OVERWRITTEN AND LOST. Changes to this configuration should be made using: +## virsh net-edit default +## or other application using the libvirt API. +## +## dnsmasq conf file created by libvirt +strict-order +local=/122.168.192.in-addr.arpa/ +local=/1.0.e.f.0.1.c.a.8.b.d.0.1.0.0.2.ip6.arpa/ +except-interface=lo +bind-dynamic +interface=virbr0 +dhcp-range=192.168.122.2,192.168.122.254 +dhcp-no-override +dhcp-authoritative +dhcp-lease-max=253 +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile +addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts +dhcp-range=2001:db8:ac10:fe01::1,ra-only +dhcp-range=2001:db8:ac10:fd01::1,ra-only diff --git a/tests/networkxml2confdata/ptr-domains-auto.xml b/tests/networkxml2confdata/ptr-domains-auto.xml new file mode 100644 index 000000000..7fe12dc67 --- /dev/null +++ b/tests/networkxml2confdata/ptr-domains-auto.xml @@ -0,0 +1,21 @@ +<network> + <name>default</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward dev='eth1' mode='nat'/> + <bridge name='virbr0' stp='on' delay='0'/> + <ip address='192.168.122.1' netmask='255.255.255.0' localPtr='yes'> + <dhcp> + <range start='192.168.122.2' end='192.168.122.254'/> + <host mac='00:16:3e:77:e2:ed' name='a.example.com' ip='192.168.122.10'/> + <host mac='00:16:3e:3e:a9:1a' name='b.example.com' ip='192.168.122.11'/> + </dhcp> + </ip> + <ip family='ipv4' address='192.168.123.1' netmask='255.255.255.0' localPtr='no'> + </ip> + <ip family='ipv6' address='2001:db8:ac10:fe01::1' prefix='64' localPtr='yes'> + </ip> + <ip family='ipv6' address='2001:db8:ac10:fd01::1' prefix='64'> + </ip> + <ip family='ipv4' address='10.24.10.1'> + </ip> +</network> diff --git a/tests/networkxml2conftest.c b/tests/networkxml2conftest.c index 65a0e3218..a80d3b2d4 100644 --- a/tests/networkxml2conftest.c +++ b/tests/networkxml2conftest.c @@ -129,6 +129,7 @@ mymain(void) DO_TEST("dhcp6-network", dhcpv6); DO_TEST("dhcp6-nat-network", dhcpv6); DO_TEST("dhcp6host-routed-network", dhcpv6); + DO_TEST("ptr-domains-auto", dhcpv6); virObjectUnref(dhcpv6); virObjectUnref(full); -- 2.11.0

On 12/16/2016 01:09 PM, Jiri Denemark wrote:
Similarly to localOnly DNS domain, localPtr attribute can be used to tell the DNS server not to forward reverse lookups for unknown IPs which belong to the virtual network.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> ---
Notes: Version 3: - <ptr> was removed from this patch and will be implemented separately - NEWS item
Version 2: - RNG schema and tests
docs/formatnetwork.html.in | 21 ++++++++----- docs/news.html.in | 2 ++ docs/schemas/network.rng | 3 ++ src/conf/network_conf.c | 19 ++++++++++++ src/conf/network_conf.h | 2 ++ src/network/bridge_driver.c | 41 +++++++++++++++++++++++++ tests/networkxml2confdata/ptr-domains-auto.conf | 20 ++++++++++++ tests/networkxml2confdata/ptr-domains-auto.xml | 21 +++++++++++++ tests/networkxml2conftest.c | 1 + 9 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 tests/networkxml2confdata/ptr-domains-auto.conf create mode 100644 tests/networkxml2confdata/ptr-domains-auto.xml
diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in index 9cf940052..390aa2e0d 100644 --- a/docs/formatnetwork.html.in +++ b/docs/formatnetwork.html.in @@ -855,14 +855,14 @@ <hostname>myhostalias</hostname> </host> </dns> -<ip address="192.168.122.1" netmask="255.255.255.0"> +<ip address="192.168.122.1" netmask="255.255.255.0" localPtr="yes"> <dhcp> <range start="192.168.122.100" end="192.168.122.254"/> <host mac="00:16:3e:77:e2:ed" name="foo.example.com" ip="192.168.122.10"/> <host mac="00:16:3e:3e:a9:1a" name="bar.example.com" ip="192.168.122.11"/> </dhcp> </ip> -<ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64"/> +<ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64" localPtr="yes"/> <route family="ipv6" address="2001:db9:ca1:1::" prefix="64" gateway="2001:db8:ca2:2::2"/> </pre>
@@ -983,11 +983,18 @@ to specify the type of address — <code>ipv4</code> or <code>ipv6</code>; if no <code>family</code> is given, <code>ipv4</code> is assumed. More than one address of each family can - be defined for a network. The <code>ip</code> element is supported - <span class="since">since 0.3.0</span>. IPv6, multiple addresses on a - single network, <code>family</code>, and <code>prefix</code> are - supported <span class="since">since 0.8.7</span>. The <code>ip</code> - element may contain the following elements: + be defined for a network. The optional <code>localPtr</code> attribute + (<span class="since">since 3.0.0</span>) configures the DNS server not + to forward
s/not to forward/to not forward/ Other than that, ACK!

On Fri, Dec 16, 2016 at 19:07:42 -0500, Laine Stump wrote:
On 12/16/2016 01:09 PM, Jiri Denemark wrote:
Similarly to localOnly DNS domain, localPtr attribute can be used to tell the DNS server not to forward reverse lookups for unknown IPs which belong to the virtual network.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> ---
Notes: Version 3: - <ptr> was removed from this patch and will be implemented separately - NEWS item Version 2: - RNG schema and tests
docs/formatnetwork.html.in | 21 ++++++++----- docs/news.html.in | 2 ++ docs/schemas/network.rng | 3 ++ src/conf/network_conf.c | 19 ++++++++++++ src/conf/network_conf.h | 2 ++ src/network/bridge_driver.c | 41 +++++++++++++++++++++++++ tests/networkxml2confdata/ptr-domains-auto.conf | 20 ++++++++++++ tests/networkxml2confdata/ptr-domains-auto.xml | 21 +++++++++++++ tests/networkxml2conftest.c | 1 + 9 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 tests/networkxml2confdata/ptr-domains-auto.conf create mode 100644 tests/networkxml2confdata/ptr-domains-auto.xml
diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in index 9cf940052..390aa2e0d 100644 --- a/docs/formatnetwork.html.in +++ b/docs/formatnetwork.html.in @@ -855,14 +855,14 @@ <hostname>myhostalias</hostname> </host> </dns> -<ip address="192.168.122.1" netmask="255.255.255.0"> +<ip address="192.168.122.1" netmask="255.255.255.0" localPtr="yes"> <dhcp> <range start="192.168.122.100" end="192.168.122.254"/> <host mac="00:16:3e:77:e2:ed" name="foo.example.com" ip="192.168.122.10"/> <host mac="00:16:3e:3e:a9:1a" name="bar.example.com" ip="192.168.122.11"/> </dhcp> </ip> -<ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64"/> +<ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64" localPtr="yes"/> <route family="ipv6" address="2001:db9:ca1:1::" prefix="64" gateway="2001:db8:ca2:2::2"/> </pre> @@ -983,11 +983,18 @@ to specify the type of address — <code>ipv4</code> or <code>ipv6</code>; if no <code>family</code> is given, <code>ipv4</code> is assumed. More than one address of each family can - be defined for a network. The <code>ip</code> element is supported - <span class="since">since 0.3.0</span>. IPv6, multiple addresses on a - single network, <code>family</code>, and <code>prefix</code> are - supported <span class="since">since 0.8.7</span>. The <code>ip</code> - element may contain the following elements: + be defined for a network. The optional <code>localPtr</code> attribute + (<span class="since">since 3.0.0</span>) configures the DNS server not + to forward
s/not to forward/to not forward/
Other than that, ACK!
Fixed and pushed, thanks. Jirka
participants (2)
-
Jiri Denemark
-
Laine Stump