network: permit upstream forwarding of unqualified DNS names

This resolves the issue that prompted the filing of

  https://bugzilla.redhat.com/show_bug.cgi?id=928638

(although the request there is for something much larger and more
general than this patch).

commit f3868259ca disabled the
forwarding to upstream DNS servers of unresolved DNS requests for
names that had no domain, but were just simple host names (no "."
character anywhere in the name). While this behavior is frowned upon
by DNS root servers (that's why it was changed in libvirt), it is
convenient in some cases, and since dnsmasq can be configured to allow
it, it must not be strictly forbidden.

This patch restores the old behavior, but since it is usually
undesirable, restoring it requires specification of a new option in
the network config. Adding the attribute "forwardPlainNames='yes'" to
the <dns> elemnt does the trick - when that attribute is added to a
network config, any simple hostnames that can't be resolved by the
network's dnsmasq instance will be forwarded to the DNS servers listed
in the host's /etc/resolv.conf for an attempt at resolution (just as
any FQDN would be forwarded).

When that attribute *isn't* specified, unresolved simple names will
*not* be forwarded to the upstream DNS server - this is the default
behavior.
This commit is contained in:
Laine Stump 2013-08-13 18:56:38 -04:00
parent 11cdc424d3
commit 4f595ba61c
13 changed files with 114 additions and 14 deletions

View File

@ -663,10 +663,27 @@
with the idiosyncrasies of the platform where libvirt is with the idiosyncrasies of the platform where libvirt is
running. <span class="since">Since 0.8.8</span> running. <span class="since">Since 0.8.8</span>
</dd> </dd>
<dt><code>dns</code></dt><dd> <dt><code>dns</code></dt>
The dns element of a network contains configuration information for the <dd> The dns element of a network contains configuration
virtual network's DNS server. <span class="since">Since 0.9.3</span> information for the virtual network's DNS
Currently supported elements are: server <span class="since">Since 0.9.3</span>.
<p>
The dns element
can have an optional <code>forwardPlainNames</code>
attribute <span class="since">Since 1.1.2</span>.
If <code>forwardPlainNames</code> is "no", then DNS resolution
requests for names that are not qualified with a domain
(i.e. names with no "." character) will not be forwarded to
the host's upstream DNS server - they will only be resolved if
they are known locally within the virtual network's own DNS
server. If <code>forwardPlainNames</code> is "yes",
unqualified names <b>will</b> be forwarded to the upstream DNS
server if they can't be resolved by the virtual network's own
DNS server.
</p>
Currently supported sub-elements of <code>&lt;dns&gt;</code> are:
<dl> <dl>
<dt><code>txt</code></dt> <dt><code>txt</code></dt>
<dd>A <code>dns</code> element can have 0 or more <code>txt</code> elements. <dd>A <code>dns</code> element can have 0 or more <code>txt</code> elements.

View File

@ -208,6 +208,14 @@
and other features in the <dns> element --> and other features in the <dns> element -->
<optional> <optional>
<element name="dns"> <element name="dns">
<optional>
<attribute name="forwardPlainNames">
<choice>
<value>yes</value>
<value>no</value>
</choice>
</attribute>
</optional>
<zeroOrMore> <zeroOrMore>
<element name="txt"> <element name="txt">
<attribute name="name"><ref name="dnsName"/></attribute> <attribute name="name"><ref name="dnsName"/></attribute>

View File

@ -1037,6 +1037,7 @@ virNetworkDNSDefParseXML(const char *networkName,
xmlNodePtr *hostNodes = NULL; xmlNodePtr *hostNodes = NULL;
xmlNodePtr *srvNodes = NULL; xmlNodePtr *srvNodes = NULL;
xmlNodePtr *txtNodes = NULL; xmlNodePtr *txtNodes = NULL;
char *forwardPlainNames = NULL;
int nhosts, nsrvs, ntxts; int nhosts, nsrvs, ntxts;
size_t i; size_t i;
int ret = -1; int ret = -1;
@ -1044,6 +1045,19 @@ virNetworkDNSDefParseXML(const char *networkName,
ctxt->node = node; ctxt->node = node;
forwardPlainNames = virXPathString("string(./@forwardPlainNames)", ctxt);
if (forwardPlainNames) {
if (STREQ(forwardPlainNames, "yes")) {
def->forwardPlainNames = true;
} else if (STRNEQ(forwardPlainNames, "no")) {
virReportError(VIR_ERR_XML_ERROR,
_("Invalid dns forwardPlainNames setting '%s' "
"in network '%s'"),
forwardPlainNames, networkName);
goto cleanup;
}
}
nhosts = virXPathNodeSet("./host", ctxt, &hostNodes); nhosts = virXPathNodeSet("./host", ctxt, &hostNodes);
if (nhosts < 0) { if (nhosts < 0) {
virReportError(VIR_ERR_XML_ERROR, virReportError(VIR_ERR_XML_ERROR,
@ -1106,6 +1120,7 @@ virNetworkDNSDefParseXML(const char *networkName,
ret = 0; ret = 0;
cleanup: cleanup:
VIR_FREE(forwardPlainNames);
VIR_FREE(hostNodes); VIR_FREE(hostNodes);
VIR_FREE(srvNodes); VIR_FREE(srvNodes);
VIR_FREE(txtNodes); VIR_FREE(txtNodes);
@ -2252,10 +2267,19 @@ virNetworkDNSDefFormat(virBufferPtr buf,
int result = 0; int result = 0;
size_t i, j; size_t i, j;
if (!(def->nhosts || def->nsrvs || def->ntxts)) if (!(def->forwardPlainNames || def->nhosts || def->nsrvs || def->ntxts))
goto out; goto out;
virBufferAddLit(buf, "<dns>\n"); virBufferAddLit(buf, "<dns");
if (def->forwardPlainNames) {
virBufferAddLit(buf, " forwardPlainNames='yes'");
if (!(def->nhosts || def->nsrvs || def->ntxts)) {
virBufferAddLit(buf, "/>\n");
goto out;
}
}
virBufferAddLit(buf, ">\n");
virBufferAdjustIndent(buf, 2); virBufferAdjustIndent(buf, 2);
for (i = 0; i < def->ntxts; i++) { for (i = 0; i < def->ntxts; i++) {

View File

@ -115,6 +115,7 @@ struct _virNetworkDNSHostDef {
typedef struct _virNetworkDNSDef virNetworkDNSDef; typedef struct _virNetworkDNSDef virNetworkDNSDef;
typedef virNetworkDNSDef *virNetworkDNSDefPtr; typedef virNetworkDNSDef *virNetworkDNSDefPtr;
struct _virNetworkDNSDef { struct _virNetworkDNSDef {
bool forwardPlainNames;
size_t ntxts; size_t ntxts;
virNetworkDNSTxtDefPtr txts; virNetworkDNSTxtDefPtr txts;
size_t nhosts; size_t nhosts;

View File

@ -678,20 +678,28 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
"## virsh net-edit %s\n" "## virsh net-edit %s\n"
"## or other application using the libvirt API.\n" "## or other application using the libvirt API.\n"
"##\n## dnsmasq conf file created by libvirt\n" "##\n## dnsmasq conf file created by libvirt\n"
"strict-order\n" "strict-order\n",
"domain-needed\n",
network->def->name); network->def->name);
if (!network->def->dns.forwardPlainNames)
virBufferAddLit(&configbuf, "domain-needed\n");
if (network->def->domain) { if (network->def->domain) {
virBufferAsprintf(&configbuf, virBufferAsprintf(&configbuf,
"domain=%s\n" "domain=%s\n"
"expand-hosts\n", "expand-hosts\n",
network->def->domain); network->def->domain);
} }
/* need to specify local even if no domain specified */
virBufferAsprintf(&configbuf, if (network->def->domain || !network->def->dns.forwardPlainNames) {
"local=/%s/\n", /* need to specify local even if no domain specified, unless
network->def->domain ? network->def->domain : ""); * the config says we should forward "plain" names (i.e. not
* fully qualified, no '.' characters)
*/
virBufferAsprintf(&configbuf,
"local=/%s/\n",
network->def->domain ? network->def->domain : "");
}
if (pidfile) if (pidfile)
virBufferAsprintf(&configbuf, "pid-file=%s\n", pidfile); virBufferAsprintf(&configbuf, "pid-file=%s\n", pidfile);

View File

@ -0,0 +1,11 @@
##WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
##OVERWRITTEN AND LOST. Changes to this configuration should be made using:
## virsh net-edit default
## or other application using the libvirt API.
##
## dnsmasq conf file created by libvirt
strict-order
except-interface=lo
bind-dynamic
interface=virbr0
addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts

View File

@ -0,0 +1,9 @@
<network>
<name>default</name>
<uuid>81ff0d90-c91e-6742-64da-4a736edb9a9c</uuid>
<forward dev='eth0' mode='nat'/>
<bridge name='virbr0' stp='on' delay='0' />
<dns forwardPlainNames='yes'/>
<ip address='192.168.122.1' netmask='255.255.255.0'>
</ip>
</network>

View File

@ -4,7 +4,7 @@
<forward dev='eth0' mode='nat'/> <forward dev='eth0' mode='nat'/>
<bridge name='virbr0' stp='on' delay='0' /> <bridge name='virbr0' stp='on' delay='0' />
<domain name="example.com"/> <domain name="example.com"/>
<dns> <dns forwardPlainNames='no'>
<host ip='192.168.122.1'> <host ip='192.168.122.1'>
<hostname>host</hostname> <hostname>host</hostname>
<hostname>gateway</hostname> <hostname>gateway</hostname>

View File

@ -144,6 +144,7 @@ mymain(void)
DO_TEST("nat-network-dns-txt-record", full); DO_TEST("nat-network-dns-txt-record", full);
DO_TEST("nat-network-dns-srv-record", full); DO_TEST("nat-network-dns-srv-record", full);
DO_TEST("nat-network-dns-hosts", full); DO_TEST("nat-network-dns-hosts", full);
DO_TEST("nat-network-dns-forward-plain", full);
DO_TEST("dhcp6-network", dhcpv6); DO_TEST("dhcp6-network", dhcpv6);
DO_TEST("dhcp6-nat-network", dhcpv6); DO_TEST("dhcp6-nat-network", dhcpv6);
DO_TEST("dhcp6host-routed-network", dhcpv6); DO_TEST("dhcp6host-routed-network", dhcpv6);

View File

@ -0,0 +1,9 @@
<network>
<name>default</name>
<uuid>81ff0d90-c91e-6742-64da-4a736edb9a9c</uuid>
<forward dev='eth0' mode='nat'/>
<bridge name='virbr0' stp='on' delay='0' />
<dns forwardPlainNames='yes'/>
<ip address='192.168.122.1' netmask='255.255.255.0'>
</ip>
</network>

View File

@ -3,7 +3,7 @@
<uuid>81ff0d90-c91e-6742-64da-4a736edb9a9c</uuid> <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9c</uuid>
<forward dev='eth0' mode='nat'/> <forward dev='eth0' mode='nat'/>
<bridge name='virbr0' stp='on' delay='0' /> <bridge name='virbr0' stp='on' delay='0' />
<dns> <dns forwardPlainNames='no'>
<host ip='192.168.122.1'> <host ip='192.168.122.1'>
<hostname>host</hostname> <hostname>host</hostname>
<hostname>gateway</hostname> <hostname>gateway</hostname>

View File

@ -0,0 +1,11 @@
<network>
<name>default</name>
<uuid>81ff0d90-c91e-6742-64da-4a736edb9a9c</uuid>
<forward dev='eth0' mode='nat'>
<interface dev='eth0'/>
</forward>
<bridge name='virbr0' stp='on' delay='0' />
<dns forwardPlainNames='yes'/>
<ip address='192.168.122.1' netmask='255.255.255.0'>
</ip>
</network>

View File

@ -104,6 +104,7 @@ mymain(void)
DO_TEST("netboot-proxy-network"); DO_TEST("netboot-proxy-network");
DO_TEST("nat-network-dns-txt-record"); DO_TEST("nat-network-dns-txt-record");
DO_TEST("nat-network-dns-hosts"); DO_TEST("nat-network-dns-hosts");
DO_TEST("nat-network-dns-forward-plain");
DO_TEST("8021Qbh-net"); DO_TEST("8021Qbh-net");
DO_TEST("direct-net"); DO_TEST("direct-net");
DO_TEST("host-bridge-net"); DO_TEST("host-bridge-net");