Hi, this is the patch to add DNS TXT record support to libvirt networking driver since this is feature that's supported by DNSMasq that's being used by the bridge driver. Maybe you fail to understand the reasons why to implement such a feature however it's a good thing IMHO since user could provide some information in the DNS TXT record headers. The headers are, of course, configurable in the network XML description and the idea got to me when I was reading an article about DKIM (DomainKeys Identified Mail) since it's using TXT records in the DNS to provide the public keys. This inspired me to implement the DNS TXT record support to libvirt bridge driver to allow users expose some information to the guest if they want to do so etc. Limitations: - Records names and values containing space (' ') arguments are altered to change spaces to underscores ('_'). This is because of proper argument handling when spawning dnsmasq. Technical details: The --txt-record argument should be supported by all version of DNSMasq which allows us to use it in all of the cases for the libvirt bridge driver. The only thing user has to do is to edit the network XML description in libvirt and append: <dns> <txt_record name='some name' value='some value' /> </dns> after the DHCP elements of network IP (<ip>) tree. After creating such a definition user has to restart this virtual network for changes to take effect, i.e. to spawn DNSMasq with new --txt-record arguments. User can confirm the proper configuration of DNS TXT records both by looking to the dnsmasq command-line (i.e. `ps aux | grep dnsmasq`) where information about --txt-record=some_name,some_value should be present or test it in the host/guest itself by digging the TXT record from there, i.e. using `dig TXT some_name @ip` from the host (since the it's running on the @ip and not the gateway for host) or `dig TXT some_name` from the guest where the value "some_value" should be output in both cases. This has been developed and tested on Fedora i386 box and everything was working fine. Michal Signed-off-by: Michal Novotny <minovotn@xxxxxxxxxx> --- src/conf/network_conf.c | 64 +++++++++++++++++++++++++++++++++++++++++++ src/conf/network_conf.h | 16 +++++++++++ src/network/bridge_driver.c | 28 +++++++++++++++++++ 3 files changed, 108 insertions(+), 0 deletions(-) diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index dcab9de..3e07496 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -435,6 +435,53 @@ virNetworkDHCPRangeDefParseXML(const char *networkName, } static int +virNetworkDNSDefParseXML(virNetworkIpDefPtr def, + xmlNodePtr node) +{ + + xmlNodePtr cur; + + if (VIR_ALLOC(def->dns)) { + virReportOOMError(); + return -1; + } + + cur = node->children; + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE && + xmlStrEqual(cur->name, BAD_CAST "txt_record")) { + char *name, *value; + + if (!(name = virXMLPropString(cur, "name"))) { + cur = cur->next; + continue; + } + if (!(value = virXMLPropString(cur, "value"))) { + VIR_FREE(name); + cur = cur->next; + continue; + } + + if (VIR_REALLOC_N(def->dns->txtrecords, def->dns->ntxtrecords + 1) < 0) { + virReportOOMError(); + return -1; + } + + def->dns->txtrecords[def->dns->ntxtrecords].name = strdup(name); + def->dns->txtrecords[def->dns->ntxtrecords].value = strdup(value); + def->dns->ntxtrecords++; + + VIR_FREE(name); + VIR_FREE(value); + } + + cur = cur->next; + } + + return 0; +} + +static int virNetworkIPParseXML(const char *networkName, virNetworkIpDefPtr def, xmlNodePtr node, @@ -550,6 +597,12 @@ virNetworkIPParseXML(const char *networkName, goto error; } else if (cur->type == XML_ELEMENT_NODE && + xmlStrEqual(cur->name, BAD_CAST "dns")) { + result = virNetworkDNSDefParseXML(def, cur); + if (result) + goto error; + + } else if (cur->type == XML_ELEMENT_NODE && xmlStrEqual(cur->name, BAD_CAST "tftp")) { char *root; @@ -828,6 +881,17 @@ virNetworkIpDefFormat(virBufferPtr buf, virBufferAddLit(buf, " </dhcp>\n"); } + if ((def->dns != NULL) && (def->dns->ntxtrecords)) { + int ii; + + 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); + } + virBufferAddLit(buf, " </dns>\n"); + } virBufferAddLit(buf, " </ip>\n"); diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h index 281124b..5f47595 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 { @@ -75,6 +89,8 @@ struct _virNetworkIpDef { unsigned int nranges; /* Zero or more dhcp ranges */ virNetworkDHCPRangeDefPtr ranges; + virNetworkDNSDefPtr dns; /* DNS related settings for DNSMasq */ + unsigned int nhosts; /* Zero or more dhcp hosts */ virNetworkDHCPHostDefPtr hosts; diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index c30620a..89c1431 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -442,6 +442,19 @@ networkSaveDnsmasqHostsfile(virNetworkIpDefPtr ipdef, return 0; } +static char * +replace_all(char *input, int chr1, int chr2) +{ + int pos; + char *tmp; + char *out; + + out = strdup(input); + while ((tmp = strchr(out, chr1)) != NULL) + out[ strlen(input) - strlen(tmp) ] = chr2; + + return out; +} static int networkBuildDnsmasqArgv(virNetworkObjPtr network, @@ -497,6 +510,21 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, if (network->def->forwardType == VIR_NETWORK_FORWARD_NONE) virCommandAddArg(cmd, "--dhcp-option=3"); + if (ipdef->dns != NULL) { + int i; + + for (i = 0; i < ipdef->dns->ntxtrecords; i++) { + virBuffer buf = VIR_BUFFER_INITIALIZER; + + virBufferVSprintf(&buf, "%s,%s", + replace_all(ipdef->dns->txtrecords[i].name, ' ', '_'), + replace_all(ipdef->dns->txtrecords[i].value, ' ', '_')); + + virCommandAddArgPair(cmd, "--txt-record", virBufferContentAndReset(&buf)); + VIR_FREE(buf); + } + } + /* * --interface does not actually work with dnsmasq < 2.47, * due to DAD for ipv6 addresses on the interface. -- 1.7.3.2 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list