Signed-off-by: Jiri Denemark <jdenemar@xxxxxxxxxx>
---
docs/formatnetwork.html.in | 37 ++++++++++---
docs/schemas/basictypes.rng | 6 +++
docs/schemas/network.rng | 8 +++
src/conf/network_conf.c | 72 ++++++++++++++++++++++++-
src/conf/network_conf.h | 4 ++
src/network/bridge_driver.c | 47 ++++++++++++++++
tests/networkxml2confdata/ptr-domains-auto.conf | 20 +++++++
tests/networkxml2confdata/ptr-domains-auto.xml | 21 ++++++++
tests/networkxml2confdata/ptr-domains.conf | 24 +++++++++
tests/networkxml2confdata/ptr-domains.xml | 24 +++++++++
tests/networkxml2conftest.c | 2 +
11 files changed, 258 insertions(+), 7 deletions(-)
create mode 100644 tests/networkxml2confdata/ptr-domains-auto.conf
create mode 100644 tests/networkxml2confdata/ptr-domains-auto.xml
create mode 100644 tests/networkxml2confdata/ptr-domains.conf
create mode 100644 tests/networkxml2confdata/ptr-domains.xml
diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
index 9cf940052..3c9414779 100644
--- a/docs/formatnetwork.html.in
+++ b/docs/formatnetwork.html.in
@@ -855,7 +855,7 @@
<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"/>
@@ -863,6 +863,10 @@
</dhcp>
</ip>
<ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64"/>
+<ip family="ipv6" address="fec0::1" prefix="31" localPtr="yes">
+ <ptr domain="0.0.0.0.0.c.e.f.ip6.arpa"/>
+ <ptr domain="1.0.0.0.0.c.e.f.ip6.arpa"/>
+</ip>
<route family="ipv6" address="2001:db9:ca1:1::" prefix="64" gateway="2001:db8:ca2:2::2"/>
</pre>
@@ -983,11 +987,20 @@
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,
+ in which case the domain has to be specified explicitly by the
+ <code>ptr</code> element described below. 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>
@@ -1051,6 +1064,18 @@
</dd>
</dl>
</dd>
+
+ <dt><code>ptr</code></dt>
+ <dd>The <code>domain</code> attribute of the optional
+ <code>ptr</code> element specifies the PTR domain used for reverse
+ DNS lookups. The domain has to end with ".in-addr.arpa" for IPv4
+ and ".ip6.arpa" for IPv6. Each <code>ip</code> element may contain
+ zero or more <code>ptr</code> elements. When
+ <code>localPtr='yes'</code> attribute is set in the parent
+ <code>ip</code> element the DNS server for this network will be
+ configured not to forward any reverse lookups within the specified
+ domains. <span class="since">Since 3.0.0</span>
+ </dd>
</dl>
</dd>
</dl>
diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng
index 1b4f980e7..f99c76392 100644
--- a/docs/schemas/basictypes.rng
+++ b/docs/schemas/basictypes.rng
@@ -239,6 +239,12 @@
</data>
</define>
+ <define name="ptrName">
+ <data type="string">
+ <param name="pattern">(((((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([1-9][0-9])|([0-9]))\.){1,3}in-addr)|((([0-9a-fA-F]\.){1,31})ip6)).arpa</param>
+ </data>
+ </define>
+
<define name="deviceName">
<data type="string">
<param name="pattern">[a-zA-Z0-9_\.\-\\:/]+</param>
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
index 986119596..1a3705a1f 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">
@@ -384,6 +387,11 @@
</interleave>
</element>
</optional>
+ <zeroOrMore>
+ <element name='ptr'>
+ <attribute name='domain'><ref name="ptrName"/></attribute>
+ </element>
+ </zeroOrMore>
</interleave>
</element>
</zeroOrMore>
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index b6849ceab..ce0bd0260 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -315,6 +315,10 @@ static void
virNetworkIPDefClear(virNetworkIPDefPtr def)
{
VIR_FREE(def->family);
+
+ virStringListFreeCount(def->ptrs, def->nptrs);
+ def->ptrs = NULL;
+
VIR_FREE(def->ranges);
while (def->nhosts)
@@ -1507,6 +1511,10 @@ virNetworkIPDefParseXML(const char *networkName,
unsigned long prefix = 0;
int prefixRc;
int result = -1;
+ char *localPtr = NULL;
+ xmlNodePtr *nodes = NULL;
+ size_t i;
+ int n;
save = ctxt->node;
ctxt->node = node;
@@ -1549,6 +1557,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) ||
@@ -1604,6 +1623,46 @@ virNetworkIPDefParseXML(const char *networkName,
goto cleanup;
}
+ if ((n = virXPathNodeSet("./ptr", ctxt, &nodes)) < 0)
+ goto cleanup;
+
+ if (n > 0) {
+ if (VIR_ALLOC_N(def->ptrs, n) < 0)
+ goto cleanup;
+ def->nptrs = n;
+ }
+ for (i = 0; i < n; i++) {
+ char *domain;
+ const char *suffix;
+ size_t len;
+ size_t suflen;
+
+ if (!(domain = virXMLPropString(nodes[i], "domain"))) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Missing PTR domain in network '%s'"),
+ networkName);
+ goto cleanup;
+ }
+
+ if (VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET))
+ suffix = VIR_SOCKET_ADDR_IPV4_ARPA;
+ else
+ suffix = VIR_SOCKET_ADDR_IPV6_ARPA;
+
+ len = strlen(domain);
+ suflen = strlen(suffix);
+ if (len <= suflen ||
+ STRNEQ(domain + len - suflen, suffix) ||
+ domain[len - suflen - 1] != '.') {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Invalid PTR domain '%s' in network '%s'"),
+ domain, networkName);
+ VIR_FREE(domain);
+ goto cleanup;
+ }
+ def->ptrs[i] = domain;
+ }
+
if ((dhcp = virXPathNode("./dhcp[1]", ctxt)) &&
virNetworkDHCPDefParseXML(networkName, dhcp, def) < 0)
goto cleanup;
@@ -1627,6 +1686,8 @@ virNetworkIPDefParseXML(const char *networkName,
virNetworkIPDefClear(def);
VIR_FREE(address);
VIR_FREE(netmask);
+ VIR_FREE(localPtr);
+ VIR_FREE(nodes);
ctxt->node = save;
return result;
@@ -2630,6 +2691,7 @@ static int
virNetworkIPDefFormat(virBufferPtr buf,
const virNetworkIPDef *def)
{
+ size_t i;
int result = -1;
virBufferAddLit(buf, "<ip");
@@ -2652,15 +2714,23 @@ 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);
+ for (i = 0; i < def->nptrs; i++)
+ virBufferAsprintf(buf, "<ptr domain='%s'/>\n", def->ptrs[i]);
+
if (def->tftproot) {
virBufferEscapeString(buf, "<tftp root='%s'/>\n",
def->tftproot);
}
if ((def->nranges || def->nhosts)) {
- size_t i;
virBufferAddLit(buf, "<dhcp>\n");
virBufferAdjustIndent(buf, 2);
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index 09e091616..edf1a1abd 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -162,6 +162,10 @@ struct _virNetworkIPDef {
unsigned int prefix; /* ipv6 - only prefix allowed */
virSocketAddr netmask; /* ipv4 - either netmask or prefix specified */
+ int localPTR; /* virTristateBool */
+ size_t nptrs;
+ char **ptrs;
+
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..49753737f 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -994,6 +994,49 @@ networkBuildDnsmasqHostsList(dnsmasqContext *dctx,
}
+static int
+networkDnsmasqConfLocalPTRs(virBufferPtr buf,
+ virNetworkDefPtr def)
+{
+ virNetworkIPDefPtr ip;
+ size_t i, j;
+ char *ptr = NULL;
+ int rc;
+
+ for (i = 0; i < def->nips; i++) {
+ ip = def->ips + i;
+
+ if (ip->localPTR != VIR_TRISTATE_BOOL_YES)
+ continue;
+
+ for (j = 0; j < ip->nptrs; j++)
+ virBufferAsprintf(buf, "local=/%s/\n", ip->ptrs[j]);
+
+ if (ip->nptrs > 0)
+ 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 +1122,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/networkxml2confdata/ptr-domains.conf b/tests/networkxml2confdata/ptr-domains.conf
new file mode 100644
index 000000000..2900eebce
--- /dev/null
+++ b/tests/networkxml2confdata/ptr-domains.conf
@@ -0,0 +1,24 @@
+##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 test
+## or other application using the libvirt API.
+##
+## dnsmasq conf file created by libvirt
+strict-order
+local=/30.20.10.in-addr.arpa/
+local=/31.20.10.in-addr.arpa/
+local=/2.0.0.0.0.c.e.f.ip6.arpa/
+local=/0.0.0.0.0.c.e.f.ip6.arpa/
+local=/1.0.0.0.0.c.e.f.ip6.arpa/
+local=/1.0.f.e.d.c.b.a.4.0.0.0.0.c.e.f.ip6.arpa/
+except-interface=lo
+bind-dynamic
+interface=virbr2
+dhcp-range=10.20.30.1,static
+dhcp-no-override
+dhcp-authoritative
+dhcp-hostsfile=/var/lib/libvirt/dnsmasq/test.hostsfile
+addn-hosts=/var/lib/libvirt/dnsmasq/test.addnhosts
+dhcp-range=fec0:2::1,ra-only
+dhcp-range=fec0::1,ra-only
+dhcp-range=fec0:4:abcd:ef01::1,ra-only
diff --git a/tests/networkxml2confdata/ptr-domains.xml b/tests/networkxml2confdata/ptr-domains.xml
new file mode 100644
index 000000000..64a329676
--- /dev/null
+++ b/tests/networkxml2confdata/ptr-domains.xml
@@ -0,0 +1,24 @@
+<network>
+ <name>test</name>
+ <uuid>cafecafe-cafe-cafe-cafe-cafecafecafe</uuid>
+ <forward mode='nat'/>
+ <bridge name='virbr2' stp='on' delay='0'/>
+ <mac address='52:54:00:eb:c2:e8'/>
+ <ip address='10.20.30.1' prefix='23' localPtr='yes'>
+ <ptr domain='30.20.10.in-addr.arpa'/>
+ <ptr domain='31.20.10.in-addr.arpa'/>
+ <dhcp>
+ <host mac='ca:fe:ca:fe:ca:fe' name='ble' ip='10.20.30.2'/>
+ <host mac='ca:fe:ca:fe:ca:fe' name='bla' ip='10.20.30.3'/>
+ <host mac='52:54:00:16:c6:1a' name='pxe' ip='10.20.30.4'/>
+ </dhcp>
+ </ip>
+ <ip family='ipv6' address='fec0:2::1' prefix='32' localPtr='yes'>
+ </ip>
+ <ip family='ipv6' address='fec0::1' prefix='31' localPtr='yes'>
+ <ptr domain='0.0.0.0.0.c.e.f.ip6.arpa'/>
+ <ptr domain='1.0.0.0.0.c.e.f.ip6.arpa'/>
+ </ip>
+ <ip family='ipv6' address='fec0:4:abcd:ef01::1' prefix='64' localPtr='yes'>
+ </ip>
+</network>
diff --git a/tests/networkxml2conftest.c b/tests/networkxml2conftest.c
index 65a0e3218..b6c967c45 100644
--- a/tests/networkxml2conftest.c
+++ b/tests/networkxml2conftest.c
@@ -129,6 +129,8 @@ mymain(void)
DO_TEST("dhcp6-network", dhcpv6);
DO_TEST("dhcp6-nat-network", dhcpv6);
DO_TEST("dhcp6host-routed-network", dhcpv6);
+ DO_TEST("ptr-domains", dhcpv6);
+ DO_TEST("ptr-domains-auto", dhcpv6);
virObjectUnref(dhcpv6);
virObjectUnref(full);