DNS Resolver

The DNS Resolver module provides user protection for DNS interception and configuration update attacks and improved network performance for DNS resolutions. The module contains the code that implements the DNS stub resolver, which translates names such as www.google.com to IP addresses such as 2001:db8::1. The DNS stub resolver backs Java API elements such as InetAddress#getAllByName and Network#getAllByName, as well as native networking functions, and implements sending and receiving DNS queries and caching the results.

Changes in Android 10

On devices running Android 9 and lower, the DNS resolver code is spread across Bionic and netd. DNS lookups are centralized in the netd daemon to allow for system-wide caching, while apps call functions (such as getaddrinfo) in Bionic. The query is sent over a UNIX socket to /dev/socket/dnsproxyd to the netd daemon, which parses the request and calls getaddrinfo again to issue DNS lookups, then caches the results so that other apps can use them. The DNS resolver implementation was mostly contained in bionic/libc/dns/ and partly in system/netd/server/dns.

Android 10 moves the DNS resolver code to system/netd/resolv, converts it to C++, then modernizes and refactors the code. The code in Bionic continues to exist for app compatibility reasons, but is no longer called by the system. These source paths are affected by the refactoring:

  • bionic/libc/dns
  • system/netd/client
  • system/netd/server/dns
  • system/netd/server/DnsProxyListener
  • system/netd/server/ResolverController
  • system/netd/resolv

Format and dependencies

The DNS Resolver module is delivered as an APEX file and is dynamically linked by netd; however, netd is not a dependency as the module serves the local socket /dev/socket/dnsproxyd directly. The Binder endpoint for the resolver configuration was moved from netd to the resolver, meaning that the system service can call directly into the resolver module without going through netd.

The DNS Resolver module depends on libc (Bionic) and statically links its dependencies; no other libraries are required.

mDNS .local resolution

Starting from November 2021, Android resolver supports mDNS .local resolution, which implements "5.1 One-Shot multicast DNS Queries" in RFC 6762 to send standard DNS queries blindly to 224.0.0.251:5353 or [FF02::FB]:5353. mDNS resolution is transparently supported by calling getaddrinfo() with a hostname ending in *.local.

mDNS .local resolution augments the existing functionality of getaddrinfo() to get the addresses. If a device supports mDNS .local resolution, then the getaddrinfo() API sends mDNS queries to 224.0.0.251:5353 or [FF02::FB]:5353 and returns the local addresses. If a device doesn't support mDNS .local resolution, then the getaddrinfo() API method sends a DNS query to the DNS server.

The code is in AOSP, located in packages/modules/DnsResolver. Users can keep their current mDNS design to get the addresses, or use getaddrinfo() instead. The behavior of this feature is like a regular DNS query sent to the mDNS multicast addresses. This feature has no impact on system health.

Users can use the command adb shell ping6 HOSTNAME.local, where HOSTNAME is the hostname of a target device on the LAN, for example, adb shell ping6 ipad.local.

VPN and mobile data connections are excluded from .local resolution.