Cache SOAs and return them with cached NXDOMAIN/NODATA replies.

Now we can cache arbirary RRs, give more correct answers when
replying negative answers from cache.

To implement this needed the DNS-doctor code to be untangled from
find_soa(), so it should be under suspicion for any regresssions
in that department.
This commit is contained in:
Simon Kelley
2024-02-01 23:37:11 +00:00
parent db07664f2a
commit 12ddb2a4b9
5 changed files with 820 additions and 732 deletions

View File

@@ -131,19 +131,11 @@ int main (int argc, char **argv)
'.' or NAME_ESCAPE then all would have to be escaped, so the
presentation format would be twice as long as the spec. */
daemon->keyname = safe_malloc((MAXDNAME * 2) + 1);
daemon->workspacename = safe_malloc((MAXDNAME * 2) + 1);
/* one char flag per possible RR in answer section (may get extended). */
daemon->rr_status_sz = 64;
daemon->rr_status = safe_malloc(sizeof(*daemon->rr_status) * daemon->rr_status_sz);
}
#endif
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
/* CONNTRACK UBUS code uses this buffer, so if not allocated above,
we need to allocate it here. */
if (option_bool(OPT_CMARK_ALST_EN) && !daemon->workspacename)
daemon->workspacename = safe_malloc((MAXDNAME * 2) + 1);
#endif
#ifdef HAVE_DHCP
if (!daemon->lease_file)

View File

@@ -341,7 +341,7 @@ union all_addr {
in the cache flags. */
struct datablock {
unsigned short rrtype;
unsigned char datalen;
unsigned char datalen; /* also length of SOA in negative records. */
char data[];
} rrdata;
};
@@ -1233,10 +1233,7 @@ extern struct daemon {
char *packet; /* packet buffer */
int packet_buff_sz; /* size of above */
char *namebuff; /* MAXDNAME size buffer */
#if (defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)) || defined(HAVE_DNSSEC)
/* CONNTRACK UBUS code uses this buffer, as well as DNSSEC code. */
char *workspacename;
#endif
#ifdef HAVE_DNSSEC
char *keyname; /* MAXDNAME size buffer */
unsigned long *rr_status; /* ceiling in TTL from DNSSEC or zero for insecure */
@@ -1376,6 +1373,7 @@ int is_name_synthetic(int flags, char *name, union all_addr *addr);
int is_rev_synth(int flag, union all_addr *addr, char *name);
/* rfc1035.c */
int do_doctor(struct dns_header *header, size_t qlen);
int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
char *name, int isExtract, int extrabytes);
unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes);
@@ -1386,7 +1384,7 @@ unsigned int extract_request(struct dns_header *header, size_t qlen,
void setup_reply(struct dns_header *header, unsigned int flags, int ede);
int extract_addresses(struct dns_header *header, size_t qlen, char *name,
time_t now, struct ipsets *ipsets, struct ipsets *nftsets, int is_sign,
int check_rebind, int no_cache_dnssec, int secure, int *doctored);
int check_rebind, int no_cache_dnssec, int secure);
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
void report_addresses(struct dns_header *header, size_t len, u32 mark);
#endif

View File

@@ -782,8 +782,13 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
server->flags |= SERV_WARNED_RECURSIVE;
}
if (daemon->bogus_addr && rcode != NXDOMAIN &&
check_for_bogus_wildcard(header, n, daemon->namebuff, now))
if (header->hb3 & HB3_TC)
{
log_query(F_UPSTREAM, NULL, NULL, "truncated", 0);
munged = 1;
}
else if (daemon->bogus_addr && rcode != NXDOMAIN &&
check_for_bogus_wildcard(header, n, daemon->namebuff, now))
{
munged = 1;
SET_RCODE(header, NXDOMAIN);
@@ -793,8 +798,6 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
}
else
{
int doctored = 0;
if (rcode == NXDOMAIN &&
extract_request(header, n, daemon->namebuff, NULL))
{
@@ -810,8 +813,11 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
cache_secure = 0;
}
}
if (do_doctor(header, n))
cache_secure = 0;
switch (extract_addresses(header, n, daemon->namebuff, now, ipsets, nftsets, is_sign, check_rebind, no_cache, cache_secure, &doctored))
switch (extract_addresses(header, n, daemon->namebuff, now, ipsets, nftsets, is_sign, check_rebind, no_cache, cache_secure))
{
case 1:
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
@@ -831,9 +837,6 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
if (rcode == NOERROR && rrfilter(header, &n, RRFILTER_CONF) > 0)
ede = EDE_FILTERED;
if (doctored)
cache_secure = 0;
}
#ifdef HAVE_DNSSEC
@@ -864,7 +867,6 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
header->ancount = htons(0);
header->nscount = htons(0);
header->arcount = htons(0);
header->hb3 &= ~HB3_TC;
}
/* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide

View File

@@ -5844,6 +5844,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
daemon = opt_malloc(sizeof(struct daemon));
memset(daemon, 0, sizeof(struct daemon));
daemon->namebuff = buff;
daemon->workspacename = safe_malloc((MAXDNAME * 2) + 1);
daemon->addrbuff = safe_malloc(ADDRSTRLEN);
/* Set defaults - everything else is zero or NULL */

File diff suppressed because it is too large Load Diff