From Fedora Project Wiki

Revision as of 12:09, 13 November 2015 by Nmav (talk | contribs) (→‎Problem statement)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

The standard C library provides a number of functions related to host and service name resolution and DNS information retrieval. The former are mainly intended to support applications when connecting to services while the latter gives them access to additional DNS information.

Contacts:

Name resolution for libraries

Problem statement

Current versions of glibc offer the getaddrinfo() function, res_*() functions and _res.options. The former two are used for host and service name resolution and for DNS record retrieval, respectively. While this works well for applications, libraries may need to tweak the configuration without affecting the application. Basically, the configuration needs to be specific to the caller and the caller needs to be able to provide the configuration when performing host/service name resolution and DNS record retrieval.

Example use case

A cryptographic library may want to configure the resolver so that it only receives records secured by DNSSEC. The same library may also want to perform ordinary name resolution where records not secured by DNSSEC are returned as well. None of the configuration should ever affect the running application, therefore three different configuration contexts are needed.

Possible solution

For each libc library function that uses the shared context, provide a new function that would accept an opaque pointer to a specific context object. We also need to provide a set of functions to create and configure the context object.

Existing solutions

For example, netresolve provides a context object and allows for all sorts of name resolution backends including DNS.

Examples:

Notes

A global context could still be available and the classic getaddrinfo() function could call the new function with the global context.

The application and the libraries can be single-threaded as well as multi-threaded. Any solutions using thread local storage are therefore not generally suitable.

File descriptor based non-blocking API

Problem statement

The libc socket API allows for both blocking and non-blocking usage, thus being useful in all sorts of single threaded and multi-threaded applications and libraries. This doesn't apply to the libc name resolution API which is strictly blocking from top to bottom. Unfortunately this also applies to the nsswitch backend API.

Solutions

Add a new non-blocking API for applications and a new non-blocking API for nsswitch backends.

Open questions

What to do with nsswitch backends that don't support the new API, yet?

Existing solutions

For example, netresolve provides a file descriptor based non-blocking API.

Examples:

Trusted validating name servers

Problem statement

The current glibc implicitly trusts all name servers specified in /etc/resolv.conf and the res_* functions pass the AD flag to calling applications. This tricks applications into believing validation results of random servers received through DHCP and other means, which are not necessarily trusted to validate DNSSEC replies. The threat here are applications (e.g. some VPN clients, DHCP clients, or network-manager) which set non-validating servers in resolv.conf, or servers which are validating but cannot be trusted because their replies travel through an insecure channel.

If the requested DNS record was for example TLSA, the application (or a security library) is tricked into believing that the key data are secured by DNSSEC and have been properly validated. The trusted dnssec nameservers for a host are longer-lived than their plain dns counterparts (e.g. most probably they will be 127.0.0.1 or some other localnet address).

The glibc practice of trusting resolv.conf for DNSSEC does not agree with the 20+ year practice of having untrusted for dnssec nameservers in resolv.conf. Applications and administrators casually modify resolv.conf to add nameservers that are got from DHCP, or other untrusted sources, thus making any resolving based on the resolv.conf information unreliable for security purposes.

Scope

We assume that in the host there will be running a validating resolver, accessible through a trusted channel (i.e., localhost). We want libc to be able separate the information coming from the trusted validating resolver and information originating from the non-validating/untrusted resolvers. So in the above system, we want the AD bit to be set only when the validating resolver believes it should be set, and unset on every other occasion. Libc (and other resolver APIs) will make sure that this notion is clear to their users, i.e., provide as DNSSEC-valid data, only data that come from the validating resolver.

Solution 1

Use the option directive or add a new directive to /etc/resolv.conf specifying that the listed nameservers are trusted. The option is preferred as it follows the resolv.conf conventions.

Potential drawbacks:

  • Trusted and untrusted for DNSSEC validation servers cannot be mixed.
  • Applications just rewriting the nameservers could theoretically leave the trusted flag on by mistake.
  • A removal of the flag by legacy applications creates a DoS for DNSSEC queries.

Example:

nameserver 1.2.3.4
nameserver 5.6.7.8
options trusted-nameservers

Solution 2

Add a new directive to specify a trusted name server.

Advantages:

  • Compared to solution 1, one can specify a single trusted for DNSSEC nameserver, but also have others listed which are not trusted for DNSSEC validation.

Drawbacks:

  • Additional complexity coming from the fact that some nameservers are trusted and some aren't.
  • A removal of the flag by legacy applications creates a DoS for DNSSEC queries.

Example:

nameserver 1.2.3.4
nameserver 5.6.7.8
options trusted-nameserver:1.2.3.4
options trusted-nameserver:5.6.7.8

Solution 3

Add a new file (resolv-sec.conf) to specify the trusted name servers.

Advantages:

  • When using dnssec-trigger, both resolv.conf and the trusted variant could be just symlinks

to dnssec-trigger's temporary resolv.conf file.

  • The libc could just use the trusted variant when it's present and the untrusted /etc/resolv.conf as a fallback.

Suggested file names:

  • resolv-sec.conf
  • resolv.conf.trusted
  • resolv-trusted.conf

Example:

nameserver 1.2.3.4
nameserver 5.6.7.8

Notes

Lennart independently suggested that /etc/resolv.conf should be a symlink to an actual resolv.conf in a temporary filesystem. It sounds like a good idea and it would deal well with dnssec-trigger where any files in /etc could be just symlinks to dnssec-trigger's temporary resolv.conf.

Secure only mode for name resolution

Problem statement

An application or a security library may want to perform a DNS information query in a secure only mode where only results secured by DNSSEC and validated by a trusted name server are returned.

Use case

A security library requests the TLSA record but only cares about one that is secured by DNSSEC and successfully validated.

Proposed solution

Add a stub resolver configuration option to only return results secured by DNSSEC.

Resolve a host name to a list of network layer addresses

Problem statement

The getaddrinfo API as implemented in glibc doesn't provide a replacement for gethostbyname, i.e. an API that would return a list of network layer addresses for a host name.

Use cases

  • IP-based access lists
  • Network layer testing tools
  • Any tools working with non-TCP non-UDP protocols
  • Possibly even tools working with TCP and UDP

Input parameters

  • host
  • family (AF_UNSPEC, AF_INET, AF_INET6)

Output parameters

  • List of sockaddr style addresses (zero ports, zero protocols, etc)
  • Canonical name (why?)

Resources