[libvirt] [PATCH 2/2] Network: Add support for DNS hosts definition

Michal Novotny minovotn at redhat.com
Wed Mar 30 12:57:12 UTC 2011


Hi,
this is the patch to add support for defining the hosts into the
DNS service on the virtual network. You can define the host IP
address and the aliases for the IP address.

The DNS hosts record can be defined in the XML file as the host
element in this form:

    <host ip='192.168.122.1'>
      <hostname>example1</hostname>
      <hostname>example2</hostname>
    </host>

This definition defines aliases example1 and example2 to the IP
address of 192.168.122.1.

Michal

Signed-off-by: Michal Novotny <minovotn at redhat.com>
---
 docs/formatnetwork.html.in                        |   11 +++
 docs/schemas/network.rng                          |    8 ++
 src/conf/network_conf.c                           |   97 +++++++++++++++++++--
 src/conf/network_conf.h                           |   10 ++
 src/network/bridge_driver.c                       |   66 ++++++++++++++
 tests/networkxml2xmlin/nat-network-dns-hosts.xml  |   27 ++++++
 tests/networkxml2xmlout/nat-network-dns-hosts.xml |   27 ++++++
 tests/networkxml2xmltest.c                        |    1 +
 8 files changed, 240 insertions(+), 7 deletions(-)
 create mode 100644 tests/networkxml2xmlin/nat-network-dns-hosts.xml
 create mode 100644 tests/networkxml2xmlout/nat-network-dns-hosts.xml

diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
index 2d76d3d..9baf2ee 100644
--- a/docs/formatnetwork.html.in
+++ b/docs/formatnetwork.html.in
@@ -125,6 +125,10 @@
           </dhcp>
           <dns>
             <txt-record name="example name" value="example value" />
+            <host ip='192.168.122.1'>
+              <hostname>gateway</hostname>
+              <hostname>host</hostname>
+            </host>
           </dns;>
         </ip>
       </network></pre>
@@ -224,6 +228,13 @@
         by commas.
         <span class="since">Since 0.9.0</span>
       </dd>
+      <dt><code>host</code></dt>
+      <dd>The <code>host</code> element is the definition of DNS hosts to be passed
+        to the DNS service. The IP address is identified by the <code>ip</code> attribute
+        and the names for the IP addresses are identified in the <code>hostname</code>
+        subelements of the <code>host</code> element.
+        <span class="since">Since 0.9.0</span>
+      </dd>
     </dl>
 
     <h2><a name="examples">Example configuration</a></h2>
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
index e27dace..d09801f 100644
--- a/docs/schemas/network.rng
+++ b/docs/schemas/network.rng
@@ -146,6 +146,14 @@
                     <attribute name="value"><text/></attribute>
                   </element>
                 </zeroOrMore>
+                <zeroOrMore>
+                  <element name="host">
+                    <attribute name="ip"><ref name="ipv4-addr"/></attribute>
+                    <zeroOrMore>
+                      <element name="hostname"><text/></element>
+                    </zeroOrMore>
+                  </element>
+                </zeroOrMore>
               </element>
             </optional>
           </element>
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 145ae20..a0d223e 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -435,6 +435,61 @@ virNetworkDHCPRangeDefParseXML(const char *networkName,
 }
 
 static int
+virNetworkDNSHostsDefParseXML(virNetworkIpDefPtr def,
+                              xmlNodePtr node,
+                              char *ip)
+{
+    xmlNodePtr cur;
+    int result = -1;
+    int i = 0;
+
+    if (def->dns->hosts == NULL) {
+        if (VIR_ALLOC(def->dns->hosts) < 0)
+            goto oom_error;
+        def->dns->nhosts = 0;
+    }
+
+    if (VIR_REALLOC_N(def->dns->hosts, def->dns->nhosts + 1) < 0)
+        goto oom_error;
+
+    i = def->dns->nhosts;
+    if (VIR_ALLOC(def->dns->hosts[i]) < 0)
+        goto oom_error;
+
+    def->dns->hosts[i]->ip = strdup(ip);
+    def->dns->nhosts++;
+
+    def->dns->hosts[i]->nhostnames = 0;
+    cur = node->children;
+    while (cur != NULL) {
+        if (cur->type == XML_ELEMENT_NODE &&
+            xmlStrEqual(cur->name, BAD_CAST "hostname")) {
+              if (cur->children != NULL) {
+                  char *hostname;
+
+                  hostname = strdup((char *)cur->children->content);
+
+                  if (VIR_REALLOC_N(def->dns->hosts[i]->hostnames, def->dns->hosts[i]->nhostnames + 1) < 0)
+                      goto oom_error;
+
+                  def->dns->hosts[i]->hostnames[def->dns->hosts[i]->nhostnames] = strdup(hostname);
+                  def->dns->hosts[i]->nhostnames++;
+
+                  VIR_FREE(hostname);
+              }
+        }
+
+        cur = cur->next;
+    }
+
+    return 0;
+
+oom_error:
+    virReportOOMError();
+    return result;
+}
+
+static int
 virNetworkDNSDefParseXML(virNetworkIpDefPtr def,
                          xmlNodePtr node)
 {
@@ -470,6 +525,17 @@ virNetworkDNSDefParseXML(virNetworkIpDefPtr def,
 
             VIR_FREE(name);
             VIR_FREE(value);
+        } else if (cur->type == XML_ELEMENT_NODE &&
+            xmlStrEqual(cur->name, BAD_CAST "host")) {
+            char *ip;
+
+            if (!(ip = virXMLPropString(cur, "ip"))) {
+                cur = cur->next;
+                continue;
+            }
+            result = virNetworkDNSHostsDefParseXML(def, cur, ip);
+            if (result)
+                goto error;
         }
 
         cur = cur->next;
@@ -479,6 +545,7 @@ virNetworkDNSDefParseXML(virNetworkIpDefPtr def,
 
 oom_error:
     virReportOOMError();
+error:
     return result;
 }
 
@@ -882,15 +949,31 @@ virNetworkIpDefFormat(virBufferPtr buf,
 
         virBufferAddLit(buf, "    </dhcp>\n");
     }
-    if ((def->dns != NULL) && (def->dns->ntxtrecords)) {
-        int ii;
-
+    if (def->dns != NULL) {
         virBufferAddLit(buf, "    <dns>\n");
-        for (ii = 0 ; ii < def->dns->ntxtrecords ; ii++) {
-            virBufferVSprintf(buf, "      <txt-record name='%s' value='%s' />\n",
-                              def->dns->txtrecords[ii].name,
-                              def->dns->txtrecords[ii].value);
+
+        if (def->dns->ntxtrecords) {
+            int ii;
+
+            for (ii = 0 ; ii < def->dns->ntxtrecords; ii++) {
+                virBufferVSprintf(buf, "      <txt-record name='%s' value='%s' />\n",
+                                  def->dns->txtrecords[ii].name,
+                                  def->dns->txtrecords[ii].value);
+            }
+        }
+        if (def->dns->nhosts) {
+            int ii, j;
+
+            for (ii = 0 ; ii < def->dns->nhosts; ii++) {
+                virBufferVSprintf(buf, "      <host ip='%s'>\n", def->dns->hosts[ii]->ip);
+                for (j = 0 ; j < def->dns->hosts[ii]->nhostnames; j++) {
+                    virBufferVSprintf(buf, "        <hostname>%s</hostname>\n",
+                                      def->dns->hosts[ii]->hostnames[j]);
+                }
+                virBufferVSprintf(buf, "      </host>\n");
+            }
         }
+
         virBufferAddLit(buf, "    </dns>\n");
     }
 
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index 5f47595..f3f1381 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -64,9 +64,19 @@ struct _virNetworkDNSTxtRecordsDef {
     char *value;
 };
 
+struct virNetworkDNSHostsDef {
+    char *ip;
+    unsigned int nhostnames;
+    char **hostnames;
+} virNetworkDNSHostsDef;
+
+typedef struct virNetworkDNSHostsDef *virNetworkDNSHostsDefPtr;
+
 struct virNetworkDNSDef {
     unsigned int ntxtrecords;
+    unsigned int nhosts;
     virNetworkDNSTxtRecordsDefPtr txtrecords;
+    virNetworkDNSHostsDefPtr *hosts;
 } virNetworkDNSDef;
 
 typedef struct virNetworkDNSDef *virNetworkDNSDefPtr;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 5d901ff..392ef23 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -60,6 +60,7 @@
 #include "dnsmasq.h"
 #include "util/network.h"
 #include "configmake.h"
+#include "files.h"
 
 #define NETWORK_PID_DIR LOCALSTATEDIR "/run/libvirt/network"
 #define NETWORK_STATE_DIR LOCALSTATEDIR "/lib/libvirt/network"
@@ -456,6 +457,60 @@ replace_all(char *input, int chr1, int chr2)
 }
 
 static int
+networkDnsmasqGenHosts(const char *hostsFile,
+                       virNetworkDNSDefPtr def)
+{
+    char *contents = NULL;
+    int fd = -1, ret = -1;
+    size_t towrite;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    int i, ii;
+
+    if ((fd = open(hostsFile,
+                   O_WRONLY | O_CREAT | O_TRUNC,
+                   S_IRUSR | S_IWUSR )) < 0) {
+        virReportSystemError(errno,
+                             _("cannot create hosts config file '%s'"),
+                             hostsFile);
+        goto cleanup;
+    }
+
+    for (i = 0; i < def->nhosts; i++) {
+        virBufferVSprintf(&buf, "%s", def->hosts[i]->ip);
+        for (ii = 0; ii < def->hosts[i]->nhostnames; ii++)
+            virBufferVSprintf(&buf, "\t%s", def->hosts[i]->hostnames[ii]);
+        virBufferVSprintf(&buf, "\n");
+    }
+
+    contents = virBufferContentAndReset(&buf);
+    VIR_FREE(buf);
+
+    towrite = strlen(contents);
+    if (safewrite(fd, contents, towrite) < 0) {
+        virReportSystemError(errno,
+                             _("cannot write hosts config file '%s'"),
+                             hostsFile);
+        goto cleanup;
+    }
+
+    fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+    if (VIR_CLOSE(fd) < 0) {
+        virReportSystemError(errno,
+                             _("cannot save hosts config file '%s'"),
+                             hostsFile);
+        goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    VIR_FORCE_CLOSE(fd);
+
+    return ret;
+}
+
+static int
 networkBuildDnsmasqArgv(virNetworkObjPtr network,
                         virNetworkIpDefPtr ipdef,
                         const char *pidfile,
@@ -522,6 +577,17 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network,
             virCommandAddArgPair(cmd, "--txt-record", virBufferContentAndReset(&buf));
             VIR_FREE(buf);
         }
+
+        if (ipdef->dns->nhosts > 0) {
+            char hostsFile[1024] = { 0 };
+
+            snprintf(hostsFile, sizeof(hostsFile), "%s/%s.hosts",
+                              NETWORK_PID_DIR, network->def->name);
+
+            networkDnsmasqGenHosts(hostsFile, ipdef->dns);
+
+            virCommandAddArgPair(cmd, "--addn-hosts", hostsFile);
+        }
     }
 
     /*
diff --git a/tests/networkxml2xmlin/nat-network-dns-hosts.xml b/tests/networkxml2xmlin/nat-network-dns-hosts.xml
new file mode 100644
index 0000000..fe545cf
--- /dev/null
+++ b/tests/networkxml2xmlin/nat-network-dns-hosts.xml
@@ -0,0 +1,27 @@
+<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'>
+    <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>
+    <dns>
+      <host ip='192.168.122.1'>
+        <hostname>host</hostname>
+        <hostname>gateway</hostname>
+      </host>
+    </dns>
+  </ip>
+  <ip family='ipv4' address='192.168.123.1' netmask='255.255.255.0'>
+  </ip>
+  <ip family='ipv6' address='2001:db8:ac10:fe01::1' prefix='64'>
+  </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/networkxml2xmlout/nat-network-dns-hosts.xml b/tests/networkxml2xmlout/nat-network-dns-hosts.xml
new file mode 100644
index 0000000..fe545cf
--- /dev/null
+++ b/tests/networkxml2xmlout/nat-network-dns-hosts.xml
@@ -0,0 +1,27 @@
+<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'>
+    <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>
+    <dns>
+      <host ip='192.168.122.1'>
+        <hostname>host</hostname>
+        <hostname>gateway</hostname>
+      </host>
+    </dns>
+  </ip>
+  <ip family='ipv4' address='192.168.123.1' netmask='255.255.255.0'>
+  </ip>
+  <ip family='ipv6' address='2001:db8:ac10:fe01::1' prefix='64'>
+  </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/networkxml2xmltest.c b/tests/networkxml2xmltest.c
index beb00ef..f5c5715 100644
--- a/tests/networkxml2xmltest.c
+++ b/tests/networkxml2xmltest.c
@@ -91,6 +91,7 @@ mymain(int argc, char **argv)
     DO_TEST("netboot-network");
     DO_TEST("netboot-proxy-network");
     DO_TEST("nat-network-dns-txt-record");
+    DO_TEST("nat-network-dns-hosts");
 
     return (ret==0 ? EXIT_SUCCESS : EXIT_FAILURE);
 }
-- 
1.7.3.2




More information about the libvir-list mailing list