diff --git a/src/cache.c b/src/cache.c index c4edfd3..cb80cde 100644 --- a/src/cache.c +++ b/src/cache.c @@ -2250,6 +2250,7 @@ static char *edestr(int ede) case EDE_UNS_NS3_ITER: return "unsupported NSEC3 iterations value"; case EDE_UNABLE_POLICY: return "uanble to conform to policy"; case EDE_SYNTHESIZED: return "synthesized"; + case EDE_US_SERVFAIL: return "upstream returned SERVFAIL"; default: return "unknown"; } } diff --git a/src/dns-protocol.h b/src/dns-protocol.h index 0db5913..e71bedc 100644 --- a/src/dns-protocol.h +++ b/src/dns-protocol.h @@ -86,6 +86,7 @@ #define EDNS0_OPTION_UMBRELLA 20292 /* Cisco Umbrella temporary assignment */ /* RFC-8914 extended errors, negative values are our definitions */ +#define EDE_US_SERVFAIL -2 /* SERVFAIL from usptream */ #define EDE_UNSET -1 /* No extended DNS error available */ #define EDE_OTHER 0 /* Other */ #define EDE_USUPDNSKEY 1 /* Unsupported DNSKEY algo */ diff --git a/src/dnsmasq.h b/src/dnsmasq.h index ef7e96d..b794e55 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -778,6 +778,7 @@ struct dyndir { #define DNSSEC_FAIL_NSEC3_ITERS 0x0200 /* too many iterations in NSEC3 */ #define DNSSEC_FAIL_BADPACKET 0x0400 /* bad packet */ #define DNSSEC_FAIL_WORK 0x0800 /* too much crypto */ +#define DNSSEC_FAIL_UPSTREAM 0x1000 /* SERVFAIL from UPSTREAM */ #define STAT_ISEQUAL(a, b) (((a) & 0xffff0000) == (b)) diff --git a/src/dnssec.c b/src/dnssec.c index 81a6fce..83cc879 100644 --- a/src/dnssec.c +++ b/src/dnssec.c @@ -1993,8 +1993,11 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch if (neganswer) *neganswer = 0; + + if (RCODE(header) == SERVFAIL) + return STAT_BOGUS | DNSSEC_FAIL_UPSTREAM; - if (RCODE(header) == SERVFAIL || ntohs(header->qdcount) != 1) + if (ntohs(header->qdcount) != 1) return STAT_BOGUS; if (RCODE(header) != NXDOMAIN && RCODE(header) != NOERROR) @@ -2365,8 +2368,9 @@ int errflags_to_ede(int status) /* We can end up with more than one flag set for some errors, so this encodes a rough priority so the (eg) No sig is reported before no-unexpired-sig. */ - - if (status & DNSSEC_FAIL_NYV) + if (status & DNSSEC_FAIL_UPSTREAM) + return EDE_US_SERVFAIL; + else if (status & DNSSEC_FAIL_NYV) return EDE_SIG_NYV; else if (status & DNSSEC_FAIL_EXP) return EDE_SIG_EXP; diff --git a/src/forward.c b/src/forward.c index 1e935eb..30adedc 100644 --- a/src/forward.c +++ b/src/forward.c @@ -1399,6 +1399,9 @@ void return_reply(time_t now, struct frec *forward, struct dns_header *header, s a.log.ede = ede; log_query(F_SECSTAT, domain, &a, result, 0); + + if (ede == EDE_US_SERVFAIL) + ede = EDE_DNSSEC_BOGUS; } } @@ -2665,6 +2668,8 @@ unsigned char *tcp_request(int confd, time_t now, a.log.ede = ede; log_query(F_SECSTAT, domain, &a, result, 0); + if (ede == EDE_US_SERVFAIL) + ede = EDE_DNSSEC_BOGUS; if ((daemon->limit[LIMIT_CRYPTO] - validatecount) > (int)daemon->metrics[METRIC_CRYPTO_HWM]) daemon->metrics[METRIC_CRYPTO_HWM] = daemon->limit[LIMIT_CRYPTO] - validatecount;