diff options
author | Simon Kelley <simon@thekelleys.org.uk> | 2023-04-01 21:35:26 +0100 |
---|---|---|
committer | Simon Kelley <simon@thekelleys.org.uk> | 2023-04-01 21:35:26 +0100 |
commit | a78487a4df8f23f99e8e8d5bb7449b6429bae1fa (patch) | |
tree | cccdb5333516b07be8c285eb23ad66c4d3ca9b02 | |
parent | 3a601d06bdf22f0312177a26f606d9b5f857c1ae (diff) | |
download | dnsmasq-a78487a4df8f23f99e8e8d5bb7449b6429bae1fa.tar.gz |
Use a simpler arrangement for the all_addr union to avoid
the compiler padding it with an extra 8 bytes.
Use the F_KEYTAG flag in a a cache record to discriminate between
an arbitrary RR stored entirely in the addr union and one
which has a point to block storage.
-rw-r--r-- | src/cache.c | 44 | ||||
-rw-r--r-- | src/dnsmasq.h | 24 | ||||
-rw-r--r-- | src/rfc1035.c | 67 |
3 files changed, 84 insertions, 51 deletions
diff --git a/src/cache.c b/src/cache.c index 06ed672..fd10240 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 && crecp->addr.rr.len == -1) - blockdata_free(crecp->addr.rr.u.block.rrdata); + if ((crecp->flags & F_RR) && (crecp->flags & F_KEYTAG)) + blockdata_free(crecp->addr.rrblock.rrdata); #ifdef HAVE_DNSSEC else if (crecp->flags & F_DNSKEY) blockdata_free(crecp->addr.key.keydata); @@ -469,10 +469,20 @@ static struct crec *cache_scan_free(char *name, union all_addr *addr, unsigned s { if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name)) { + int rrmatch = 0; + if (crecp->flags & flags & F_RR) + { + unsigned short rrc = (crecp->flags & F_KEYTAG) ? crecp->addr.rrblock.rrtype : crecp->addr.rrdata.rrtype; + unsigned short rra = (flags & F_KEYTAG) ? addr->rrblock.rrtype : addr->rrdata.rrtype; + + if (rrc == rra) + rrmatch = 1; + } + /* Don't delete DNSSEC in favour of a CNAME, they can co-exist */ - if ((flags & crecp->flags & (F_IPV4 | F_IPV6 | F_RR | F_NXDOMAIN)) || + if ((flags & crecp->flags & (F_IPV4 | F_IPV6 | F_NXDOMAIN)) || (((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))) || - ((crecp->flags & flags & F_RR) && addr->rr.rrtype == crecp->addr.rr.rrtype)) + rrmatch) { if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) return crecp; @@ -795,8 +805,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) && 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); + 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) @@ -869,8 +879,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.len == -1 && !(addr.rr.u.block.rrdata = blockdata_read(fd, addr.rr.u.block.datalen))) + 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) @@ -1796,7 +1806,12 @@ static void dump_cache_entry(struct crec *cache, time_t now) if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache)) a = sanitise(cache_get_cname_target(cache)); else if (cache->flags & F_RR) - sprintf(a, "%s", querystr(NULL, cache->addr.rr.rrtype)); + { + if (cache->flags & F_KEYTAG) + sprintf(a, "%s", querystr(NULL, cache->addr.rrblock.rrtype)); + else + sprintf(a, "%s", querystr(NULL, cache->addr.rrdata.rrtype)); + } #ifdef HAVE_DNSSEC else if (cache->flags & F_DS) { @@ -2052,7 +2067,14 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg, { dest = daemon->addrbuff; - if (flags & F_KEYTAG) + if (flags & F_RR) + { + if (flags & F_KEYTAG) + dest = querystr(NULL, addr->rrblock.rrtype); + else + dest = querystr(NULL, addr->rrdata.rrtype); + } + else if (flags & F_KEYTAG) sprintf(daemon->addrbuff, arg, addr->log.keytag, addr->log.algo, addr->log.digest); else if (flags & F_RCODE) { @@ -2083,8 +2105,6 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg, sprintf(portstring, "#%u", type); } } - else if (flags & F_RR) - dest = querystr(NULL, addr->rr.rrtype); else dest = arg; } diff --git a/src/dnsmasq.h b/src/dnsmasq.h index b6712f0..b7196f0 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -329,21 +329,23 @@ union all_addr { unsigned short keytag, algo, digest, rcode; int ede; } log; - /* for arbitrary RR record. */ + /* for arbitrary RR record stored in block */ struct { -#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; + unsigned short datalen; + struct blockdata *rrdata; + } rrblock; + /* for arbitrary RR record small enough to go in addr. + NOTE: rrblock and rrdata are discriminated by the F_KEYTAG bit + in the cache flags. */ + struct datablock { + unsigned short rrtype; + unsigned char datalen; + char data[]; + } rrdata; }; +#define RR_IMDATALEN (sizeof(union all_addr) - offsetof(struct datablock, data)) struct bogus_addr { int is6, prefix; diff --git a/src/rfc1035.c b/src/rfc1035.c index d4c6a26..ccf88df 100644 --- a/src/rfc1035.c +++ b/src/rfc1035.c @@ -806,20 +806,20 @@ 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; - /* 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) + if (*rrdesc == -1 && ardlen <= (int)RR_IMDATALEN) { - addr.rr.len = (char)ardlen; - if (ardlen != 0) - memcpy(addr.rr.u.data, p1, ardlen); + addr.rrdata.rrtype = aqtype; + addr.rrdata.datalen = (char)ardlen; + if (ardlen != 0) + memcpy(addr.rrdata.data, p1, ardlen); } else { - addr.rr.len = -1; - addr.rr.u.block.datalen = 0; + addr.rrblock.rrtype = aqtype; + addr.rrblock.datalen = 0; + flags |= F_KEYTAG; /* discriminates between rrdata and rrblock */ /* The RR data may include names, and those names may include compression, which will be rendered meaningless when @@ -827,7 +827,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t 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))) + if (!(addr.rrblock.rrdata = blockdata_alloc(NULL, 0))) return 0; do { @@ -836,9 +836,9 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t 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)) + if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, (char *)p1, endrr - p1)) return 0; - addr.rr.u.block.datalen += endrr - p1; + addr.rrblock.datalen += endrr - p1; } else if (desc == 0) { @@ -849,18 +849,18 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t return 2; len = to_wire(name); - if (!blockdata_expand(addr.rr.u.block.rrdata, addr.rr.u.block.datalen, name, len)) + if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, name, len)) return 0; - addr.rr.u.block.datalen += len; + addr.rrblock.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)) + if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, (char *)p1, desc)) return 0; - addr.rr.u.block.datalen += desc; + addr.rrblock.datalen += desc; p1 += desc; } } while (desc != -1); @@ -968,7 +968,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t ttl = cttl; if (flags & F_RR) - addr.rr.rrtype = qtype; + addr.rrdata.rrtype = qtype; newc = cache_insert(name, &addr, C_IN, now, ttl, F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0)); if (newc && cpp) @@ -2103,8 +2103,14 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, do { int flags = crecp->flags; + unsigned short rrtype; + + if (flags & F_KEYTAG) + rrtype = crecp->addr.rrblock.rrtype; + else + rrtype = crecp->addr.rrdata.rrtype; - if ((flags & F_NXDOMAIN) || crecp->addr.rr.rrtype == qtype) + if ((flags & F_NXDOMAIN) || rrtype == qtype) { if (crec_isstale(crecp, now)) { @@ -2127,23 +2133,28 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, if (!dryrun) { - char *rrdata = crecp->addr.rr.u.data; - unsigned short rrlen = crecp->addr.rr.len; - + char *rrdata = NULL; + unsigned short rrlen = 0; + if (!(flags & F_NEG)) { - if (crecp->addr.rr.len == -1) + if (flags & F_KEYTAG) + { + rrlen = crecp->addr.rrblock.datalen; + rrdata = blockdata_retrieve(crecp->addr.rrblock.rrdata, crecp->addr.rrblock.datalen, NULL); + } + else { - rrlen = crecp->addr.rr.u.block.datalen; - rrdata = blockdata_retrieve(crecp->addr.rr.u.block.rrdata, crecp->addr.rr.u.block.datalen, NULL); + rrlen = crecp->addr.rrdata.datalen; + rrdata = crecp->addr.rrdata.data; } - - if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, - crec_ttl(crecp, now), NULL, qtype, C_IN, "t", - rrlen, rrdata)) - anscount++; } + if (!(flags & F_NEG) && add_resource_record(header, limit, &trunc, nameoffset, &ansp, + crec_ttl(crecp, now), NULL, qtype, C_IN, "t", + 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, rrlen, crecp->flags & F_DNSSECOK); |