This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[RFC] support for trusted validating resolver configuration
- From: Pavel Simerda <psimerda at redhat dot com>
- To: libc-alpha <libc-alpha at sourceware dot org>
- Cc: Tomas Hozza <thozza at redhat dot com>, Petr Spacek <pspacek at redhat dot com>, Alexandre Oliva <aoliva at redhat dot com>, siddhesh at redhat dot com, schwab at suse dot de, neleai at seznam dot cz
- Date: Tue, 18 Nov 2014 07:40:24 -0500 (EST)
- Subject: [RFC] support for trusted validating resolver configuration
- Authentication-results: sourceware.org; auth=none
Hello all,
the trusted and untrusted resolver configuration is still an outstanding
issue for us. We are looking for a way to configure a list of trusted
name servers that can be used for validation. In most cases this would
be simply "localhost" or "127.0.0.1" where a local valdating resolver
would be other scenarios could be supported as well.
One way to achieve that is an additional directive written in
/etc/resolv.conf that would say the name servers are to be trusted, another
is to have an separate directive to actually list the trusted nameservers.
I became interested in a different way that doesn't affect /etc/resolv.conf
which is written and read by many security unaware tools. That is to create
a special version of the file just for security aware tools. For now I'm
using the name /etc/resolv-secure.conf.
Goals:
* Applications can rely on the AD flag coming from the library.
- It's either cleared out or it comes from a trusted validating resolver.
Solution:
* When /etc/resolv-secure.conf exists, it is used instead of /etc/resolv.conf
and all name servers are trusted for DNSSEC validation. Queries are sent
with AD flag set, answers are passed to the application without changing
the flag.
* When /etc/resolv-secure.conf doesn't exist, /etc/resolv.conf is used and
no servers are trusted for DNSSEC validation. Queries are preferably sent
without the AD flag and the AD flags in responses are cleared out before
passing them to the application.
(Corner cases like unreadable /etc/resolv-secure.conf are yet to be defined.)
A proof of concept patch is attached. I tried it and it worked for me. I used
netresolve[1] tools to perform the testing.
[1] https://sourceware.org/git/?p=netresolve.git;a=blob;f=README;hb=HEAD
Advantages:
* Simple logic, based on the existance of /etc/resolv-secure.conf.
* Backwards compatibility for free.
- Supporting software writes both resolv.conf and resolv-secure.conf and
reads resolv-secure.conf falling back to resolv.conf when missing.
- Other software writes resolv.conf (thus won't overwrite
resolv-secure.conf) and reads resolv.conf.
* Format of /etc/resolv-secure.conf is identical to that of /etc/resolv.conf.
- It is easy to update security aware software to use the new file and
fallback to the old one.
* Easy to support in dynamic configuration tools like dnssec-trigger.
- The tool simply stores its resolv.conf somewhere in /run and creates
symlinks /etc/resolv.conf and /etc/resolv-secure.conf.
- Any other tools will immediatly learn where the data comes from by
checking the symlink target and act accordingly.
Disadvantages:
* A new file to look into for DNS configuration.
Resources:
* fedora: glibc ticket: https://bugzilla.redhat.com/show_bug.cgi?id=1164339
* fedora: c-ares ticket: https://bugzilla.redhat.com/show_bug.cgi?id=1164337
* fedora: dnssec-trigger ticket: https://bugzilla.redhat.com/show_bug.cgi?id=1165126
Cheers,
Pavel
From 05583564e627edbe2a8bfea7b28e6ea9732c438e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20=C5=A0imerda?= <psimerda@redhat.com>
Date: Sun, 16 Nov 2014 00:28:04 +0100
Subject: [PATCH] don't blindly trust AD flag, support /etc/resolv-secure.conf
---
resolv/res_init.c | 13 ++++++++++++-
resolv/res_mkquery.c | 2 ++
resolv/res_query.c | 4 ++++
resolv/resolv.h | 3 ++-
4 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/resolv/res_init.c b/resolv/res_init.c
index ea133f8..a063b29 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -234,7 +234,12 @@ __res_vinit(res_state statp, int preinit) {
(line[sizeof(name) - 1] == ' ' || \
line[sizeof(name) - 1] == '\t'))
- if ((fp = fopen(_PATH_RESCONF, "rce")) != NULL) {
+ bool secure = true;
+ const char *path;
+resolvconf:
+ path = secure ? "/etc/resolv-secure.conf" : _PATH_RESCONF;
+
+ if ((fp = fopen(path, "rce")) != NULL) {
/* No threads use this stream. */
__fsetlocking (fp, FSETLOCKING_BYCALLER);
/* read the config file */
@@ -426,6 +431,12 @@ __res_vinit(res_state statp, int preinit) {
statp->nsort = nsort;
#endif
(void) fclose(fp);
+
+ if (secure)
+ statp->trust_ad_flag = true;
+ } else if (secure) {
+ secure = false;
+ goto resolvconf;
}
if (__builtin_expect(statp->nscount == 0, 0)) {
statp->nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
diff --git a/resolv/res_mkquery.c b/resolv/res_mkquery.c
index 1635e6a..f89935d 100644
--- a/resolv/res_mkquery.c
+++ b/resolv/res_mkquery.c
@@ -143,6 +143,8 @@ res_nmkquery(res_state statp,
hp->opcode = op;
hp->rd = (statp->options & RES_RECURSE) != 0;
hp->rcode = NOERROR;
+ if (statp->trust_ad_flag)
+ hp->ad = 1;
cp = buf + HFIXEDSZ;
buflen -= HFIXEDSZ;
dpp = dnptrs;
diff --git a/resolv/res_query.c b/resolv/res_query.c
index e4ee2a6..b1edc88 100644
--- a/resolv/res_query.c
+++ b/resolv/res_query.c
@@ -242,6 +242,10 @@ __libc_res_nquery(res_state statp,
/* __libc_res_nsend might have reallocated the buffer. */
hp = (HEADER *) *answerp;
+ /* Clear untrusted AD flag. */
+ if (!statp->trust_ad_flag)
+ hp->ad = 0;
+
/* We simplify the following tests by assigning HP to HP2 or
vice versa. It is easy to verify that this is the same as
ignoring all tests of HP or HP2. */
diff --git a/resolv/resolv.h b/resolv/resolv.h
index 53c3bba..1b51e5c 100644
--- a/resolv/resolv.h
+++ b/resolv/resolv.h
@@ -117,7 +117,8 @@ struct __res_state {
unsigned ndots:4; /* threshold for initial abs. query */
unsigned nsort:4; /* number of elements in sort_list[] */
unsigned ipv6_unavail:1; /* connecting to IPv6 server failed */
- unsigned unused:23;
+ unsigned trust_ad_flag:1; /* trust AD flag from the server */
+ unsigned unused:22;
struct {
struct in_addr addr;
u_int32_t mask;
--
1.8.5.5