From 931108e92d6451cf619fc74dec5b7d66c67f834c Mon Sep 17 00:00:00 2001 From: jca Date: Mon, 22 Nov 2021 20:18:27 +0000 Subject: [PATCH] Implement rfc6840 (AD flag processing) if using trusted name servers libc can't do DNSSEC validation but it can ask a "security-aware" resolver to do so. Let's send queries with the AD flag set when appropriate, and let applications look at the AD flag in responses in a safe way, ie clear the AD flag if the resolvers aren't trusted. By default we only trust resolvers if resolv.conf(5) only lists name servers on localhost - the obvious candidates being unwind(8) and unbound(8). For non-localhost resolvers, an admin who trusts *all the name servers* listed in resolv.conf(5) *and the network path leading to them* can annotate this with "options trust-ad". AD flag processing gives ssh -o VerifyHostkeyDNS=Yes a chance to fetch SSHFP records in a secure manner, and tightens the situation for other applications, eg those using RES_USE_DNSSEC for DANE. It should be noted that postfix currently assumes trusted name servers by default and forces RES_TRUSTAD if available. RES_TRUSTAD and "options trust-ad" were first introduced in glibc by Florian Weimer. Florian Obser (florian@) contributed various improvements, fixed a bug and added automatic trust for name servers on localhost. ok florian@ phessler@ --- include/resolv.h | 3 ++- lib/libc/asr/asr.c | 31 ++++++++++++++++++++++++++++--- lib/libc/asr/asr_debug.c | 3 ++- lib/libc/asr/res_mkquery.c | 4 +++- lib/libc/asr/res_send_async.c | 23 ++++++++++++++++++++++- lib/libc/net/res_init.3 | 16 ++++++++++++++-- share/man/man5/resolv.conf.5 | 16 ++++++++++++++-- 7 files changed, 85 insertions(+), 11 deletions(-) diff --git a/include/resolv.h b/include/resolv.h index fb02483871e..449779e40fe 100644 --- a/include/resolv.h +++ b/include/resolv.h @@ -1,4 +1,4 @@ -/* $OpenBSD: resolv.h,v 1.22 2019/01/14 06:23:06 otto Exp $ */ +/* $OpenBSD: resolv.h,v 1.23 2021/11/22 20:18:27 jca Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -191,6 +191,7 @@ struct __res_state_ext { /* DNSSEC extensions: use higher bit to avoid conflict with ISC use */ #define RES_USE_DNSSEC 0x20000000 /* use DNSSEC using OK bit in OPT */ #define RES_USE_CD 0x10000000 /* set Checking Disabled flag */ +#define RES_TRUSTAD 0x80000000 /* Request AD, keep it in responses. */ #define RES_DEFAULT (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH) diff --git a/lib/libc/asr/asr.c b/lib/libc/asr/asr.c index 8bcb61b6000..7cbf6aab5c9 100644 --- a/lib/libc/asr/asr.c +++ b/lib/libc/asr/asr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: asr.c,v 1.66 2021/11/05 13:08:58 kn Exp $ */ +/* $OpenBSD: asr.c,v 1.67 2021/11/22 20:18:27 jca Exp $ */ /* * Copyright (c) 2010-2012 Eric Faurot * @@ -661,7 +661,8 @@ pass0(char **tok, int n, struct asr_ctx *ac) d = strtonum(tok[i] + 6, 1, 16, &e); if (e == NULL) ac->ac_ndots = d; - } + } else if (!strcmp(tok[i], "trust-ad")) + ac->ac_options |= RES_TRUSTAD; } } } @@ -672,7 +673,10 @@ pass0(char **tok, int n, struct asr_ctx *ac) static int asr_ctx_from_string(struct asr_ctx *ac, const char *str) { - char buf[512], *ch; + struct sockaddr_in6 *sin6; + struct sockaddr_in *sin; + int i, trustad; + char buf[512], *ch; asr_ctx_parse(ac, str); @@ -702,6 +706,27 @@ asr_ctx_from_string(struct asr_ctx *ac, const char *str) break; } + trustad = 1; + for (i = 0; i < ac->ac_nscount && trustad; i++) { + switch (ac->ac_ns[i]->sa_family) { + case AF_INET: + sin = (struct sockaddr_in *)ac->ac_ns[i]; + if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) + trustad = 0; + break; + case AF_INET6: + sin6 = (struct sockaddr_in6 *)ac->ac_ns[i]; + if (!IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) + trustad = 0; + break; + default: + trustad = 0; + break; + } + } + if (trustad) + ac->ac_options |= RES_TRUSTAD; + return (0); } diff --git a/lib/libc/asr/asr_debug.c b/lib/libc/asr/asr_debug.c index f9378d156b7..791a067f72d 100644 --- a/lib/libc/asr/asr_debug.c +++ b/lib/libc/asr/asr_debug.c @@ -1,4 +1,4 @@ -/* $OpenBSD: asr_debug.c,v 1.27 2021/04/02 07:00:30 eric Exp $ */ +/* $OpenBSD: asr_debug.c,v 1.28 2021/11/22 20:18:27 jca Exp $ */ /* * Copyright (c) 2012 Eric Faurot * @@ -286,6 +286,7 @@ _asr_dump_config(FILE *f, struct asr *a) PRINTOPT(RES_USE_EDNS0, "USE_EDNS0"); PRINTOPT(RES_USE_DNSSEC, "USE_DNSSEC"); PRINTOPT(RES_USE_CD, "USE_CD"); + PRINTOPT(RES_TRUSTAD, "TRUSTAD"); if (o) fprintf(f, " 0x%08x", o); fprintf(f, "\n"); diff --git a/lib/libc/asr/res_mkquery.c b/lib/libc/asr/res_mkquery.c index c3d5af30f29..3e02dbba908 100644 --- a/lib/libc/asr/res_mkquery.c +++ b/lib/libc/asr/res_mkquery.c @@ -1,4 +1,4 @@ -/* $OpenBSD: res_mkquery.c,v 1.13 2019/01/14 06:49:42 otto Exp $ */ +/* $OpenBSD: res_mkquery.c,v 1.14 2021/11/22 20:18:27 jca Exp $ */ /* * Copyright (c) 2012 Eric Faurot * @@ -62,6 +62,8 @@ res_mkquery(int op, const char *dname, int class, int type, h.flags |= RD_MASK; if (ac->ac_options & RES_USE_CD) h.flags |= CD_MASK; + if (ac->ac_options & RES_TRUSTAD) + h.flags |= AD_MASK; h.qdcount = 1; if (ac->ac_options & (RES_USE_EDNS0 | RES_USE_DNSSEC)) h.arcount = 1; diff --git a/lib/libc/asr/res_send_async.c b/lib/libc/asr/res_send_async.c index c5cc41f56df..a309070efcd 100644 --- a/lib/libc/asr/res_send_async.c +++ b/lib/libc/asr/res_send_async.c @@ -1,4 +1,4 @@ -/* $OpenBSD: res_send_async.c,v 1.39 2019/09/28 11:21:07 eric Exp $ */ +/* $OpenBSD: res_send_async.c,v 1.40 2021/11/22 20:18:27 jca Exp $ */ /* * Copyright (c) 2012 Eric Faurot * @@ -42,6 +42,7 @@ static int udp_recv(struct asr_query *); static int tcp_write(struct asr_query *); static int tcp_read(struct asr_query *); static int validate_packet(struct asr_query *); +static void clear_ad(struct asr_result *); static int setup_query(struct asr_query *, const char *, const char *, int, int); static int ensure_ibuf(struct asr_query *, size_t); static int iter_ns(struct asr_query *); @@ -258,6 +259,8 @@ res_send_async_run(struct asr_query *as, struct asr_result *ar) as->as.dns.ibuf = NULL; ar->ar_errno = 0; ar->ar_rcode = as->as.dns.rcode; + if (!(as->as_ctx->ac_options & RES_TRUSTAD)) + clear_ad(ar); async_set_state(as, ASR_STATE_HALT); break; @@ -378,6 +381,9 @@ setup_query(struct asr_query *as, const char *name, const char *dom, h.flags |= RD_MASK; if (as->as_ctx->ac_options & RES_USE_CD) h.flags |= CD_MASK; + if (as->as_ctx->ac_options & RES_TRUSTAD) + h.flags |= AD_MASK; + h.qdcount = 1; if (as->as_ctx->ac_options & (RES_USE_EDNS0 | RES_USE_DNSSEC)) h.arcount = 1; @@ -747,6 +753,21 @@ validate_packet(struct asr_query *as) return (-1); } +/* + * Clear AD flag in the answer. + */ +static void +clear_ad(struct asr_result *ar) +{ + struct asr_dns_header *h; + uint16_t flags; + + h = (struct asr_dns_header *)ar->ar_data; + flags = ntohs(h->flags); + flags &= ~(AD_MASK); + h->flags = htons(flags); +} + /* * Set the async context nameserver index to the next nameserver, cycling * over the list until the maximum retry counter is reached. Return 0 on diff --git a/lib/libc/net/res_init.3 b/lib/libc/net/res_init.3 index 4a4d0950a5e..03e6fca7470 100644 --- a/lib/libc/net/res_init.3 +++ b/lib/libc/net/res_init.3 @@ -1,4 +1,4 @@ -.\" $OpenBSD: res_init.3,v 1.4 2020/04/25 21:06:17 jca Exp $ +.\" $OpenBSD: res_init.3,v 1.5 2021/11/22 20:18:27 jca Exp $ .\" .\" Copyright (c) 1985, 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -27,7 +27,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd $Mdocdate: April 25 2020 $ +.Dd $Mdocdate: November 22 2021 $ .Dt RES_INIT 3 .Os .Sh NAME @@ -179,6 +179,18 @@ This option has no effect. In the past, it turned off the legacy .Ev HOSTALIASES feature. +.It Dv RES_TRUSTAD +If set, the resolver routines will set the AD flag in DNS queries and +preserve the value of the AD flag in DNS replies. +If not set, the resolver routines will clear the AD flag in responses. +Direct use of this option to enable AD bit processing is discouraged. +Instead the use of trusted name servers should be annotated with +.Dq options trust-ad +in +.Xr resolv.conf 5 . +This option is automatically enabled if +.Xr resolv.conf 5 +only lists name servers on localhost. .It Dv RES_USE_INET6 With this option .Xr gethostbyname 3 diff --git a/share/man/man5/resolv.conf.5 b/share/man/man5/resolv.conf.5 index 8d3b91c0832..5808cc65d6a 100644 --- a/share/man/man5/resolv.conf.5 +++ b/share/man/man5/resolv.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: resolv.conf.5,v 1.62 2021/08/24 07:30:32 florian Exp $ +.\" $OpenBSD: resolv.conf.5,v 1.63 2021/11/22 20:18:27 jca Exp $ .\" $NetBSD: resolv.conf.5,v 1.7 1996/03/06 18:22:16 scottr Exp $ .\" .\" Copyright (c) 1986, 1991 The Regents of the University of California. @@ -30,7 +30,7 @@ .\" .\" @(#)resolver.5 5.12 (Berkeley) 5/10/91 .\" -.Dd $Mdocdate: August 24 2021 $ +.Dd $Mdocdate: November 22 2021 $ .Dt RESOLV.CONF 5 .Os .Sh NAME @@ -259,6 +259,18 @@ first as an absolute name before any search list elements are appended to it. .It Cm tcp Forces the use of TCP for queries. Normal behaviour is to query via UDP but fall back to TCP on failure. +.It Cm trust-ad +A name server indicating that it performed DNSSEC validation by setting the +Authentic Data (AD) flag in the answer can only be trusted if the +name server itself is trusted and the network path is trusted. +Generally this is not the case and the AD flag is cleared in the answer. +The +.Cm trust-ad +option lets the system administrator indicate that the name server and the +network path are trusted. +This option is automatically enabled if +.Nm resolv.conf +only lists name servers on localhost. .El .El .Pp -- 2.20.1