On Wed, Apr 15, 2020 at 10:36:26AM +0200, Christian wrote: > > I don't yet have access to systems with this recent a glibc to confirm > > the above, but this is likely relevant to Postfix administrators who > > enable DANE. You may need to explicitly add the "trust-ad" option to > > your /etc/resolv.conf, while making sure that all the listed nameservers > > are local (loopback interface). > > I don't have a glibc 2.31 right now, otherwise I would try it.
With a bit of luck, someone will step forward. > Without setting the "trust-ad" option someone testing it would get the > same symptoms as I did on musl-libc? That's my working hypothesis. > Hence DNSSEC information would be missing in resolver response and > silently deactivating outgoing DANE? Yes. But I have an untested patch for that (it is only effective if Postfix running on a system with Glibc >= 2.31 was actually compiled against glibc >= 2.31). It'd be great if the patch got a code review and some testing. -- Viktor.
diff --git a/src/dns/dns.h b/src/dns/dns.h index f758e44a..b69cd9fe 100644 --- a/src/dns/dns.h +++ b/src/dns/dns.h @@ -55,20 +55,25 @@ #endif /* - * Disable DNSSEC at compile-time even if RES_USE_DNSSEC is available + * Disable DNSSEC at compile-time even if RES_USE_DNSSEC is available. */ #ifdef NO_DNSSEC #undef RES_USE_DNSSEC +#undef RES_TRUSTAD #endif /* - * Compatibility with systems that lack RES_USE_DNSSEC and RES_USE_EDNS0 + * Compatibility with systems that lack RES_USE_DNSSEC, RES_USE_EDNS0 or + * RES_TRUSTAD. */ #ifndef RES_USE_DNSSEC #define RES_USE_DNSSEC 0 #endif #ifndef RES_USE_EDNS0 #define RES_USE_EDNS0 0 +#endif +#ifndef RES_TRUSTAD +#define RES_TRUSTAD 0 #endif /*- @@ -239,6 +244,8 @@ extern int dns_lookup_rv(const char *, unsigned, DNS_RR **, VSTRING *, dns_lookup_rv((name), (rflags), (list), (fqdn), (why), (int *) 0, \ (lflags), (ltype)) +extern int dns_dnssec_available(void); + /* * Request flags. */ diff --git a/src/dns/dns_lookup.c b/src/dns/dns_lookup.c index 17377530..0ce0f802 100644 --- a/src/dns/dns_lookup.c +++ b/src/dns/dns_lookup.c @@ -74,6 +74,8 @@ /* VSTRING *why; /* int *rcode; /* unsigned lflags; +/* +/* int dns_dnssec_available() /* DESCRIPTION /* dns_lookup() looks up DNS resource records. When requested to /* look up data other than type CNAME, it will follow a limited @@ -89,6 +91,10 @@ /* dns_lookup_x, dns_lookup_r(), dns_lookup_rl() and dns_lookup_rv() /* accept or return additional information. /* +/* dns_dnssec_available() returns true when a (presumably) trusted +/* AD bit can be solicited from the configured nameserver(s) and is +/* not censored by the stub resolver library. +/* /* The var_dns_ncache_ttl_fix variable controls a workaround /* for res_search(3) implementations that break the /* DNS_REQ_FLAG_NCACHE_TTL feature. The workaround does not @@ -455,6 +461,23 @@ static int dns_query(const char *name, int type, unsigned flags, if ((flags & USER_FLAGS) != flags) msg_panic("dns_query: bad flags: %d", flags); + if (flags & RES_USE_DNSSEC) { + int avail = dns_dnssec_available(); + +#if RES_TRUSTAD != 0 + + /* + * On systems that implement RES_TRUSTAD, we can't elicit the AD bit + * via RES_USE_DNSSEC. The AD bit is unconditionally solicited or + * else stripped via the "trust-ad" option in /etc/resolv.conf. + */ + flags &= ~RES_USE_DNSSEC; +#else + if (!avail) + flags &= ~RES_USE_DNSSEC; +#endif + } + /* * Set extra options that aren't exposed to the application. */ @@ -560,8 +583,8 @@ static int dns_query(const char *name, int type, unsigned flags, * Initialize the reply structure. Some structure members are filled on * the fly while the reply is being parsed. Coerce AD bit to boolean. */ -#if RES_USE_DNSSEC != 0 - reply->dnssec_ad = (flags & RES_USE_DNSSEC) ? !!reply_header->ad : 0; +#if (RES_USE_DNSSEC != 0) || (RES_TRUSTAD != 0) + reply->dnssec_ad = !!reply_header->ad; #else reply->dnssec_ad = 0; #endif @@ -1053,7 +1076,6 @@ int dns_lookup_x(const char *name, unsigned type, unsigned flags, case DNS_RECURSE: if (msg_verbose) msg_info("dns_lookup: %s aliased to %s", name, cname); -#if RES_USE_DNSSEC /* * Once an intermediate CNAME reply is not validated, all @@ -1062,7 +1084,6 @@ int dns_lookup_x(const char *name, unsigned type, unsigned flags, */ if (maybe_secure == 0) flags &= ~RES_USE_DNSSEC; -#endif name = cname; } } @@ -1198,3 +1219,55 @@ int dns_lookup_rv(const char *name, unsigned flags, DNS_RR **rrlist, vstring_free(hpref_rtext); return (status); } + +/* dns_dnssec_available - can the stub resolver report a trusted AD bit */ + +int dns_dnssec_available(void) +{ + static int available = -1; + + if (available >= 0) + return (available); + +#ifdef NO_DNSSEC + available = 0; +#elif (RES_USE_DNSSEC == 0) && (RES_TRUSTAD == 0) + msg_warn("DNSSEC lookups are not supported by the C-library DNS resolver"); + available = 0; +#else + available = 1; + + /* + * Initialize the name service. + */ + if ((_res.options & RES_INIT) == 0 && res_init() < 0) { + msg_warn("DNSSEC lookups are not possible," + " name service initialization failure"); + available = 0; + } +#if RES_TRUSTAD != 0 + + /* + * On systems with GLIBC >= 2.31, the AD bit is solicited or else + * censored via the "trust-ad" resolv.conf option. On such systems we + * gain nothing by setting RES_USE_DNSSEC and RES_USE_EDNS0, since the AD + * bit will still be censored unless RES_TRUSTAD is set. Just setting + * "trust-ad" suffices to solicit the nameserver's "AD" bit, and is more + * efficient than using RES_USE_DNSSEC. + * + * Since we don't know what nameservers appear in /etc/resolv.conf, it is + * not our job to set this bit, but we can issue a warning if it is not + * set, and the user is requesting RES_USE_DNSSEC. + */ + if ((_res.options & RES_TRUSTAD) == 0) { + msg_warn("DNSSEC lookups are not possible, because the \"trust-ad\"" + " option is not set in /etc/resolv.conf."); + msg_warn("The \"trust-ad\" option should only be set when the only" + " nameserver listed in /etc/resolv.conf is a local DNSSEC-" + "validating resolver listening on the loopback interface"); + available = 0; + } +#endif +#endif + return (available); +} diff --git a/src/tls/tls_dane.c b/src/tls/tls_dane.c index 013426b1..44b9e845 100644 --- a/src/tls/tls_dane.c +++ b/src/tls/tls_dane.c @@ -207,7 +207,7 @@ #undef DANE_TLSA_SUPPORT -#if defined(TLSEXT_MAXLEN_host_name) && RES_USE_DNSSEC && RES_USE_EDNS0 +#if defined(TLSEXT_MAXLEN_host_name) #define DANE_TLSA_SUPPORT static int dane_tlsa_support = 1; @@ -418,6 +418,15 @@ static void dane_init(void) /* Don't report old news */ ERR_clear_error(); + /* + * DANE TLSA support may require the "trust-ad" bit to be set in the + * resolver options with GLIBC >= 2.31. + */ + if (!dns_dnssec_available()) { + msg_warn("No trusted validating resolvers, no DANE support"); + dane_tlsa_support = 0; + } + /* * DANE TLSA support requires working DANE digests. */