For some unknown reason the original implementation of the <forwarder>
element only took advantage of part of the functionality in the
dnsmasq feature it exposes - it allowed specifying the ip address of a
DNS server which *all* DNS requests would be forwarded to, like this:
<forwarder addr='192.168.123.25'/>
This is a frontend for dnsmasq's "server" option, which also allows
you to specify a domain that must be matched in order for a request to
be forwarded to a particular server. This patch adds support for
specifying the domain. For example:
<forwarder domain='example.com' addr='192.168.1.1'/>
<forwarder domain='www.example.com'/>
<forwarder domain='travesty.org' addr='10.0.0.1'/>
would forward requests for
bob.example.com,
ftp.example.com and
joe.corp.example.com all to the DNS server at 192.168.1.1, but would
forward requests for
travesty.org and
www.travesty.org to
10.0.0.1. And due to the second line, requests for
www.example.com,
and
odd.www.example.com would be resolved by the libvirt network's own
DNS server (i.e. thery wouldn't be immediately forwarded) even though
they also match 'example.com' - the match is given to the entry with
the longest matching domain. DNS requests not matching any of the
entries would be resolved by the libvirt network's own DNS server.
Resolves:
https://bugzilla.redhat.com/show_bug.cgi?id=1331796
---
docs/formatnetwork.html.in | 28 +++++++++----
docs/schemas/network.rng | 8 +++-
src/conf/network_conf.c | 49 ++++++++++++++++++----
src/conf/network_conf.h | 8 +++-
src/network/bridge_driver.c | 17 +++++++-
.../nat-network-dns-forwarders.conf | 2 +
.../nat-network-dns-forwarders.xml | 2 +
.../nat-network-dns-forwarders.xml | 6 ++-
.../nat-network-dns-forwarders.xml | 2 +
9 files changed, 101 insertions(+), 21 deletions(-)
diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
index e103dd7..13ca32d 100644
--- a/docs/formatnetwork.html.in
+++ b/docs/formatnetwork.html.in
@@ -847,7 +847,8 @@
<dns>
<txt name="example" value="example value" />
<forwarder addr="8.8.8.8"/>
- <forwarder addr="8.8.4.4"/>
+ <forwarder domain='example.com'
addr="8.8.4.4"/>
+ <forwarder domain='www.example.com'/>
<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>
@@ -915,12 +916,25 @@
Currently supported sub-elements of <code><dns></code>
are:
<dl>
<dt><code>forwarder</code></dt>
- <dd>A <code>dns</code> element can have 0 or
- more <code>forwarder</code> elements. Each forwarder
- element defines an IP address to be used as forwarder in
- DNS server configuration. The addr attribute is required
- and defines the IP address of every
- forwarder. <span class="since">Since 1.1.3</span>
+ <dd>The dns element can have 0 or
+ more <code><forwarder></code> elements. Each
+ forwarder element defines an alternate DNS server to use
+ for some, or all, DNS requests sent to this network's DNS
+ server. There are two attributes - <code>domain</code>,
+ and <code>addr</code>; at least one of these must be
+ specified in any <code><forwarder></code>
+ element. If both <code>domain</code> and
<code>addr</code>
+ are specified, then all requests that match the given
+ domain will be forwarded to the DNS server at addr. If
+ only <code>domain</code> is specified, then all matching
+ domains will be resolved locally (or via the host's
+ standard DNS forwarding if they can't be resolved
+ locally). If an <code>addr</code> is specified by itself,
+ then all DNS requests to the network's DNS server will be
+ forwarded to the DNS server at that address with no
+ exceptions. <code>addr</code> <span
class="since">Since
+ 1.1.3</span>, <code>domain</code> <span
class="since">Since
+ 2.2.0</span>.
</dd>
<dt><code>txt</code></dt>
<dd>A <code>dns</code> element can have 0 or more
<code>txt</code> elements.
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
index 12d4b34..1a18e64 100644
--- a/docs/schemas/network.rng
+++ b/docs/schemas/network.rng
@@ -260,7 +260,13 @@
<interleave>
<zeroOrMore>
<element name="forwarder">
- <attribute name="addr"><ref
name="ipAddr"/></attribute>
+ <optional>
+ <attribute name="addr"><ref
name="ipAddr"/></attribute>
+ </optional>
+ <optional>
+ <attribute name="domain"><ref
name="dnsName"/></attribute>
+ </optional>
+ <empty/>
</element>
</zeroOrMore>
<zeroOrMore>
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 490574f..a7d42cc 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -349,12 +349,20 @@ virNetworkDNSSrvDefClear(virNetworkDNSSrvDefPtr def)
VIR_FREE(def->target);
}
+
+static void
+virNetworkDNSForwarderClear(virNetworkDNSForwarderPtr def)
+{
+ VIR_FREE(def->domain);
+}
+
+
static void
virNetworkDNSDefClear(virNetworkDNSDefPtr def)
{
if (def->forwarders) {
while (def->nfwds)
- VIR_FREE(def->forwarders[--def->nfwds]);
+ virNetworkDNSForwarderClear(&def->forwarders[--def->nfwds]);
VIR_FREE(def->forwarders);
}
if (def->txts) {
@@ -1379,14 +1387,25 @@ virNetworkDNSDefParseXML(const char *networkName,
goto cleanup;
for (i = 0; i < nfwds; i++) {
- def->forwarders[i] = virXMLPropString(fwdNodes[i], "addr");
- if (virSocketAddrParse(NULL, def->forwarders[i], AF_UNSPEC) < 0) {
+ char *addr = virXMLPropString(fwdNodes[i], "addr");
+
+ if (addr && virSocketAddrParse(&def->forwarders[i].addr,
+ addr, AF_UNSPEC) < 0) {
virReportError(VIR_ERR_XML_ERROR,
- _("Invalid forwarder IP address '%s' "
- "in network '%s'"),
- def->forwarders[i], networkName);
+ _("Invalid forwarder IP address '%s' "
+ "in network '%s'"),
+ addr, networkName);
+ VIR_FREE(addr);
+ goto cleanup;
+ }
+ def->forwarders[i].domain = virXMLPropString(fwdNodes[i],
"domain");
+ if (!(addr || def->forwarders[i].domain)) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Invalid forwarder element, must contain "
+ "at least one of addr or domain"));
goto cleanup;
}
+ VIR_FREE(addr);
def->nfwds++;
}
}
@@ -2546,8 +2565,22 @@ virNetworkDNSDefFormat(virBufferPtr buf,
virBufferAdjustIndent(buf, 2);
for (i = 0; i < def->nfwds; i++) {
- virBufferAsprintf(buf, "<forwarder addr='%s'/>\n",
- def->forwarders[i]);
+
+ virBufferAddLit(buf, "<forwarder");
+ if (def->forwarders[i].domain) {
+ virBufferEscapeString(buf, " domain='%s'",
+ def->forwarders[i].domain);
+ }
+ if (VIR_SOCKET_ADDR_VALID(&def->forwarders[i].addr)) {
+ char *addr = virSocketAddrFormat(&def->forwarders[i].addr);
+
+ if (!addr)
+ return -1;
+
+ virBufferAsprintf(buf, " addr='%s'", addr);
+ VIR_FREE(addr);
+ }
+ virBufferAddLit(buf, "/>\n");
}
for (i = 0; i < def->ntxts; i++) {
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index 9ebd4a7..3b227db 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -125,6 +125,12 @@ struct _virNetworkDNSHostDef {
char **names;
};
+
+typedef struct _virNetworkDNSForwarder {
+ virSocketAddr addr;
+ char *domain;
+} virNetworkDNSForwarder, *virNetworkDNSForwarderPtr;
+
typedef struct _virNetworkDNSDef virNetworkDNSDef;
typedef virNetworkDNSDef *virNetworkDNSDefPtr;
struct _virNetworkDNSDef {
@@ -137,7 +143,7 @@ struct _virNetworkDNSDef {
size_t nsrvs;
virNetworkDNSSrvDefPtr srvs;
size_t nfwds;
- char **forwarders;
+ virNetworkDNSForwarderPtr forwarders;
};
typedef struct _virNetworkIPDef virNetworkIPDef;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 49c0a2f..74f75d0 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -958,8 +958,21 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
if (wantDNS && network->def->dns.forwarders) {
virBufferAddLit(&configbuf, "no-resolv\n");
for (i = 0; i < network->def->dns.nfwds; i++) {
- virBufferAsprintf(&configbuf, "server=%s\n",
- network->def->dns.forwarders[i]);
+ virNetworkDNSForwarderPtr fwd = &network->def->dns.forwarders[i];
+
+ virBufferAddLit(&configbuf, "server=");
+ if (fwd->domain)
+ virBufferAsprintf(&configbuf, "/%s/", fwd->domain);
+ if (VIR_SOCKET_ADDR_VALID(&fwd->addr)) {
+ char *addr = virSocketAddrFormat(&fwd->addr);
+
+ if (!addr)
+ goto cleanup;
+ virBufferAsprintf(&configbuf, "%s\n", addr);
+ } else {
+ /* "don't forward requests for this domain" */
+ virBufferAddLit(&configbuf, "#\n");
+ }
}
}
diff --git a/tests/networkxml2confdata/nat-network-dns-forwarders.conf
b/tests/networkxml2confdata/nat-network-dns-forwarders.conf
index 8bf3b9c..0bd76bf 100644
--- a/tests/networkxml2confdata/nat-network-dns-forwarders.conf
+++ b/tests/networkxml2confdata/nat-network-dns-forwarders.conf
@@ -8,6 +8,8 @@ strict-order
no-resolv
server=8.8.8.8
server=8.8.4.4
+server=/example.com/192.168.1.1
+server=/www.example.com/#
except-interface=lo
bind-dynamic
interface=virbr0
diff --git a/tests/networkxml2confdata/nat-network-dns-forwarders.xml
b/tests/networkxml2confdata/nat-network-dns-forwarders.xml
index 8fab78e..5d4f3fa 100644
--- a/tests/networkxml2confdata/nat-network-dns-forwarders.xml
+++ b/tests/networkxml2confdata/nat-network-dns-forwarders.xml
@@ -6,6 +6,8 @@
<dns>
<forwarder addr='8.8.8.8'/>
<forwarder addr='8.8.4.4'/>
+ <forwarder domain='example.com' addr='192.168.1.1'/>
+ <forwarder domain='www.example.com'/>
</dns>
<ip address='192.168.122.1' netmask='255.255.255.0'>
</ip>
diff --git a/tests/networkxml2xmlin/nat-network-dns-forwarders.xml
b/tests/networkxml2xmlin/nat-network-dns-forwarders.xml
index 4d7310d..426dd45 100644
--- a/tests/networkxml2xmlin/nat-network-dns-forwarders.xml
+++ b/tests/networkxml2xmlin/nat-network-dns-forwarders.xml
@@ -4,8 +4,10 @@
<forward dev='eth0' mode='nat'/>
<bridge name='virbr0' stp='on' delay='0' />
<dns>
- <forwarder addr='8.8.8.8' />
- <forwarder addr='8.8.4.4' />
+ <forwarder addr='8.8.8.8'/>
+ <forwarder addr='8.8.4.4'/>
+ <forwarder domain='example.com' addr='192.168.1.1'/>
+ <forwarder domain='www.example.com'/>
</dns>
<ip address='192.168.122.1' netmask='255.255.255.0'>
</ip>
diff --git a/tests/networkxml2xmlout/nat-network-dns-forwarders.xml
b/tests/networkxml2xmlout/nat-network-dns-forwarders.xml
index 930a42a..c05ad55 100644
--- a/tests/networkxml2xmlout/nat-network-dns-forwarders.xml
+++ b/tests/networkxml2xmlout/nat-network-dns-forwarders.xml
@@ -8,6 +8,8 @@
<dns>
<forwarder addr='8.8.8.8'/>
<forwarder addr='8.8.4.4'/>
+ <forwarder domain='example.com' addr='192.168.1.1'/>
+ <forwarder domain='www.example.com'/>
</dns>
<ip address='192.168.122.1' netmask='255.255.255.0'>
</ip>
--
2.7.4