>From c104ab2370a7dd601c0ad2aff08e176e6eae1e3b Mon Sep 17 00:00:00 2001
From: Laine Stump <laine@laine.org>
Date: Tue, 18 Mar 2014 15:06:22 -0600
Subject: [PATCH] Changes to squash into SRV patch

1) we must allow leading _ in service, just in case someone has it in an
   already-saved config.

2) otherwise narrow down the acceptable characters in protocol and
   service to alphnumerics plus those special characters already found
   in /etc/services and /etc/protocol (with the exception of ".",
   which can't be allowed due to its use as a separator character).

3) default for port is 1, not 0. Don't allow "port='0'" (so that value
   can be reserved to mean "default"), and adjust dnsmasq commandline
   and test cases accordingly.
---
 src/conf/network_conf.c                            | 30 +++++++++++++++++-----
 src/network/bridge_driver.c                        |  9 +++++--
 .../nat-network-dns-srv-record.conf                |  4 +--
 3 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 3a28ac7..f1e6243 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -924,6 +924,21 @@ error:
     return -1;
 }
 
+/* This includes all characters used in the names of current
+ * /etc/services and /etc/protocols files (on Fedora 20), except ".",
+ * which we can't allow because it would conflict with the use of "."
+ * as a field separator in the SRV record, there appears to be no way
+ * to escape it in, and the protocols/services that use "." in the
+ * name are obscure and unlikely to be used anyway.
+ */
+#define PROTOCOL_CHARS \
+    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" \
+    "-+/"
+
+#define SERVICE_CHARS \
+    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" \
+    "_-+/*"
+
 static int
 virNetworkDNSSrvDefParseXML(const char *networkName,
                             xmlNodePtr node,
@@ -950,10 +965,10 @@ virNetworkDNSSrvDefParseXML(const char *networkName,
                            def->service, networkName, DNS_RECORD_LENGTH_SRV);
             goto error;
         }
-        if (def->service[0] == '_') {
+        if (strspn(def->service, SERVICE_CHARS) < strlen(def->service)) {
             virReportError(VIR_ERR_XML_DETAIL,
-                           _("service attribute '%s' in network %s DNS SRV "
-                             "record cannot start with '_'"),
+                           _("invalid character in service attribute '%s' "
+                             "in network %s DNS SRV record"),
                            def->service, networkName);
             goto error;
         }
@@ -966,10 +981,11 @@ virNetworkDNSSrvDefParseXML(const char *networkName,
                        def->service, networkName);
         goto error;
     }
-    if (def->protocol && def->protocol[0] == '_') {
+    if (def->protocol &&
+        strspn(def->protocol, PROTOCOL_CHARS) < strlen(def->protocol)) {
         virReportError(VIR_ERR_XML_DETAIL,
-                       _("protocol attribute '%s' in network %s DNS SRV record "
-                         "cannot start with '_'"),
+                       _("invalid character in protocol attribute '%s' "
+                         "in network %s DNS SRV record"),
                        def->protocol, networkName);
         goto error;
     }
@@ -986,7 +1002,7 @@ virNetworkDNSSrvDefParseXML(const char *networkName,
                        def->service, networkName);
         goto error;
     }
-    if (ret == -2 || (ret >= 0 && def->port > 65535)) {
+    if (ret == -2 || (ret >= 0 && (def->port < 1 || def->port > 65535))) {
         virReportError(VIR_ERR_XML_DETAIL,
                        _("Invalid DNS SRV port attribute "
                          "for service %s in network %s"),
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 94400cf..3ad6874 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -909,11 +909,16 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
 
             virBufferAsprintf(&configbuf, ",%s", dns->srvs[i].target);
             /* port, priority, and weight are optional, but are
-             * identified by their position in the line
+             * identified by their position in the line. If an item is
+             * unspecified, but something later in the line *is*
+             * specified, we need to give the default value for the
+             * unspecified item. (According to the dnsmasq manpage,
+             * the default for port is 1).
              */
             if (dns->srvs[i].port ||
                 dns->srvs[i].priority || dns->srvs[i].weight)
-                virBufferAsprintf(&configbuf, ",%d", dns->srvs[i].port);
+                virBufferAsprintf(&configbuf, ",%d",
+                                  dns->srvs[i].port ? dns->srvs[i].port : 1);
             if (dns->srvs[i].priority || dns->srvs[i].weight)
                 virBufferAsprintf(&configbuf, ",%d", dns->srvs[i].priority);
             if (dns->srvs[i].weight)
diff --git a/tests/networkxml2confdata/nat-network-dns-srv-record.conf b/tests/networkxml2confdata/nat-network-dns-srv-record.conf
index b6fe6f9..16e7dca 100644
--- a/tests/networkxml2confdata/nat-network-dns-srv-record.conf
+++ b/tests/networkxml2confdata/nat-network-dns-srv-record.conf
@@ -12,9 +12,9 @@ srv-host=_name._tcp.test-domain-name.com,test.example.com,1111,11,111
 srv-host=_name2._udp,test2.example.com,2222,22,222
 srv-host=_name3._tcp.test3.com,test3.example.com,3333,33
 srv-host=_name4._tcp.test4.com,test4.example.com,4444
-srv-host=_name5._udp,test5.example.com,0,55,555
+srv-host=_name5._udp,test5.example.com,1,55,555
 srv-host=_name6._tcp.test6.com,test6.example.com,6666,0,666
-srv-host=_name7._tcp.test7.com,test7.example.com,0,0,777
+srv-host=_name7._tcp.test7.com,test7.example.com,1,0,777
 dhcp-range=192.168.122.2,192.168.122.254
 dhcp-no-override
 dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases
-- 
1.8.5.3

