From 059aded0700309308dafd9720b0313ce52f6e189 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Thu, 12 Nov 2020 23:09:15 +0000 Subject: Optimse RR digest calculation in DNSSEC. If an RR is of a type which doesn't need canonicalisation, bypass the relatively slow canonicalisation code, and insert it direct into the digest. --- src/dnssec.c | 82 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 33 deletions(-) --- a/src/dnssec.c +++ b/src/dnssec.c @@ -559,7 +559,7 @@ static int validate_rrset(time_t now, st hash->update(ctx, (unsigned int)wire_len, (unsigned char*)keyname); from_wire(keyname); -#define RRBUFLEN 300 /* Most RRs are smaller than this. */ +#define RRBUFLEN 128 /* Most RRs are smaller than this. */ for (i = 0; i < rrsetidx; ++i) { @@ -597,50 +597,66 @@ static int validate_rrset(time_t now, st hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name_start); hash->update(ctx, 4, p); /* class and type */ hash->update(ctx, 4, (unsigned char *)&nsigttl); - - p += 8; /* skip class, type, ttl */ + + p += 8; /* skip type, class, ttl */ GETSHORT(rdlen, p); if (!CHECK_LEN(header, p, plen, rdlen)) return STAT_BOGUS; - - /* canonicalise rdata and calculate length of same, use - name buffer as workspace for get_rdata. */ - state.ip = p; - state.op = NULL; - state.desc = rr_desc; - state.buff = name; - state.end = p + rdlen; - - for (j = 0; get_rdata(header, plen, &state); j++) - if (j < RRBUFLEN) - rrbuf[j] = *state.op; - len = htons((u16)j); - hash->update(ctx, 2, (unsigned char *)&len); - - /* If the RR is shorter than RRBUFLEN (most of them, in practice) - then we can just digest it now. If it exceeds RRBUFLEN we have to - go back to the start and do it in chunks. */ - if (j >= RRBUFLEN) + /* Optimisation for RR types which need no cannonicalisation. + This includes DNSKEY DS NSEC and NSEC3, which are also long, so + it saves lots of calls to get_rdata, and avoids the pessimal + segmented insertion, even with a small rrbuf[]. + + If canonicalisation is not needed, a simple insertion into the hash works. + */ + if (*rr_desc == (u16)-1) + { + len = htons(rdlen); + hash->update(ctx, 2, (unsigned char *)&len); + hash->update(ctx, rdlen, p); + } + else { + /* canonicalise rdata and calculate length of same, use + name buffer as workspace for get_rdata. */ state.ip = p; state.op = NULL; state.desc = rr_desc; - + state.buff = name; + state.end = p + rdlen; + for (j = 0; get_rdata(header, plen, &state); j++) + if (j < RRBUFLEN) + rrbuf[j] = *state.op; + + len = htons((u16)j); + hash->update(ctx, 2, (unsigned char *)&len); + + /* If the RR is shorter than RRBUFLEN (most of them, in practice) + then we can just digest it now. If it exceeds RRBUFLEN we have to + go back to the start and do it in chunks. */ + if (j >= RRBUFLEN) { - rrbuf[j] = *state.op; - - if (j == RRBUFLEN - 1) - { - hash->update(ctx, RRBUFLEN, rrbuf); - j = -1; - } + state.ip = p; + state.op = NULL; + state.desc = rr_desc; + + for (j = 0; get_rdata(header, plen, &state); j++) + { + rrbuf[j] = *state.op; + + if (j == RRBUFLEN - 1) + { + hash->update(ctx, RRBUFLEN, rrbuf); + j = -1; + } + } } + + if (j != 0) + hash->update(ctx, j, rrbuf); } - - if (j != 0) - hash->update(ctx, j, rrbuf); } hash->digest(ctx, hash->digest_size, digest);