mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
Always save forwarded query locally.
We do this in many cases anyway (DNSSEC, fast-retry) and doing it unconditionally allows much simplification of knarly code, to follow.
This commit is contained in:
149
src/forward.c
149
src/forward.c
@@ -21,14 +21,13 @@ static struct frec *lookup_frec(unsigned short id, int fd, void *hash, int *firs
|
|||||||
static struct frec *lookup_frec_by_query(void *hash, unsigned int flags, unsigned int flagmask);
|
static struct frec *lookup_frec_by_query(void *hash, unsigned int flags, unsigned int flagmask);
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
static struct frec *lookup_frec_dnssec(char *target, int class, int flags, struct dns_header *header);
|
static struct frec *lookup_frec_dnssec(char *target, int class, int flags, struct dns_header *header);
|
||||||
|
static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n,
|
||||||
|
int class, char *name, char *keyname, struct server *server,
|
||||||
|
int have_mark, unsigned int mark, int *keycount, int *validatecount);
|
||||||
#endif
|
#endif
|
||||||
static unsigned short get_id(void);
|
static unsigned short get_id(void);
|
||||||
static void free_frec(struct frec *f);
|
static void free_frec(struct frec *f);
|
||||||
static void query_full(time_t now, char *domain);
|
static void query_full(time_t now, char *domain);
|
||||||
static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n,
|
|
||||||
int class, char *name, char *keyname, struct server *server,
|
|
||||||
int have_mark, unsigned int mark, int *keycount, int *validatecount);
|
|
||||||
|
|
||||||
|
|
||||||
/* Send a UDP packet with its source address set as "source"
|
/* Send a UDP packet with its source address set as "source"
|
||||||
unless nowild is true, when we just send it with the kernel default */
|
unless nowild is true, when we just send it with the kernel default */
|
||||||
@@ -294,6 +293,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
flags = 0;
|
flags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
master = daemon->serverarray[first];
|
||||||
|
|
||||||
/* don't forward A or AAAA queries for simple names, except the empty name */
|
/* don't forward A or AAAA queries for simple names, except the empty name */
|
||||||
if (!flags &&
|
if (!flags &&
|
||||||
option_bool(OPT_NODOTS_LOCAL) &&
|
option_bool(OPT_NODOTS_LOCAL) &&
|
||||||
@@ -306,18 +307,41 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
if (flags || ede == EDE_NOT_READY)
|
if (flags || ede == EDE_NOT_READY)
|
||||||
goto reply;
|
goto reply;
|
||||||
|
|
||||||
master = daemon->serverarray[first];
|
|
||||||
|
|
||||||
if (!(forward = get_new_frec(now, master, 0)))
|
if (!(forward = get_new_frec(now, master, 0)))
|
||||||
goto reply;
|
goto reply;
|
||||||
/* table full - flags == 0, return REFUSED */
|
/* table full - flags == 0, return REFUSED */
|
||||||
|
|
||||||
/* Keep copy of query if we're doing fast retry or DNSSEC. */
|
plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->frec_src.source, now, &cacheable);
|
||||||
if (daemon->fast_retry_time != 0 || option_bool(OPT_DNSSEC_VALID))
|
|
||||||
|
if (!cacheable)
|
||||||
|
forward->flags |= FREC_NO_CACHE;
|
||||||
|
|
||||||
|
#ifdef HAVE_DNSSEC
|
||||||
|
if (option_bool(OPT_DNSSEC_VALID) && (master->flags & SERV_DO_DNSSEC))
|
||||||
{
|
{
|
||||||
forward->stash = blockdata_alloc((char *)header, plen);
|
plen = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
|
||||||
forward->stash_len = plen;
|
|
||||||
|
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
|
||||||
|
this allows it to select auth servers when one is returning bad data. */
|
||||||
|
if (option_bool(OPT_DNSSEC_DEBUG))
|
||||||
|
header->hb4 |= HB4_CD;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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)
|
||||||
|
forward->flags |= FREC_ADDED_PHEADER;
|
||||||
|
|
||||||
|
/* Reduce udp size on retransmits. */
|
||||||
|
if (forward->flags & FREC_TEST_PKTSZ)
|
||||||
|
PUTSHORT(SAFE_PKTSZ, pheader);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keep copy of query. */
|
||||||
|
forward->stash = blockdata_alloc((char *)header, plen);
|
||||||
|
forward->stash_len = plen;
|
||||||
|
|
||||||
forward->frec_src.log_id = daemon->log_id;
|
forward->frec_src.log_id = daemon->log_id;
|
||||||
forward->frec_src.source = *udpaddr;
|
forward->frec_src.source = *udpaddr;
|
||||||
@@ -327,6 +351,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
forward->frec_src.next = NULL;
|
forward->frec_src.next = NULL;
|
||||||
forward->frec_src.fd = udpfd;
|
forward->frec_src.fd = udpfd;
|
||||||
forward->new_id = get_id();
|
forward->new_id = get_id();
|
||||||
|
header->id = htons(forward->new_id);
|
||||||
memcpy(forward->hash, hash, HASH_SIZE);
|
memcpy(forward->hash, hash, HASH_SIZE);
|
||||||
forward->forwardall = 0;
|
forward->forwardall = 0;
|
||||||
forward->flags = fwd_flags;
|
forward->flags = fwd_flags;
|
||||||
@@ -383,6 +408,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
/* get query for logging. */
|
/* get query for logging. */
|
||||||
extract_request(header, plen, daemon->namebuff, NULL);
|
extract_request(header, plen, daemon->namebuff, NULL);
|
||||||
|
|
||||||
|
/* Use go-anywhere size limit, as it's a retry. */
|
||||||
if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
|
if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
|
||||||
PUTSHORT(SAFE_PKTSZ, pheader);
|
PUTSHORT(SAFE_PKTSZ, pheader);
|
||||||
|
|
||||||
@@ -442,45 +468,6 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
forward->flags |= FREC_TEST_PKTSZ;
|
forward->flags |= FREC_TEST_PKTSZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We may be resending a DNSSEC query here, for which the below processing is not necessary. */
|
|
||||||
if (!is_dnssec)
|
|
||||||
{
|
|
||||||
header->id = htons(forward->new_id);
|
|
||||||
|
|
||||||
plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->frec_src.source, now, &cacheable);
|
|
||||||
|
|
||||||
if (!cacheable)
|
|
||||||
forward->flags |= FREC_NO_CACHE;
|
|
||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
|
||||||
if (option_bool(OPT_DNSSEC_VALID) && (master->flags & SERV_DO_DNSSEC))
|
|
||||||
{
|
|
||||||
plen = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
|
|
||||||
|
|
||||||
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
|
|
||||||
this allows it to select auth servers when one is returning bad data. */
|
|
||||||
if (option_bool(OPT_DNSSEC_DEBUG))
|
|
||||||
header->hb4 |= HB4_CD;
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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)
|
|
||||||
forward->flags |= FREC_ADDED_PHEADER;
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (forward->forwardall)
|
if (forward->forwardall)
|
||||||
start = first;
|
start = first;
|
||||||
|
|
||||||
@@ -656,7 +643,6 @@ int fast_retry(time_t now)
|
|||||||
if (ret == -1 || ret > to_run)
|
if (ret == -1 || ret > to_run)
|
||||||
ret = to_run;
|
ret = to_run;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1227,10 +1213,8 @@ void reply_query(int fd, time_t now)
|
|||||||
!(forward->flags & FREC_HAS_EXTRADATA))
|
!(forward->flags & FREC_HAS_EXTRADATA))
|
||||||
/* for broken servers, attempt to send to another one. */
|
/* for broken servers, attempt to send to another one. */
|
||||||
{
|
{
|
||||||
unsigned char *pheader, *udpsz;
|
unsigned char *udpsz;
|
||||||
unsigned short udp_size = PACKETSZ; /* default if no EDNS0 */
|
unsigned short udp_size = PACKETSZ; /* default if no EDNS0 */
|
||||||
size_t plen;
|
|
||||||
int is_sign;
|
|
||||||
size_t nn = 0;
|
size_t nn = 0;
|
||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
@@ -1239,56 +1223,15 @@ void reply_query(int fd, time_t now)
|
|||||||
The Stash contains something else and we don't need to retry anyway. */
|
The Stash contains something else and we don't need to retry anyway. */
|
||||||
if (forward->blocking_query || (forward->flags & FREC_GONE_TO_TCP))
|
if (forward->blocking_query || (forward->flags & FREC_GONE_TO_TCP))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
|
|
||||||
{
|
|
||||||
/* DNSSEC queries have a copy of the original query stashed. */
|
|
||||||
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
|
|
||||||
nn = forward->stash_len;
|
|
||||||
udp_size = daemon->edns_pktsz;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
#endif
|
||||||
{
|
|
||||||
/* in fast retry mode, we have a copy of the query. */
|
|
||||||
if ((daemon->fast_retry_time != 0 || option_bool(OPT_DNSSEC_VALID)) && forward->stash)
|
|
||||||
{
|
|
||||||
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
|
|
||||||
nn = forward->stash_len;
|
|
||||||
/* UDP size already set in saved query. */
|
|
||||||
if (find_pseudoheader(header, (size_t)n, NULL, &udpsz, NULL, NULL))
|
|
||||||
GETSHORT(udp_size, udpsz);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* recreate query from reply */
|
|
||||||
if ((pheader = find_pseudoheader(header, (size_t)n, &plen, &udpsz, &is_sign, NULL)))
|
|
||||||
GETSHORT(udp_size, udpsz);
|
|
||||||
|
|
||||||
/* If the client provides an EDNS0 UDP size, use that to limit our reply.
|
/* Get the saved query back. */
|
||||||
(bounded by the maximum configured). If no EDNS0, then it
|
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
|
||||||
defaults to 512 */
|
nn = forward->stash_len;
|
||||||
if (udp_size > daemon->edns_pktsz)
|
|
||||||
udp_size = daemon->edns_pktsz;
|
|
||||||
else if (udp_size < PACKETSZ)
|
|
||||||
udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
|
|
||||||
|
|
||||||
header->ancount = htons(0);
|
/* UDP size already set in saved query. */
|
||||||
header->nscount = htons(0);
|
if (find_pseudoheader(header, (size_t)n, NULL, &udpsz, NULL, NULL))
|
||||||
header->arcount = htons(0);
|
GETSHORT(udp_size, udpsz);
|
||||||
header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
|
|
||||||
header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
|
|
||||||
if (forward->flags & FREC_CHECKING_DISABLED)
|
|
||||||
header->hb4 |= HB4_CD;
|
|
||||||
if (forward->flags & FREC_AD_QUESTION)
|
|
||||||
header->hb4 |= HB4_AD;
|
|
||||||
|
|
||||||
if (!is_sign &&
|
|
||||||
(nn = resize_packet(header, (size_t)n, pheader, plen)) &&
|
|
||||||
(forward->flags & FREC_DO_QUESTION))
|
|
||||||
add_do_bit(header, nn, (unsigned char *)pheader + plen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nn)
|
if (nn)
|
||||||
{
|
{
|
||||||
@@ -2169,9 +2112,9 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *ple
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Recurse down the key hierarchy */
|
/* Recurse down the key hierarchy */
|
||||||
int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n,
|
static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n,
|
||||||
int class, char *name, char *keyname, struct server *server,
|
int class, char *name, char *keyname, struct server *server,
|
||||||
int have_mark, unsigned int mark, int *keycount, int *validatecount)
|
int have_mark, unsigned int mark, int *keycount, int *validatecount)
|
||||||
{
|
{
|
||||||
int first, last, start, new_status;
|
int first, last, start, new_status;
|
||||||
unsigned char *packet = NULL;
|
unsigned char *packet = NULL;
|
||||||
|
|||||||
Reference in New Issue
Block a user