mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
Mass edit of INSECURE->BOGUS returns for server failure/bad input.
This commit is contained in:
157
src/dnssec.c
157
src/dnssec.c
@@ -592,8 +592,8 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
|
|||||||
STAT_SECURE if it validates.
|
STAT_SECURE if it validates.
|
||||||
STAT_SECURE_WILDCARD if it validates and is the result of wildcard expansion.
|
STAT_SECURE_WILDCARD if it validates and is the result of wildcard expansion.
|
||||||
STAT_NO_SIG no RRsigs found.
|
STAT_NO_SIG no RRsigs found.
|
||||||
STAT_INSECURE can't validate (no RRSIG, bad packet).
|
STAT_INSECURE RRset empty.
|
||||||
STAT_BOGUS signature is wrong.
|
STAT_BOGUS signature is wrong, bad packet.
|
||||||
STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname)
|
STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname)
|
||||||
|
|
||||||
if key is non-NULL, use that key, which has the algo and tag given in the params of those names,
|
if key is non-NULL, use that key, which has the algo and tag given in the params of those names,
|
||||||
@@ -614,7 +614,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
|||||||
u16 *rr_desc = get_desc(type);
|
u16 *rr_desc = get_desc(type);
|
||||||
|
|
||||||
if (!(p = skip_questions(header, plen)))
|
if (!(p = skip_questions(header, plen)))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
name_labels = count_labels(name); /* For 4035 5.3.2 check */
|
name_labels = count_labels(name); /* For 4035 5.3.2 check */
|
||||||
|
|
||||||
@@ -628,7 +628,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
|||||||
pstart = p;
|
pstart = p;
|
||||||
|
|
||||||
if (!(res = extract_name(header, plen, &p, name, 0, 10)))
|
if (!(res = extract_name(header, plen, &p, name, 0, 10)))
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
|
|
||||||
GETSHORT(stype, p);
|
GETSHORT(stype, p);
|
||||||
GETSHORT(sclass, p);
|
GETSHORT(sclass, p);
|
||||||
@@ -639,14 +639,14 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
|||||||
GETSHORT(rdlen, p);
|
GETSHORT(rdlen, p);
|
||||||
|
|
||||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
if (res == 1 && sclass == class)
|
if (res == 1 && sclass == class)
|
||||||
{
|
{
|
||||||
if (stype == type)
|
if (stype == type)
|
||||||
{
|
{
|
||||||
if (!expand_workspace(&rrset, &rrset_sz, rrsetidx))
|
if (!expand_workspace(&rrset, &rrset_sz, rrsetidx))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
rrset[rrsetidx++] = pstart;
|
rrset[rrsetidx++] = pstart;
|
||||||
}
|
}
|
||||||
@@ -654,14 +654,14 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
|||||||
if (stype == T_RRSIG)
|
if (stype == T_RRSIG)
|
||||||
{
|
{
|
||||||
if (rdlen < 18)
|
if (rdlen < 18)
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
|
|
||||||
GETSHORT(type_covered, p);
|
GETSHORT(type_covered, p);
|
||||||
|
|
||||||
if (type_covered == type)
|
if (type_covered == type)
|
||||||
{
|
{
|
||||||
if (!expand_workspace(&sigs, &sig_sz, sigidx))
|
if (!expand_workspace(&sigs, &sig_sz, sigidx))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
sigs[sigidx++] = pdata;
|
sigs[sigidx++] = pdata;
|
||||||
}
|
}
|
||||||
@@ -671,7 +671,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!ADD_RDLEN(header, p, plen, rdlen))
|
if (!ADD_RDLEN(header, p, plen, rdlen))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RRset empty */
|
/* RRset empty */
|
||||||
@@ -710,7 +710,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
|||||||
GETSHORT(key_tag, p);
|
GETSHORT(key_tag, p);
|
||||||
|
|
||||||
if (!extract_name(header, plen, &p, keyname, 1, 0))
|
if (!extract_name(header, plen, &p, keyname, 1, 0))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
/* RFC 4035 5.3.1 says that the Signer's Name field MUST equal
|
/* RFC 4035 5.3.1 says that the Signer's Name field MUST equal
|
||||||
the name of the zone containing the RRset. We can't tell that
|
the name of the zone containing the RRset. We can't tell that
|
||||||
@@ -765,7 +765,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
|||||||
|
|
||||||
p = rrset[i];
|
p = rrset[i];
|
||||||
if (!extract_name(header, plen, &p, name, 1, 10))
|
if (!extract_name(header, plen, &p, name, 1, 10))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
name_start = name;
|
name_start = name;
|
||||||
|
|
||||||
@@ -788,7 +788,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
|||||||
p += 8; /* skip class, type, ttl */
|
p += 8; /* skip class, type, ttl */
|
||||||
GETSHORT(rdlen, p);
|
GETSHORT(rdlen, p);
|
||||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
end = p + rdlen;
|
end = p + rdlen;
|
||||||
|
|
||||||
@@ -839,10 +839,10 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
|||||||
/* The DNS packet is expected to contain the answer to a DNSKEY query.
|
/* The DNS packet is expected to contain the answer to a DNSKEY query.
|
||||||
Put all DNSKEYs in the answer which are valid into the cache.
|
Put all DNSKEYs in the answer which are valid into the cache.
|
||||||
return codes:
|
return codes:
|
||||||
STAT_INSECURE bad packet, no DNSKEYs in reply.
|
STAT_INSECURE No DNSKEYs in reply.
|
||||||
STAT_SECURE At least one valid DNSKEY found and in cache.
|
STAT_SECURE At least one valid DNSKEY found and in cache.
|
||||||
STAT_BOGUS No DNSKEYs found, which can be validated with DS,
|
STAT_BOGUS No DNSKEYs found, which can be validated with DS,
|
||||||
or self-sign for DNSKEY RRset is not valid.
|
or self-sign for DNSKEY RRset is not valid, bad packet.
|
||||||
STAT_NEED_DS DS records to validate a key not found, name in keyname
|
STAT_NEED_DS DS records to validate a key not found, name in keyname
|
||||||
*/
|
*/
|
||||||
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
|
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
|
||||||
@@ -855,13 +855,16 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
|
|
||||||
if (ntohs(header->qdcount) != 1 ||
|
if (ntohs(header->qdcount) != 1 ||
|
||||||
!extract_name(header, plen, &p, name, 1, 4))
|
!extract_name(header, plen, &p, name, 1, 4))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
GETSHORT(qtype, p);
|
GETSHORT(qtype, p);
|
||||||
GETSHORT(qclass, p);
|
GETSHORT(qclass, p);
|
||||||
|
|
||||||
if (qtype != T_DNSKEY || qclass != class || ntohs(header->ancount) == 0)
|
if (qtype != T_DNSKEY || qclass != class)
|
||||||
return STAT_BOGUS;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
|
if (ntohs(header->ancount) == 0)
|
||||||
|
return STAT_INSECURE;
|
||||||
|
|
||||||
/* See if we have cached a DS record which validates this key */
|
/* See if we have cached a DS record which validates this key */
|
||||||
if (!(crecp = cache_find_by_name(NULL, name, now, F_DS)))
|
if (!(crecp = cache_find_by_name(NULL, name, now, F_DS)))
|
||||||
@@ -879,7 +882,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
{
|
{
|
||||||
/* Ensure we have type, class TTL and length */
|
/* Ensure we have type, class TTL and length */
|
||||||
if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
|
if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
|
|
||||||
GETSHORT(qtype, p);
|
GETSHORT(qtype, p);
|
||||||
GETSHORT(qclass, p);
|
GETSHORT(qclass, p);
|
||||||
@@ -887,7 +890,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
GETSHORT(rdlen, p);
|
GETSHORT(rdlen, p);
|
||||||
|
|
||||||
if (!CHECK_LEN(header, p, plen, rdlen) || rdlen < 4)
|
if (!CHECK_LEN(header, p, plen, rdlen) || rdlen < 4)
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
|
|
||||||
if (qclass != class || qtype != T_DNSKEY || rc == 2)
|
if (qclass != class || qtype != T_DNSKEY || rc == 2)
|
||||||
{
|
{
|
||||||
@@ -914,7 +917,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
{
|
{
|
||||||
if (key)
|
if (key)
|
||||||
blockdata_free(key);
|
blockdata_free(key);
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No zone key flag or malloc failure */
|
/* No zone key flag or malloc failure */
|
||||||
@@ -976,7 +979,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
GETSHORT(rdlen, p);
|
GETSHORT(rdlen, p);
|
||||||
|
|
||||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
|
|
||||||
if (qclass == class && rc == 1)
|
if (qclass == class && rc == 1)
|
||||||
{
|
{
|
||||||
@@ -985,7 +988,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
if (qtype == T_DNSKEY)
|
if (qtype == T_DNSKEY)
|
||||||
{
|
{
|
||||||
if (rdlen < 4)
|
if (rdlen < 4)
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
|
|
||||||
GETSHORT(flags, p);
|
GETSHORT(flags, p);
|
||||||
if (*p++ != 3)
|
if (*p++ != 3)
|
||||||
@@ -1017,7 +1020,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
{
|
{
|
||||||
/* RRSIG, cache if covers DNSKEY RRset */
|
/* RRSIG, cache if covers DNSKEY RRset */
|
||||||
if (rdlen < 18)
|
if (rdlen < 18)
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
|
|
||||||
GETSHORT(type_covered, p);
|
GETSHORT(type_covered, p);
|
||||||
|
|
||||||
@@ -1049,7 +1052,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!ADD_RDLEN(header, p, plen, rdlen))
|
if (!ADD_RDLEN(header, p, plen, rdlen))
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* commit cache insert. */
|
/* commit cache insert. */
|
||||||
@@ -1064,10 +1067,10 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
/* The DNS packet is expected to contain the answer to a DS query
|
/* The DNS packet is expected to contain the answer to a DS query
|
||||||
Put all DSs in the answer which are valid into the cache.
|
Put all DSs in the answer which are valid into the cache.
|
||||||
return codes:
|
return codes:
|
||||||
STAT_INSECURE bad packet, no DS in reply, proven no DS in reply.
|
STAT_INSECURE no DS in reply or not signed.
|
||||||
STAT_SECURE At least one valid DS found and in cache.
|
STAT_SECURE At least one valid DS found and in cache.
|
||||||
STAT_NO_DS It's proved there's no DS here.
|
STAT_NO_DS It's proved there's no DS here.
|
||||||
STAT_BOGUS At least one DS found, which fails validation.
|
STAT_BOGUS At least one DS found, which fails validation, bad packet.
|
||||||
STAT_NEED_DNSKEY DNSKEY records to validate a DS not found, name in keyname
|
STAT_NEED_DNSKEY DNSKEY records to validate a DS not found, name in keyname
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -1078,7 +1081,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
|||||||
|
|
||||||
if (ntohs(header->qdcount) != 1 ||
|
if (ntohs(header->qdcount) != 1 ||
|
||||||
!(p = skip_name(p, header, plen, 4)))
|
!(p = skip_name(p, header, plen, 4)))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
GETSHORT(qtype, p);
|
GETSHORT(qtype, p);
|
||||||
GETSHORT(qclass, p);
|
GETSHORT(qclass, p);
|
||||||
@@ -1096,7 +1099,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
|||||||
p += 4; /* qtype, qclass */
|
p += 4; /* qtype, qclass */
|
||||||
|
|
||||||
if (!(p = skip_section(p, ntohs(header->ancount), header, plen)))
|
if (!(p = skip_section(p, ntohs(header->ancount), header, plen)))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
if (val == STAT_BOGUS)
|
if (val == STAT_BOGUS)
|
||||||
log_query(F_UPSTREAM, name, NULL, "BOGUS DS");
|
log_query(F_UPSTREAM, name, NULL, "BOGUS DS");
|
||||||
@@ -1116,7 +1119,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
|||||||
for (i = ntohs(header->nscount); i != 0; i--)
|
for (i = ntohs(header->nscount); i != 0; i--)
|
||||||
{
|
{
|
||||||
if (!(p = skip_name(p, header, plen, 0)))
|
if (!(p = skip_name(p, header, plen, 0)))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
GETSHORT(qtype, p);
|
GETSHORT(qtype, p);
|
||||||
GETSHORT(qclass, p);
|
GETSHORT(qclass, p);
|
||||||
@@ -1124,7 +1127,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
|||||||
GETSHORT(rdlen, p);
|
GETSHORT(rdlen, p);
|
||||||
|
|
||||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
|
|
||||||
if (qclass != class || qtype != T_SOA)
|
if (qclass != class || qtype != T_SOA)
|
||||||
{
|
{
|
||||||
@@ -1137,10 +1140,10 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
|||||||
|
|
||||||
/* MNAME */
|
/* MNAME */
|
||||||
if (!(p = skip_name(p, header, plen, 0)))
|
if (!(p = skip_name(p, header, plen, 0)))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
/* RNAME */
|
/* RNAME */
|
||||||
if (!(p = skip_name(p, header, plen, 20)))
|
if (!(p = skip_name(p, header, plen, 20)))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
p += 16; /* SERIAL REFRESH RETRY EXPIRE */
|
p += 16; /* SERIAL REFRESH RETRY EXPIRE */
|
||||||
|
|
||||||
GETLONG(ttl, p); /* minTTL */
|
GETLONG(ttl, p); /* minTTL */
|
||||||
@@ -1237,7 +1240,7 @@ static int find_nsec_records(struct dns_header *header, size_t plen, unsigned ch
|
|||||||
static unsigned char **nsecset = NULL;
|
static unsigned char **nsecset = NULL;
|
||||||
static int nsecset_sz = 0;
|
static int nsecset_sz = 0;
|
||||||
|
|
||||||
int type_found = -1;
|
int type_found = 0;
|
||||||
unsigned char *p = skip_questions(header, plen);
|
unsigned char *p = skip_questions(header, plen);
|
||||||
int type, class, rdlen, i, nsecs_found;
|
int type, class, rdlen, i, nsecs_found;
|
||||||
|
|
||||||
@@ -1296,12 +1299,12 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
|
|||||||
{
|
{
|
||||||
p = nsecs[i];
|
p = nsecs[i];
|
||||||
if (!extract_name(header, plen, &p, workspace1, 1, 10))
|
if (!extract_name(header, plen, &p, workspace1, 1, 10))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
p += 8; /* class, type, TTL */
|
p += 8; /* class, type, TTL */
|
||||||
GETSHORT(rdlen, p);
|
GETSHORT(rdlen, p);
|
||||||
psave = p;
|
psave = p;
|
||||||
if (!extract_name(header, plen, &p, workspace2, 1, 10))
|
if (!extract_name(header, plen, &p, workspace2, 1, 10))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
rc = hostname_cmp(workspace1, name);
|
rc = hostname_cmp(workspace1, name);
|
||||||
|
|
||||||
@@ -1319,7 +1322,7 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
|
|||||||
while (rdlen >= 2)
|
while (rdlen >= 2)
|
||||||
{
|
{
|
||||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
if (p[0] == type >> 8)
|
if (p[0] == type >> 8)
|
||||||
{
|
{
|
||||||
@@ -1434,7 +1437,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
|||||||
for (i = 0; i < nsec_count; i++)
|
for (i = 0; i < nsec_count; i++)
|
||||||
{
|
{
|
||||||
if (!(p = skip_name(nsecs[i], header, plen, 15)))
|
if (!(p = skip_name(nsecs[i], header, plen, 15)))
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
|
|
||||||
p += 10; /* type, class, TTL, rdlen */
|
p += 10; /* type, class, TTL, rdlen */
|
||||||
algo = *p++;
|
algo = *p++;
|
||||||
@@ -1452,7 +1455,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
|||||||
salt_len = *p++;
|
salt_len = *p++;
|
||||||
salt = p;
|
salt = p;
|
||||||
if (!CHECK_LEN(header, salt, plen, salt_len))
|
if (!CHECK_LEN(header, salt, plen, salt_len))
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
|
|
||||||
/* Now prune so we only have NSEC3 records with same iterations, salt and algo */
|
/* Now prune so we only have NSEC3 records with same iterations, salt and algo */
|
||||||
for (i = 0; i < nsec_count; i++)
|
for (i = 0; i < nsec_count; i++)
|
||||||
@@ -1463,7 +1466,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
|||||||
nsecs[i] = NULL; /* Speculative, will be restored if OK. */
|
nsecs[i] = NULL; /* Speculative, will be restored if OK. */
|
||||||
|
|
||||||
if (!(p = skip_name(nsec3p, header, plen, 15)))
|
if (!(p = skip_name(nsec3p, header, plen, 15)))
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
|
|
||||||
p += 10; /* type, class, TTL, rdlen */
|
p += 10; /* type, class, TTL, rdlen */
|
||||||
|
|
||||||
@@ -1480,7 +1483,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!CHECK_LEN(header, p, plen, salt_len))
|
if (!CHECK_LEN(header, p, plen, salt_len))
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
|
|
||||||
if (memcmp(p, salt, salt_len) != 0)
|
if (memcmp(p, salt, salt_len) != 0)
|
||||||
continue;
|
continue;
|
||||||
@@ -1491,7 +1494,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
|||||||
|
|
||||||
/* Algo is checked as 1 above */
|
/* Algo is checked as 1 above */
|
||||||
if (!(hash = hash_find("sha1")))
|
if (!(hash = hash_find("sha1")))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
/* Now, we need the "closest encloser NSEC3" */
|
/* Now, we need the "closest encloser NSEC3" */
|
||||||
closest_encloser = name;
|
closest_encloser = name;
|
||||||
@@ -1503,14 +1506,14 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
|||||||
closest_encloser++;
|
closest_encloser++;
|
||||||
|
|
||||||
if ((digest_len = hash_name(closest_encloser, &digest, hash, salt, salt_len, iterations)) == 0)
|
if ((digest_len = hash_name(closest_encloser, &digest, hash, salt, salt_len, iterations)) == 0)
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
for (i = 0; i < nsec_count; i++)
|
for (i = 0; i < nsec_count; i++)
|
||||||
if ((p = nsecs[i]))
|
if ((p = nsecs[i]))
|
||||||
{
|
{
|
||||||
if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
|
if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
|
||||||
!(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
|
!(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
if (digest_len == base32_len &&
|
if (digest_len == base32_len &&
|
||||||
memcmp(digest, workspace2, digest_len) == 0)
|
memcmp(digest, workspace2, digest_len) == 0)
|
||||||
@@ -1543,14 +1546,14 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
|||||||
p += 5 + salt_len; /* algo, flags, iterations, salt_len, salt */
|
p += 5 + salt_len; /* algo, flags, iterations, salt_len, salt */
|
||||||
hash_len = *p++;
|
hash_len = *p++;
|
||||||
if (!CHECK_LEN(header, p, plen, hash_len))
|
if (!CHECK_LEN(header, p, plen, hash_len))
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
p += hash_len;
|
p += hash_len;
|
||||||
rdlen -= p - psave;
|
rdlen -= p - psave;
|
||||||
|
|
||||||
while (rdlen >= 2)
|
while (rdlen >= 2)
|
||||||
{
|
{
|
||||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
if (p[0] == type >> 8)
|
if (p[0] == type >> 8)
|
||||||
{
|
{
|
||||||
@@ -1570,20 +1573,20 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
|||||||
|
|
||||||
/* Look for NSEC3 that proves the non-existence of the next-closest encloser */
|
/* Look for NSEC3 that proves the non-existence of the next-closest encloser */
|
||||||
if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0)
|
if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0)
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
for (i = 0; i < nsec_count; i++)
|
for (i = 0; i < nsec_count; i++)
|
||||||
if ((p = nsecs[i]))
|
if ((p = nsecs[i]))
|
||||||
{
|
{
|
||||||
if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
|
if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
|
||||||
!(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
|
!(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
p += 15 + salt_len; /* class, type, TTL, rdlen, algo, flags, iterations, salt_len, salt */
|
p += 15 + salt_len; /* class, type, TTL, rdlen, algo, flags, iterations, salt_len, salt */
|
||||||
hash_len = *p++; /* p now points to next hashed name */
|
hash_len = *p++; /* p now points to next hashed name */
|
||||||
|
|
||||||
if (!CHECK_LEN(header, p, plen, hash_len))
|
if (!CHECK_LEN(header, p, plen, hash_len))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
if (digest_len == base32_len && hash_len == base32_len)
|
if (digest_len == base32_len && hash_len == base32_len)
|
||||||
{
|
{
|
||||||
@@ -1611,20 +1614,20 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
|||||||
*wildcard = '*';
|
*wildcard = '*';
|
||||||
|
|
||||||
if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
|
if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
for (i = 0; i < nsec_count; i++)
|
for (i = 0; i < nsec_count; i++)
|
||||||
if ((p = nsecs[i]))
|
if ((p = nsecs[i]))
|
||||||
{
|
{
|
||||||
if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
|
if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
|
||||||
!(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
|
!(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
p += 15 + salt_len; /* class, type, TTL, rdlen, algo, flags, iterations, salt_len, salt */
|
p += 15 + salt_len; /* class, type, TTL, rdlen, algo, flags, iterations, salt_len, salt */
|
||||||
hash_len = *p++; /* p now points to next hashed name */
|
hash_len = *p++; /* p now points to next hashed name */
|
||||||
|
|
||||||
if (!CHECK_LEN(header, p, plen, hash_len))
|
if (!CHECK_LEN(header, p, plen, hash_len))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
if (digest_len == base32_len && hash_len == base32_len)
|
if (digest_len == base32_len && hash_len == base32_len)
|
||||||
{
|
{
|
||||||
@@ -1659,16 +1662,16 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
if (neganswer)
|
if (neganswer)
|
||||||
*neganswer = 0;
|
*neganswer = 0;
|
||||||
|
|
||||||
if (RCODE(header) == SERVFAIL)
|
if (RCODE(header) == SERVFAIL || ntohs(header->qdcount) != 1)
|
||||||
return STAT_BOGUS;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
if ((RCODE(header) != NXDOMAIN && RCODE(header) != NOERROR) || ntohs(header->qdcount) != 1)
|
if (RCODE(header) != NXDOMAIN && RCODE(header) != NOERROR)
|
||||||
return STAT_INSECURE;
|
return STAT_INSECURE;
|
||||||
|
|
||||||
qname = p1 = (unsigned char *)(header+1);
|
qname = p1 = (unsigned char *)(header+1);
|
||||||
|
|
||||||
if (!extract_name(header, plen, &p1, name, 1, 4))
|
if (!extract_name(header, plen, &p1, name, 1, 4))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
GETSHORT(qtype, p1);
|
GETSHORT(qtype, p1);
|
||||||
GETSHORT(qclass, p1);
|
GETSHORT(qclass, p1);
|
||||||
@@ -1684,7 +1687,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
/* leave pointer to missing name in qname */
|
/* leave pointer to missing name in qname */
|
||||||
|
|
||||||
if (!(rc = extract_name(header, plen, &p1, name, 0, 10)))
|
if (!(rc = extract_name(header, plen, &p1, name, 0, 10)))
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
|
|
||||||
GETSHORT(type2, p1);
|
GETSHORT(type2, p1);
|
||||||
GETSHORT(class2, p1);
|
GETSHORT(class2, p1);
|
||||||
@@ -1705,7 +1708,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
|
|
||||||
/* looped CNAMES */
|
/* looped CNAMES */
|
||||||
if (!cname_count-- || !extract_name(header, plen, &p1, name, 1, 0))
|
if (!cname_count-- || !extract_name(header, plen, &p1, name, 1, 0))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
p1 = ans_start;
|
p1 = ans_start;
|
||||||
goto cname_loop;
|
goto cname_loop;
|
||||||
@@ -1713,7 +1716,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!ADD_RDLEN(header, p1, plen, rdlen2))
|
if (!ADD_RDLEN(header, p1, plen, rdlen2))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (neganswer && !have_answer)
|
if (neganswer && !have_answer)
|
||||||
@@ -1726,7 +1729,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
for (p1 = ans_start, i = 0; i < ntohs(header->ancount) + ntohs(header->nscount); i++)
|
for (p1 = ans_start, i = 0; i < ntohs(header->ancount) + ntohs(header->nscount); i++)
|
||||||
{
|
{
|
||||||
if (!extract_name(header, plen, &p1, name, 1, 10))
|
if (!extract_name(header, plen, &p1, name, 1, 10))
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
|
|
||||||
GETSHORT(type1, p1);
|
GETSHORT(type1, p1);
|
||||||
GETSHORT(class1, p1);
|
GETSHORT(class1, p1);
|
||||||
@@ -1740,7 +1743,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
for (p2 = ans_start, j = 0; j < i; j++)
|
for (p2 = ans_start, j = 0; j < i; j++)
|
||||||
{
|
{
|
||||||
if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
|
if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
|
|
||||||
GETSHORT(type2, p2);
|
GETSHORT(type2, p2);
|
||||||
GETSHORT(class2, p2);
|
GETSHORT(class2, p2);
|
||||||
@@ -1751,7 +1754,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
break; /* Done it before: name, type, class all match. */
|
break; /* Done it before: name, type, class all match. */
|
||||||
|
|
||||||
if (!ADD_RDLEN(header, p2, plen, rdlen2))
|
if (!ADD_RDLEN(header, p2, plen, rdlen2))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Not done, validate now */
|
/* Not done, validate now */
|
||||||
@@ -1771,15 +1774,8 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
answer and overlay a genuine RR. To prove this
|
answer and overlay a genuine RR. To prove this
|
||||||
hasn't happened, the answer must prove that
|
hasn't happened, the answer must prove that
|
||||||
the gennuine record doesn't exist. Check that here. */
|
the gennuine record doesn't exist. Check that here. */
|
||||||
if (!nsec_type)
|
if (!nsec_type && !(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, class1)))
|
||||||
{
|
return STAT_BOGUS; /* No NSECs or bad packet */
|
||||||
nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, class1);
|
|
||||||
|
|
||||||
if (nsec_type == 0)
|
|
||||||
return STAT_INSECURE; /* Bad packet */
|
|
||||||
if (nsec_type == -1)
|
|
||||||
return STAT_BOGUS; /* No NSECs */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nsec_type == T_NSEC)
|
if (nsec_type == T_NSEC)
|
||||||
rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1);
|
rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1);
|
||||||
@@ -1802,7 +1798,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
for (p2 = ans_start, j = 0; j < ntohs(header->ancount); j++)
|
for (p2 = ans_start, j = 0; j < ntohs(header->ancount); j++)
|
||||||
{
|
{
|
||||||
if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
|
if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
|
|
||||||
GETSHORT(type2, p2);
|
GETSHORT(type2, p2);
|
||||||
GETSHORT(class2, p2);
|
GETSHORT(class2, p2);
|
||||||
@@ -1810,7 +1806,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
GETSHORT(rdlen2, p2);
|
GETSHORT(rdlen2, p2);
|
||||||
|
|
||||||
if (!CHECK_LEN(header, p2, plen, rdlen2))
|
if (!CHECK_LEN(header, p2, plen, rdlen2))
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
|
|
||||||
if (class2 == class1 && rc == 1)
|
if (class2 == class1 && rc == 1)
|
||||||
{
|
{
|
||||||
@@ -1819,7 +1815,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
if (type1 == T_DS && type2 == T_DS)
|
if (type1 == T_DS && type2 == T_DS)
|
||||||
{
|
{
|
||||||
if (rdlen2 < 4)
|
if (rdlen2 < 4)
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
|
|
||||||
GETSHORT(keytag, p2);
|
GETSHORT(keytag, p2);
|
||||||
algo = *p2++;
|
algo = *p2++;
|
||||||
@@ -1847,7 +1843,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
else if (type2 == T_RRSIG)
|
else if (type2 == T_RRSIG)
|
||||||
{
|
{
|
||||||
if (rdlen2 < 18)
|
if (rdlen2 < 18)
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
|
|
||||||
GETSHORT(type_covered, p2);
|
GETSHORT(type_covered, p2);
|
||||||
|
|
||||||
@@ -1883,7 +1879,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!ADD_RDLEN(header, p2, plen, rdlen2))
|
if (!ADD_RDLEN(header, p2, plen, rdlen2))
|
||||||
return STAT_INSECURE; /* bad packet */
|
return STAT_BOGUS; /* bad packet */
|
||||||
}
|
}
|
||||||
|
|
||||||
cache_end_insert();
|
cache_end_insert();
|
||||||
@@ -1891,7 +1887,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!ADD_RDLEN(header, p1, plen, rdlen1))
|
if (!ADD_RDLEN(header, p1, plen, rdlen1))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OK, all the RRsets validate, now see if we have a NODATA or NXDOMAIN reply */
|
/* OK, all the RRsets validate, now see if we have a NODATA or NXDOMAIN reply */
|
||||||
@@ -1900,19 +1896,12 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
|
|
||||||
/* NXDOMAIN or NODATA reply, prove that (name, class1, type1) can't exist */
|
/* NXDOMAIN or NODATA reply, prove that (name, class1, type1) can't exist */
|
||||||
/* First marshall the NSEC records, if we've not done it previously */
|
/* First marshall the NSEC records, if we've not done it previously */
|
||||||
if (!nsec_type)
|
if (!nsec_type && !(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, qclass)))
|
||||||
{
|
return STAT_BOGUS; /* No NSECs */
|
||||||
nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, qclass);
|
|
||||||
|
|
||||||
if (nsec_type == 0)
|
|
||||||
return STAT_INSECURE; /* Bad packet */
|
|
||||||
if (nsec_type == -1)
|
|
||||||
return STAT_BOGUS; /* No NSECs */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get name of missing answer */
|
/* Get name of missing answer */
|
||||||
if (!extract_name(header, plen, &qname, name, 1, 0))
|
if (!extract_name(header, plen, &qname, name, 1, 0))
|
||||||
return STAT_INSECURE;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
if (nsec_type == T_NSEC)
|
if (nsec_type == T_NSEC)
|
||||||
return prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype);
|
return prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype);
|
||||||
|
|||||||
Reference in New Issue
Block a user