From 5dd986dbd7ff0bdae0b572bafde16b4b94237ff8 Mon Sep 17 00:00:00 2001 From: Michal Novotny Date: Fri, 24 Jun 2011 12:04:36 +0200 Subject: [PATCH] Add TXT record support for virtual DNS service This commit introduces the element and record for the virtual DNS network. The DNS TXT record can be defined using following syntax in the network XML file: Also, the Relax-NG scheme has been altered to allow the texts without spaces only for the name element and some nitpicks about memory free'ing have been fixed by Laine so therefore I'm adding Laine to the SOB clause ;-) Signed-off-by: Michal Novotny Signed-off-by: Laine Stump --- docs/formatnetwork.html.in | 23 +++- docs/schemas/network.rng | 20 ++++ src/conf/network_conf.c | 112 ++++++++++++++++++ src/conf/network_conf.h | 16 +++ src/network/bridge_driver.c | 18 +++ .../nat-network-dns-txt-record.xml | 24 ++++ .../nat-network-dns-txt-record.xml | 24 ++++ tests/networkxml2xmltest.c | 1 + 8 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 tests/networkxml2xmlin/nat-network-dns-txt-record.xml create mode 100644 tests/networkxml2xmlout/nat-network-dns-txt-record.xml diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in index 589aaff20e..4a5cb0347b 100644 --- a/docs/formatnetwork.html.in +++ b/docs/formatnetwork.html.in @@ -114,6 +114,9 @@
         ...
         <mac address='00:16:3E:5D:C7:9E'/>
+        <dns>
+          <txt name="example" value="example value" />
+        </dns>
         <ip address="192.168.122.1" netmask="255.255.255.0">
           <dhcp>
             <range start="192.168.122.100" end="192.168.122.254" />
@@ -166,7 +169,25 @@
         supported for IPv6 addresses, can only be specified on a single IPv4 address
         per network.
         Since 0.7.1
-      
dhcp
Also within the ip element there is an +
+ +
dns
+ The dns element of a network contains configuration information for the + virtual network's DNS server. Since 0.9.3 + Currently supported elements are: +
+
txt
+
A dns element can have 0 or more txt elements. + Each txt element defines a DNS TXT record and has two attributes, both + required: a name that can be queried via dns, and a value that will be + returned when that name is queried. names cannot contain embedded spaces + or commas. value is a single string that can contain multiple values + separated by commas. Since 0.9.3 +
+
+
+
dhcp
+
Also within the ip element there is an optional dhcp element. The presence of this element enables DHCP services on the virtual network. It will further contain one or more range elements. The diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng index 6d01b06082..c42382e4db 100644 --- a/docs/schemas/network.rng +++ b/docs/schemas/network.rng @@ -87,6 +87,19 @@ + + + + + + + + + + + + + + + ([a-zA-Z\-]+) + + + diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index e4765ea48c..d8f1e25c2f 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -104,6 +104,20 @@ static void virNetworkIpDefClear(virNetworkIpDefPtr def) VIR_FREE(def->bootfile); } +static void virNetworkDNSDefFree(virNetworkDNSDefPtr def) +{ + if (def) { + if (def->txtrecords) { + while (def->ntxtrecords--) { + VIR_FREE(def->txtrecords[def->ntxtrecords].name); + VIR_FREE(def->txtrecords[def->ntxtrecords].value); + } + VIR_FREE(def->txtrecords); + } + VIR_FREE(def); + } +} + void virNetworkDefFree(virNetworkDefPtr def) { int ii; @@ -121,6 +135,8 @@ void virNetworkDefFree(virNetworkDefPtr def) } VIR_FREE(def->ips); + virNetworkDNSDefFree(def->dns); + VIR_FREE(def); } @@ -434,6 +450,69 @@ virNetworkDHCPRangeDefParseXML(const char *networkName, return 0; } +static int +virNetworkDNSDefParseXML(virNetworkDNSDefPtr *dnsdef, + xmlNodePtr node) +{ + xmlNodePtr cur; + int ret = -1; + char *name = NULL; + char *value = NULL; + virNetworkDNSDefPtr def = NULL; + + if (VIR_ALLOC(def) < 0) { + virReportOOMError(); + goto error; + } + + cur = node->children; + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE && + xmlStrEqual(cur->name, BAD_CAST "txt")) { + if (!(name = virXMLPropString(cur, "name"))) { + virNetworkReportError(VIR_ERR_XML_DETAIL, + "%s", _("Missing required name attribute in dns txt record")); + goto error; + } + if (!(value = virXMLPropString(cur, "value"))) { + virNetworkReportError(VIR_ERR_XML_DETAIL, + _("Missing required value attribute in dns txt record '%s'"), name); + goto error; + } + + if (strchr(name, ' ') != NULL) { + virNetworkReportError(VIR_ERR_XML_DETAIL, + _("spaces are not allowed in DNS TXT record names (name is '%s')"), name); + goto error; + } + + if (VIR_REALLOC_N(def->txtrecords, def->ntxtrecords + 1) < 0) { + virReportOOMError(); + goto error; + } + + def->txtrecords[def->ntxtrecords].name = name; + def->txtrecords[def->ntxtrecords].value = value; + def->ntxtrecords++; + name = NULL; + value = NULL; + } + + cur = cur->next; + } + + ret = 0; +error: + if (ret < 0) { + VIR_FREE(name); + VIR_FREE(value); + virNetworkDNSDefFree(def); + } else { + *dnsdef = def; + } + return ret; +} + static int virNetworkIPParseXML(const char *networkName, virNetworkIpDefPtr def, @@ -584,6 +663,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) virNetworkDefPtr def; char *tmp; xmlNodePtr *ipNodes = NULL; + xmlNodePtr dnsNode = NULL; int nIps; if (VIR_ALLOC(def) < 0) { @@ -641,6 +721,12 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) def->mac_specified = true; } + dnsNode = virXPathNode("./dns", ctxt); + if (dnsNode != NULL) { + if (virNetworkDNSDefParseXML(&def->dns, dnsNode) < 0) + goto error; + } + nIps = virXPathNodeSet("./ip", ctxt, &ipNodes); if (nIps < 0) goto error; @@ -750,6 +836,29 @@ cleanup: return def; } +static int +virNetworkDNSDefFormat(virBufferPtr buf, + virNetworkDNSDefPtr def) +{ + int result = 0; + int i; + + if (def == NULL) + goto out; + + virBufferAddLit(buf, " \n"); + + for (i = 0 ; i < def->ntxtrecords ; i++) { + virBufferAsprintf(buf, " \n", + def->txtrecords[i].name, + def->txtrecords[i].value); + } + + virBufferAddLit(buf, " \n"); +out: + return result; +} + static int virNetworkIpDefFormat(virBufferPtr buf, const virNetworkIpDefPtr def) @@ -881,6 +990,9 @@ char *virNetworkDefFormat(const virNetworkDefPtr def) if (def->domain) virBufferAsprintf(&buf, " \n", def->domain); + if (virNetworkDNSDefFormat(&buf, def->dns) < 0) + goto error; + for (ii = 0; ii < def->nips; ii++) { if (virNetworkIpDefFormat(&buf, &def->ips[ii]) < 0) goto error; diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h index 281124bff6..d0dac02196 100644 --- a/src/conf/network_conf.h +++ b/src/conf/network_conf.h @@ -57,6 +57,20 @@ struct _virNetworkDHCPHostDef { virSocketAddr ip; }; +typedef struct _virNetworkDNSTxtRecordsDef virNetworkDNSTxtRecordsDef; +typedef virNetworkDNSTxtRecordsDef *virNetworkDNSTxtRecordsDefPtr; +struct _virNetworkDNSTxtRecordsDef { + char *name; + char *value; +}; + +struct virNetworkDNSDef { + unsigned int ntxtrecords; + virNetworkDNSTxtRecordsDefPtr txtrecords; +} virNetworkDNSDef; + +typedef struct virNetworkDNSDef *virNetworkDNSDefPtr; + typedef struct _virNetworkIpDef virNetworkIpDef; typedef virNetworkIpDef *virNetworkIpDefPtr; struct _virNetworkIpDef { @@ -101,6 +115,8 @@ struct _virNetworkDef { size_t nips; virNetworkIpDefPtr ips; /* ptr to array of IP addresses on this network */ + + virNetworkDNSDefPtr dns; /* ptr to dns related configuration */ }; typedef struct _virNetworkObj virNetworkObj; diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 4b94959333..dc143dbe77 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -510,6 +510,24 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, if (network->def->forwardType == VIR_NETWORK_FORWARD_NONE) virCommandAddArg(cmd, "--dhcp-option=3"); + if (network->def->dns != NULL) { + virNetworkDNSDefPtr dns = network->def->dns; + int i; + + for (i = 0; i < dns->ntxtrecords; i++) { + char *record = NULL; + if (virAsprintf(&record, "%s,%s", + dns->txtrecords[i].name, + dns->txtrecords[i].value) < 0) { + virReportOOMError(); + goto cleanup; + } + + virCommandAddArgPair(cmd, "--txt-record", record); + VIR_FREE(record); + } + } + /* * --interface does not actually work with dnsmasq < 2.47, * due to DAD for ipv6 addresses on the interface. diff --git a/tests/networkxml2xmlin/nat-network-dns-txt-record.xml b/tests/networkxml2xmlin/nat-network-dns-txt-record.xml new file mode 100644 index 0000000000..bd1697608c --- /dev/null +++ b/tests/networkxml2xmlin/nat-network-dns-txt-record.xml @@ -0,0 +1,24 @@ + + default + 81ff0d90-c91e-6742-64da-4a736edb9a9b + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/networkxml2xmlout/nat-network-dns-txt-record.xml b/tests/networkxml2xmlout/nat-network-dns-txt-record.xml new file mode 100644 index 0000000000..bd1697608c --- /dev/null +++ b/tests/networkxml2xmlout/nat-network-dns-txt-record.xml @@ -0,0 +1,24 @@ + + default + 81ff0d90-c91e-6742-64da-4a736edb9a9b + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/networkxml2xmltest.c b/tests/networkxml2xmltest.c index 468785b7f1..2cc8e560fe 100644 --- a/tests/networkxml2xmltest.c +++ b/tests/networkxml2xmltest.c @@ -86,6 +86,7 @@ mymain(void) DO_TEST("nat-network"); DO_TEST("netboot-network"); DO_TEST("netboot-proxy-network"); + DO_TEST("nat-network-dns-txt-record"); return (ret==0 ? EXIT_SUCCESS : EXIT_FAILURE); }