From: Michal Novotny Date: Mon, 2 Jan 2012 14:23:54 +0000 (+0100) Subject: Implement DNS SRV record into the bridge driver X-Git-Tag: v0.9.9-rc2~12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=973af2362cbf5348134b7ee90dbd34481182b9ac;p=thirdparty%2Flibvirt.git Implement DNS SRV record into the bridge driver Hi, this is the fifth version of my SRV record for DNSMasq patch rebased for the current codebase to the bridge driver and libvirt XML file to include support for the SRV records in the DNS. The syntax is based on DNSMasq man page and tests for both xml2xml and xml2argv were added as well. There are some things written a better way in comparison with version 4, mainly there's no hack in tests/networkxml2argvtest.c and also the xPath context is changed to use a simpler query using the virXPathInt() function relative to the current node. Also, the patch is also fixing the networkxml2argv test to pass both checks, i.e. both unit tests and also syntax check. Please review, Michal Signed-off-by: Michal Novotny --- diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in index 02302fafa0..755d51098b 100644 --- a/docs/formatnetwork.html.in +++ b/docs/formatnetwork.html.in @@ -345,6 +345,7 @@ <domain name="example.com"/> <dns> <txt name="example" value="example value" /> + <srv service='name' protocol='tcp' domain='test-domain-name' target='.' port='1024' priority='10' weight='10'/> <host ip='192.168.122.2'> <hostname>myhost</hostname> <hostname>myhostalias</hostname> @@ -396,6 +397,17 @@ Since 0.9.3 +
+
srv
+
The dns element can have also 0 or more srv + record elements. Each srv record element defines a DNS SRV record + and has 2 mandatory and 5 optional attributes. The mandatory attributes + are service name and protocol (tcp, udp) and the optional attributes are + target, port, priority, weight and domain as defined in DNS server SRV + RFC (RFC 2782). + Since 0.9.9 +
+
ip
The address attribute defines an IPv4 address in diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng index 937e1808ee..5d58fe4021 100644 --- a/docs/schemas/network.rng +++ b/docs/schemas/network.rng @@ -137,6 +137,19 @@ + + + + + + + + + + + + + @@ -216,11 +229,4 @@ - - - - (ipv4)|(ipv6) - - - diff --git a/docs/schemas/networkcommon.rng b/docs/schemas/networkcommon.rng index 3a168c337c..2328892f17 100644 --- a/docs/schemas/networkcommon.rng +++ b/docs/schemas/networkcommon.rng @@ -95,4 +95,21 @@ 1 + + + + 0 + 65535 + + + + + (tcp)|(udp) + + + + + (ipv4)|(ipv6) + + diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index 1058b0774a..347954374c 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -138,6 +138,15 @@ static void virNetworkDNSDefFree(virNetworkDNSDefPtr def) } } VIR_FREE(def->hosts); + if (def->nsrvrecords) { + while (def->nsrvrecords--) { + VIR_FREE(def->srvrecords[def->nsrvrecords].domain); + VIR_FREE(def->srvrecords[def->nsrvrecords].service); + VIR_FREE(def->srvrecords[def->nsrvrecords].protocol); + VIR_FREE(def->srvrecords[def->nsrvrecords].target); + } + } + VIR_FREE(def->srvrecords); VIR_FREE(def); } } @@ -552,9 +561,104 @@ error: return ret; } +static int +virNetworkDNSSrvDefParseXML(virNetworkDNSDefPtr def, + xmlNodePtr cur, + xmlXPathContextPtr ctxt) +{ + char *domain; + char *service; + char *protocol; + char *target; + int port; + int priority; + int weight; + int ret = 0; + + if (!(service = virXMLPropString(cur, "service"))) { + virNetworkReportError(VIR_ERR_XML_DETAIL, + "%s", _("Missing required service attribute in dns srv record")); + goto error; + } + + if (strlen(service) > DNS_RECORD_LENGTH_SRV) { + char *name = NULL; + + virAsprintf(&name, _("Service name is too long, limit is %d bytes"), DNS_RECORD_LENGTH_SRV); + virNetworkReportError(VIR_ERR_XML_DETAIL, + "%s", name); + free(name); + goto error; + } + + if (!(protocol = virXMLPropString(cur, "protocol"))) { + virNetworkReportError(VIR_ERR_XML_DETAIL, + _("Missing required protocol attribute in dns srv record '%s'"), service); + goto error; + } + + /* Check whether protocol value is the supported one */ + if (STRNEQ(protocol, "tcp") && (STRNEQ(protocol, "udp"))) { + virNetworkReportError(VIR_ERR_XML_DETAIL, + _("Invalid protocol attribute value '%s'"), protocol); + goto error; + } + + if (VIR_REALLOC_N(def->srvrecords, def->nsrvrecords + 1) < 0) { + virReportOOMError(); + goto error; + } + + def->srvrecords[def->nsrvrecords].service = service; + def->srvrecords[def->nsrvrecords].protocol = protocol; + def->srvrecords[def->nsrvrecords].domain = NULL; + def->srvrecords[def->nsrvrecords].target = NULL; + def->srvrecords[def->nsrvrecords].port = 0; + def->srvrecords[def->nsrvrecords].priority = 0; + def->srvrecords[def->nsrvrecords].weight = 0; + + /* Following attributes are optional but we had to make sure they're NULL above */ + if ((target = virXMLPropString(cur, "target")) && (domain = virXMLPropString(cur, "domain"))) { + xmlNodePtr save_ctxt = ctxt->node; + + ctxt->node = cur; + if (virXPathInt("string(./@port)", ctxt, &port)) + def->srvrecords[def->nsrvrecords].port = port; + + if (virXPathInt("string(./@priority)", ctxt, &priority)) + def->srvrecords[def->nsrvrecords].priority = priority; + + if (virXPathInt("string(./@weight)", ctxt, &weight)) + def->srvrecords[def->nsrvrecords].weight = weight; + ctxt->node = save_ctxt; + + def->srvrecords[def->nsrvrecords].domain = domain; + def->srvrecords[def->nsrvrecords].target = target; + def->srvrecords[def->nsrvrecords].port = port; + def->srvrecords[def->nsrvrecords].priority = priority; + def->srvrecords[def->nsrvrecords].weight = weight; + } + + def->nsrvrecords++; + + goto cleanup; + +error: + VIR_FREE(domain); + VIR_FREE(service); + VIR_FREE(protocol); + VIR_FREE(target); + + ret = -1; + +cleanup: + return ret; +} + static int virNetworkDNSDefParseXML(virNetworkDNSDefPtr *dnsdef, - xmlNodePtr node) + xmlNodePtr node, + xmlXPathContextPtr ctxt) { xmlNodePtr cur; int ret = -1; @@ -598,6 +702,11 @@ virNetworkDNSDefParseXML(virNetworkDNSDefPtr *dnsdef, def->ntxtrecords++; name = NULL; value = NULL; + } else if (cur->type == XML_ELEMENT_NODE && + xmlStrEqual(cur->name, BAD_CAST "srv")) { + ret = virNetworkDNSSrvDefParseXML(def, cur, ctxt); + if (ret < 0) + goto error; } else if (cur->type == XML_ELEMENT_NODE && xmlStrEqual(cur->name, BAD_CAST "host")) { ret = virNetworkDNSHostsDefParseXML(def, cur); @@ -887,7 +996,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) dnsNode = virXPathNode("./dns", ctxt); if (dnsNode != NULL) { - if (virNetworkDNSDefParseXML(&def->dns, dnsNode) < 0) + if (virNetworkDNSDefParseXML(&def->dns, dnsNode, ctxt) < 0) goto error; } @@ -1146,6 +1255,27 @@ virNetworkDNSDefFormat(virBufferPtr buf, def->txtrecords[i].value); } + for (i = 0 ; i < def->nsrvrecords ; i++) { + if (def->srvrecords[i].service && def->srvrecords[i].protocol) { + virBufferAsprintf(buf, " srvrecords[i].service, + def->srvrecords[i].protocol); + + if (def->srvrecords[i].domain) + virBufferAsprintf(buf, " domain='%s'", def->srvrecords[i].domain); + if (def->srvrecords[i].target) + virBufferAsprintf(buf, " target='%s'", def->srvrecords[i].target); + if (def->srvrecords[i].port) + virBufferAsprintf(buf, " port='%d'", def->srvrecords[i].port); + if (def->srvrecords[i].priority) + virBufferAsprintf(buf, " priority='%d'", def->srvrecords[i].priority); + if (def->srvrecords[i].weight) + virBufferAsprintf(buf, " weight='%d'", def->srvrecords[i].weight); + + virBufferAsprintf(buf, "/>\n"); + } + } + if (def->nhosts) { int ii, j; diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h index 1be20f8d93..975d5e843c 100644 --- a/src/conf/network_conf.h +++ b/src/conf/network_conf.h @@ -24,6 +24,8 @@ #ifndef __NETWORK_CONF_H__ # define __NETWORK_CONF_H__ + #define DNS_RECORD_LENGTH_SRV (512 - 30) /* Limit minus overhead as mentioned in RFC-2782 */ + # include # include # include @@ -69,6 +71,18 @@ struct _virNetworkDNSTxtRecordsDef { char *value; }; +typedef struct _virNetworkDNSSrvRecordsDef virNetworkDNSSrvRecordsDef; +typedef virNetworkDNSSrvRecordsDef *virNetworkDNSSrvRecordsDefPtr; +struct _virNetworkDNSSrvRecordsDef { + char *domain; + char *service; + char *protocol; + char *target; + int port; + int priority; + int weight; +}; + struct _virNetworkDNSHostsDef { virSocketAddr ip; int nnames; @@ -82,6 +96,8 @@ struct _virNetworkDNSDef { virNetworkDNSTxtRecordsDefPtr txtrecords; unsigned int nhosts; virNetworkDNSHostsDefPtr hosts; + unsigned int nsrvrecords; + virNetworkDNSSrvRecordsDefPtr srvrecords; }; typedef struct _virNetworkDNSDef *virNetworkDNSDefPtr; diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 44c80e1852..9afada73bb 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -527,6 +527,49 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, virCommandAddArgPair(cmd, "--txt-record", record); VIR_FREE(record); } + + for (i = 0; i < dns->nsrvrecords; i++) { + char *record = NULL; + char *recordPort = NULL; + char *recordPriority = NULL; + char *recordWeight = NULL; + + if (dns->srvrecords[i].service && dns->srvrecords[i].protocol) { + if (dns->srvrecords[i].port) { + if (virAsprintf(&recordPort, "%d", dns->srvrecords[i].port) < 0) { + virReportOOMError(); + goto cleanup; + } + } + if (dns->srvrecords[i].priority) { + if (virAsprintf(&recordPriority, "%d", dns->srvrecords[i].priority) < 0) { + virReportOOMError(); + goto cleanup; + } + } + if (dns->srvrecords[i].weight) { + if (virAsprintf(&recordWeight, "%d", dns->srvrecords[i].weight) < 0) { + virReportOOMError(); + goto cleanup; + } + } + + if (virAsprintf(&record, "%s.%s.%s,%s,%s,%s,%s", + dns->srvrecords[i].service, + dns->srvrecords[i].protocol, + dns->srvrecords[i].domain ? dns->srvrecords[i].domain : "", + dns->srvrecords[i].target ? dns->srvrecords[i].target : "", + recordPort ? recordPort : "", + recordPriority ? recordPriority : "", + recordWeight ? recordWeight : "") < 0) { + virReportOOMError(); + goto cleanup; + } + + virCommandAddArgPair(cmd, "--srv-host", record); + VIR_FREE(record); + } + } } /* diff --git a/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv b/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv new file mode 100644 index 0000000000..021e8f07a5 --- /dev/null +++ b/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv @@ -0,0 +1,16 @@ +/usr/sbin/dnsmasq \ +--strict-order \ +--bind-interfaces \ +--conf-file= \ +--except-interface lo \ +--srv-host=name.tcp.,,,, \ +--listen-address 192.168.122.1 \ +--listen-address 192.168.123.1 \ +--listen-address 2001:db8:ac10:fe01::1 \ +--listen-address 2001:db8:ac10:fd01::1 \ +--listen-address 10.24.10.1 \ +--dhcp-range 192.168.122.2,192.168.122.254 \ +--dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases \ +--dhcp-lease-max=253 \ +--dhcp-no-override \ +--dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile\ diff --git a/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.xml b/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.xml new file mode 100644 index 0000000000..e9b7680603 --- /dev/null +++ b/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.xml @@ -0,0 +1,26 @@ + + default + 81ff0d90-c91e-6742-64da-4a736edb9a9b + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/networkxml2argvdata/nat-network-dns-srv-record.argv b/tests/networkxml2argvdata/nat-network-dns-srv-record.argv new file mode 100644 index 0000000000..85afbba700 --- /dev/null +++ b/tests/networkxml2argvdata/nat-network-dns-srv-record.argv @@ -0,0 +1,16 @@ +/usr/sbin/dnsmasq \ +--strict-order \ +--bind-interfaces \ +--conf-file= \ +--except-interface lo \ +--srv-host=name.tcp.test-domain-name,.,1024,10,10 \ +--listen-address 192.168.122.1 \ +--listen-address 192.168.123.1 \ +--listen-address 2001:db8:ac10:fe01::1 \ +--listen-address 2001:db8:ac10:fd01::1 \ +--listen-address 10.24.10.1 \ +--dhcp-range 192.168.122.2,192.168.122.254 \ +--dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases \ +--dhcp-lease-max=253 \ +--dhcp-no-override \ +--dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile\ diff --git a/tests/networkxml2argvdata/nat-network-dns-srv-record.xml b/tests/networkxml2argvdata/nat-network-dns-srv-record.xml new file mode 100644 index 0000000000..4be85b50a0 --- /dev/null +++ b/tests/networkxml2argvdata/nat-network-dns-srv-record.xml @@ -0,0 +1,26 @@ + + default + 81ff0d90-c91e-6742-64da-4a736edb9a9b + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/networkxml2argvtest.c b/tests/networkxml2argvtest.c index 4a11d6fea1..2dd9b7f14a 100644 --- a/tests/networkxml2argvtest.c +++ b/tests/networkxml2argvtest.c @@ -120,6 +120,8 @@ mymain(void) DO_TEST("netboot-network"); DO_TEST("netboot-proxy-network"); DO_TEST("nat-network-dns-txt-record"); + DO_TEST("nat-network-dns-srv-record"); + DO_TEST("nat-network-dns-srv-record-minimal"); DO_TEST("nat-network-dns-hosts"); return (ret==0 ? EXIT_SUCCESS : EXIT_FAILURE); diff --git a/tests/networkxml2xmlin/nat-network-dns-srv-record-minimal.xml b/tests/networkxml2xmlin/nat-network-dns-srv-record-minimal.xml new file mode 100644 index 0000000000..e9b7680603 --- /dev/null +++ b/tests/networkxml2xmlin/nat-network-dns-srv-record-minimal.xml @@ -0,0 +1,26 @@ + + default + 81ff0d90-c91e-6742-64da-4a736edb9a9b + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/networkxml2xmlin/nat-network-dns-srv-record.xml b/tests/networkxml2xmlin/nat-network-dns-srv-record.xml new file mode 100644 index 0000000000..4be85b50a0 --- /dev/null +++ b/tests/networkxml2xmlin/nat-network-dns-srv-record.xml @@ -0,0 +1,26 @@ + + default + 81ff0d90-c91e-6742-64da-4a736edb9a9b + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/networkxml2xmlout/nat-network-dns-srv-record-minimal.xml b/tests/networkxml2xmlout/nat-network-dns-srv-record-minimal.xml new file mode 100644 index 0000000000..e9b7680603 --- /dev/null +++ b/tests/networkxml2xmlout/nat-network-dns-srv-record-minimal.xml @@ -0,0 +1,26 @@ + + default + 81ff0d90-c91e-6742-64da-4a736edb9a9b + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/networkxml2xmlout/nat-network-dns-srv-record.xml b/tests/networkxml2xmlout/nat-network-dns-srv-record.xml new file mode 100644 index 0000000000..4be85b50a0 --- /dev/null +++ b/tests/networkxml2xmlout/nat-network-dns-srv-record.xml @@ -0,0 +1,26 @@ + + default + 81ff0d90-c91e-6742-64da-4a736edb9a9b + + + + + + + + + + + + + + + + + + + + + + +