summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2023-04-01 22:03:49 +0100
committerSimon Kelley <simon@thekelleys.org.uk>2023-04-01 22:03:49 +0100
commitb14aa762ff2a42573b8b9ead85ccfa1f2b938a72 (patch)
tree23486dd971a328e359bbd459c8312203074e23de
parenta78487a4df8f23f99e8e8d5bb7449b6429bae1fa (diff)
downloaddnsmasq-b14aa762ff2a42573b8b9ead85ccfa1f2b938a72.tar.gz
Fix long-term bug in TCP caching code which would lose NXDOMAIN.
A NXDOMAIN answer recieved over TCP by a child process would be correctly sent back to the master process which would then fail to insert it into the cache.
-rw-r--r--src/cache.c109
1 files changed, 57 insertions, 52 deletions
diff --git a/src/cache.c b/src/cache.c
index fd10240..3884d4c 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -800,28 +800,30 @@ void cache_end_insert(void)
read_write(daemon->pipe_to_parent, (unsigned char *)&flags, sizeof(flags), 0);
if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_RR))
- read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), 0);
-
- if (flags & F_RR)
{
- /* A negative RR entry is possible and has no data, obviously. */
- if (!(flags & F_NEG) && (flags & F_KEYTAG))
- blockdata_write(new_chain->addr.rrblock.rrdata, new_chain->addr.rrblock.datalen, daemon->pipe_to_parent);
- }
+ read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), 0);
+
+ if (flags & F_RR)
+ {
+ /* A negative RR entry is possible and has no data, obviously. */
+ if (!(flags & F_NEG) && (flags & F_KEYTAG))
+ blockdata_write(new_chain->addr.rrblock.rrdata, new_chain->addr.rrblock.datalen, daemon->pipe_to_parent);
+ }
#ifdef HAVE_DNSSEC
- if (flags & F_DNSKEY)
- {
- read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
- blockdata_write(new_chain->addr.key.keydata, new_chain->addr.key.keylen, daemon->pipe_to_parent);
- }
- else if (flags & F_DS)
- {
- read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
- /* A negative DS entry is possible and has no data, obviously. */
- if (!(flags & F_NEG))
- blockdata_write(new_chain->addr.ds.keydata, new_chain->addr.ds.keylen, daemon->pipe_to_parent);
- }
+ if (flags & F_DNSKEY)
+ {
+ read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
+ blockdata_write(new_chain->addr.key.keydata, new_chain->addr.key.keylen, daemon->pipe_to_parent);
+ }
+ else if (flags & F_DS)
+ {
+ read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
+ /* A negative DS entry is possible and has no data, obviously. */
+ if (!(flags & F_NEG))
+ blockdata_write(new_chain->addr.ds.keydata, new_chain->addr.ds.keylen, daemon->pipe_to_parent);
+ }
#endif
+ }
}
}
@@ -872,34 +874,7 @@ int cache_recv_insert(time_t now, int fd)
ttl = difftime(ttd, now);
- if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_RR))
- {
- unsigned short class = C_IN;
-
- if (!read_write(fd, (unsigned char *)&addr, sizeof(addr), 1))
- return 0;
-
- if ((flags & F_RR) && !(flags & F_NEG) && (flags & F_KEYTAG)
- && !(addr.rrblock.rrdata = blockdata_read(fd, addr.rrblock.datalen)))
- return 0;
-#ifdef HAVE_DNSSEC
- if (flags & F_DNSKEY)
- {
- if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
- !(addr.key.keydata = blockdata_read(fd, addr.key.keylen)))
- return 0;
- }
- else if (flags & F_DS)
- {
- if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
- (!(flags & F_NEG) && !(addr.key.keydata = blockdata_read(fd, addr.key.keylen))))
- return 0;
- }
-#endif
-
- crecp = really_insert(daemon->namebuff, &addr, class, now, ttl, flags);
- }
- else if (flags & F_CNAME)
+ if (flags & F_CNAME)
{
struct crec *newc = really_insert(daemon->namebuff, NULL, C_IN, now, ttl, flags);
/* This relies on the fact that the target of a CNAME immediately precedes
@@ -907,11 +882,11 @@ int cache_recv_insert(time_t now, int fd)
the order reversal on the new_chain. */
if (newc)
{
- newc->addr.cname.is_name_ptr = 0;
-
- if (!crecp)
- newc->addr.cname.target.cache = NULL;
- else
+ newc->addr.cname.is_name_ptr = 0;
+
+ if (!crecp)
+ newc->addr.cname.target.cache = NULL;
+ else
{
next_uid(crecp);
newc->addr.cname.target.cache = crecp;
@@ -919,6 +894,36 @@ int cache_recv_insert(time_t now, int fd)
}
}
}
+ else
+ {
+ unsigned short class = C_IN;
+
+ if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_RR))
+ {
+ if (!read_write(fd, (unsigned char *)&addr, sizeof(addr), 1))
+ return 0;
+
+ if ((flags & F_RR) && !(flags & F_NEG) && (flags & F_KEYTAG)
+ && !(addr.rrblock.rrdata = blockdata_read(fd, addr.rrblock.datalen)))
+ return 0;
+#ifdef HAVE_DNSSEC
+ if (flags & F_DNSKEY)
+ {
+ if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
+ !(addr.key.keydata = blockdata_read(fd, addr.key.keylen)))
+ return 0;
+ }
+ else if (flags & F_DS)
+ {
+ if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
+ (!(flags & F_NEG) && !(addr.key.keydata = blockdata_read(fd, addr.key.keylen))))
+ return 0;
+ }
+#endif
+ }
+
+ crecp = really_insert(daemon->namebuff, &addr, class, now, ttl, flags);
+ }
}
}