mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
Initial changes for extended DNS error codes.
This commit is contained in:
@@ -80,10 +80,41 @@
|
||||
|
||||
#define EDNS0_OPTION_MAC 65001 /* dyndns.org temporary assignment */
|
||||
#define EDNS0_OPTION_CLIENT_SUBNET 8 /* IANA */
|
||||
#define EDNS0_OPTION_EDE 15 /* IANA - RFC 8914 */
|
||||
#define EDNS0_OPTION_NOMDEVICEID 65073 /* Nominum temporary assignment */
|
||||
#define EDNS0_OPTION_NOMCPEID 65074 /* Nominum temporary assignment */
|
||||
#define EDNS0_OPTION_UMBRELLA 20292 /* Cisco Umbrella temporary assignment */
|
||||
|
||||
/* RFC-8914 extended errors */
|
||||
#define EDE_OTHER 0 /* Other */
|
||||
#define EDE_USUPDNSKEY 1 /* Unsupported DNSKEY algo */
|
||||
#define EDE_USUPDS 2 /* Unsupported DS Digest */
|
||||
#define EDE_STALE 3 /* Stale answer */
|
||||
#define EDE_FORGED 4 /* Forged answer */
|
||||
#define EDE_DNSSEC_IND 5 /* DNSSEC Indeterminate */
|
||||
#define EDE_DNSSEC_BOGUS 6 /* DNSSEC Bogus */
|
||||
#define EDE_SIG_EXP 7 /* Signature Expired */
|
||||
#define EDE_SIG_NYV 8 /* Signature Not Yet Valid */
|
||||
#define EDE_NO_DNSKEY 9 /* DNSKEY missing */
|
||||
#define EDE_NO_RRISG 10 /* RRSIGs missing */
|
||||
#define EDE_NO_ZONEKEY 11 /* No Zone Key Bit Set */
|
||||
#define EDE_NO_NSEC 12 /* NSEC Missing */
|
||||
#define EDE_CACHED_ERR 13 /* Cached Error */
|
||||
#define EDE_NOT_READY 14 /* Not Ready */
|
||||
#define EDE_BLOCKED 15 /* Blocked */
|
||||
#define EDE_CENSORED 16 /* Censored */
|
||||
#define EDE_FILTERED 17 /* Filtered */
|
||||
#define EDE_PROHIBITED 18 /* Prohibited */
|
||||
#define EDE_STALE_NXD 19 /* Stale NXDOMAIN */
|
||||
#define EDE_NOT_AUTH 20 /* Not Authoritative */
|
||||
#define EDE_NOT_SUP 21 /* Not Supported */
|
||||
#define EDE_NO_AUTH 22 /* No Reachable Authority */
|
||||
#define EDE_NETERR 23 /* Network error */
|
||||
#define EDE_INVALID_DATA 24 /* Invalid Data */
|
||||
|
||||
|
||||
|
||||
|
||||
struct dns_header {
|
||||
u16 id;
|
||||
u8 hb3,hb4;
|
||||
|
||||
@@ -686,17 +686,18 @@ struct hostsfile {
|
||||
#define DUMP_BOGUS 0x0040
|
||||
#define DUMP_SEC_BOGUS 0x0080
|
||||
|
||||
|
||||
/* DNSSEC status values. */
|
||||
#define STAT_SECURE 1
|
||||
#define STAT_INSECURE 2
|
||||
#define STAT_BOGUS 3
|
||||
#define STAT_NEED_DS 4
|
||||
#define STAT_NEED_KEY 5
|
||||
#define STAT_TRUNCATED 6
|
||||
#define STAT_SECURE_WILDCARD 7
|
||||
#define STAT_OK 8
|
||||
#define STAT_ABANDONED 9
|
||||
#define STAT_SECURE 0x10000
|
||||
#define STAT_INSECURE 0x20000
|
||||
#define STAT_BOGUS 0x30000
|
||||
#define STAT_NEED_DS 0x40000
|
||||
#define STAT_NEED_KEY 0x50000
|
||||
#define STAT_TRUNCATED 0x60000
|
||||
#define STAT_SECURE_WILDCARD 0x70000
|
||||
#define STAT_OK 0x80000
|
||||
#define STAT_ABANDONED 0x90000
|
||||
|
||||
#define STAT_ISEQUAL(a, b) (((a) & 0xffff0000) == (b))
|
||||
|
||||
#define FREC_NOREBIND 1
|
||||
#define FREC_CHECKING_DISABLED 2
|
||||
|
||||
31
src/dnssec.c
31
src/dnssec.c
@@ -847,8 +847,9 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
memcmp(ds_digest, digest, recp1->addr.ds.keylen) == 0 &&
|
||||
explore_rrset(header, plen, class, T_DNSKEY, name, keyname, &sigcnt, &rrcnt) &&
|
||||
sigcnt != 0 && rrcnt != 0 &&
|
||||
validate_rrset(now, header, plen, class, T_DNSKEY, sigcnt, rrcnt, name, keyname,
|
||||
NULL, key, rdlen - 4, algo, keytag, &sig_ttl) == STAT_SECURE)
|
||||
STAT_ISEQUAL(validate_rrset(now, header, plen, class, T_DNSKEY, sigcnt, rrcnt, name, keyname,
|
||||
NULL, key, rdlen - 4, algo, keytag, &sig_ttl),
|
||||
STAT_SECURE))
|
||||
{
|
||||
valid = 1;
|
||||
break;
|
||||
@@ -971,7 +972,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
else
|
||||
rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons, &neg_ttl);
|
||||
|
||||
if (rc == STAT_INSECURE)
|
||||
if (STAT_ISEQUAL(rc, STAT_INSECURE))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("Insecure DS reply received for %s, check domain configuration and upstream DNS server DNSSEC support"), name);
|
||||
rc = STAT_BOGUS;
|
||||
@@ -984,13 +985,13 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
/* If the key needed to validate the DS is on the same domain as the DS, we'll
|
||||
loop getting nowhere. Stop that now. This can happen of the DS answer comes
|
||||
from the DS's zone, and not the parent zone. */
|
||||
if (rc == STAT_BOGUS || (rc == STAT_NEED_KEY && hostname_isequal(name, keyname)))
|
||||
if (STAT_ISEQUAL(rc, STAT_BOGUS) || (STAT_ISEQUAL(rc, STAT_NEED_KEY) && hostname_isequal(name, keyname)))
|
||||
{
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS");
|
||||
return STAT_BOGUS;
|
||||
}
|
||||
|
||||
if (rc != STAT_SECURE)
|
||||
if (!STAT_ISEQUAL(rc, STAT_SECURE))
|
||||
return rc;
|
||||
|
||||
if (!neganswer)
|
||||
@@ -1959,15 +1960,15 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
if (check_unsigned && i < ntohs(header->ancount))
|
||||
{
|
||||
rc = zone_status(name, class1, keyname, now);
|
||||
if (rc == STAT_SECURE)
|
||||
if (STAT_ISEQUAL(rc, STAT_SECURE))
|
||||
rc = STAT_BOGUS;
|
||||
if (class)
|
||||
*class = class1; /* Class for NEED_DS or NEED_KEY */
|
||||
}
|
||||
else
|
||||
else
|
||||
rc = STAT_INSECURE;
|
||||
|
||||
if (rc != STAT_INSECURE)
|
||||
if (!STAT_ISEQUAL(rc, STAT_INSECURE))
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
@@ -1978,7 +1979,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
strcpy(daemon->workspacename, keyname);
|
||||
rc = zone_status(daemon->workspacename, class1, keyname, now);
|
||||
|
||||
if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
|
||||
if (STAT_ISEQUAL(rc, STAT_BOGUS) || STAT_ISEQUAL(rc, STAT_NEED_KEY) || STAT_ISEQUAL(rc, STAT_NEED_DS))
|
||||
{
|
||||
if (class)
|
||||
*class = class1; /* Class for NEED_DS or NEED_KEY */
|
||||
@@ -1986,13 +1987,13 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
}
|
||||
|
||||
/* Zone is insecure, don't need to validate RRset */
|
||||
if (rc == STAT_SECURE)
|
||||
if (STAT_ISEQUAL(rc, STAT_SECURE))
|
||||
{
|
||||
unsigned long sig_ttl;
|
||||
rc = validate_rrset(now, header, plen, class1, type1, sigcnt,
|
||||
rrcnt, name, keyname, &wildname, NULL, 0, 0, 0, &sig_ttl);
|
||||
|
||||
if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
|
||||
if (STAT_ISEQUAL(rc, STAT_BOGUS) || STAT_ISEQUAL(rc, STAT_NEED_KEY) || STAT_ISEQUAL(rc, STAT_NEED_DS))
|
||||
{
|
||||
if (class)
|
||||
*class = class1; /* Class for DS or DNSKEY */
|
||||
@@ -2025,7 +2026,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
Note that we may not yet have validated the NSEC/NSEC3 RRsets.
|
||||
That's not a problem since if the RRsets later fail
|
||||
we'll return BOGUS then. */
|
||||
if (rc == STAT_SECURE_WILDCARD &&
|
||||
if (STAT_ISEQUAL(rc, STAT_SECURE_WILDCARD) &&
|
||||
!prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL, NULL))
|
||||
return STAT_BOGUS;
|
||||
|
||||
@@ -2034,12 +2035,12 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == STAT_INSECURE)
|
||||
if (STAT_ISEQUAL(rc, STAT_INSECURE))
|
||||
secure = STAT_INSECURE;
|
||||
}
|
||||
|
||||
/* OK, all the RRsets validate, now see if we have a missing answer or CNAME target. */
|
||||
if (secure == STAT_SECURE)
|
||||
if (STAT_ISEQUAL(secure, STAT_SECURE))
|
||||
for (j = 0; j <targetidx; j++)
|
||||
if ((p2 = targets[j]))
|
||||
{
|
||||
@@ -2059,7 +2060,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
if (qtype == T_DS)
|
||||
return STAT_BOGUS;
|
||||
|
||||
if ((rc = zone_status(name, qclass, keyname, now)) != STAT_SECURE)
|
||||
if (STAT_ISEQUAL((rc = zone_status(name, qclass, keyname, now)), STAT_SECURE))
|
||||
{
|
||||
if (class)
|
||||
*class = qclass; /* Class for NEED_DS or NEED_KEY */
|
||||
|
||||
@@ -556,7 +556,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
int munged = 0, is_sign;
|
||||
unsigned int rcode = RCODE(header);
|
||||
size_t plen;
|
||||
|
||||
|
||||
(void)ad_reqd;
|
||||
(void)do_bit;
|
||||
(void)bogusanswer;
|
||||
@@ -604,11 +604,10 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned short udpsz;
|
||||
|
||||
/* If upstream is advertising a larger UDP packet size
|
||||
than we allow, trim it so that we don't get overlarge
|
||||
requests for the client. We can't do this for signed packets. */
|
||||
unsigned short udpsz;
|
||||
GETSHORT(udpsz, sizep);
|
||||
if (udpsz > daemon->edns_pktsz)
|
||||
{
|
||||
@@ -722,7 +721,6 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
|
||||
/* do this after extract_addresses. Ensure NODATA reply and remove
|
||||
nameserver info. */
|
||||
|
||||
if (munged)
|
||||
{
|
||||
header->ancount = htons(0);
|
||||
@@ -762,7 +760,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
||||
/* As soon as anything returns BOGUS, we stop and unwind, to do otherwise
|
||||
would invite infinite loops, since the answers to DNSKEY and DS queries
|
||||
will not be cached, so they'll be repeated. */
|
||||
if (status != STAT_BOGUS && status != STAT_TRUNCATED && status != STAT_ABANDONED)
|
||||
if (!STAT_ISEQUAL(status, STAT_BOGUS) && !STAT_ISEQUAL(status, STAT_TRUNCATED) && !STAT_ISEQUAL(status, STAT_ABANDONED))
|
||||
{
|
||||
if (forward->flags & FREC_DNSKEY_QUERY)
|
||||
status = dnssec_validate_by_ds(now, header, plen, daemon->namebuff, daemon->keyname, forward->class);
|
||||
@@ -773,7 +771,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
||||
!option_bool(OPT_DNSSEC_IGN_NS) && (forward->sentto->flags & SERV_DO_DNSSEC),
|
||||
NULL, NULL, NULL);
|
||||
#ifdef HAVE_DUMPFILE
|
||||
if (status == STAT_BOGUS)
|
||||
if (STAT_ISEQUAL(status, STAT_BOGUS))
|
||||
dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_BOGUS : DUMP_BOGUS,
|
||||
header, (size_t)plen, &forward->sentto->addr, NULL);
|
||||
#endif
|
||||
@@ -781,7 +779,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
||||
|
||||
/* Can't validate, as we're missing key data. Put this
|
||||
answer aside, whilst we get that. */
|
||||
if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
|
||||
if (STAT_ISEQUAL(status, STAT_NEED_DS) || STAT_ISEQUAL(status, STAT_NEED_KEY))
|
||||
{
|
||||
struct frec *new = NULL;
|
||||
int serverind;
|
||||
@@ -800,9 +798,9 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
||||
/* validate routines leave name of required record in daemon->keyname */
|
||||
nn = dnssec_generate_query(header, ((unsigned char *) header) + server->edns_pktsz,
|
||||
daemon->keyname, forward->class,
|
||||
status == STAT_NEED_KEY ? T_DNSKEY : T_DS, server->edns_pktsz);
|
||||
STAT_ISEQUAL(status, STAT_NEED_KEY) ? T_DNSKEY : T_DS, server->edns_pktsz);
|
||||
|
||||
flags = (status == STAT_NEED_KEY) ? FREC_DNSKEY_QUERY : FREC_DS_QUERY;
|
||||
flags = STAT_ISEQUAL(status, STAT_NEED_KEY) ? FREC_DNSKEY_QUERY : FREC_DS_QUERY;
|
||||
hash = hash_questions(header, nn, daemon->namebuff);
|
||||
|
||||
if ((new = lookup_frec_by_query(hash, flags, FREC_DNSKEY_QUERY | FREC_DS_QUERY)))
|
||||
@@ -872,7 +870,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
||||
#endif
|
||||
server_send_log(server, fd, header, nn, DUMP_SEC_QUERY,
|
||||
F_NOEXTRA | F_DNSSEC, daemon->keyname,
|
||||
querystr("dnssec-query", status == STAT_NEED_KEY ? T_DNSKEY : T_DS));
|
||||
querystr("dnssec-query", STAT_ISEQUAL(status, STAT_NEED_KEY) ? T_DNSKEY : T_DS));
|
||||
server->queries++;
|
||||
}
|
||||
|
||||
@@ -1085,33 +1083,33 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he
|
||||
no_cache_dnssec = 1;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (status != STAT_OK)
|
||||
if (!STAT_ISEQUAL(status, STAT_OK))
|
||||
{
|
||||
no_cache_dnssec = 0;
|
||||
|
||||
if (status == STAT_TRUNCATED)
|
||||
if (STAT_ISEQUAL(status, STAT_TRUNCATED))
|
||||
header->hb3 |= HB3_TC;
|
||||
else
|
||||
{
|
||||
char *result, *domain = "result";
|
||||
|
||||
if (status == STAT_ABANDONED)
|
||||
if (STAT_ISEQUAL(status, STAT_ABANDONED))
|
||||
{
|
||||
result = "ABANDONED";
|
||||
status = STAT_BOGUS;
|
||||
}
|
||||
else
|
||||
result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
|
||||
result = (STAT_ISEQUAL(status, STAT_SECURE) ? "SECURE" : (STAT_ISEQUAL(status, STAT_INSECURE) ? "INSECURE" : "BOGUS"));
|
||||
|
||||
if (status == STAT_BOGUS && extract_request(header, n, daemon->namebuff, NULL))
|
||||
if (STAT_ISEQUAL(status, STAT_BOGUS) && extract_request(header, n, daemon->namebuff, NULL))
|
||||
domain = daemon->namebuff;
|
||||
|
||||
log_query(F_SECSTAT, domain, NULL, result);
|
||||
}
|
||||
|
||||
if (status == STAT_SECURE)
|
||||
if (STAT_ISEQUAL(status, STAT_SECURE))
|
||||
cache_secure = 1;
|
||||
else if (status == STAT_BOGUS)
|
||||
else if (STAT_ISEQUAL(status, STAT_BOGUS))
|
||||
{
|
||||
no_cache_dnssec = 1;
|
||||
bogusanswer = 1;
|
||||
@@ -1731,16 +1729,16 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
/* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
|
||||
if (--(*keycount) == 0)
|
||||
new_status = STAT_ABANDONED;
|
||||
else if (status == STAT_NEED_KEY)
|
||||
else if (STAT_ISEQUAL(status, STAT_NEED_KEY))
|
||||
new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
|
||||
else if (status == STAT_NEED_DS)
|
||||
else if (STAT_ISEQUAL(status, STAT_NEED_DS))
|
||||
new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
|
||||
else
|
||||
new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
|
||||
!option_bool(OPT_DNSSEC_IGN_NS) && (server->flags & SERV_DO_DNSSEC),
|
||||
NULL, NULL, NULL);
|
||||
|
||||
if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
|
||||
if (!STAT_ISEQUAL(new_status, STAT_NEED_DS) && !STAT_ISEQUAL(new_status, STAT_NEED_KEY))
|
||||
break;
|
||||
|
||||
/* Can't validate because we need a key/DS whose name now in keyname.
|
||||
@@ -1758,7 +1756,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
}
|
||||
|
||||
m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class,
|
||||
new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, server->edns_pktsz);
|
||||
STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS, server->edns_pktsz);
|
||||
|
||||
if ((start = dnssec_server(server, daemon->keyname, &first, &last)) == -1 ||
|
||||
(m = tcp_talk(first, last, start, packet, m, have_mark, mark, &server)) == 0)
|
||||
@@ -1771,13 +1769,13 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
daemon->log_display_id = ++daemon->log_id;
|
||||
|
||||
log_query_mysockaddr(F_NOEXTRA | F_DNSSEC, keyname, &server->addr,
|
||||
querystr("dnssec-query", new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS));
|
||||
querystr("dnssec-query", STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS));
|
||||
|
||||
new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
|
||||
|
||||
daemon->log_display_id = log_save;
|
||||
|
||||
if (new_status != STAT_OK)
|
||||
if (!STAT_ISEQUAL(new_status, STAT_OK))
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2043,26 +2041,26 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
serv, have_mark, mark, &keycount);
|
||||
char *result, *domain = "result";
|
||||
|
||||
if (status == STAT_ABANDONED)
|
||||
if (STAT_ISEQUAL(status, STAT_ABANDONED))
|
||||
{
|
||||
result = "ABANDONED";
|
||||
status = STAT_BOGUS;
|
||||
}
|
||||
else
|
||||
result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
|
||||
result = (STAT_ISEQUAL(status, STAT_SECURE) ? "SECURE" : (STAT_ISEQUAL(status, STAT_INSECURE) ? "INSECURE" : "BOGUS"));
|
||||
|
||||
if (status == STAT_BOGUS && extract_request(header, m, daemon->namebuff, NULL))
|
||||
if (STAT_ISEQUAL(status, STAT_BOGUS) && extract_request(header, m, daemon->namebuff, NULL))
|
||||
domain = daemon->namebuff;
|
||||
|
||||
log_query(F_SECSTAT, domain, NULL, result);
|
||||
|
||||
if (status == STAT_BOGUS)
|
||||
if (STAT_ISEQUAL(status, STAT_BOGUS))
|
||||
{
|
||||
no_cache_dnssec = 1;
|
||||
bogusanswer = 1;
|
||||
}
|
||||
|
||||
if (status == STAT_SECURE)
|
||||
if (STAT_ISEQUAL(status, STAT_SECURE))
|
||||
cache_secure = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user