On Wed, Mar 19, 2014 at 11:48:14AM -0600, Laine Stump wrote:
A patch submitted by Steven Malin last week pointed out a problem
with
libvirt's DNS SRV record configuration:
https://www.redhat.com/archives/libvir-list/2014-March/msg00536.html
When searching for that message later, I found another series that had
been posted by Guannan Ren back in 2012 that somehow slipped between
the cracks:
https://www.redhat.com/archives/libvir-list/2012-July/msg00236.html
That patch was very much out of date, but also pointed out some real
problems.
This patch fixes all the noted problems by refactoring
virNetworkDNSSrvDefParseXML() and networkDnsmasqConfContents(), then
verifies those fixes by added several new records to the test case.
Problems fixed:
* both service and protocol now have an underscore ("_") prepended on
the commandline, as required by RFC2782.
<srv service='sip' protocol='udp' domain='example.com'
target='tests.example.com' port='5060' priority='10'
weight='150'/>
before: srv-host=sip.udp.example.com,tests.example.com,5060,10,150
after: srv-host=_sip._udp.example.com,tests.example.com,5060,10,150
* if "domain" wasn't specified in the <srv> element, the extra
trailing "." will no longer be added to the dnsmasq commandline.
<srv service='sip' protocol='udp'
target='tests.example.com'
port='5060' priority='10' weight='150'/>
before: srv-host=sip.udp.,tests.example.com,5060,10,150
after: srv-host=_sip._udp,tests.example.com,5060,10,150
* when optional attributes aren't specified, the separating comma is
also now not placed on the dnsmasq commandline. If optional
attributes in the middle of the line are not specified, they are
replaced with a default value in the commandline (1 for port, 0 for
priority and weight).
<srv service='sip' protocol='udp'
target='tests.example.com'
port='5060'/>
before: srv-host=sip.udp.,tests.example.com,5060,,
after: srv-host=_sip._udp,tests.example.com,5060
(actually the would have generated an error, because "optional"
attributes weren't really optional.)
* The allowed characters for both service and protocol are now limited
to alphanumerics, plus a few special characters that are found in
existing names in /etc/services and /etc/protocols. (One exception
is that both of these files contain names with an embedded ".", but
"." can't be used in these fields of an SRV record because it is
used as a field separator and there is no method to escape a "."
into a field.) (Previously only the strings "tcp" and "udp" were
allowed for protocol, but this restriction has been removed, since
RFC2782 specifically says that it isn't limited to those, and that
anyway it is case insensitive.)
* the "domain" attribute is no longer required in order to recognize
the port, priority, and weight attributes during parsing. Only
"target" is required for this.
* if "target" isn't specified, port, priority, and weight are not
allowed (since they are meaningless - an empty target means "this
service is *not available* for this domain").
* port, priority, and weight are now truly optional, as the comments
originally suggested, but which was not actually true.
---
Changes from V1:
https://www.redhat.com/archives/libvir-list/2014-March/msg01172.html
src/conf/network_conf.c | 129 ++++++++++++++-------
src/network/bridge_driver.c | 80 ++++++++-----
.../nat-network-dns-srv-record-minimal.conf | 2 +-
.../nat-network-dns-srv-record.conf | 8 +-
.../nat-network-dns-srv-record.xml | 8 +-
5 files changed, 149 insertions(+), 78 deletions(-)
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 9be06d3..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" \
+ "_-+/*"
+
We are using this [a-zA-Z0-9] string on few places, maybe we could put
those together, but that's just a thought, definitely not related to
this patch.
static int
virNetworkDNSSrvDefParseXML(const char *networkName,
xmlNodePtr node,
@@ -931,80 +946,108 @@ virNetworkDNSSrvDefParseXML(const char *networkName,
virNetworkDNSSrvDefPtr def,
bool partialOkay)
{
+ int ret;
+ xmlNodePtr save_ctxt = ctxt->node;
+
+ ctxt->node = node;
+
if (!(def->service = virXMLPropString(node, "service")) &&
!partialOkay) {
virReportError(VIR_ERR_XML_DETAIL,
_("Missing required service attribute in DNS SRV record
"
"of network %s"), networkName);
goto error;
}
- if (def->service && strlen(def->service) > DNS_RECORD_LENGTH_SRV)
{
- virReportError(VIR_ERR_XML_DETAIL,
- _("Service name '%s' in network %s is too long,
limit is %d bytes"),
- def->service, networkName, DNS_RECORD_LENGTH_SRV);
- goto error;
+ if (def->service) {
+ if (strlen(def->service) > DNS_RECORD_LENGTH_SRV) {
+ virReportError(VIR_ERR_XML_DETAIL,
+ _("service attribute '%s' in network %s is too
long, "
The patch looks great, if I may, I'd suggest few super-tiny clean-ups.
Here it's pre-existing, but on other places in this patch it is
created with the similar pattern. The thing I don't really like is
that one parameter is "escaped" and one not, I mean the difference
between 'def->service' and networkName. Please add those apostrophes
around other %s parts of these strings to unify that.
+ "limit is %d bytes"),
+ def->service, networkName, DNS_RECORD_LENGTH_SRV);
+ goto error;
+ }
+ if (strspn(def->service, SERVICE_CHARS) < strlen(def->service)) {
+ virReportError(VIR_ERR_XML_DETAIL,
+ _("invalid character in service attribute '%s'
"
+ "in network %s DNS SRV record"),
And here I'd use a bit different wording, what would you say for:
"in DNS SRV record of network '%s'"
+ def->service, networkName);
+ goto error;
+ }
}
if (!(def->protocol = virXMLPropString(node, "protocol")) &&
!partialOkay) {
virReportError(VIR_ERR_XML_DETAIL,
_("Missing required protocol attribute "
You were changing messages to lowercase, but forgot this one.
- "in dns srv record '%s' of
network %s"),
+ "in DNS SRV record '%s' of network %s"),
def->service, networkName);
goto error;
}
-
- /* Check whether protocol value is the supported one */
- if (def->protocol && STRNEQ(def->protocol, "tcp")
&&
- (STRNEQ(def->protocol, "udp"))) {
+ if (def->protocol &&
+ strspn(def->protocol, PROTOCOL_CHARS) < strlen(def->protocol)) {
virReportError(VIR_ERR_XML_DETAIL,
- _("Invalid protocol attribute value '%s' "
- "in DNS SRV record of network %s"),
+ _("invalid character in protocol attribute '%s'
"
+ "in network %s DNS SRV record"),
def->protocol, networkName);
goto error;
}
/* Following attributes are optional */
- if ((def->target = virXMLPropString(node, "target")) &&
- (def->domain = virXMLPropString(node, "domain"))) {
- xmlNodePtr save_ctxt = ctxt->node;
-
- ctxt->node = node;
- if (virXPathUInt("string(./@port)", ctxt, &def->port) < 0
||
- def->port > 65535) {
- virReportError(VIR_ERR_XML_DETAIL,
- _("Missing or invalid port attribute "
- "in network %s"), networkName);
- goto error;
- }
-
- if (virXPathUInt("string(./@priority)", ctxt, &def->priority)
< 0 ||
- def->priority > 65535) {
- virReportError(VIR_ERR_XML_DETAIL,
- _("Missing or invalid priority attribute "
- "in network %s"), networkName);
- goto error;
- }
+ def->domain = virXMLPropString(node, "domain");
+ def->target = virXMLPropString(node, "target");
- if (virXPathUInt("string(./@weight)", ctxt, &def->weight) <
0 ||
- def->weight > 65535) {
- virReportError(VIR_ERR_XML_DETAIL,
- _("Missing or invalid weight attribute "
- "in network %s"), networkName);
- goto error;
- }
+ ret = virXPathUInt("string(./@port)", ctxt, &def->port);
+ if (ret >= 0 && !def->target) {
+ virReportError(VIR_ERR_XML_DETAIL,
+ _("DNS SRV port attribute not permitted without "
+ "target for service %s in network %s"),
+ def->service, networkName);
+ goto error;
+ }
+ if (ret == -2 || (ret >= 0 && (def->port < 1 || def->port >
65535))) {
+ virReportError(VIR_ERR_XML_DETAIL,
+ _("Invalid DNS SRV port attribute "
And for example here you have uppercase 'I' again.
ACK to this patch with cleaned up apostrophes and unified
Capital/all-lower-case messages.
Thanks,
Martin