|
|
6d0937 |
From 3ae073ab82183075a93e71ed889e0ee4fdb780e6 Mon Sep 17 00:00:00 2001
|
|
|
6d0937 |
From: Simon Kelley <simon@thekelleys.org.uk>
|
|
|
6d0937 |
Date: Wed, 17 Feb 2021 23:56:32 +0000
|
|
|
6d0937 |
Subject: [PATCH] Fix problem with DNS retries in 2.83/2.84.
|
|
|
6d0937 |
|
|
|
6d0937 |
The new logic in 2.83/2.84 which merges distinct requests for the
|
|
|
6d0937 |
same domain causes problems with clients which do retries as distinct
|
|
|
6d0937 |
requests (differing IDs and/or source ports.) The retries just get
|
|
|
6d0937 |
piggy-backed on the first, failed, request.
|
|
|
6d0937 |
|
|
|
6d0937 |
The logic is now changed so that distinct requests for repeated
|
|
|
6d0937 |
queries still get merged into a single ID/source port, but they now
|
|
|
6d0937 |
always trigger a re-try upstream.
|
|
|
6d0937 |
|
|
|
6d0937 |
Thanks to Nicholas Mu for his analysis.
|
|
|
6d0937 |
|
|
|
6d0937 |
(cherry picked from commit 141a26f979b4bc959d8e866a295e24f8cf456920)
|
|
|
6d0937 |
|
|
|
6d0937 |
Simplify preceding fix.
|
|
|
6d0937 |
|
|
|
6d0937 |
Remove distinction between retry with same QID/SP and
|
|
|
6d0937 |
retry for same query with different QID/SP. If the
|
|
|
6d0937 |
QID/SP are the same as an existing one, simply retry,
|
|
|
6d0937 |
if a new QID/SP is seen, add to the list to be replied to.
|
|
|
6d0937 |
|
|
|
6d0937 |
(cherry picked from commit 305cb79c5754d5554729b18a2c06fe7ce699687a)
|
|
|
6d0937 |
---
|
|
|
6d0937 |
src/forward.c | 105 ++++++++++++++++++++++----------------------------
|
|
|
6d0937 |
1 file changed, 45 insertions(+), 60 deletions(-)
|
|
|
6d0937 |
|
|
|
6d0937 |
diff --git a/src/forward.c b/src/forward.c
|
|
|
6d0937 |
index 637f220..1e9c509 100644
|
|
|
6d0937 |
--- a/src/forward.c
|
|
|
6d0937 |
+++ b/src/forward.c
|
|
|
6d0937 |
@@ -17,9 +17,6 @@
|
|
|
6d0937 |
#include "dnsmasq.h"
|
|
|
6d0937 |
|
|
|
6d0937 |
static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash);
|
|
|
6d0937 |
-static struct frec *lookup_frec_by_sender(unsigned short id,
|
|
|
6d0937 |
- union mysockaddr *addr,
|
|
|
6d0937 |
- void *hash);
|
|
|
6d0937 |
static struct frec *lookup_frec_by_query(void *hash, unsigned int flags);
|
|
|
6d0937 |
|
|
|
6d0937 |
static unsigned short get_id(void);
|
|
|
6d0937 |
@@ -260,8 +257,48 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|
|
6d0937 |
fwd_flags |= FREC_DO_QUESTION;
|
|
|
6d0937 |
#endif
|
|
|
6d0937 |
|
|
|
6d0937 |
- /* may be no servers available. */
|
|
|
6d0937 |
- if (forward || (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash)))
|
|
|
6d0937 |
+ /* Check for retry on existing query */
|
|
|
6d0937 |
+ if (!forward && (forward = lookup_frec_by_query(hash, fwd_flags)))
|
|
|
6d0937 |
+ {
|
|
|
6d0937 |
+ struct frec_src *src;
|
|
|
6d0937 |
+
|
|
|
6d0937 |
+ for (src = &forward->frec_src; src; src = src->next)
|
|
|
6d0937 |
+ if (src->orig_id == ntohs(header->id) &&
|
|
|
6d0937 |
+ sockaddr_isequal(&src->source, udpaddr))
|
|
|
6d0937 |
+ break;
|
|
|
6d0937 |
+
|
|
|
6d0937 |
+ /* Existing query, but from new source, just add this
|
|
|
6d0937 |
+ client to the list that will get the reply.*/
|
|
|
6d0937 |
+ if (!src)
|
|
|
6d0937 |
+ {
|
|
|
6d0937 |
+ /* Note whine_malloc() zeros memory. */
|
|
|
6d0937 |
+ if (!daemon->free_frec_src &&
|
|
|
6d0937 |
+ daemon->frec_src_count < daemon->ftabsize &&
|
|
|
6d0937 |
+ (daemon->free_frec_src = whine_malloc(sizeof(struct frec_src))))
|
|
|
6d0937 |
+ {
|
|
|
6d0937 |
+ daemon->frec_src_count++;
|
|
|
6d0937 |
+ daemon->free_frec_src->next = NULL;
|
|
|
6d0937 |
+ }
|
|
|
6d0937 |
+
|
|
|
6d0937 |
+ /* If we've been spammed with many duplicates, just drop the query. */
|
|
|
6d0937 |
+ if (!daemon->free_frec_src)
|
|
|
6d0937 |
+ return 0;
|
|
|
6d0937 |
+
|
|
|
6d0937 |
+ src = daemon->free_frec_src;
|
|
|
6d0937 |
+ daemon->free_frec_src = src->next;
|
|
|
6d0937 |
+ src->next = forward->frec_src.next;
|
|
|
6d0937 |
+ forward->frec_src.next = src;
|
|
|
6d0937 |
+ src->orig_id = ntohs(header->id);
|
|
|
6d0937 |
+ src->source = *udpaddr;
|
|
|
6d0937 |
+ src->dest = *dst_addr;
|
|
|
6d0937 |
+ src->log_id = daemon->log_id;
|
|
|
6d0937 |
+ src->iface = dst_iface;
|
|
|
6d0937 |
+ src->fd = udpfd;
|
|
|
6d0937 |
+ }
|
|
|
6d0937 |
+ }
|
|
|
6d0937 |
+
|
|
|
6d0937 |
+ /* retry existing query */
|
|
|
6d0937 |
+ if (forward)
|
|
|
6d0937 |
{
|
|
|
6d0937 |
/* If we didn't get an answer advertising a maximal packet in EDNS,
|
|
|
6d0937 |
fall back to 1280, which should work everywhere on IPv6.
|
|
|
6d0937 |
@@ -336,42 +373,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|
|
6d0937 |
}
|
|
|
6d0937 |
else
|
|
|
6d0937 |
{
|
|
|
6d0937 |
- /* Query from new source, but the same query may be in progress
|
|
|
6d0937 |
- from another source. If so, just add this client to the
|
|
|
6d0937 |
- list that will get the reply.
|
|
|
6d0937 |
-
|
|
|
6d0937 |
- Note that is the EDNS client subnet option is in use, we can't do this,
|
|
|
6d0937 |
- as the clients (and therefore query EDNS options) will be different
|
|
|
6d0937 |
- for each query. The EDNS subnet code has checks to avoid
|
|
|
6d0937 |
- attacks in this case. */
|
|
|
6d0937 |
- if (!option_bool(OPT_CLIENT_SUBNET) && (forward = lookup_frec_by_query(hash, fwd_flags)))
|
|
|
6d0937 |
- {
|
|
|
6d0937 |
- if (!daemon->free_frec_src &&
|
|
|
6d0937 |
- daemon->frec_src_count < daemon->ftabsize &&
|
|
|
6d0937 |
- (daemon->free_frec_src = whine_malloc(sizeof(struct frec_src))))
|
|
|
6d0937 |
- {
|
|
|
6d0937 |
- daemon->frec_src_count++;
|
|
|
6d0937 |
- daemon->free_frec_src->next = NULL;
|
|
|
6d0937 |
- }
|
|
|
6d0937 |
-
|
|
|
6d0937 |
- /* If we've been spammed with many duplicates, just drop the query. */
|
|
|
6d0937 |
- if (daemon->free_frec_src)
|
|
|
6d0937 |
- {
|
|
|
6d0937 |
- struct frec_src *new = daemon->free_frec_src;
|
|
|
6d0937 |
- daemon->free_frec_src = new->next;
|
|
|
6d0937 |
- new->next = forward->frec_src.next;
|
|
|
6d0937 |
- forward->frec_src.next = new;
|
|
|
6d0937 |
- new->orig_id = ntohs(header->id);
|
|
|
6d0937 |
- new->source = *udpaddr;
|
|
|
6d0937 |
- new->dest = *dst_addr;
|
|
|
6d0937 |
- new->log_id = daemon->log_id;
|
|
|
6d0937 |
- new->iface = dst_iface;
|
|
|
6d0937 |
- new->fd = udpfd;
|
|
|
6d0937 |
- }
|
|
|
6d0937 |
-
|
|
|
6d0937 |
- return 1;
|
|
|
6d0937 |
- }
|
|
|
6d0937 |
-
|
|
|
6d0937 |
+ /* new query */
|
|
|
6d0937 |
+
|
|
|
6d0937 |
if (gotname)
|
|
|
6d0937 |
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
|
|
|
6d0937 |
|
|
|
6d0937 |
@@ -380,6 +383,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|
|
6d0937 |
#endif
|
|
|
6d0937 |
type &= ~SERV_DO_DNSSEC;
|
|
|
6d0937 |
|
|
|
6d0937 |
+ /* may be no servers available. */
|
|
|
6d0937 |
if (daemon->servers && !flags)
|
|
|
6d0937 |
forward = get_new_frec(now, NULL, 0);
|
|
|
6d0937 |
/* table full - flags == 0, return REFUSED */
|
|
|
6d0937 |
@@ -2249,25 +2253,6 @@ static struct frec *lookup_frec(unsigned short id, int fd, int family, void *has
|
|
|
6d0937 |
return NULL;
|
|
|
6d0937 |
}
|
|
|
6d0937 |
|
|
|
6d0937 |
-static struct frec *lookup_frec_by_sender(unsigned short id,
|
|
|
6d0937 |
- union mysockaddr *addr,
|
|
|
6d0937 |
- void *hash)
|
|
|
6d0937 |
-{
|
|
|
6d0937 |
- struct frec *f;
|
|
|
6d0937 |
- struct frec_src *src;
|
|
|
6d0937 |
-
|
|
|
6d0937 |
- for (f = daemon->frec_list; f; f = f->next)
|
|
|
6d0937 |
- if (f->sentto &&
|
|
|
6d0937 |
- !(f->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) &&
|
|
|
6d0937 |
- memcmp(hash, f->hash, HASH_SIZE) == 0)
|
|
|
6d0937 |
- for (src = &f->frec_src; src; src = src->next)
|
|
|
6d0937 |
- if (src->orig_id == id &&
|
|
|
6d0937 |
- sockaddr_isequal(&src->source, addr))
|
|
|
6d0937 |
- return f;
|
|
|
6d0937 |
-
|
|
|
6d0937 |
- return NULL;
|
|
|
6d0937 |
-}
|
|
|
6d0937 |
-
|
|
|
6d0937 |
static struct frec *lookup_frec_by_query(void *hash, unsigned int flags)
|
|
|
6d0937 |
{
|
|
|
6d0937 |
struct frec *f;
|
|
|
6d0937 |
--
|
|
|
6d0937 |
2.26.2
|
|
|
6d0937 |
|