[libvirt] [PATCH 2/5] network_conf: refactor the implementation of SRV parsering

Guannan Ren gren at redhat.com
Sun Jul 8 10:53:40 UTC 2012


Refacor the virNetworkDNSSrvDefParseXML function.
Prefix service and protocol with a underscore during parsing according
to RFC2782.

<srv service='kerberos' protocol='tcp'/>
before:  "--srv-host=kerberos.tcp"
after:   "--srv-host=_kerberos._tcp"

domain is optional which will override the value of --domain options
to dnsmasq if supplied to form the following format

<_service>.<_prot>.[<domain>]
--srv-host=_kerberos._tcp.pony.demo.redhat.com,pony
domain has nothing to do with port,priority,weight, so extract it
from if clause.

target is optional. If it is not supplied, it means the SRV RR is
invalid in this DNS zone. Values of port,priority,weight are meaningful
only when target is supplied. These three values have toplimit 65535,
so checking the range of them.

The default for port is 1 and the defaults for weight and priority are 0.
---
 src/conf/network_conf.c |  200 +++++++++++++++++++++++++++++++----------------
 src/conf/network_conf.h |    3 +
 2 files changed, 136 insertions(+), 67 deletions(-)

diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 012be6a..f6694ed 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -603,92 +603,143 @@ virNetworkDNSSrvDefAlloc(void)
     return srv;
 }
 
-static int
-virNetworkDNSSrvDefParseXML(virNetworkDNSDefPtr def,
-                            xmlNodePtr cur,
-                            xmlXPathContextPtr ctxt)
+static char *
+virNetworkDNSSrvDefParseServiceAndProtocol(xmlNodePtr cur,
+                                           const char *attr)
 {
-    char *domain = NULL;
-    char *service = NULL;
-    char *protocol = NULL;
-    char *target = NULL;
-    int port;
-    int priority;
-    int weight;
-    int ret = 0;
-
-    virNetworkDNSSrvRecordsDefPtr srv = NULL;
+    char *value = NULL;
+    char *ret = NULL;
+    const char *prefix = "_";
+    int offset = 1;
+    size_t length;
 
-    if (!(srv = virNetworkDNSSrvDefAlloc()))
-        goto error;
+    if (!cur || !attr)
+        return NULL;
 
-    if (!(service = virXMLPropString(cur, "service"))) {
+    if (!(value = virXMLPropString(cur, attr))) {
         virNetworkReportError(VIR_ERR_XML_DETAIL,
-                              "%s", _("Missing required service attribute in dns srv record"));
+                              _("Missing required '%s' attribute in dns srv record"),
+                              attr);
         goto error;
     }
 
-    if (strlen(service) > DNS_RECORD_LENGTH_SRV) {
-        virNetworkReportError(VIR_ERR_XML_DETAIL,
-                              _("Service name is too long, limit is %d bytes"),
-                              DNS_RECORD_LENGTH_SRV);
-        goto error;
-    }
+    length = strlen(value);
 
-    if (!(protocol = virXMLPropString(cur, "protocol"))) {
+    if (STREQ(attr, "service") &&
+           (length == 0 || length > DNS_RECORD_LENGTH_SRV)) {
         virNetworkReportError(VIR_ERR_XML_DETAIL,
-                              _("Missing required protocol attribute in dns srv record '%s'"), service);
+                              _("Service name should not be null, limit is %d bytes"),
+                              DNS_RECORD_LENGTH_SRV);
         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 (STREQ(attr, "protocol")) {
+        if (length == 0 || (STRNEQ(value, "tcp") && STRNEQ(value, "udp"))) {
+            virNetworkReportError(VIR_ERR_XML_DETAIL,
+                                  _("Protocol should not be null, 'tcp' or 'udp'"));
+            goto error;
+        }
     }
 
-    if (VIR_REALLOC_N(def->srvrecords, def->nsrvrecords + 1) < 0) {
+    /* Prefix the service and protocol with '_'.
+     */
+    if (VIR_ALLOC_N(ret, length + offset + 1) < 0) {
         virReportOOMError();
         goto error;
     }
+    strcpy(ret, prefix);
+    strcat(ret + offset, value);
+    VIR_FREE(value);
+
+    return ret;
+error:
+    VIR_FREE(value);
+    VIR_FREE(ret);
+    return NULL;
+}
+
+static char *
+virNetworkDNSSrvDefParseTarget(xmlNodePtr cur)
+{
+    char *target = NULL;
+
+    if (!cur)
+        return NULL;
+
+    /* Target is optional, we ignore null string ""
+     * According to RFC 2782, a target of "." means that the service
+     * is decidedly not available at this domain. We just ignore "."
+     * given by user explicitly because dnsmasq implements it via
+     * not feeding target value in command line.
+     */
+    target = virXMLPropString(cur, "target");
+
+    if (target && (!strlen(target) || *target == '.'))
+        VIR_FREE(target);
+
+    return target;
+}
+
+static virNetworkDNSSrvRecordsDefPtr
+virNetworkDNSSrvDefParseXML(xmlNodePtr cur,
+                            xmlXPathContextPtr ctxt)
+{
+    virNetworkDNSSrvRecordsDefPtr srv = NULL;
+
+    if (!(srv = virNetworkDNSSrvDefAlloc()))
+        goto error;
+
+    if (!(srv->service =
+            virNetworkDNSSrvDefParseServiceAndProtocol(cur, "service")))
+        goto error;
+
+    if (!(srv->protocol =
+            virNetworkDNSSrvDefParseServiceAndProtocol(cur, "protocol")))
+        goto error;
 
-    srv->service = service;
-    srv->protocol = protocol;
+    /* Domain is optional. If domain is NULL,
+     * SRV will use the domain label from <domain>.
+     */
+    srv->domain = virXMLPropString(cur, "domain");
 
-    /* Following attributes are optional but we had to make sure they're NULL above */
-    if ((target = virXMLPropString(cur, "target")) && (domain = virXMLPropString(cur, "domain"))) {
-        srv->target = target;
-        srv->domain = domain;
+    srv->target = virNetworkDNSSrvDefParseTarget(cur);
 
+    /* Without target, the service provided by SRV RR will be
+     * treated as not availiable, giving up parsing.
+     */
+    if (srv->target) {
         xmlNodePtr save_ctxt = ctxt->node;
         ctxt->node = cur;
-        if (virXPathInt("string(./@port)", ctxt, &port) == 0)
-            srv->port = port;
 
-        if (virXPathInt("string(./@priority)", ctxt, &priority) == 0)
-            srv->priority = priority;
+        if (virXPathInt("string(./@port)", ctxt, &srv->port) == 0)
+            if (srv->port < 0 || srv->port > DNS_SRV_PORT_MAX) {
+                virNetworkReportError(VIR_ERR_XML_DETAIL,
+                                      _("Service port on target is out of range(0-65535)"));
+                goto error;
+            }
 
-        if (virXPathInt("string(./@weight)", ctxt, &weight) == 0)
-            srv->weight = weight;
-        ctxt->node = save_ctxt;
-    }
+        if (virXPathInt("string(./@priority)", ctxt, &srv->priority) == 0)
+            if (srv->priority < 0 || srv->priority > DNS_SRV_PRIORITY_MAX) {
+                virNetworkReportError(VIR_ERR_XML_DETAIL,
+                                      _("SRV priority value is out of range(0-65535)"));
+                goto error;
+            }
 
-    def->srvrecords[def->nsrvrecords++] = srv;
+        if (virXPathInt("string(./@weight)", ctxt, &srv->weight) == 0)
+            if (srv->weight < 0 || srv->weight > DNS_SRV_WEIGHT_MAX) {
+                virNetworkReportError(VIR_ERR_XML_DETAIL,
+                                     _("SRV weight value is out of range(0-65535)"));
+                goto error;
+            }
 
-    goto cleanup;
+        ctxt->node = save_ctxt;
+    }
 
+    return srv;
 error:
-    VIR_FREE(domain);
-    VIR_FREE(service);
-    VIR_FREE(protocol);
-    VIR_FREE(target);
     virNetworkDNSSrvDefFree(srv);
-
-    ret = -1;
-
-cleanup:
-    return ret;
+    return NULL;
 }
 
 static int
@@ -696,17 +747,36 @@ virNetworkDNSDefParseXML(virNetworkDNSDefPtr *dnsdef,
                          xmlNodePtr node,
                          xmlXPathContextPtr ctxt)
 {
+    xmlNodePtr *nodes = NULL;
     xmlNodePtr cur;
+    int i, n;
     int ret = -1;
     char *name = NULL;
     char *value = NULL;
     virNetworkDNSDefPtr def = NULL;
 
-    if (VIR_ALLOC(def) < 0) {
-        virReportOOMError();
+    if (VIR_ALLOC(def) < 0)
+        goto no_memory;
+
+    if ((n = virXPathNodeSet("./dns/srv", ctxt, &nodes)) < 0) {
+        virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
+                              "%s", _("cannot extract srv nodes"));
         goto error;
     }
 
+    if (n && VIR_REALLOC_N(def->srvrecords, def->nsrvrecords + n) < 0)
+        goto no_memory;
+    for (i = 0; i < n; i++) {
+        virNetworkDNSSrvRecordsDefPtr srv;
+
+        srv = virNetworkDNSSrvDefParseXML(nodes[i], ctxt);
+        if (!srv)
+            goto error;
+
+        def->srvrecords[def->nsrvrecords++] = srv;
+    }
+    VIR_FREE(nodes);
+
     cur = node->children;
     while (cur != NULL) {
         if (cur->type == XML_ELEMENT_NODE &&
@@ -728,10 +798,8 @@ virNetworkDNSDefParseXML(virNetworkDNSDefPtr *dnsdef,
                 goto error;
             }
 
-            if (VIR_REALLOC_N(def->txtrecords, def->ntxtrecords + 1) < 0) {
-                virReportOOMError();
-                goto error;
-            }
+            if (VIR_REALLOC_N(def->txtrecords, def->ntxtrecords + 1) < 0)
+                goto no_memory;
 
             def->txtrecords[def->ntxtrecords].name = name;
             def->txtrecords[def->ntxtrecords].value = value;
@@ -739,11 +807,6 @@ virNetworkDNSDefParseXML(virNetworkDNSDefPtr *dnsdef,
             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);
             if (ret < 0)
@@ -754,6 +817,9 @@ virNetworkDNSDefParseXML(virNetworkDNSDefPtr *dnsdef,
     }
 
     ret = 0;
+no_memory:
+    virReportOOMError();
+
 error:
     if (ret < 0) {
         VIR_FREE(name);
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index 10b8328..345c99f 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -25,6 +25,9 @@
 # define __NETWORK_CONF_H__
 
 # define DNS_RECORD_LENGTH_SRV  (512 - 30)  /* Limit minus overhead as mentioned in RFC-2782 */
+# define DNS_SRV_PORT_MAX      65535
+# define DNS_SRV_PRIORITY_MAX  65535
+# define DNS_SRV_WEIGHT_MAX    65535
 
 # include <libxml/parser.h>
 # include <libxml/tree.h>
-- 
1.7.7.5




More information about the libvir-list mailing list