]> xenbits.xensource.com Git - libvirt.git/commitdiff
network: allow limiting a <forwarder> element to certain domains
authorLaine Stump <laine@laine.org>
Fri, 12 Aug 2016 02:28:27 +0000 (22:28 -0400)
committerLaine Stump <laine@laine.org>
Sat, 20 Aug 2016 01:34:51 +0000 (21:34 -0400)
For some unknown reason the original implementation of the <forwarder>
element only took advantage of part of the functionality in the
dnsmasq feature it exposes - it allowed specifying the ip address of a
DNS server which *all* DNS requests would be forwarded to, like this:

   <forwarder addr='192.168.123.25'/>

This is a frontend for dnsmasq's "server" option, which also allows
you to specify a domain that must be matched in order for a request to
be forwarded to a particular server. This patch adds support for
specifying the domain. For example:

   <forwarder domain='example.com' addr='192.168.1.1'/>
   <forwarder domain='www.example.com'/>
   <forwarder domain='travesty.org' addr='10.0.0.1'/>

would forward requests for bob.example.com, ftp.example.com and
joe.corp.example.com all to the DNS server at 192.168.1.1, but would
forward requests for travesty.org and www.travesty.org to
10.0.0.1. And due to the second line, requests for www.example.com,
and odd.www.example.com would be resolved by the libvirt network's own
DNS server (i.e. thery wouldn't be immediately forwarded) even though
they also match 'example.com' - the match is given to the entry with
the longest matching domain. DNS requests not matching any of the
entries would be resolved by the libvirt network's own DNS server.

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1331796

docs/formatnetwork.html.in
docs/schemas/network.rng
src/conf/network_conf.c
src/conf/network_conf.h
src/network/bridge_driver.c
tests/networkxml2confdata/nat-network-dns-forwarders.conf
tests/networkxml2confdata/nat-network-dns-forwarders.xml
tests/networkxml2xmlin/nat-network-dns-forwarders.xml
tests/networkxml2xmlout/nat-network-dns-forwarders.xml

index e103dd7857c8446d2b119ed057ad9b38ee0ec78a..13ca32de9765d3e887e0ab29434ca5b68fd0d936 100644 (file)
         &lt;dns&gt;
           &lt;txt name="example" value="example value" /&gt;
           &lt;forwarder addr="8.8.8.8"/&gt;
-          &lt;forwarder addr="8.8.4.4"/&gt;
+          &lt;forwarder domain='example.com' addr="8.8.4.4"/&gt;
+          &lt;forwarder domain='www.example.com'/&gt;
           &lt;srv service='name' protocol='tcp' domain='test-domain-name' target='.' port='1024' priority='10' weight='10'/&gt;
           &lt;host ip='192.168.122.2'&gt;
             &lt;hostname&gt;myhost&lt;/hostname&gt;
         Currently supported sub-elements of <code>&lt;dns&gt;</code> are:
         <dl>
           <dt><code>forwarder</code></dt>
-          <dd>A <code>dns</code> element can have 0 or
-            more <code>forwarder</code> elements.  Each forwarder
-            element defines an IP address to be used as forwarder in
-            DNS server configuration. The addr attribute is required
-            and defines the IP address of every
-            forwarder. <span class="since">Since 1.1.3</span>
+          <dd>The dns element can have 0 or
+            more <code>&lt;forwarder&gt;</code> elements.  Each
+            forwarder element defines an alternate DNS server to use
+            for some, or all, DNS requests sent to this network's DNS
+            server. There are two attributes - <code>domain</code>,
+            and <code>addr</code>; at least one of these must be
+            specified in any <code>&lt;forwarder&gt;</code>
+            element. If both <code>domain</code> and <code>addr</code>
+            are specified, then all requests that match the given
+            domain will be forwarded to the DNS server at addr. If
+            only <code>domain</code> is specified, then all matching
+            domains will be resolved locally (or via the host's
+            standard DNS forwarding if they can't be resolved
+            locally). If an <code>addr</code> is specified by itself,
+            then all DNS requests to the network's DNS server will be
+            forwarded to the DNS server at that address with no
+            exceptions. <code>addr</code> <span class="since">Since
+            1.1.3</span>, <code>domain</code> <span class="since">Since
+            2.2.0</span>.
           </dd>
           <dt><code>txt</code></dt>
           <dd>A <code>dns</code> element can have 0 or more <code>txt</code> elements.
index 12d4b345050e8cb968a8deec2a4a6255bf673aed..1a18e64b24f99548f43ef8d01a85c99463d92cae 100644 (file)
             <interleave>
               <zeroOrMore>
                 <element name="forwarder">
-                  <attribute name="addr"><ref name="ipAddr"/></attribute>
+                  <optional>
+                    <attribute name="addr"><ref name="ipAddr"/></attribute>
+                  </optional>
+                  <optional>
+                    <attribute name="domain"><ref name="dnsName"/></attribute>
+                  </optional>
+                  <empty/>
                 </element>
               </zeroOrMore>
               <zeroOrMore>
index d77b8379fe067c582ac9b4326e53e7bd68c3649e..aa397768c9c43441d425db2ad844b288ca57c126 100644 (file)
@@ -349,12 +349,20 @@ virNetworkDNSSrvDefClear(virNetworkDNSSrvDefPtr def)
     VIR_FREE(def->target);
 }
 
+
+static void
+virNetworkDNSForwarderClear(virNetworkDNSForwarderPtr def)
+{
+    VIR_FREE(def->domain);
+}
+
+
 static void
 virNetworkDNSDefClear(virNetworkDNSDefPtr def)
 {
     if (def->forwarders) {
         while (def->nfwds)
-            VIR_FREE(def->forwarders[--def->nfwds]);
+            virNetworkDNSForwarderClear(&def->forwarders[--def->nfwds]);
         VIR_FREE(def->forwarders);
     }
     if (def->txts) {
@@ -1379,14 +1387,25 @@ virNetworkDNSDefParseXML(const char *networkName,
             goto cleanup;
 
         for (i = 0; i < nfwds; i++) {
-            def->forwarders[i] = virXMLPropString(fwdNodes[i], "addr");
-            if (virSocketAddrParse(NULL, def->forwarders[i], AF_UNSPEC) < 0) {
+            char *addr = virXMLPropString(fwdNodes[i], "addr");
+
+            if (addr && virSocketAddrParse(&def->forwarders[i].addr,
+                                           addr, AF_UNSPEC) < 0) {
                 virReportError(VIR_ERR_XML_ERROR,
-                           _("Invalid forwarder IP address '%s' "
-                             "in network '%s'"),
-                           def->forwarders[i], networkName);
+                               _("Invalid forwarder IP address '%s' "
+                                 "in network '%s'"),
+                               addr, networkName);
+                VIR_FREE(addr);
+                goto cleanup;
+            }
+            def->forwarders[i].domain = virXMLPropString(fwdNodes[i], "domain");
+            if (!(addr || def->forwarders[i].domain)) {
+                virReportError(VIR_ERR_XML_ERROR, "%s",
+                               _("Invalid forwarder element, must contain "
+                                 "at least one of addr or domain"));
                 goto cleanup;
             }
+            VIR_FREE(addr);
             def->nfwds++;
         }
     }
@@ -2554,8 +2573,22 @@ virNetworkDNSDefFormat(virBufferPtr buf,
     virBufferAdjustIndent(buf, 2);
 
     for (i = 0; i < def->nfwds; i++) {
-        virBufferAsprintf(buf, "<forwarder addr='%s'/>\n",
-                          def->forwarders[i]);
+
+        virBufferAddLit(buf, "<forwarder");
+        if (def->forwarders[i].domain) {
+            virBufferEscapeString(buf, " domain='%s'",
+                                  def->forwarders[i].domain);
+        }
+        if (VIR_SOCKET_ADDR_VALID(&def->forwarders[i].addr)) {
+        char *addr = virSocketAddrFormat(&def->forwarders[i].addr);
+
+        if (!addr)
+            return -1;
+
+        virBufferAsprintf(buf, " addr='%s'", addr);
+        VIR_FREE(addr);
+        }
+        virBufferAddLit(buf, "/>\n");
     }
 
     for (i = 0; i < def->ntxts; i++) {
index 9ebd4a73ebdd68e880f024cee65110707dd23e58..3b227db6f3ffd9c0f30f92129cb4edcc8285a333 100644 (file)
@@ -125,6 +125,12 @@ struct _virNetworkDNSHostDef {
     char **names;
 };
 
+
+typedef struct _virNetworkDNSForwarder {
+    virSocketAddr addr;
+    char *domain;
+} virNetworkDNSForwarder, *virNetworkDNSForwarderPtr;
+
 typedef struct _virNetworkDNSDef virNetworkDNSDef;
 typedef virNetworkDNSDef *virNetworkDNSDefPtr;
 struct _virNetworkDNSDef {
@@ -137,7 +143,7 @@ struct _virNetworkDNSDef {
     size_t nsrvs;
     virNetworkDNSSrvDefPtr srvs;
     size_t nfwds;
-    char **forwarders;
+    virNetworkDNSForwarderPtr forwarders;
 };
 
 typedef struct _virNetworkIPDef virNetworkIPDef;
index 49c0a2fa76ed3c879a15944251fd71c3135e14f7..74f75d015f79c4c73caa92808315773b33b010f3 100644 (file)
@@ -958,8 +958,21 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
     if (wantDNS && network->def->dns.forwarders) {
         virBufferAddLit(&configbuf, "no-resolv\n");
         for (i = 0; i < network->def->dns.nfwds; i++) {
-            virBufferAsprintf(&configbuf, "server=%s\n",
-                              network->def->dns.forwarders[i]);
+            virNetworkDNSForwarderPtr fwd = &network->def->dns.forwarders[i];
+
+            virBufferAddLit(&configbuf, "server=");
+            if (fwd->domain)
+                virBufferAsprintf(&configbuf, "/%s/", fwd->domain);
+            if (VIR_SOCKET_ADDR_VALID(&fwd->addr)) {
+                char *addr = virSocketAddrFormat(&fwd->addr);
+
+                if (!addr)
+                    goto cleanup;
+                virBufferAsprintf(&configbuf, "%s\n", addr);
+            } else {
+                /* "don't forward requests for this domain" */
+                virBufferAddLit(&configbuf, "#\n");
+            }
         }
     }
 
index 8bf3b9c360080e2ea323270bef6f0e60d80f0f1b..0bd76bf60c9701a52a4c8502fd79ccb74af2fa7c 100644 (file)
@@ -8,6 +8,8 @@ strict-order
 no-resolv
 server=8.8.8.8
 server=8.8.4.4
+server=/example.com/192.168.1.1
+server=/www.example.com/#
 except-interface=lo
 bind-dynamic
 interface=virbr0
index 8fab78ea3a3f4ee3360e45cecd734bfd17626230..5d4f3fa6977e6660672e1d076acb3a8690509eb7 100644 (file)
@@ -6,6 +6,8 @@
   <dns>
     <forwarder addr='8.8.8.8'/>
     <forwarder addr='8.8.4.4'/>
+    <forwarder domain='example.com' addr='192.168.1.1'/>
+    <forwarder domain='www.example.com'/>
   </dns>
   <ip address='192.168.122.1' netmask='255.255.255.0'>
   </ip>
index 4d7310d1c6dff59c8aab7feae51b7e9226437909..426dd45cd9a14cc74f1e3f92f8aefea0940693a7 100644 (file)
@@ -4,8 +4,10 @@
   <forward dev='eth0' mode='nat'/>
   <bridge name='virbr0' stp='on' delay='0' />
   <dns>
-    <forwarder addr='8.8.8.8' />
-    <forwarder addr='8.8.4.4' />
+    <forwarder addr='8.8.8.8'/>
+    <forwarder addr='8.8.4.4'/>
+    <forwarder domain='example.com' addr='192.168.1.1'/>
+    <forwarder domain='www.example.com'/>
   </dns>
   <ip address='192.168.122.1' netmask='255.255.255.0'>
   </ip>
index 930a42abc0e5d18599614007a758d28a2f41e20c..c05ad5514de611a6751fefabcf7f26c2ab7429d3 100644 (file)
@@ -8,6 +8,8 @@
   <dns>
     <forwarder addr='8.8.8.8'/>
     <forwarder addr='8.8.4.4'/>
+    <forwarder domain='example.com' addr='192.168.1.1'/>
+    <forwarder domain='www.example.com'/>
   </dns>
   <ip address='192.168.122.1' netmask='255.255.255.0'>
   </ip>