Optimse memory use for arbitrary-RR caching.

RRs 13 bytes or less don't need to allocate block storage.

Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
Simon Kelley 2023-03-31 17:44:02 +01:00 committed by DL6ER
parent bfa44353ae
commit fe007b7507
No known key found for this signature in database
GPG Key ID: 00135ACBD90B28DD
3 changed files with 86 additions and 58 deletions

View File

@ -276,8 +276,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);
@ -796,8 +796,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)
@ -870,7 +870,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)

View File

@ -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;
};

View File

@ -818,56 +818,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)
{
desc = *rrdesc++;
addr.rr.len = (char)ardlen;
if (ardlen != 0)
memcpy(addr.rr.u.data, p1, ardlen);
}
else
{
addr.rr.len = -1;
addr.rr.u.block.datalen = 0;
if (desc == -1)
/* 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
{
/* 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)
{
/* 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))
{
@ -2141,21 +2155,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);
}