network: allow limiting a <forwarder> element to certain domains

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
This commit is contained in:
Laine Stump 2016-08-11 22:28:27 -04:00
parent 9065cfaa88
commit 0b6336c2d9
9 changed files with 101 additions and 21 deletions

View File

@ -847,7 +847,8 @@
&lt;dns&gt;
&lt;txt name="example" value="example value" /&gt;
&lt;forwarder addr="8.8.8.8"/&gt;
&lt;forwarder addr="8.8.4.4"/&gt;
&lt;forwarder domain='example.com' addr="8.8.4.4"/&gt;
&lt;forwarder domain='www.example.com'/&gt;
&lt;srv service='name' protocol='tcp' domain='test-domain-name' target='.' port='1024' priority='10' weight='10'/&gt;
&lt;host ip='192.168.122.2'&gt;
&lt;hostname&gt;myhost&lt;/hostname&gt;
@ -915,12 +916,25 @@
Currently supported sub-elements of <code>&lt;dns&gt;</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>&lt;forwarder&gt;</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>&lt;forwarder&gt;</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.

View File

@ -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>

View File

@ -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++;
}
}
@ -2554,8 +2573,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++) {

View File

@ -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;

View File

@ -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");
}
}
}

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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>