From c1a4e257a3ee914d7a7dcf1ddb654a42c642ff78 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Fri, 19 Jan 2018 22:00:05 +0000 Subject: [PATCH] Try to be a little more clever at falling back to smaller DNS packet sizes. --- src/config.h | 1 + src/dnsmasq.h | 1 + src/forward.c | 26 ++++++++++++++++++-------- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/config.h b/src/config.h index 7bd3c16..b317071 100644 --- a/src/config.h +++ b/src/config.h @@ -26,6 +26,7 @@ #define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */ #define FORWARD_TEST 50 /* try all servers every 50 queries */ #define FORWARD_TIME 20 /* or 20 seconds */ +#define UDP_TEST_TIME 60 /* How often to reset our idea of max packet size. */ #define SERVERS_LOGGED 30 /* Only log this many servers when logging state */ #define LOCALS_LOGGED 8 /* Only log this many local addresses when logging state */ #define RANDOM_SOCKS 64 /* max simultaneous random ports */ diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 0ee4c04..f4d330a 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -520,6 +520,7 @@ struct server { struct serverfd *sfd; char *domain; /* set if this server only handles a domain. */ int flags, tcpfd, edns_pktsz; + time_t pktsz_reduced; unsigned int queries, failed_queries; #ifdef HAVE_LOOP u32 uid; diff --git a/src/forward.c b/src/forward.c index 71bc495..cdd11d3 100644 --- a/src/forward.c +++ b/src/forward.c @@ -272,14 +272,13 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, while (forward->blocking_query) forward = forward->blocking_query; - forward->flags |= FREC_TEST_PKTSZ; - blockdata_retrieve(forward->stash, forward->stash_len, (void *)header); plen = forward->stash_len; + forward->flags |= FREC_TEST_PKTSZ; if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign) PUTSHORT(SAFE_PKTSZ, pheader); - + if (forward->sentto->addr.sa.sa_family == AF_INET) log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec"); #ifdef HAVE_IPV6 @@ -401,7 +400,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, int subnet, forwarded = 0; size_t edns0_len; unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL); - + unsigned char *pheader; + /* If a query is retried, use the log_id for the retry when logging the answer. */ forward->log_id = daemon->log_id; @@ -423,7 +423,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, } #endif - if (find_pseudoheader(header, plen, &edns0_len, NULL, NULL, NULL)) + if (find_pseudoheader(header, plen, &edns0_len, &pheader, NULL, NULL)) { /* If there wasn't a PH before, and there is now, we added it. */ if (!oph) @@ -432,6 +432,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, /* If we're sending an EDNS0 with any options, we can't recreate the query from a reply. */ if (edns0_len > 11) forward->flags |= FREC_HAS_EXTRADATA; + + /* Reduce udp size on retransmits. */ + if (forward->flags & FREC_TEST_PKTSZ) + PUTSHORT(SAFE_PKTSZ, pheader); } while (1) @@ -764,7 +768,11 @@ void reply_query(int fd, int family, time_t now) if (!server) return; - + + /* If sufficient time has elapsed, try and expand UDP buffer size again. */ + if (difftime(now, server->pktsz_reduced) > UDP_TEST_TIME) + server->edns_pktsz = daemon->edns_pktsz; + #ifdef HAVE_DNSSEC hash = hash_questions(header, n, daemon->namebuff); #else @@ -853,14 +861,16 @@ void reply_query(int fd, int family, time_t now) /* We tried resending to this server with a smaller maximum size and got an answer. Make that permanent. To avoid reduxing the packet size for a single dropped packet, only do this when we get a truncated answer, or one larger than the safe size. */ - if (server && (forward->flags & FREC_TEST_PKTSZ) && + if (server && server->edns_pktsz > SAFE_PKTSZ && (forward->flags & FREC_TEST_PKTSZ) && ((header->hb3 & HB3_TC) || n >= SAFE_PKTSZ)) { server->edns_pktsz = SAFE_PKTSZ; + server->pktsz_reduced = now; prettyprint_addr(&server->addr, daemon->addrbuff); my_syslog(LOG_WARNING, _("reducing DNS packet size for nameserver %s to %d"), daemon->addrbuff, SAFE_PKTSZ); } - + + /* If the answer is an error, keep the forward record in place in case we get a good reply from another server. Kill it when we've had replies from all to avoid filling the forwarding table when