On Fri, May 26, 2023 at 05:19:49PM +0100, Simon Kelley wrote:
> On 25/05/2023 20:32, Petr Menšík wrote:
> > This problem is best tested by an example, taken from [2] but a bit
> > modified.
> > 
> > Let's create hepothetical network issue with one forwarder, which worked
> > fine a while ago.
> > 
> > $ sudo iptables -I INPUT -i lo -d 127.0.0.255 -j DROP
> > 
> > Now start dnsmasq and send tcp query to it
> > 
> > $ dnsmasq -d --log-queries --port 2053 --no-resolv --conf-file=/dev/null 
> > --server=127.0.0.255 --server=127.0.0.1
> > $ dig +tcp @localhost -p 2053 test
> > 
> > ;; communications error to ::1#2053: timed out
> > ;; communications error to ::1#2053: timed out
> > ;; communications error to ::1#2053: timed out
> > ;; communications error to 127.0.0.1#2053: timed out
> > 
> > ; <<>> DiG 9.18.15 <<>> +tcp @localhost -p 2053 test
> > ; (2 servers found)
> > ;; global options: +cmd
> > ;; no servers could be reached
> > 
> > Because dig waits much shorter time than dnsmasq does, it never receives
> > any reply. Even when the other server is responding just fine. That is
> > main advantage of having local cache running, isn't it? It should
> > improve things!
> > 
> > Now lets be persistent and keep trying:
> > 
> > $ time for TRY in {1..6}; do dig +tcp @localhost -p 2053 test; done
> > 
> > After few timeouts, it will finally notice something is wrong and tries
> > also the second server, which will answer fast. However this works only
> > with dnsmasq -d, which is not used in production. If I replace it with
> > dnsmasq -k, it will not answer at all!
> > 
> > $ dnsmasq -k --log-queries --port 2053 --no-resolv --conf-file=/dev/null 
> > --server=127.0.0.255 --server=127.0.0.1
> > $ time for TRY in {1..8}; do dig +tcp @localhost -p 2053 test; done
> > 
> > ...
> > ;; communications error to ::1#2053: timed out
> > ;; communications error to ::1#2053: timed out
> > ;; communications error to ::1#2053: timed out
> > ;; communications error to 127.0.0.1#2053: timed out
> > 
> > ; <<>> DiG 9.18.15 <<>> +tcp @localhost -p 2053 test
> > ; (2 servers found)
> > ;; global options: +cmd
> > ;; no servers could be reached
> > 
> > 
> > real    5m20,602s
> > user    0m0,094s
> > sys    0m0,115s
> > 
> > This is because with -k it spawns tcp workers, which start always with
> > whatever last_server prepared by last UDP. And until any UDP query
> > arrives to save the day, it will stubbornly try non-responding server
> > first. Even when the other one answers in miliseconds. Notice it have
> > been trying 5 minutes without success.
> > 
> > I think this has to be fixed somehow. This is corner case, because TCP
> > queries are usually caused by UDP queries with TC bit set. But there
> > exist real-world examples, where TCP only query makes sense. But dnsmasq
> > does not handle them well. Summarized this at [3].
> > 
> > My proposal would be sending UDP query + EDNS0 header in case sending
> > query failed to the main process, which can then trigger forwarders
> > responsiveness and change the last_server to a working one. So
> > subsequent attempts do not fall into the blackhole again and again.
> > EDNS0 header would be there to increase chance for a positive reply from
> > upstream, which can be cached.
> > 
> > Would you have other ideas, how to solve this problem?
> > 
> > Cheers,
> > Petr
> > 
> 
> 
> The long delay awaiting a connection from a non-responsive server may be
> improved by reducing the value of the TCP_SYNCNT socket option, at least on
> Linux.
> 
> 
> I think it's pretty easy to pass back the identity of a server which is
> responding to TCP connections to the main process using the same mechanism
> that passes back cache entries. The only wrinkle is if the list of servers
> changes between forking the child process and is sending back data about
> which server worked, for instance is the srever list gets reconfigured.
> Detecting that just needs an "epoch" counter to be included. It's rare, so
> just rejecting a "use this server" update from a child that was spawned in a
> different epoch from the current one should avoid problems. Provided the
> epoch is the same, indices into the server[] array are valid to send across
> the pipe.
> 
> I like the idea of using a different valid server for TCP and UDP.
> 
> Note that the TCP code does try to pick a good server. It's not currently
> much good with long connection delays, but it does cope with ignoring a
> server which accepts connections and then immediately closes them.
> I guess that must have been a real-world problem sometime.

No one claimt yet it is a real-world problem.
 
> Cheers,
> 
> Simon.
> > [2] https://bugzilla.redhat.com/show_bug.cgi?id=2160466#c6
> > [3] https://bugzilla.redhat.com/show_bug.cgi?id=2160466#c13
> > 
> > On 19. 05. 23 13:40, Petr Menšík wrote:
> > > When analysing report [1] for non-responding queries over TCP, I
> > > have found forwarded TCP connections have quite high timeout. If for
> > > whatever reason the forwarder currently set as a last used forwarder
> > > is dropping packets without reject, the TCP will timeout for about
> > > 120 seconds on my system. That is way too much, I think any TCP
> > > clients will give up far before that. This is just quick workaround
> > > to improve the situation, not final fix.
> > > 
> > > ...
> > > 
> > > [1] https://bugzilla.redhat.com/show_bug.cgi?id=2160466
> > > 


Groeten
Geert Stappers
-- 
Silence is hard to parse

_______________________________________________
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk
https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss

Reply via email to