[LEDE-DEV] [PATCH] dnsmasq: write resolv.conf also when noresolv = 1
Paul Oranje
phoranje at gmail.com
Mon Jun 5 03:48:24 PDT 2017
Good morning !
The intended invariant is that /tmp/resolv.conf is handled whenever a resolver listens on 127.0.0.1#53.
Within just the scope of dnsmasq, finding the instance that is to be regarded the main instance, seems a fairly simple test:
(dnsmasq listens on loopback by default irrespective of the setting of nonwildcard)
Proposed code:
dnsmasq_ismain() # true=0, false=1.
{
local cfg="$1"
local port notinterfaces
config_get port "$cfg" port “53"
[ $port = "53" ] || return 1
config_get notinterfaces "$cfg" notinterface ""
[ -n $notinterfaces -a list_contains $notinterfaces "loopback" ] || return 1
# dnsmasq instance is designated to listen on 127.0.0.1#53.
return 0
}
The dnsmasq init script will then handle /tmp/resolv.conf dnsmasq_ismain() is true.
When running unbound as resolver with dnsmasq as the dhcp companion (dhcp_link is dnsmasq), dnsmasq is configured to listen on another port, e.g. 1053, and subsequently the above test will return false and the dnsmasq init start/stop routines will not handle /tmp/resolv.conf, which is correct. In this setup, it is unbound that listens on 127.0.0.1#53 and it should therefor be regarded the designated main resolver.
The current guard (resolvsym) is now determined with:
if [ ! -x /usr/sbin/dnsmasq -o ! -x /etc/init.d/dnsmasq ] ; then
resolvsym=1
else
/etc/init.d/dnsmasq enabled || resolvsym=1
fi
This assumes that dnsmasq when enabled, in whatever way, will handle /tmp/resolv.conf.
A correct solution would be to handle /tmp/resolv.conf in the unbound init script whenever unbound will listen on 127.0.0.1#53. Then /tmp/resolv.conf is handled whenever either dnsmasq or unbound listens on 127.0.0.1#53.
Agree ?
The unbound init routines **should** handle /tmp/resolv in this case, but currently do not (when dnsmasq is the dhcp_link).
Proposed code:
unbound_ismain() # true=0, false=1.
{
if [ "$UNBOUND_D_DHCP_LINK" = "none" ] \
&& /etc/init.d/dnsmasq enabled && [ -x /usr/sbin/dnsmasq -a -x /etc/init.d/dnsmasq ] ; then
return 1
fi
# unbound is designated to listen on 127.0.0.1#53.
return 0
}
Do you agree ?
If so, then I will post two patches, one for dnsmasq and one for unbound.
Ciao,
Paul
> Op 5 jun. 2017, om 05:37 heeft Eric Luehrsen <ericluehrsen at hotmail.com> het volgende geschreven:
>
> Hi Paul -
>
> The solution I put into Unbound scripts was due to this trickiness.
> dnsmasq and its little extra functions have become entrenched and
> necessary in base OpenWrt/LEDE. This includes the oddities in
> architecture for UCI and LuCI.
>
> Normally, it is much easier to bind to the wild card address. So one
> might assume that the primary binds to #53, and any other instance must
> use a different port. It is also possible to bind per interface. An
> instance may bind to 127.0.0.1#53, another 192.168.1.1#53, and yet
> another to 192.168.2.1#53. Depending on subnet management and access
> limiting controls, this could get complicated.
>
> Requirements first. In an ecosystem with a choice of DNS servers
> (multiple instances each and stub vs recursive), what shall be the
> direct or inferred protocol to denote the primary DNS instance? The
> scripts all but write themselves with such requirement set and agreed to.
>
> - Eric
>
>> (in short: when dnsmasq.noresolv=1 and dnsmasq.resolvfile is unset, then /tmp/resolv.conf is not handled).
>>
>> After some analysis the conclusion is that the dnsmasq init script should handle /tmp/resolv.conf, if and only if, when its main instance is run. The main instance is designated the one that will listen on 127.0.0.1#53 (naturally there can be only one such instance).
>>
>> When using unbound with UCI unbound.dhcp_link set to “dnsmasq”, the unbound init script does **not** handle /tmp/resolv.conf and leaves it to dnsmasq to do so. In the dhcp_link=dnsmasq setup it is unbound that listens on 127.0.0.1#53 and so no instance of dnsmasq can possibly be the main instance. Which makes sense.
>>
>> An attempt to solve this problem just within the scope of the dnsmasq init script has proven to be more convoluted than I first thought.
>>
>> A simple, sane and much more elegant solution would be:
>> a) dnsmasq indeed only handles /tmp/resolv.conf when it runs the main instance and
>> b) unbound does so when it the main instance, i.e. will listen on 127.0.0.1#53.
>>
>> Do you agree ?
>>
>> If so, could you share your thoughts on how best to do the unbound change ?
>> A few different approaches to the determination of $resolvsym seem possible, but I’m sure that picking best/easiest/whatever approach is best chosen by you.
>>
>> Regards,
>> Paul
>>
>>
>>> Op 4 jun. 2017, om 16:26 heeft Paul Oranje <por at xs4all.nl> het volgende geschreven:
>>>
>>> Good afternoon,
>>>
>>> Conclusions:
>>> 1) Always initialise $resolvfile (i.e. independently of the state of noresolv).
>>> 2) The value of $resolvfile cannot not be used the determine the dnsmasq main instance since several instances likely will an equal value.
>>> 3) The main dnsmasq instance is the instance that listens on 127.0.0.1:53 (of which there can only be one or none).
>>> 4) When no local DNS resolver runs /tmp/resolv.conf should soft-link $resolvfile (and that could possible be something else than /tmp/resolv.conf.auto).
>>>
>>> ad 3)
>>> The designated main instance can be determined at runtime by:
>>> - at start of an instance X, when this instance is configured to listen on 127.0.0.1#53 and no process listens on that socket, then
>>> - at stop of an instance X, when this instance is configured to listen on 127.0.0.1#53 and a process listens on that socket, then
>>>
>>> For a listening-on test something like “nslookup localhost 127.0.0.1#53 >/dev/null” would seemingly work (though not on OWRT CC), but that will incur a timeout delay (10 sec ?) when no daemon is listening.
>>> Understandably, suggestions for an alternative test that will not incur such a timeout are welcome.
>>>
>>> The above determination of the main instance assume that only one of multiple instances is configured to listen on 127.0.0.1#53, otherwise the tests may result erroneously in undefined behaviour.
>>>
>>> ad 4)
>>> A use-case for setting resolvfile to a non-default might be the use of different upstream resolvers for different subnets, though that could easily be achieved with the server options of UCI dhcp.dnsmasq[x].
>>>
>>>
>>> Regards,
>>> Paul
>>>
>>>
>>>
>>>> Op 4 jun. 2017, om 00:09 heeft Hans Dedecker <dedeckeh at gmail.com> het volgende geschreven:
>>>>
>>>> On Sat, Jun 3, 2017 at 3:33 PM, Paul Oranje <por at xs4all.nl> wrote:
>>>>> Thanks, please see a few quick reactions of mine inline ...
>>>>> Paul
>>>>>
>>>>>> Op 3 jun. 2017, om 14:18 heeft Hans Dedecker <dedeckeh at gmail.com> het volgende geschreven:
>>>>>>
>>>>>> On Thu, Jun 1, 2017 at 12:00 PM, Paul Oranje <por at xs4all.nl> wrote:
>>>>>>> Hello Hans,
>>>>>>>
>>>>>>> A new version of this small patch is worked on -overlooked your previous comment and have lately been busy with other stuff-, but after studying the code a little more I’ve a few questions. The intended patch changes code that was added with commit a35f9bbc43c3da06eed042f80dc09e8c1da681b4 (dnsmasq: Multiple dnsmasq instances support) that was authored by you.
>>>>>>>
>>>>>>>
>>>>>>> The routines dnsmasq_start() and dnsmasq_stop() contain a guard on writing and resetting /tmp/resolv.conf:
>>>>>>> [ "$resolvfile" = "/tmp/resolv.conf.auto” ] &&
>>>>>>>
>>>>>>> As explained in FS#785, the guard test fails when $noresolv is true and $resolvfile has not been explicitly configured to its default "/tmp/resolv.conf.auto", causing /tmp/resolv.conf to remain a soft link to /tmp/resolv.conf.auto (the WAN its DNS).
>>>>>>>
>>>>>>> The routine dnsmasq_stop() the guard is commented with
>>>>>>> #relink /tmp/resolve.conf only for main instance
>>>>>>>
>>>>>>> This suggests that only for the main (first ?) instance /tmp/resolv.conf would be handled, which makes sense, but the test to accomplish that seems wrong.
>>>>>>>
>>>>>>> Q1:
>>>>>>> What is the supposed relation between dnsmasq instance and the value of the value/setting of resolvfile ?
>>>>>> The DNS servers learned on the wan interface(s) by netifd are written
>>>>>> in /tmp/resolv.conf.auto. By default a dnsmasq instance uses
>>>>>> /tmp/resolv.conf.auto as resolver file unless configured otherwise.
>>>>> Indeed and whether dnsmasq uses the (whatever) resolvfile is governed by the noresolv parameter; these two parameters are orthogonal.
>>>>> The init script though skips setting resolvfile when noresolv is true.
>>>> Agree the value of noresolv should have no influence on reading he
>>>> resolvfile parameter; this behavior has been introduced in commit
>>>> 2ac21bd793946a214295b760cd652b4150d3dc07
>>> So I blamed the wrong commit.
>>>
>>>>>> Using /tmp/rsolv.conf.auto as resolver file triggers logic to rewrite
>>>>>> /tmp/resolv.conf
>>>>> Why would the question whether local DNS resolution is handled by the DNS available on WAN interface be determined by this specific **value** of $resolvfile (and irrespective of the actual existence of that file) ?
>>>>>
>>>>> Also the above question (Q1) is about the relation with the dnsmasq **instance**.
>>>>> Could you please share your thoughts on the relation behind first instance and the value of $resolvfile ?
>>>> If resolvfile is set to /tmp/resolv.conf.auto assumption is made this
>>>> is the main dnsmasq instance due to a lack of a better criterium. DHCP
>>>> configs in use before the introduction of multiple dnsmasq instances
>>>> used /tmp/resolv.conf.auto as netifd by default populates the file
>>>> /tmp/resolv.conf.auto. That's the only link I see between the main
>>>> dnsmasq instance and the value of resolvfile
>>>>>
>>>>>>> A fix I considered is to omit this guard altogether (so different from the patch previously submitted), so that the local DNS service will allways be used for local (router) DNS resolution when dnsmasq is started; at stop of dnsmasq the local resolution would return to use $resolvfile. Obviously doing so in dnsmasq_start() and dnsmasq_stop() routines that start or stop an instance would be the wrong place to do so, since that code will be called for each instance. These routines ar spawned from the start_service() and stop_service() routines that do iterate on the instances.
>>>>>>>
>>>>>>> Q2:
>>>>>>> Would placement of the /tmp/resolv.conf handling not be better placed in the start_ and stop_service() routines or, be guarded by a better test in the dnsmasq_start() and _stop() routines ? In other words: what would be a correct test ?
>>>>>> we could move rewriting of /tmp/resolv.conf to the start routine; but
>>>>>> this will not be trivial as for every dnsmasq instance DNS_SERVERS and
>>>>>> DOMAIN state will need to be kept
>>>>> The objective is to rewrite /tmp/resolv.conf to use local resolution whenever a local resolver runs (i.e. dnsmasq, unbound, ... listening on localhost:53). As multiple instances may be started, triggering on the first/main one seems to make sense (for lack of a better criterium).
>>>>> So the question is: what do you think is a (practical) guard for that (and in what routines would those be placed best) ?
>>>> The dnsmasq instance which listens on 127.0.0.1 (and thus does not
>>>> exclude the loopback interface in the notinterface parameter) for dns
>>>> requests can be used as trigger to rewrite /tmp/resolv.conf.auto which
>>>> means the logic needs to be kept in dnsmasq_start
>>>>>>> In the stop routine the file /tmp/resolv.conf is (re)set to a soft link to $resolvfile, which currently because of the test always is "/tmp/resolv.conf.auto”, irrespective whether that file exists or not.
>>>>>>>
>>>>>>> Q3:
>>>>>>> What would be the desired state of /tmp/resolv.conf after dnsmasq has been stopped ?
>>>>>> In case dnsmasq is stopped /tmp/resolv.conf needs to use only the wan
>>>>>> DNS servers; which are written by netifd in /tmp/resolv.conf.auto; and
>>>>>> not anymore 127.0.0.1.
>>>>> Okay, so that should never be any self user defined resolvfile ?
>>>> AFAIK this has never been the case before
>>>>
>>>> Hans
>>>>>> Hans
>>>>>>>
>>>>>>> Bye,
>>>>>>> Paul
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> Op 20 mei 2017, om 20:58 heeft Hans Dedecker <dedeckeh at gmail.com> het volgende geschreven:
>>>>>>>>
>>>>>>>> On Sat, May 20, 2017 at 12:41 AM, Paul Oranje <por at xs4all.nl> wrote:
>>>>>>>>> When UCI dhcp.dnsmasq.noresolv is true, dnsmasq ignores the (wan) resolv.conf
>>>>>>>>> for upstream name resolution and the dnsmasq init script ialso skips writing
>>>>>>>>> /tmp/resolv.conf (/etc/resolv.conf soft links that file).
>>>>>>>>>
>>>>>>>>> Not using the local running DNS service when noresolv is true does not make
>>>>>>>>> sence; the semantics of that config value do not imply this. With this patch
>>>>>>>>> the init script also writes /tmp/resolv.conf when noresolv is true.
>>>>>>>>>
>>>>>>>>> fixes FS#785
>>>>>>>>>
>>>>>>>>> Signed-off-by: Paul Oranje <por at xs4all.nl>
>>>>>>>>> ---
>>>>>>>>> This patch replaces an earlier patch with subject
>>>>>>>>> dnsmasq: also write /tmp/resolv.conf when UCI dhcp.dnsmasq.noresolv is '1'
>>>>>>>>> which is obsoleted because that subject was required to be shorter.
>>>>>>>>> ---
>>>>>>>>> package/network/services/dnsmasq/files/dnsmasq.init | 4 ++--
>>>>>>>>> 1 file changed, 2 insertions(+), 2 deletions(-)
>>>>>>>>>
>>>>>>>>> diff --git a/package/network/services/dnsmasq/files/dnsmasq.init b/package/network/services/dnsmasq/files/dnsmasq.init
>>>>>>>>> index 30fec7a4ee..197aae9de1 100644
>>>>>>>>> --- a/package/network/services/dnsmasq/files/dnsmasq.init
>>>>>>>>> +++ b/package/network/services/dnsmasq/files/dnsmasq.init
>>>>>>>>> @@ -947,7 +947,7 @@ dnsmasq_start()
>>>>>>>>> echo >> $CONFIGFILE_TMP
>>>>>>>>> mv -f $CONFIGFILE_TMP $CONFIGFILE
>>>>>>>>>
>>>>>>>>> - [ "$resolvfile" = "/tmp/resolv.conf.auto" ] && {
>>>>>>>>> + [ "$noresolv" = "1" -o "$resolvfile" = "/tmp/resolv.conf.auto" ] && {
>>>>>>>>> rm -f /tmp/resolv.conf
>>>>>>>>> [ $ADD_LOCAL_DOMAIN -eq 1 ] && [ -n "$DOMAIN" ] && {
>>>>>>>>> echo "search $DOMAIN" >> /tmp/resolv.conf
>>>>>>>>> @@ -982,7 +982,7 @@ dnsmasq_stop()
>>>>>>>>> config_get resolvfile "$cfg" "resolvfile"
>>>>>>>>>
>>>>>>>>> #relink /tmp/resolve.conf only for main instance
>>>>>>>>> - [ "$resolvfile" = "/tmp/resolv.conf.auto" ] && {
>>>>>>>>> + [ "$noresolv" = "1" -o "$resolvfile" = "/tmp/resolv.conf.auto" ] && {
>>>>>>>> As mentioned in the previous code review noresolv value must be read
>>>>>>>> from config (similar to resolvfile) otherwise this will not work
>>>>>>>>> [ -f /tmp/resolv.conf ] && {
>>>>>>>>> rm -f /tmp/resolv.conf
>>>>>>>>> ln -s "$resolvfile" /tmp/resolv.conf
>>>>>>>> As mentioned in the previous code review resolvfile can now be empty
>>>>>>>> which will make ln -s produce an error
>>>>>>>>
>>>>>>>> Hans
>>>>>>>>> --
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> _______________________________________________
>>>>>>>>> Lede-dev mailing list
>>>>>>>>> Lede-dev at lists.infradead.org
>>>>>>>>> http://lists.infradead.org/mailman/listinfo/lede-dev
>>>>>>>> _______________________________________________
>>>>>>>> Lede-dev mailing list
>>>>>>>> Lede-dev at lists.infradead.org
>>>>>>>> http://lists.infradead.org/mailman/listinfo/lede-dev
>>>>>> _______________________________________________
>>>>>> Lede-dev mailing list
>>>>>> Lede-dev at lists.infradead.org
>>>>>> http://lists.infradead.org/mailman/listinfo/lede-dev
>>>> _______________________________________________
>>>> Lede-dev mailing list
>>>> Lede-dev at lists.infradead.org
>>>> http://lists.infradead.org/mailman/listinfo/lede-dev
>>>
>>> _______________________________________________
>>> Lede-dev mailing list
>>> Lede-dev at lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/lede-dev
>
> _______________________________________________
> Lede-dev mailing list
> Lede-dev at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/lede-dev
More information about the Lede-dev
mailing list