summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2023-03-31 17:44:02 +0100
committerSimon Kelley <simon@thekelleys.org.uk>2023-03-31 17:44:02 +0100
commit138e1e2a2d918b37cb0274fe310d53be35acf4cf (patch)
treeafcdf96d213a93f10b836346c3e85ebe2fa4650f
parent153eeb070b2135cac9e12fc38e944ca8683b74c7 (diff)
downloaddnsmasq-138e1e2a2d918b37cb0274fe310d53be35acf4cf.tar.gz
Optimse memory use for arbitrary-RR caching.
RRs 13 bytes or less don't need to allocate block storage.
-rw-r--r--src/cache.c11
-rw-r--r--src/dnsmasq.h12
-rw-r--r--src/rfc1035.c123
3 files changed, 87 insertions, 59 deletions
diff --git a/src/cache.c b/src/cache.c
index f49def4..64e19cb 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -275,8 +275,8 @@ static void cache_blockdata_free(struct crec *crecp)
{
if (!(crecp->flags & F_NEG))
{
- if (crecp->flags & F_RR)
- blockdata_free(crecp->addr.rr.rrdata);
+ if (crecp->flags & F_RR && crecp->addr.rr.len == -1)
+ blockdata_free(crecp->addr.rr.u.block.rrdata);
#ifdef HAVE_DNSSEC
else if (crecp->flags & F_DNSKEY)
blockdata_free(crecp->addr.key.keydata);
@@ -795,8 +795,8 @@ void cache_end_insert(void)
if (flags & F_RR)
{
/* A negative RR entry is possible and has no data, obviously. */
- if (!(flags & F_NEG))
- blockdata_write(new_chain->addr.rr.rrdata, new_chain->addr.rr.datalen, daemon->pipe_to_parent);
+ if (!(flags & F_NEG) && new_chain->addr.rr.len == -1)
+ blockdata_write(new_chain->addr.rr.u.block.rrdata, new_chain->addr.rr.u.block.datalen, daemon->pipe_to_parent);
}
#ifdef HAVE_DNSSEC
if (flags & F_DNSKEY)
@@ -869,7 +869,8 @@ int cache_recv_insert(time_t now, int fd)
if (!read_write(fd, (unsigned char *)&addr, sizeof(addr), 1))
return 0;
- if ((flags & F_RR) && !(flags & F_NEG) && !(addr.rr.rrdata = blockdata_read(fd, addr.rr.datalen)))
+ if ((flags & F_RR) && !(flags & F_NEG) &&
+ new_chain->addr.rr.len == -1 && !(addr.rr.u.block.rrdata = blockdata_read(fd, addr.rr.u.block.datalen)))
return 0;
#ifdef HAVE_DNSSEC
if (flags & F_DNSKEY)
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 9ee5e39..b6712f0 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -331,8 +331,16 @@ union all_addr {
} log;
/* for arbitrary RR record. */
struct {
- struct blockdata *rrdata;
- unsigned short rrtype, datalen;
+#define RR_IMDATALEN 13 /* 16 - sizeof(short) - sizeof (char) */
+ unsigned short rrtype;
+ char len; /* -1 for blockdata */
+ union {
+ char data[RR_IMDATALEN];
+ struct {
+ unsigned short datalen;
+ struct blockdata *rrdata;
+ } block;
+ } u;
} rr;
};
diff --git a/src/rfc1035.c b/src/rfc1035.c
index 8c8b73a..d4c6a26 100644
--- a/src/rfc1035.c
+++ b/src/rfc1035.c
@@ -805,56 +805,70 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
if (!CHECK_LEN(header, p1, qlen, ardlen))
return 2; /* bad packet */
+
addr.rr.rrtype = aqtype;
- addr.rr.datalen = 0;
-
- /* The RR data may include names, and those names may include
- compression, which will be rendered meaningless when
- copied into another packet.
- Here we go through a description of the packet type to
- find the names, and extract them to a c-string and then
- re-encode them to standalone DNS format without compression. */
- if (!(addr.rr.rrdata = blockdata_alloc(NULL, 0)))
- return 0;
- do
+
+ /* If the data has no names and is small enough, store it in
+ the crec address field rather than allocate a block. */
+ if (*rrdesc == -1 && ardlen <= RR_IMDATALEN)
+ {
+ addr.rr.len = (char)ardlen;
+ if (ardlen != 0)
+ memcpy(addr.rr.u.data, p1, ardlen);
+ }
+ else
{
- desc = *rrdesc++;
+ addr.rr.len = -1;
+ addr.rr.u.block.datalen = 0;
- if (desc == -1)
- {
- /* Copy the rest of the RR and end. */
- if (!blockdata_expand(addr.rr.rrdata, addr.rr.datalen, (char *)p1, endrr - p1))
- return 0;
- addr.rr.datalen += endrr - p1;
- }
- else if (desc == 0)
+ /* The RR data may include names, and those names may include
+ compression, which will be rendered meaningless when
+ copied into another packet.
+ Here we go through a description of the packet type to
+ find the names, and extract them to a c-string and then
+ re-encode them to standalone DNS format without compression. */
+ if (!(addr.rr.u.block.rrdata = blockdata_alloc(NULL, 0)))
+ return 0;
+ do
{
- /* Name, extract it then re-encode. */
- int len;
-
- if (!extract_name(header, qlen, &p1, name, 1, 0))
- return 2;
-
- len = to_wire(name);
- if (!blockdata_expand(addr.rr.rrdata, addr.rr.datalen, name, len))
- return 0;
- addr.rr.datalen += len;
- }
- else
- {
- /* desc is length of a block of data to be used as-is */
- if (desc > endrr - p1)
- desc = endrr - p1;
- if (!blockdata_expand(addr.rr.rrdata, addr.rr.datalen, (char *)p1, desc))
- return 0;
- addr.rr.datalen += desc;
- p1 += desc;
- }
- } while (desc != -1);
-
- /* we overwrote the original name, so get it back here. */
- if (!extract_name(header, qlen, &tmp, name, 1, 0))
- return 2;
+ desc = *rrdesc++;
+
+ if (desc == -1)
+ {
+ /* Copy the rest of the RR and end. */
+ if (!blockdata_expand(addr.rr.u.block.rrdata, addr.rr.u.block.datalen, (char *)p1, endrr - p1))
+ return 0;
+ addr.rr.u.block.datalen += endrr - p1;
+ }
+ else if (desc == 0)
+ {
+ /* Name, extract it then re-encode. */
+ int len;
+
+ if (!extract_name(header, qlen, &p1, name, 1, 0))
+ return 2;
+
+ len = to_wire(name);
+ if (!blockdata_expand(addr.rr.u.block.rrdata, addr.rr.u.block.datalen, name, len))
+ return 0;
+ addr.rr.u.block.datalen += len;
+ }
+ else
+ {
+ /* desc is length of a block of data to be used as-is */
+ if (desc > endrr - p1)
+ desc = endrr - p1;
+ if (!blockdata_expand(addr.rr.u.block.rrdata, addr.rr.u.block.datalen, (char *)p1, desc))
+ return 0;
+ addr.rr.u.block.datalen += desc;
+ p1 += desc;
+ }
+ } while (desc != -1);
+
+ /* we overwrote the original name, so get it back here. */
+ if (!extract_name(header, qlen, &tmp, name, 1, 0))
+ return 2;
+ }
}
else if (flags & (F_IPV4 | F_IPV6))
{
@@ -2113,21 +2127,26 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (!dryrun)
{
- char *rrdata = NULL;
-
+ char *rrdata = crecp->addr.rr.u.data;
+ unsigned short rrlen = crecp->addr.rr.len;
+
if (!(flags & F_NEG))
{
- rrdata = blockdata_retrieve(crecp->addr.rr.rrdata, crecp->addr.rr.datalen, NULL);
-
+ if (crecp->addr.rr.len == -1)
+ {
+ rrlen = crecp->addr.rr.u.block.datalen;
+ rrdata = blockdata_retrieve(crecp->addr.rr.u.block.rrdata, crecp->addr.rr.u.block.datalen, NULL);
+ }
+
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), NULL, qtype, C_IN, "t",
- crecp->addr.rr.datalen, rrdata))
+ rrlen, rrdata))
anscount++;
}
/* log after cache insertion as log_txt mangles rrdata */
if (qtype == T_TXT && !(crecp->flags & F_NEG))
- log_txt(name, (unsigned char *)rrdata, crecp->addr.rr.datalen, crecp->flags & F_DNSSECOK);
+ log_txt(name, (unsigned char *)rrdata, rrlen, crecp->flags & F_DNSSECOK);
else
log_query(flags, name, &crecp->addr, NULL, 0);
}