[Dnsmasq-discuss] [PATCH] TCP client timeout setting
Geert Stappers
stappers at stappers.nl
Mon Jul 17 13:16:12 UTC 2023
On Wed, May 31, 2023 at 01:40:30PM +0200, Petr Menšík wrote:
> Attached my bigger attempt to solve this problem.
> 7 separate patches included.
>
> Because in rare circumstances servers might have changed since TCP
> connection process started, I serialize domain, server address and its last
> position in server array. Hacked a redirection with special -2 value from
> cache inserting, where it always reads just one server. It then tries server
> at reported position first, iterating on all servers for this domain.
>
> In rare cases there might be a problem, because it does not send source
> address or interface, which might identify correct server. But I doubt those
> would make it different in any real world examples. We have no simple
> identification for changed servers. It works in basic testing well.
>
> Added also separation of TCP and UDP last servers. It should be able to
> forward UDP to server responding just over UDP and TCP to server responding
> just TCP. That should be quite rare case, more teoretical than real-world.
> Maybe change of UDP server should change also TCP, because UDP test can be
> done in parallel.
>
> I have found also unwanted difference from UDP queries. If the response is
> REFUSED, even that were accepted as valid last_server response. Now it sets
> TCP last_server just after non-refused response, not just successful
> connection.
>
> I have tried to look into glibc, that does not seem to set any timeout for
> TCP (vc) queries. Default timeout in dig tool is 10 seconds, it does not
> seem to tweak number of SYN packets sent. I think it just measures time
> before reply arrives. I think ideally we should be able to spawn another TCP
> connection to the other server if it didn't respond in few seconds. And wait
> for fastest response from any of those. But that would require quite
> significant rework of current code.
>
> Did just a basic testing, but those changes improve tested situation.
>
> What do you think about it?
I haven't yet reviewed the patch at the begin of this thread ...
Below some feedback
> Cheers,
> Petr
> From c02cfcb0a358e04636ffd2bcc595860b25b3a440 Mon Sep 17 00:00:00 2001
> From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik at redhat.com>
> Date: Wed, 17 May 2023 21:40:19 +0200
> Subject: [PATCH 1/7] Add --dns-tcp-timeout option
>
> Changes send timeout of outgoing TCP connections. Allows waiting just
> short time for successful connection before trying another server.
> Makes possible faster switch to working server if previous is not
> responding. Default socket timeout seems too high for DNS connections.
> ---
> man/dnsmasq.8 | 4 ++++
> src/config.h | 1 +
> src/dnsmasq.h | 1 +
> src/forward.c | 10 ++++++++--
> src/option.c | 10 +++++++++-
> 5 files changed, 23 insertions(+), 3 deletions(-)
>
> diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
> index 30429df..94fd5b1 100644
> --- a/man/dnsmasq.8
> +++ b/man/dnsmasq.8
> @@ -860,6 +860,10 @@ where this needs to be increased is when using web-server log file
> resolvers, which can generate large numbers of concurrent queries. This
> parameter actually controls the number of concurrent queries per server group, where a server group is the set of server(s) associated with a single domain. So if a domain has it's own server via --server=/example.com/1.2.3.4 and 1.2.3.4 is not responding, but queries for *.example.com cannot go elsewhere, then other queries will not be affected. On configurations with many such server groups and tight resources, this value may need to be reduced.
> .TP
> +.B --dns-tcp-timeout=<seconds>
> +Sets send timeout for forwarded TCP connections. Can be used to reduce time of waiting
> +for successful TCP connection. Default value 0 skips the change of it.
> +.TP
> .B --dnssec
> Validate DNS replies and cache DNSSEC data. When forwarding DNS queries, dnsmasq requests the
> DNSSEC records needed to validate the replies. The replies are validated and the result returned as
...
> diff --git a/src/forward.c b/src/forward.c
> index ecfeebd..f323fee 100644
> --- a/src/forward.c
> +++ b/src/forward.c
> @@ -1929,8 +1929,14 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
> /* Copy connection mark of incoming query to outgoing connection. */
> if (have_mark)
> setsockopt(serv->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
> -#endif
> -
Thanks for removing those trailing white spaces.
> +#endif
> +
> + if (daemon->tcp_timeout>0)
> + {
> + struct timeval tv = {daemon->tcp_timeout, 0};
> + setsockopt(serv->tcpfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
> + }
> +
> if ((!local_bind(serv->tcpfd, &serv->source_addr, serv->interface, 0, 1)))
> {
> close(serv->tcpfd);
> diff --git a/src/option.c b/src/option.c
> index 8322725..b94a5ff 100644
> --- a/src/option.c
> +++ b/src/option.c
> @@ -190,6 +190,7 @@ struct myoption {
> #define LOPT_FILTER_RR 381
> #define LOPT_NO_DHCP6 382
> #define LOPT_NO_DHCP4 383
> +#define LOPT_TCP_TIMEOUT 384
>
> #ifdef HAVE_GETOPT_LONG
> static const struct option opts[] =
> @@ -3391,7 +3393,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
> case '0': /* --dns-forward-max */
> if (!atoi_check(arg, &daemon->ftabsize))
> ret_err(gen_err);
> - break;
;-)
> + break;
> +
> + case LOPT_TCP_TIMEOUT: /* --dns-tcp-timeout */
> + if (!atoi_check(arg, &daemon->tcp_timeout))
> + ret_err(gen_err);
> + break;
>
> case 'q': /* --log-queries */
> set_option_bool(OPT_LOG);
> @@ -5833,6 +5840,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
> daemon->soa_expiry = SOA_EXPIRY;
> daemon->randport_limit = 1;
> daemon->host_index = SRC_AH;
> + daemon->tcp_timeout = TCP_TIMEOUT;
>
> /* See comment above make_servers(). Optimises server-read code. */
> mark_servers(0);
> --
> 2.40.1
>
> From d9a8d33f195c6c406ff28a0084d1be8b46583b08 Mon Sep 17 00:00:00 2001
> From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik at redhat.com>
> Date: Tue, 23 May 2023 21:31:05 +0200
> Subject: [PATCH 2/7] Reduce few TCP related repeated code
>
> Provide special function for repeated setting of ede code in
> pseudoheader. Introduce read_tcp reusing query length and payload.
> ---
> src/dnsmasq.h | 2 +
> src/edns0.c | 9 ++
> src/forward.c | 223 ++++++++++++++++++++------------------------------
> 3 files changed, 100 insertions(+), 134 deletions(-)
>
> diff --git a/src/dnsmasq.h b/src/dnsmasq.h
> index 4113ccb..77296ed 100644
> --- a/src/dnsmasq.h
> +++ b/src/dnsmasq.h
> @@ -1852,6 +1852,8 @@ unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
> size_t *len, unsigned char **p, int *is_sign, int *is_last);
> size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
> unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do, int replace);
> +size_t add_pseudoheader_ede(struct dns_header *header, size_t plen, unsigned char *limit,
> + unsigned short udp_sz, int ede, int set_do, int replace);
> size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit);
> size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
> union mysockaddr *source, time_t now, int *cacheable);
....
> diff --git a/src/forward.c b/src/forward.c
> index f323fee..37696c8 100644
> --- a/src/forward.c
> +++ b/src/forward.c
....
> @@ -1694,7 +1708,6 @@ void receive_query(struct listener *listen, time_t now)
> if (extract_request(header, (size_t)n, daemon->namebuff, &type))
> {
> #ifdef HAVE_AUTH
> - struct auth_zone *zone;
> #endif
That would become
> #ifdef HAVE_AUTH
> #endif
I suggest
> -#ifdef HAVE_AUTH
> - struct auth_zone *zone;
> -#endif
(removing three lines)
> log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
> &source_addr, auth_dns ? "auth" : "query", type);
> @@ -1704,15 +1717,8 @@ void receive_query(struct listener *listen, time_t now)
.....
Groeten
Geert Stappers
--
Silence is hard to parse
More information about the Dnsmasq-discuss
mailing list