render / rpms / libvirt

Forked from rpms/libvirt 10 months ago
Clone
Blob Blame History Raw
From 25b0aab07debcb40c4eb1868013f6cbbb119754b Mon Sep 17 00:00:00 2001
Message-Id: <25b0aab07debcb40c4eb1868013f6cbbb119754b.1391615407.git.jdenemar@redhat.com>
From: Laine Stump <laine@laine.org>
Date: Wed, 5 Feb 2014 03:09:09 -0700
Subject: [PATCH] network: permit upstream forwarding of unqualified DNS names

This patch is a prerequisite patch to fixing

  https://bugzilla.redhat.com/show_bug.cgi?id=1061099 (RHEL7)

It *attempted* (and failed) to resolve the issue that prompted the
filing of

  https://bugzilla.redhat.com/show_bug.cgi?id=928638 (RHEL6)

(although the request there is for something much larger and more
general than this patch)

commit f3868259ca0517212e439a65c9060868f673b6c9 disabled the
forwarding to upstream DNS servers of unresolved DNS requests for
names that had no domain, but were just simple host names (no "."
character anywhere in the name). While this behavior is frowned upon
by DNS root servers (that's why it was changed in libvirt), it is
convenient in some cases, and since dnsmasq can be configured to allow
it, it must not be strictly forbidden.

This patch restores [NB: attempts and *fails* to restore] the old
behavior, but since it is usually undesirable, restoring it requires
specification of a new option in the network config. Adding the
attribute "forwardPlainNames='yes'" to the <dns> elemnt does the trick
- when that attribute is added to a network config, any simple
hostnames that can't be resolved by the network's dnsmasq instance
will be forwarded to the DNS servers listed in the host's
/etc/resolv.conf for an attempt at resolution (just as any FQDN would
be forwarded).

When that attribute *isn't* specified, unresolved simple names will
*not* be forwarded to the upstream DNS server - this is the default
behavior.

(cherry picked from commit 4f595ba61c792267dcd547a0e3c2887ab286e45b)

Conflicts:
	tests/networkxml2xmltest.c - extra tests were added upstream

Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
---
 docs/formatnetwork.html.in                         | 25 +++++++++++++++----
 docs/schemas/network.rng                           |  8 +++++++
 src/conf/network_conf.c                            | 28 ++++++++++++++++++++--
 src/conf/network_conf.h                            |  1 +
 src/network/bridge_driver.c                        | 20 +++++++++++-----
 .../nat-network-dns-forward-plain.conf             | 11 +++++++++
 .../nat-network-dns-forward-plain.xml              |  9 +++++++
 .../networkxml2confdata/nat-network-dns-hosts.xml  |  2 +-
 tests/networkxml2conftest.c                        |  1 +
 .../nat-network-dns-forward-plain.xml              |  9 +++++++
 tests/networkxml2xmlin/nat-network-dns-hosts.xml   |  2 +-
 .../nat-network-dns-forward-plain.xml              | 11 +++++++++
 tests/networkxml2xmltest.c                         |  1 +
 13 files changed, 114 insertions(+), 14 deletions(-)
 create mode 100644 tests/networkxml2confdata/nat-network-dns-forward-plain.conf
 create mode 100644 tests/networkxml2confdata/nat-network-dns-forward-plain.xml
 create mode 100644 tests/networkxml2xmlin/nat-network-dns-forward-plain.xml
 create mode 100644 tests/networkxml2xmlout/nat-network-dns-forward-plain.xml

diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
index eb7c4c7..e1482db 100644
--- a/docs/formatnetwork.html.in
+++ b/docs/formatnetwork.html.in
@@ -663,10 +663,27 @@
         with the idiosyncrasies of the platform where libvirt is
         running. <span class="since">Since 0.8.8</span>
       </dd>
-      <dt><code>dns</code></dt><dd>
-        The dns element of a network contains configuration information for the
-        virtual network's DNS server. <span class="since">Since 0.9.3</span>
-        Currently supported elements are:
+      <dt><code>dns</code></dt>
+      <dd> The dns element of a network contains configuration
+        information for the virtual network's DNS
+        server <span class="since">Since 0.9.3</span>.
+
+        <p>
+          The dns element
+          can have an optional <code>forwardPlainNames</code>
+          attribute <span class="since">Since 1.1.2</span>.
+          If <code>forwardPlainNames</code> is "no", then DNS resolution
+          requests for names that are not qualified with a domain
+          (i.e. names with no "." character) will not be forwarded to
+          the host's upstream DNS server - they will only be resolved if
+          they are known locally within the virtual network's own DNS
+          server. If <code>forwardPlainNames</code> is "yes",
+          unqualified names <b>will</b> be forwarded to the upstream DNS
+          server if they can't be resolved by the virtual network's own
+          DNS server.
+        </p>
+
+        Currently supported sub-elements of <code>&lt;dns&gt;</code> are:
         <dl>
           <dt><code>txt</code></dt>
           <dd>A <code>dns</code> element can have 0 or more <code>txt</code> elements.
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
index 11adbac..d7edb09 100644
--- a/docs/schemas/network.rng
+++ b/docs/schemas/network.rng
@@ -234,6 +234,14 @@
              and other features in the <dns> element -->
         <optional>
             <element name="dns">
+              <optional>
+                <attribute name="forwardPlainNames">
+                  <choice>
+                    <value>yes</value>
+                    <value>no</value>
+                  </choice>
+                </attribute>
+              </optional>
               <zeroOrMore>
                 <element name="txt">
                   <attribute name="name"><ref name="dnsName"/></attribute>
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 8846675..d611d71 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -1037,6 +1037,7 @@ virNetworkDNSDefParseXML(const char *networkName,
     xmlNodePtr *hostNodes = NULL;
     xmlNodePtr *srvNodes = NULL;
     xmlNodePtr *txtNodes = NULL;
+    char *forwardPlainNames = NULL;
     int nhosts, nsrvs, ntxts;
     size_t i;
     int ret = -1;
@@ -1044,6 +1045,19 @@ virNetworkDNSDefParseXML(const char *networkName,
 
     ctxt->node = node;
 
+    forwardPlainNames = virXPathString("string(./@forwardPlainNames)", ctxt);
+    if (forwardPlainNames) {
+        if (STREQ(forwardPlainNames, "yes")) {
+            def->forwardPlainNames = true;
+        } else if (STRNEQ(forwardPlainNames, "no")) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("Invalid dns forwardPlainNames setting '%s' "
+                             "in network '%s'"),
+                           forwardPlainNames, networkName);
+            goto cleanup;
+        }
+    }
+
     nhosts = virXPathNodeSet("./host", ctxt, &hostNodes);
     if (nhosts < 0) {
         virReportError(VIR_ERR_XML_ERROR,
@@ -1106,6 +1120,7 @@ virNetworkDNSDefParseXML(const char *networkName,
 
     ret = 0;
 cleanup:
+    VIR_FREE(forwardPlainNames);
     VIR_FREE(hostNodes);
     VIR_FREE(srvNodes);
     VIR_FREE(txtNodes);
@@ -2252,10 +2267,19 @@ virNetworkDNSDefFormat(virBufferPtr buf,
     int result = 0;
     size_t i, j;
 
-    if (!(def->nhosts || def->nsrvs || def->ntxts))
+    if (!(def->forwardPlainNames || def->nhosts || def->nsrvs || def->ntxts))
         goto out;
 
-    virBufferAddLit(buf, "<dns>\n");
+    virBufferAddLit(buf, "<dns");
+    if (def->forwardPlainNames) {
+        virBufferAddLit(buf, " forwardPlainNames='yes'");
+        if (!(def->nhosts || def->nsrvs || def->ntxts)) {
+            virBufferAddLit(buf, "/>\n");
+            goto out;
+        }
+    }
+
+    virBufferAddLit(buf, ">\n");
     virBufferAdjustIndent(buf, 2);
 
     for (i = 0; i < def->ntxts; i++) {
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index a1d3282..920e899 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -115,6 +115,7 @@ struct _virNetworkDNSHostDef {
 typedef struct _virNetworkDNSDef virNetworkDNSDef;
 typedef virNetworkDNSDef *virNetworkDNSDefPtr;
 struct _virNetworkDNSDef {
+    bool forwardPlainNames;
     size_t ntxts;
     virNetworkDNSTxtDefPtr txts;
     size_t nhosts;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 54d388b..57c88ae 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -695,20 +695,28 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
                       "##    virsh net-edit %s\n"
                       "## or other application using the libvirt API.\n"
                       "##\n## dnsmasq conf file created by libvirt\n"
-                      "strict-order\n"
-                      "domain-needed\n",
+                      "strict-order\n",
                       network->def->name);
 
+    if (!network->def->dns.forwardPlainNames)
+        virBufferAddLit(&configbuf, "domain-needed\n");
+
     if (network->def->domain) {
         virBufferAsprintf(&configbuf,
                           "domain=%s\n"
                           "expand-hosts\n",
                           network->def->domain);
     }
-    /* need to specify local even if no domain specified */
-    virBufferAsprintf(&configbuf,
-                      "local=/%s/\n",
-                      network->def->domain ? network->def->domain : "");
+
+    if (network->def->domain || !network->def->dns.forwardPlainNames) {
+        /* need to specify local even if no domain specified, unless
+         * the config says we should forward "plain" names (i.e. not
+         * fully qualified, no '.' characters)
+         */
+        virBufferAsprintf(&configbuf,
+                          "local=/%s/\n",
+                          network->def->domain ? network->def->domain : "");
+    }
 
     if (pidfile)
         virBufferAsprintf(&configbuf, "pid-file=%s\n", pidfile);
diff --git a/tests/networkxml2confdata/nat-network-dns-forward-plain.conf b/tests/networkxml2confdata/nat-network-dns-forward-plain.conf
new file mode 100644
index 0000000..9a000b8
--- /dev/null
+++ b/tests/networkxml2confdata/nat-network-dns-forward-plain.conf
@@ -0,0 +1,11 @@
+##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
+except-interface=lo
+bind-dynamic
+interface=virbr0
+addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts
diff --git a/tests/networkxml2confdata/nat-network-dns-forward-plain.xml b/tests/networkxml2confdata/nat-network-dns-forward-plain.xml
new file mode 100644
index 0000000..10bacb5
--- /dev/null
+++ b/tests/networkxml2confdata/nat-network-dns-forward-plain.xml
@@ -0,0 +1,9 @@
+<network>
+  <name>default</name>
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9c</uuid>
+  <forward dev='eth0' mode='nat'/>
+  <bridge name='virbr0' stp='on' delay='0' />
+  <dns forwardPlainNames='yes'/>
+  <ip address='192.168.122.1' netmask='255.255.255.0'>
+  </ip>
+</network>
diff --git a/tests/networkxml2confdata/nat-network-dns-hosts.xml b/tests/networkxml2confdata/nat-network-dns-hosts.xml
index 2180a5d..351df4f 100644
--- a/tests/networkxml2confdata/nat-network-dns-hosts.xml
+++ b/tests/networkxml2confdata/nat-network-dns-hosts.xml
@@ -4,7 +4,7 @@
   <forward dev='eth0' mode='nat'/>
   <bridge name='virbr0' stp='on' delay='0' />
   <domain name="example.com"/>
-  <dns>
+  <dns forwardPlainNames='no'>
     <host ip='192.168.122.1'>
       <hostname>host</hostname>
       <hostname>gateway</hostname>
diff --git a/tests/networkxml2conftest.c b/tests/networkxml2conftest.c
index b234b30..5825af3 100644
--- a/tests/networkxml2conftest.c
+++ b/tests/networkxml2conftest.c
@@ -144,6 +144,7 @@ mymain(void)
     DO_TEST("nat-network-dns-txt-record", full);
     DO_TEST("nat-network-dns-srv-record", full);
     DO_TEST("nat-network-dns-hosts", full);
+    DO_TEST("nat-network-dns-forward-plain", full);
     DO_TEST("dhcp6-network", dhcpv6);
     DO_TEST("dhcp6-nat-network", dhcpv6);
     DO_TEST("dhcp6host-routed-network", dhcpv6);
diff --git a/tests/networkxml2xmlin/nat-network-dns-forward-plain.xml b/tests/networkxml2xmlin/nat-network-dns-forward-plain.xml
new file mode 100644
index 0000000..10bacb5
--- /dev/null
+++ b/tests/networkxml2xmlin/nat-network-dns-forward-plain.xml
@@ -0,0 +1,9 @@
+<network>
+  <name>default</name>
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9c</uuid>
+  <forward dev='eth0' mode='nat'/>
+  <bridge name='virbr0' stp='on' delay='0' />
+  <dns forwardPlainNames='yes'/>
+  <ip address='192.168.122.1' netmask='255.255.255.0'>
+  </ip>
+</network>
diff --git a/tests/networkxml2xmlin/nat-network-dns-hosts.xml b/tests/networkxml2xmlin/nat-network-dns-hosts.xml
index 9a83fed..954c9db 100644
--- a/tests/networkxml2xmlin/nat-network-dns-hosts.xml
+++ b/tests/networkxml2xmlin/nat-network-dns-hosts.xml
@@ -3,7 +3,7 @@
   <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9c</uuid>
   <forward dev='eth0' mode='nat'/>
   <bridge name='virbr0' stp='on' delay='0' />
-  <dns>
+  <dns forwardPlainNames='no'>
     <host ip='192.168.122.1'>
       <hostname>host</hostname>
       <hostname>gateway</hostname>
diff --git a/tests/networkxml2xmlout/nat-network-dns-forward-plain.xml b/tests/networkxml2xmlout/nat-network-dns-forward-plain.xml
new file mode 100644
index 0000000..3b50828
--- /dev/null
+++ b/tests/networkxml2xmlout/nat-network-dns-forward-plain.xml
@@ -0,0 +1,11 @@
+<network>
+  <name>default</name>
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9c</uuid>
+  <forward dev='eth0' mode='nat'>
+    <interface dev='eth0'/>
+  </forward>
+  <bridge name='virbr0' stp='on' delay='0' />
+  <dns forwardPlainNames='yes'/>
+  <ip address='192.168.122.1' netmask='255.255.255.0'>
+  </ip>
+</network>
diff --git a/tests/networkxml2xmltest.c b/tests/networkxml2xmltest.c
index b48eed2..ba21818 100644
--- a/tests/networkxml2xmltest.c
+++ b/tests/networkxml2xmltest.c
@@ -105,6 +105,7 @@ mymain(void)
     DO_TEST("nat-network-dns-txt-record");
     DO_TEST("nat-network-dns-hosts");
     DO_TEST("nat-network-forward-nat-address");
+    DO_TEST("nat-network-dns-forward-plain");
     DO_TEST("8021Qbh-net");
     DO_TEST("direct-net");
     DO_TEST("host-bridge-net");
-- 
1.8.5.3