diff --git a/src/dnssec.c b/src/dnssec.c index 414b213..4eb6e53 100644 --- a/src/dnssec.c +++ b/src/dnssec.c @@ -1243,15 +1243,23 @@ static int hostname_cmp(const char *a, const char *b) } } +static int check_type_bitmap(unsigned char *p, int type) +{ + int offset = (type & 0xff) >> 3; + + if (p[0] == type >> 8 && p[1] > offset && (p[offset + 2] & (0x80 >> (type & 0x07)))) + return 1; + + return 0; +} + /* returns 0 on success, or DNSSEC_FAIL_* value on failure. */ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, unsigned char **labels, int nsec_count, char *workspace1_in, char *workspace2, char *name, int type, int *nons) { int i, rc, rdlen; unsigned char *p, *psave; - int offset = (type & 0xff) >> 3; - int mask = 0x80 >> (type & 0x07); - + if (nons) *nons = 1; @@ -1295,17 +1303,6 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi /* rdlen is now length of type map, and p points to it packet checked to be as long as rdlen implies in prove_non_existence() */ - /* check that the first typemap is complete. */ - if (rdlen < 2 || rdlen < p[1] + 2) - return DNSSEC_FAIL_BADPACKET; - - /* RFC 6672 5.3.4.1. */ -#define DNAME_OFFSET (T_DNAME >> 3) -#define DNAME_MASK (0x80 >> (T_DNAME & 0x07)) - if (p[0] == 0 && (p[1] >= DNAME_OFFSET + 1) && (p[2 + DNAME_OFFSET] & DNAME_MASK) != 0 && - hostname_issubdomain(name, workspace1) == 1) - return DNSSEC_FAIL_NONSEC; - rc = hostname_cmp(workspace1, name); if (rc == 0) @@ -1314,42 +1311,37 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi if (type == T_NSEC || type == T_RRSIG) return 0; - /* NSEC with the same name as the RR we're testing, check - that the type in question doesn't appear in the type map */ - if (p[0] == 0 && p[1] >= 1) - { - /* If we can prove that there's no NS record, return that information. */ - if (nons && (p[2] & (0x80 >> T_NS)) != 0) - *nons = 0; - - /* A CNAME answer would also be valid, so if there's a CNAME is should - have been returned. */ - if ((p[2] & (0x80 >> T_CNAME)) != 0) - return DNSSEC_FAIL_NONSEC; - - /* If the SOA bit is set for a DS record, then we have the - DS from the wrong side of the delegation. For the root DS, - this is expected. */ - if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0) - return DNSSEC_FAIL_NONSEC; - } - while (rdlen > 0) { if (rdlen < 2 || rdlen < p[1] + 2) return DNSSEC_FAIL_BADPACKET; - if (p[0] == type >> 8) - { - /* Does the NSEC say our type exists? */ - if (offset < p[1] && (p[offset+2] & mask) != 0) - return DNSSEC_FAIL_NONSEC; - - break; /* finished checking */ - } + /* NSEC with the same name as the RR we're testing, check + that the type in question doesn't appear in the type map */ + if (check_type_bitmap(p, type)) + return DNSSEC_FAIL_NONSEC; + + /* If we can prove that there's no NS record, return that information. */ + if (nons && check_type_bitmap(p, T_NS)) + *nons = 0; - rdlen -= p[1]; - p += p[1]; + /* A CNAME answer would also be valid, so if there's a CNAME it should + have been returned. */ + if (check_type_bitmap(p, T_CNAME)) + return DNSSEC_FAIL_NONSEC; + + /* If the SOA bit is set for a DS record, then we have the + DS from the wrong side of the delegation. For the root DS, + this is expected. */ + if (name_labels != 0 && check_type_bitmap(p, T_DS)) + return DNSSEC_FAIL_NONSEC; + + /* RFC 6672 5.3.4.1. */ + if (check_type_bitmap(p, T_DNAME) && hostname_issubdomain(name, workspace1) == 1) + return DNSSEC_FAIL_NONSEC; + + rdlen -= p[1] + 2; + p += p[1] + 2; } return 0; @@ -1473,50 +1465,35 @@ static int check_nsec3_coverage(struct dns_header *header, size_t plen, int dige we just need to check the type map. p points to the RR data for the record. Note we have packet length up to rdlen bytes checked. */ - int offset = (type & 0xff) >> 3; - int mask = 0x80 >> (type & 0x07); - p += hash_len; /* skip next-domain hash */ rdlen -= p - psave; - - /* check that the first typemap is complete. */ - if (rdlen < 2 || rdlen < p[1] + 2) - return DNSSEC_FAIL_BADPACKET; - if (p[0] == 0 && p[1] >= 1) - { - /* If we can prove that there's no NS record, return that information. */ - if (nons && (p[2] & (0x80 >> T_NS)) != 0) - *nons = 0; - - /* A CNAME answer would also be valid, so if there's a CNAME is should - have been returned. */ - if ((p[2] & (0x80 >> T_CNAME)) != 0) - return 0; - - /* If the SOA bit is set for a DS record, then we have the - DS from the wrong side of the delegation. For the root DS, - this is expected. */ - if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0) - return 0; - } - while (rdlen > 0) { if (rdlen < 2 || rdlen < p[1] + 2) - return DNSSEC_FAIL_BADPACKET; + return 0; + + /* Does the NSEC3 say our type exists? */ + if (check_type_bitmap(p, type)) + return 0; - if (p[0] == type >> 8) - { - /* Does the NSEC3 say our type exists? */ - if (offset < p[1] && (p[offset+2] & mask) != 0) - return 0; - - break; /* finished checking */ - } - - rdlen -= p[1]; - p += p[1]; + /* If we can prove that there's no NS record, return that information. */ + if (nons && check_type_bitmap(p, T_NS)) + *nons = 0; + + /* A CNAME answer would also be valid, so if there's a CNAME it should + have been returned. */ + if (check_type_bitmap(p, T_CNAME)) + return DNSSEC_FAIL_NONSEC; + + /* If the SOA bit is set for a DS record, then we have the + DS from the wrong side of the delegation. For the root DS, + this is expected. */ + if (name_labels != 0 && check_type_bitmap(p, T_DS)) + return 0; + + rdlen -= p[1] + 2; + p += p[1] + 2; } return 1;