From 50adf82199c362da6c542f1d22be2eeab7481211 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Fri, 26 May 2023 17:55:35 +0100 Subject: [PATCH] Behave better when attempting to contact unresponsive TCP servers. By default TCP connect takes minutes to fail when trying to connect a server which is not responding and for which the network layer doesn't generate HOSTUNREACH errors. This is doubled because having failed to connect in FASTOPEN mode, the code then tries again with a call to connect(). We set TCP_SYNCNT to 2, which make the timeout about 10 seconds. This in an unportable Linux feature, so it doesn't work on other platforms. No longer try connect() if sendmsg in fastopen mode fails with ETIMEDOUT or EHOSTUNREACH since the story will just be the same. --- src/forward.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/forward.c b/src/forward.c index ecfeebd..fc49029 100644 --- a/src/forward.c +++ b/src/forward.c @@ -1899,7 +1899,7 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet, while (1) { - int data_sent = 0; + int data_sent = 0, timedout = 0; struct server *serv; if (firstsendto == -1) @@ -1937,15 +1937,27 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet, serv->tcpfd = -1; continue; } + +#ifdef TCP_SYNCNT + /* TCP connections by default take ages to time out. + At least on Linux, we can reduce that to only two attempts + to get a reply. For DNS, that's more sensible. */ + mark = 2; + setsockopt(serv->tcpfd, IPPROTO_TCP, TCP_SYNCNT, &mark, sizeof(unsigned int)); +#endif #ifdef MSG_FASTOPEN server_send(serv, serv->tcpfd, packet, qsize + sizeof(u16), MSG_FASTOPEN); if (errno == 0) data_sent = 1; + else if (errno = ETIMEDOUT || errno == EHOSTUNREACH) + timedout = 1; #endif - if (!data_sent && connect(serv->tcpfd, &serv->addr.sa, sa_len(&serv->addr)) == -1) + /* If fastopen failed due to lack of reply, then there's no point in + trying again in non-FASTOPEN mode. */ + if (timedout || (!data_sent && connect(serv->tcpfd, &serv->addr.sa, sa_len(&serv->addr)) == -1)) { close(serv->tcpfd); serv->tcpfd = -1;