[libvirt] [PATCH] network: Let domains be restricted to local DNS

Josh Stone jistone at redhat.com
Mon Dec 1 18:50:46 UTC 2014


On 12/01/2014 05:18 AM, Martin Kletzander wrote:
> On Mon, Dec 01, 2014 at 07:49:32AM -0500, Laine Stump wrote:
>> On 11/30/2014 04:06 PM, Martin Kletzander wrote:
>>> On Thu, Nov 20, 2014 at 06:46:41PM -0800, Josh Stone wrote:
>>>> This adds a new "localOnly" attribute on the domain element of the
>>>> network xml.  With this set to "yes", DNS requests under that domain
>>>> will only be resolved by libvirt's dnsmasq, never forwarded upstream.
>>>>
>>>> This was how it worked before commit f69a6b987d616, and I found that
>>>> functionality useful.  For example, I have my host's NetworkManager
>>>> dnsmasq configured to forward that domain to libvirt's dnsmasq, so I can
>>>> easily resolve guest names from outside.  But if libvirt's dnsmasq
>>>> doesn't know a name and forwards it to the host, I'd get an endless
>>>> forwarding loop.  Now I can set localOnly="yes" to prevent the loop.
>>>>
>>>
>>> I've found 2 things in this patch I'm not sure about:
>>>
>>> 1) According to the documentation about --local= parameter, it says:
>>>    "Setting this flag does not suppress reading of /etc/resolv.conf,
>>>    use -R to do that."  Shouldn't "no-resolv" be added as the option
>>>    you want in the config file?
>>
>> No, "-R" (aka "no-resolv") tells dnsmasq to not use the servers listed
>> in /etc/resolv.conf for *anything*. In this case, all that is wanted is
>> to resolve requests _within the configured domain_ only locally, and not
>> forward those requests upstream. Requests for any other domain _should_
>> be forwarded to whatever server is listed in /etc/resolv.conf. Based on
>> a discussion with Josh, I'm certain that this is the behavior he wants
>> (and it makes sense to have it available).
>>
> 
> OK, I just misunderstood this part, sorry for that.

Right, I want to keep its own domain local, but go out otherwise.

>>> 2) If your answer to the previous question is "NO", which might very
>>>    well be the case, for example if you don't want to forward that
>>>    one particular domain only (and I misunderstood the commit
>>>    message), I think you should just use the ",local" subparameter of
>>>    the domain parameter (domain=example.com,local).
>>
>> Interesting idea - this requires specifying the IP/prefix of the network
>> in the option along with domain (which I suppose isn't a problem), and
>> has the same effect as adding local=/domain.com/ as well as the reverse
>> resolution, which is a nice plus. However, the prefix for the network
>> must be 8, 16, or 24 for this to work (because of the way that
>> *.in-addr.arpa records are defined), so we can't do this all the time.
>> The question is then - do we write in a special case to do it this way
>> when the prefix is one of the right lengths, or just not do it at all?
>> Having it "magically happen" for some configs and not others could lead
>> to confusion, but having reverse resolution when possible would be very
>> useful (for example, some sshd setups have a long delay if the
>> reverse-resolve of the client's IP doesn't return something other than
>> "not found"; a pointless piece of security theater, but still fairly
>> common).
>>
> 
> Looking at the documentation again, I understand it a bit more yet
> again.  Let's assume people use normal domain names.  Libvirt can use
> the IP address and netmask from the 'ip' element (if known) and
> construct the domain parameter for the config file:
> 
>   domain=virt,192.168.13.0/24,local
> 
> If there's no IP address known, then it could be constructed as
> follows:
> 
>   domain=virt
>   local=/virt/
> 
> What do you say?
> 
> 
> Currently this is possible to achieve with the following in the XML:
> 
>   <domain name='virt,192.168.13.0/24,local'/>
> 
> But that's just plain ugly ;-)

Interesting.  If this works, and libvirt promises not to take it away
from me later, then it would be enough to satisfy my itch. :)

However, it doesn't actually seem to do the right thing.  The option
does survive from XML to the dnsmasq conf, but it doesn't seem to
actually behave as local.  When I manually tweak the conf and restart
libvirt's dnsmasq myself, it seems that having separate "domain=foo" and
"local=/foo/" terminates properly, but having a oneliner
"domain=foo,192.168.122.0/24,local" is still forwarding to the host.
Which then forwards back to libvirt, and I get my loop. :(

This is dnsmasq-2.72-3.fc21.x86_64.  Maybe dnsmasq only only treats it
local when coming from that subnet?  But it's documented as equivalent
to local=/foo/, so maybe dnsmasq has a bug here.  Did you try it?

>>>   If you want to
>>>    use the local= parameter, you would have to parse the domain value
>>>    as it can be multiple domains separated by a comma and for domains
>>>    that are actually IP addresses, you'd need to add the reverse of
>>>    that (e.g. 122.168.192.in-addr.arpa).
>>
>> I'm not following this. Although the parsing code doesn't validate it,
>> the domain name in libvirt's XML is only allowed to be a single
>> "dnsName" according to the schema, and that is also what is documented
>> in formatnetwork.html. And I can't think of any useful reason for
>> specifying an IP address as the name (even though neither libvirt nor
>> dnsmasq produces an error when you do that, it is simply a broken
>> concept from the beginning).
>>
> 
> I misunderstood the dnsmasq manual.  I didn't know that the commas
> only separated particular parameters.  And dnsmasq actually validates
> it, for example using ,local with /23 network outputs an error when
> starting the network or if there are more than 2 commas in the
> parameter.
> 
> Martin
> 
>>>
>>>> Signed-off-by: Josh Stone <jistone at redhat.com>
>>>> Cc: Laine Stump <laine at laine.org>
>>>> ---
>>>> docs/formatnetwork.html.in                                 | 12
>>>> +++++++++++-
>>>> docs/schemas/network.rng                                   |  3 +++
>>>> src/conf/network_conf.c                                    |  5 +++++
>>>> src/conf/network_conf.h                                    |  1 +
>>>> src/network/bridge_driver.c                                |  5 +++++
>>>> .../networkxml2confdata/nat-network-dns-local-domain.conf  | 14
>>>> ++++++++++++++
>>>> tests/networkxml2confdata/nat-network-dns-local-domain.xml |  9
>>>> +++++++++
>>>> tests/networkxml2conftest.c                                |  1 +
>>>> 8 files changed, 49 insertions(+), 1 deletion(-)
>>>> create mode 100644
>>>> tests/networkxml2confdata/nat-network-dns-local-domain.conf
>>>> create mode 100644
>>>> tests/networkxml2confdata/nat-network-dns-local-domain.xml
>>>>
>>>> diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
>>>> index dc438aee8622..defcdba00930 100644
>>>> --- a/docs/formatnetwork.html.in
>>>> +++ b/docs/formatnetwork.html.in
>>>> @@ -82,7 +82,7 @@
>>>>     <pre>
>>>>         ...
>>>>         <bridge name="virbr0" stp="on" delay="5"/>
>>>> -        <domain name="example.com"/>
>>>> +        <domain name="example.com" localOnly="no"/>
>>>>         <forward mode="nat" dev="eth0"/>
>>>>         ...</pre>
>>>>
>>>> @@ -113,6 +113,16 @@
>>>>         a <code><forward></code> mode of "nat" or "route" (or an
>>>>         isolated network with no <code><forward></code>
>>>>         element). <span class="since">Since 0.4.5</span>
>>>> +
>>>> +        <p>
>>>> +          If the optional <code>localOnly</code> attribute on the
>>>> +          <code>domain</code> element is "yes", then DNS requests under
>>>> +          this domain will only be resolved by the virtual network's
>>>> own
>>>> +          DNS server - they will not be forwarded to the host's
>>>> upstream
>>>> +          DNS server.  If <code>localOnly</code> is "no", and by
>>>> +          default, unresolved requests <b>will</b> be forwarded.
>>>> +          <span class="since">Since 1.2.11</span>
>>>> +        </p>
>>>>       </dd>
>>>>       <dt><code>forward</code></dt>
>>>>       <dd>Inclusion of the <code>forward</code> element indicates that
>>>> diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
>>>> index 4546f8037580..a1da28092375 100644
>>>> --- a/docs/schemas/network.rng
>>>> +++ b/docs/schemas/network.rng
>>>> @@ -225,6 +225,9 @@
>>>>         <optional>
>>>>           <element name="domain">
>>>>             <attribute name="name"><ref name="dnsName"/></attribute>
>>>> +            <optional>
>>>> +              <attribute name="localOnly"><ref
>>>> name="virYesNo"/></attribute>
>>>> +            </optional>
>>>>           </element>
>>>>         </optional>
>>>>
>>>> diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
>>>> index 067334e87cb0..61451c39805f 100644
>>>> --- a/src/conf/network_conf.c
>>>> +++ b/src/conf/network_conf.c
>>>> @@ -2083,6 +2083,11 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
>>>>
>>>>     /* Parse network domain information */
>>>>     def->domain = virXPathString("string(./domain[1]/@name)", ctxt);
>>>> +    tmp = virXPathString("string(./domain[1]/@localOnly)", ctxt);
>>>> +    if (tmp) {
>>>> +        def->domain_local = STRCASEEQ(tmp, "yes");
>>>> +        VIR_FREE(tmp);
>>>> +    }
>>>>
>>>>     if ((bandwidthNode = virXPathNode("./bandwidth", ctxt)) != NULL &&
>>>>         (def->bandwidth = virNetDevBandwidthParse(bandwidthNode, -1))
>>>> == NULL)
>>>> diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
>>>> index 660cd2d10cd1..6308a7dcfbf7 100644
>>>> --- a/src/conf/network_conf.h
>>>> +++ b/src/conf/network_conf.h
>>>> @@ -232,6 +232,7 @@ struct _virNetworkDef {
>>>>
>>>>     char *bridge;       /* Name of bridge device */
>>>>     char *domain;
>>>> +    bool domain_local; /* Choose not to forward dns for this domain */
>>>>     unsigned long delay;   /* Bridge forward delay (ms) */
>>>>     bool stp; /* Spanning tree protocol */
>>>>     virMacAddr mac; /* mac address of bridge device */
>>>> diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
>>>> index 6cb421c52850..dfa375d3aa72 100644
>>>> --- a/src/network/bridge_driver.c
>>>> +++ b/src/network/bridge_driver.c
>>>> @@ -912,6 +912,11 @@ networkDnsmasqConfContents(virNetworkObjPtr
>>>> network,
>>>>     }
>>>>
>>>>     if (network->def->domain) {
>>>> +        if (network->def->domain_local) {
>>>> +            virBufferAsprintf(&configbuf,
>>>> +                              "local=/%s/\n",
>>>> +                              network->def->domain);
>>>> +        }
>>>>         virBufferAsprintf(&configbuf,
>>>>                           "domain=%s\n"
>>>>                           "expand-hosts\n",
>>>> diff --git
>>>> a/tests/networkxml2confdata/nat-network-dns-local-domain.conf
>>>> b/tests/networkxml2confdata/nat-network-dns-local-domain.conf
>>>> new file mode 100644
>>>> index 000000000000..5f41b9186cbc
>>>> --- /dev/null
>>>> +++ b/tests/networkxml2confdata/nat-network-dns-local-domain.conf
>>>> @@ -0,0 +1,14 @@
>>>> +##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
>>>> +local=/example.com/
>>>> +domain=example.com
>>>> +expand-hosts
>>>> +except-interface=lo
>>>> +bind-dynamic
>>>> +interface=virbr0
>>>> +addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts
>>>> diff --git
>>>> a/tests/networkxml2confdata/nat-network-dns-local-domain.xml
>>>> b/tests/networkxml2confdata/nat-network-dns-local-domain.xml
>>>> new file mode 100644
>>>> index 000000000000..a92d71f1f2f6
>>>> --- /dev/null
>>>> +++ b/tests/networkxml2confdata/nat-network-dns-local-domain.xml
>>>> @@ -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' />
>>>> +  <domain name='example.com' localOnly='yes'/>
>>>> +  <ip address='192.168.122.1' netmask='255.255.255.0'>
>>>> +  </ip>
>>>> +</network>
>>>> diff --git a/tests/networkxml2conftest.c b/tests/networkxml2conftest.c
>>>> index 4f1d9345ffe4..d2aa8c62cfcd 100644
>>>> --- a/tests/networkxml2conftest.c
>>>> +++ b/tests/networkxml2conftest.c
>>>> @@ -146,6 +146,7 @@ mymain(void)
>>>>     DO_TEST("nat-network-dns-hosts", full);
>>>>     DO_TEST("nat-network-dns-forward-plain", full);
>>>>     DO_TEST("nat-network-dns-forwarders", full);
>>>> +    DO_TEST("nat-network-dns-local-domain", full);
>>>>     DO_TEST("dhcp6-network", dhcpv6);
>>>>     DO_TEST("dhcp6-nat-network", dhcpv6);
>>>>     DO_TEST("dhcp6host-routed-network", dhcpv6);
>>>> --
>>>> 2.1.0
>>>>
>>>> --
>>>> libvir-list mailing list
>>>> libvir-list at redhat.com
>>>> https://www.redhat.com/mailman/listinfo/libvir-list
>>




More information about the libvir-list mailing list