diff options
author | Simon Kelley <simon@thekelleys.org.uk> | 2023-03-31 17:44:02 +0100 |
---|---|---|
committer | Simon Kelley <simon@thekelleys.org.uk> | 2023-03-31 17:44:02 +0100 |
commit | 138e1e2a2d918b37cb0274fe310d53be35acf4cf (patch) | |
tree | afcdf96d213a93f10b836346c3e85ebe2fa4650f | |
parent | 153eeb070b2135cac9e12fc38e944ca8683b74c7 (diff) | |
download | dnsmasq-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.c | 11 | ||||
-rw-r--r-- | src/dnsmasq.h | 12 | ||||
-rw-r--r-- | src/rfc1035.c | 123 |
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); } |