c401cc
From 25b0aab07debcb40c4eb1868013f6cbbb119754b Mon Sep 17 00:00:00 2001
c401cc
Message-Id: <25b0aab07debcb40c4eb1868013f6cbbb119754b.1391615407.git.jdenemar@redhat.com>
c401cc
From: Laine Stump <laine@laine.org>
c401cc
Date: Wed, 5 Feb 2014 03:09:09 -0700
c401cc
Subject: [PATCH] network: permit upstream forwarding of unqualified DNS names
c401cc
c401cc
This patch is a prerequisite patch to fixing
c401cc
c401cc
  https://bugzilla.redhat.com/show_bug.cgi?id=1061099 (RHEL7)
c401cc
c401cc
It *attempted* (and failed) to resolve the issue that prompted the
c401cc
filing of
c401cc
c401cc
  https://bugzilla.redhat.com/show_bug.cgi?id=928638 (RHEL6)
c401cc
c401cc
(although the request there is for something much larger and more
c401cc
general than this patch)
c401cc
c401cc
commit f3868259ca0517212e439a65c9060868f673b6c9 disabled the
c401cc
forwarding to upstream DNS servers of unresolved DNS requests for
c401cc
names that had no domain, but were just simple host names (no "."
c401cc
character anywhere in the name). While this behavior is frowned upon
c401cc
by DNS root servers (that's why it was changed in libvirt), it is
c401cc
convenient in some cases, and since dnsmasq can be configured to allow
c401cc
it, it must not be strictly forbidden.
c401cc
c401cc
This patch restores [NB: attempts and *fails* to restore] the old
c401cc
behavior, but since it is usually undesirable, restoring it requires
c401cc
specification of a new option in the network config. Adding the
c401cc
attribute "forwardPlainNames='yes'" to the <dns> elemnt does the trick
c401cc
- when that attribute is added to a network config, any simple
c401cc
hostnames that can't be resolved by the network's dnsmasq instance
c401cc
will be forwarded to the DNS servers listed in the host's
c401cc
/etc/resolv.conf for an attempt at resolution (just as any FQDN would
c401cc
be forwarded).
c401cc
c401cc
When that attribute *isn't* specified, unresolved simple names will
c401cc
*not* be forwarded to the upstream DNS server - this is the default
c401cc
behavior.
c401cc
c401cc
(cherry picked from commit 4f595ba61c792267dcd547a0e3c2887ab286e45b)
c401cc
c401cc
Conflicts:
c401cc
	tests/networkxml2xmltest.c - extra tests were added upstream
c401cc
c401cc
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
c401cc
---
c401cc
 docs/formatnetwork.html.in                         | 25 +++++++++++++++----
c401cc
 docs/schemas/network.rng                           |  8 +++++++
c401cc
 src/conf/network_conf.c                            | 28 ++++++++++++++++++++--
c401cc
 src/conf/network_conf.h                            |  1 +
c401cc
 src/network/bridge_driver.c                        | 20 +++++++++++-----
c401cc
 .../nat-network-dns-forward-plain.conf             | 11 +++++++++
c401cc
 .../nat-network-dns-forward-plain.xml              |  9 +++++++
c401cc
 .../networkxml2confdata/nat-network-dns-hosts.xml  |  2 +-
c401cc
 tests/networkxml2conftest.c                        |  1 +
c401cc
 .../nat-network-dns-forward-plain.xml              |  9 +++++++
c401cc
 tests/networkxml2xmlin/nat-network-dns-hosts.xml   |  2 +-
c401cc
 .../nat-network-dns-forward-plain.xml              | 11 +++++++++
c401cc
 tests/networkxml2xmltest.c                         |  1 +
c401cc
 13 files changed, 114 insertions(+), 14 deletions(-)
c401cc
 create mode 100644 tests/networkxml2confdata/nat-network-dns-forward-plain.conf
c401cc
 create mode 100644 tests/networkxml2confdata/nat-network-dns-forward-plain.xml
c401cc
 create mode 100644 tests/networkxml2xmlin/nat-network-dns-forward-plain.xml
c401cc
 create mode 100644 tests/networkxml2xmlout/nat-network-dns-forward-plain.xml
c401cc
c401cc
diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
c401cc
index eb7c4c7..e1482db 100644
c401cc
--- a/docs/formatnetwork.html.in
c401cc
+++ b/docs/formatnetwork.html.in
c401cc
@@ -663,10 +663,27 @@
c401cc
         with the idiosyncrasies of the platform where libvirt is
c401cc
         running. Since 0.8.8
c401cc
       
c401cc
-      
dns
c401cc
-        The dns element of a network contains configuration information for the
c401cc
-        virtual network's DNS server. Since 0.9.3
c401cc
-        Currently supported elements are:
c401cc
+      
dns
c401cc
+      
The dns element of a network contains configuration
c401cc
+        information for the virtual network's DNS
c401cc
+        server Since 0.9.3.
c401cc
+
c401cc
+        

c401cc
+          The dns element
c401cc
+          can have an optional forwardPlainNames
c401cc
+          attribute Since 1.1.2.
c401cc
+          If forwardPlainNames is "no", then DNS resolution
c401cc
+          requests for names that are not qualified with a domain
c401cc
+          (i.e. names with no "." character) will not be forwarded to
c401cc
+          the host's upstream DNS server - they will only be resolved if
c401cc
+          they are known locally within the virtual network's own DNS
c401cc
+          server. If forwardPlainNames is "yes",
c401cc
+          unqualified names will be forwarded to the upstream DNS
c401cc
+          server if they can't be resolved by the virtual network's own
c401cc
+          DNS server.
c401cc
+        

c401cc
+
c401cc
+        Currently supported sub-elements of <dns> are:
c401cc
         
c401cc
           
txt
c401cc
           
A dns element can have 0 or more txt elements.
c401cc
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
c401cc
index 11adbac..d7edb09 100644
c401cc
--- a/docs/schemas/network.rng
c401cc
+++ b/docs/schemas/network.rng
c401cc
@@ -234,6 +234,14 @@
c401cc
              and other features in the <dns> element -->
c401cc
         <optional>
c401cc
             <element name="dns">
c401cc
+              <optional>
c401cc
+                <attribute name="forwardPlainNames">
c401cc
+                  <choice>
c401cc
+                    <value>yes</value>
c401cc
+                    <value>no</value>
c401cc
+                  </choice>
c401cc
+                </attribute>
c401cc
+              </optional>
c401cc
               <zeroOrMore>
c401cc
                 <element name="txt">
c401cc
                   <attribute name="name"><ref name="dnsName"/></attribute>
c401cc
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
c401cc
index 8846675..d611d71 100644
c401cc
--- a/src/conf/network_conf.c
c401cc
+++ b/src/conf/network_conf.c
c401cc
@@ -1037,6 +1037,7 @@ virNetworkDNSDefParseXML(const char *networkName,
c401cc
     xmlNodePtr *hostNodes = NULL;
c401cc
     xmlNodePtr *srvNodes = NULL;
c401cc
     xmlNodePtr *txtNodes = NULL;
c401cc
+    char *forwardPlainNames = NULL;
c401cc
     int nhosts, nsrvs, ntxts;
c401cc
     size_t i;
c401cc
     int ret = -1;
c401cc
@@ -1044,6 +1045,19 @@ virNetworkDNSDefParseXML(const char *networkName,
c401cc
 
c401cc
     ctxt->node = node;
c401cc
 
c401cc
+    forwardPlainNames = virXPathString("string(./@forwardPlainNames)", ctxt);
c401cc
+    if (forwardPlainNames) {
c401cc
+        if (STREQ(forwardPlainNames, "yes")) {
c401cc
+            def->forwardPlainNames = true;
c401cc
+        } else if (STRNEQ(forwardPlainNames, "no")) {
c401cc
+            virReportError(VIR_ERR_XML_ERROR,
c401cc
+                           _("Invalid dns forwardPlainNames setting '%s' "
c401cc
+                             "in network '%s'"),
c401cc
+                           forwardPlainNames, networkName);
c401cc
+            goto cleanup;
c401cc
+        }
c401cc
+    }
c401cc
+
c401cc
     nhosts = virXPathNodeSet("./host", ctxt, &hostNodes);
c401cc
     if (nhosts < 0) {
c401cc
         virReportError(VIR_ERR_XML_ERROR,
c401cc
@@ -1106,6 +1120,7 @@ virNetworkDNSDefParseXML(const char *networkName,
c401cc
 
c401cc
     ret = 0;
c401cc
 cleanup:
c401cc
+    VIR_FREE(forwardPlainNames);
c401cc
     VIR_FREE(hostNodes);
c401cc
     VIR_FREE(srvNodes);
c401cc
     VIR_FREE(txtNodes);
c401cc
@@ -2252,10 +2267,19 @@ virNetworkDNSDefFormat(virBufferPtr buf,
c401cc
     int result = 0;
c401cc
     size_t i, j;
c401cc
 
c401cc
-    if (!(def->nhosts || def->nsrvs || def->ntxts))
c401cc
+    if (!(def->forwardPlainNames || def->nhosts || def->nsrvs || def->ntxts))
c401cc
         goto out;
c401cc
 
c401cc
-    virBufferAddLit(buf, "<dns>\n");
c401cc
+    virBufferAddLit(buf, "
c401cc
+    if (def->forwardPlainNames) {
c401cc
+        virBufferAddLit(buf, " forwardPlainNames='yes'");
c401cc
+        if (!(def->nhosts || def->nsrvs || def->ntxts)) {
c401cc
+            virBufferAddLit(buf, "/>\n");
c401cc
+            goto out;
c401cc
+        }
c401cc
+    }
c401cc
+
c401cc
+    virBufferAddLit(buf, ">\n");
c401cc
     virBufferAdjustIndent(buf, 2);
c401cc
 
c401cc
     for (i = 0; i < def->ntxts; i++) {
c401cc
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
c401cc
index a1d3282..920e899 100644
c401cc
--- a/src/conf/network_conf.h
c401cc
+++ b/src/conf/network_conf.h
c401cc
@@ -115,6 +115,7 @@ struct _virNetworkDNSHostDef {
c401cc
 typedef struct _virNetworkDNSDef virNetworkDNSDef;
c401cc
 typedef virNetworkDNSDef *virNetworkDNSDefPtr;
c401cc
 struct _virNetworkDNSDef {
c401cc
+    bool forwardPlainNames;
c401cc
     size_t ntxts;
c401cc
     virNetworkDNSTxtDefPtr txts;
c401cc
     size_t nhosts;
c401cc
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
c401cc
index 54d388b..57c88ae 100644
c401cc
--- a/src/network/bridge_driver.c
c401cc
+++ b/src/network/bridge_driver.c
c401cc
@@ -695,20 +695,28 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
c401cc
                       "##    virsh net-edit %s\n"
c401cc
                       "## or other application using the libvirt API.\n"
c401cc
                       "##\n## dnsmasq conf file created by libvirt\n"
c401cc
-                      "strict-order\n"
c401cc
-                      "domain-needed\n",
c401cc
+                      "strict-order\n",
c401cc
                       network->def->name);
c401cc
 
c401cc
+    if (!network->def->dns.forwardPlainNames)
c401cc
+        virBufferAddLit(&configbuf, "domain-needed\n");
c401cc
+
c401cc
     if (network->def->domain) {
c401cc
         virBufferAsprintf(&configbuf,
c401cc
                           "domain=%s\n"
c401cc
                           "expand-hosts\n",
c401cc
                           network->def->domain);
c401cc
     }
c401cc
-    /* need to specify local even if no domain specified */
c401cc
-    virBufferAsprintf(&configbuf,
c401cc
-                      "local=/%s/\n",
c401cc
-                      network->def->domain ? network->def->domain : "");
c401cc
+
c401cc
+    if (network->def->domain || !network->def->dns.forwardPlainNames) {
c401cc
+        /* need to specify local even if no domain specified, unless
c401cc
+         * the config says we should forward "plain" names (i.e. not
c401cc
+         * fully qualified, no '.' characters)
c401cc
+         */
c401cc
+        virBufferAsprintf(&configbuf,
c401cc
+                          "local=/%s/\n",
c401cc
+                          network->def->domain ? network->def->domain : "");
c401cc
+    }
c401cc
 
c401cc
     if (pidfile)
c401cc
         virBufferAsprintf(&configbuf, "pid-file=%s\n", pidfile);
c401cc
diff --git a/tests/networkxml2confdata/nat-network-dns-forward-plain.conf b/tests/networkxml2confdata/nat-network-dns-forward-plain.conf
c401cc
new file mode 100644
c401cc
index 0000000..9a000b8
c401cc
--- /dev/null
c401cc
+++ b/tests/networkxml2confdata/nat-network-dns-forward-plain.conf
c401cc
@@ -0,0 +1,11 @@
c401cc
+##WARNING:  THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
c401cc
+##OVERWRITTEN AND LOST.  Changes to this configuration should be made using:
c401cc
+##    virsh net-edit default
c401cc
+## or other application using the libvirt API.
c401cc
+##
c401cc
+## dnsmasq conf file created by libvirt
c401cc
+strict-order
c401cc
+except-interface=lo
c401cc
+bind-dynamic
c401cc
+interface=virbr0
c401cc
+addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts
c401cc
diff --git a/tests/networkxml2confdata/nat-network-dns-forward-plain.xml b/tests/networkxml2confdata/nat-network-dns-forward-plain.xml
c401cc
new file mode 100644
c401cc
index 0000000..10bacb5
c401cc
--- /dev/null
c401cc
+++ b/tests/networkxml2confdata/nat-network-dns-forward-plain.xml
c401cc
@@ -0,0 +1,9 @@
c401cc
+<network>
c401cc
+  <name>default</name>
c401cc
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9c</uuid>
c401cc
+  <forward dev='eth0' mode='nat'/>
c401cc
+  <bridge name='virbr0' stp='on' delay='0' />
c401cc
+  <dns forwardPlainNames='yes'/>
c401cc
+  <ip address='192.168.122.1' netmask='255.255.255.0'>
c401cc
+  </ip>
c401cc
+</network>
c401cc
diff --git a/tests/networkxml2confdata/nat-network-dns-hosts.xml b/tests/networkxml2confdata/nat-network-dns-hosts.xml
c401cc
index 2180a5d..351df4f 100644
c401cc
--- a/tests/networkxml2confdata/nat-network-dns-hosts.xml
c401cc
+++ b/tests/networkxml2confdata/nat-network-dns-hosts.xml
c401cc
@@ -4,7 +4,7 @@
c401cc
   <forward dev='eth0' mode='nat'/>
c401cc
   <bridge name='virbr0' stp='on' delay='0' />
c401cc
   <domain name="example.com"/>
c401cc
-  <dns>
c401cc
+  <dns forwardPlainNames='no'>
c401cc
     <host ip='192.168.122.1'>
c401cc
       <hostname>host</hostname>
c401cc
       <hostname>gateway</hostname>
c401cc
diff --git a/tests/networkxml2conftest.c b/tests/networkxml2conftest.c
c401cc
index b234b30..5825af3 100644
c401cc
--- a/tests/networkxml2conftest.c
c401cc
+++ b/tests/networkxml2conftest.c
c401cc
@@ -144,6 +144,7 @@ mymain(void)
c401cc
     DO_TEST("nat-network-dns-txt-record", full);
c401cc
     DO_TEST("nat-network-dns-srv-record", full);
c401cc
     DO_TEST("nat-network-dns-hosts", full);
c401cc
+    DO_TEST("nat-network-dns-forward-plain", full);
c401cc
     DO_TEST("dhcp6-network", dhcpv6);
c401cc
     DO_TEST("dhcp6-nat-network", dhcpv6);
c401cc
     DO_TEST("dhcp6host-routed-network", dhcpv6);
c401cc
diff --git a/tests/networkxml2xmlin/nat-network-dns-forward-plain.xml b/tests/networkxml2xmlin/nat-network-dns-forward-plain.xml
c401cc
new file mode 100644
c401cc
index 0000000..10bacb5
c401cc
--- /dev/null
c401cc
+++ b/tests/networkxml2xmlin/nat-network-dns-forward-plain.xml
c401cc
@@ -0,0 +1,9 @@
c401cc
+<network>
c401cc
+  <name>default</name>
c401cc
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9c</uuid>
c401cc
+  <forward dev='eth0' mode='nat'/>
c401cc
+  <bridge name='virbr0' stp='on' delay='0' />
c401cc
+  <dns forwardPlainNames='yes'/>
c401cc
+  <ip address='192.168.122.1' netmask='255.255.255.0'>
c401cc
+  </ip>
c401cc
+</network>
c401cc
diff --git a/tests/networkxml2xmlin/nat-network-dns-hosts.xml b/tests/networkxml2xmlin/nat-network-dns-hosts.xml
c401cc
index 9a83fed..954c9db 100644
c401cc
--- a/tests/networkxml2xmlin/nat-network-dns-hosts.xml
c401cc
+++ b/tests/networkxml2xmlin/nat-network-dns-hosts.xml
c401cc
@@ -3,7 +3,7 @@
c401cc
   <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9c</uuid>
c401cc
   <forward dev='eth0' mode='nat'/>
c401cc
   <bridge name='virbr0' stp='on' delay='0' />
c401cc
-  <dns>
c401cc
+  <dns forwardPlainNames='no'>
c401cc
     <host ip='192.168.122.1'>
c401cc
       <hostname>host</hostname>
c401cc
       <hostname>gateway</hostname>
c401cc
diff --git a/tests/networkxml2xmlout/nat-network-dns-forward-plain.xml b/tests/networkxml2xmlout/nat-network-dns-forward-plain.xml
c401cc
new file mode 100644
c401cc
index 0000000..3b50828
c401cc
--- /dev/null
c401cc
+++ b/tests/networkxml2xmlout/nat-network-dns-forward-plain.xml
c401cc
@@ -0,0 +1,11 @@
c401cc
+<network>
c401cc
+  <name>default</name>
c401cc
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9c</uuid>
c401cc
+  <forward dev='eth0' mode='nat'>
c401cc
+    <interface dev='eth0'/>
c401cc
+  </forward>
c401cc
+  <bridge name='virbr0' stp='on' delay='0' />
c401cc
+  <dns forwardPlainNames='yes'/>
c401cc
+  <ip address='192.168.122.1' netmask='255.255.255.0'>
c401cc
+  </ip>
c401cc
+</network>
c401cc
diff --git a/tests/networkxml2xmltest.c b/tests/networkxml2xmltest.c
c401cc
index b48eed2..ba21818 100644
c401cc
--- a/tests/networkxml2xmltest.c
c401cc
+++ b/tests/networkxml2xmltest.c
c401cc
@@ -105,6 +105,7 @@ mymain(void)
c401cc
     DO_TEST("nat-network-dns-txt-record");
c401cc
     DO_TEST("nat-network-dns-hosts");
c401cc
     DO_TEST("nat-network-forward-nat-address");
c401cc
+    DO_TEST("nat-network-dns-forward-plain");
c401cc
     DO_TEST("8021Qbh-net");
c401cc
     DO_TEST("direct-net");
c401cc
     DO_TEST("host-bridge-net");
c401cc
-- 
c401cc
1.8.5.3
c401cc