DNS 解析器模块可保护用户免受 DNS 拦截和配置更新攻击,并改进了 DNS 解析的网络性能。此模块包含用于实现 DNS 桩解析器的代码,该解析器可将 www.google.com 等名称转换为 IP 地址(例如 2001:db8::1)。DNS 桩解析器支持 Java API 元素(如 InetAddress#getAllByName 和 Network#getAllByName)以及原生网络功能,且可发送和接收 DNS 查询以及缓存结果。
在搭载 Android 9 及更低版本的设备上,DNS 解析器代码分布在 Bionic 和 netd
上。DNS 查找操作集中在 netd
守护程序中,以便进行系统级缓存,而应用在 Bionic 中调用函数(例如 getaddrinfo
)。查询会通过 UNIX 套接字发送到 /dev/socket/dnsproxyd
,再到 netd
守护程序,该守护程序会解析请求并再次调用 getaddrinfo
,以发出 DNS 查找请求,然后它会缓存结果以供其他应用使用。DNS 解析器实现主要包含在 bionic/libc/dns/
中,部分包含在 system/netd/server/dns
中。
Android 10 将 DNS 解析器代码移至 system/netd/resolv,
,将其转换为 C++,然后对代码进行了翻新和重构。由于应用兼容性方面的原因,Bionic 中的代码继续存在,但系统不会再调用它们。以下源文件路径受到重构的影响:
bionic/libc/dns
system/netd/client
system/netd/server/dns
system/netd/server/DnsProxyListener.*
system/netd/resolv
(1)获取ip地址(域名–>IP地址)
ConnectivityService.updateDnses() ->
DnsManager.setDnsConfigurationForNetwork() ->
mDnsResolver.setResolverConfiguration() -> IDnsResolver.aidl ()
DnsResolverService.setResolverConfiguration() ->
ResolverController.setResolverConfiguration() ->
res_cache.int resolv_set_nameservers_for_net() ->
getaddrinfo.getaddrinfo_numeric() -> getaddrinfo.android_getaddrinfofornetcontext(hostname, servname, &hints, &netcontext, result);
(2)DNS server list 设置(set name servers for a network)
_resolv_set_nameservers_for_net
http://androidxref.com/9.0.0_r3/xref/libcore/ojluni/src/main/java/java/net/InetAddress.java#1105
1077 /**
1078 * Determines the IP address of a host, given the host's name.
1097 * @param host the specified host, or {@code null}.
1098 * @return an IP address for the given host name.
1104 */
1105 public static InetAddress getByName(String host)
1106 throws UnknownHostException {
1107 // Android-changed: Rewritten on the top of Libcore.os.
1108 return impl.lookupAllHostAddr(host, NETID_UNSET)[0];
1109 }
1111 /**
1112 * Given the name of a host, returns an array of its IP addresses,
1113 * based on the configured name service on the system.
1139 * @param host the name of the host, or {@code null}.
1140 * @return an array of all the IP addresses for a given host name.
1149 */
1150 public static InetAddress[] getAllByName(String host)
1151 throws UnknownHostException {
1152 // Android-changed: Resolves a hostname using Libcore.os.
1153 // Also, returns both the Inet4 and Inet6 loopback for null/empty host
1154 return impl.lookupAllHostAddr(host, NETID_UNSET).clone();
1155 }
lookupAllHostAddr在Android M上的名字叫做getAllByNameImpl
http://androidxref.com/9.0.0_r3/xref/libcore/ojluni/src/main/java/java/net/Inet6AddressImpl.java#88
79 // BEGIN Android-changed: Rewrote hostname lookup methods on top of Libcore.os.
80 /*
81 public native String getLocalHostName() throws UnknownHostException;
82 public native InetAddress[]
83 lookupAllHostAddr(String hostname) throws UnknownHostException;
84 public native String getHostByAddr(byte[] addr) throws UnknownHostException;
85 private native boolean isReachable0(byte[] addr, int scope, int timeout, byte[] inf, int ttl, int if_scope) throws IOException;
86 */
87 @Override
88 public InetAddress[] lookupAllHostAddr(String host, int netId) throws UnknownHostException {
89 if (host == null || host.isEmpty()) {
90 // Android-changed: Return both the Inet4 and Inet6 loopback addresses
91 // when host == null or empty.
92 return loopbackAddresses();
93 }
94
95 // Is it a numeric address?
96 InetAddress result = InetAddress.parseNumericAddressNoThrow(host);
97 if (result != null) {
98 result = InetAddress.disallowDeprecatedFormats(host, result);
99 if (result == null) {
100 throw new UnknownHostException("Deprecated IPv4 address format: " + host);
101 }
102 return new InetAddress[] { result };
103 }
104
105 return lookupHostByName(host, netId);
106 }
323 // BEGIN Android-changed: Let loopbackAddresses() return both Inet4 and Inet6 loopbacks.
324 @Override
325 public InetAddress[] loopbackAddresses() {
326 synchronized (Inet6AddressImpl.class) {
327 // We avoid initializing anyLocalAddress during to avoid issues
328 // caused by the dependency chains of these classes. InetAddress depends on
329 // InetAddressImpl, but Inet6Address & Inet4Address are its subclasses.
330 // Also see {@code anyLocalAddress).
331 if (loopbackAddresses == null) {
332 loopbackAddresses = new InetAddress[]{Inet6Address.LOOPBACK, Inet4Address.LOOPBACK};
333 }
334
335 return loopbackAddresses;
336 }
337 }
http://androidxref.com/9.0.0_r3/xref/libcore/ojluni/src/main/java/java/net/InetAddress.java#1622
1622 static InetAddress parseNumericAddressNoThrow(String address) {
1623 // Accept IPv6 addresses (only) in square brackets for compatibility.
1624 if (address.startsWith("[") && address.endsWith("]") && address.indexOf(':') != -1) {
1625 address = address.substring(1, address.length() - 1);
1626 }
1627 StructAddrinfo hints = new StructAddrinfo();
1628 hints.ai_flags = AI_NUMERICHOST;
1629 InetAddress[] addresses = null;
1630 try {
1631 addresses = Libcore.os.android_getaddrinfo(address, hints, NETID_UNSET);
1632 } catch (GaiException ignored) {
1633 }
1634 return (addresses != null) ? addresses[0] : null;
1635 }
http://androidxref.com/9.0.0_r3/xref/libcore/ojluni/src/main/java/java/net/Inet6AddressImpl.java#115
108 /**
109 * Resolves a hostname to its IP addresses using a cache.
110 *
111 * @param host the hostname to resolve.
112 * @param netId the network to perform resolution upon.
113 * @return the IP addresses of the host.
114 */
115 private static InetAddress[] lookupHostByName(String host, int netId)
116 throws UnknownHostException {
117 BlockGuard.getThreadPolicy().onNetwork();
118 // Do we have a result cached?
119 Object cachedResult = addressCache.get(host, netId);
120 if (cachedResult != null) {
121 if (cachedResult instanceof InetAddress[]) {
122 // A cached positive result.
123 return (InetAddress[]) cachedResult;
124 } else {
125 // A cached negative result.
126 throw new UnknownHostException((String) cachedResult);
127 }
128 }
129 try {
130 StructAddrinfo hints = new StructAddrinfo();
131 hints.ai_flags = AI_ADDRCONFIG;
132 hints.ai_family = AF_UNSPEC;
133 // If we don't specify a socket type, every address will appear twice, once
134 // for SOCK_STREAM and one for SOCK_DGRAM. Since we do not return the family
135 // anyway, just pick one.
136 hints.ai_socktype = SOCK_STREAM;
137 InetAddress[] addresses = Libcore.os.android_getaddrinfo(host, hints, netId);
138 // TODO: should getaddrinfo set the hostname of the InetAddresses it returns?
139 for (InetAddress address : addresses) {
140 address.holder().hostName = host;
141 address.holder().originalHostName = host;
142 }
143 addressCache.put(host, netId, addresses);
144 return addresses;
145 } catch (GaiException gaiException) {
146 // If the failure appears to have been a lack of INTERNET permission, throw a clear
147 // SecurityException to aid in debugging this common mistake.
148 // http://code.google.com/p/android/issues/detail?id=15722
149 if (gaiException.getCause() instanceof ErrnoException) {
150 if (((ErrnoException) gaiException.getCause()).errno == EACCES) {
151 throw new SecurityException("Permission denied (missing INTERNET permission?)", gaiException);
152 }
153 }
154 // Otherwise, throw an UnknownHostException.
155 String detailMessage = "Unable to resolve host \"" + host + "\": " + Libcore.os.gai_strerror(gaiException.error);
156 addressCache.putUnknownHost(host, netId, detailMessage);
157 throw gaiException.rethrowAsUnknownHostException(detailMessage);
158 }
159 }
上面都调用了Libcore.os.android_getaddrinfo
http://androidxref.com/9.0.0_r3/xref/libcore/luni/src/main/java/libcore/io/Libcore.java#19
19public final class Libcore {
20 private Libcore() { }
21
22 /**
23 * Direct access to syscalls. Code should strongly prefer using {@link #os}
24 * unless it has a strong reason to bypass the helpful checks/guards that it
25 * provides.
26 */
27 public static Os rawOs = new Linux();
28
29 /**
30 * Access to syscalls with helpful checks/guards.
31 */
32 public static Os os = new BlockGuardOs(rawOs);
33}
Os对象是一系列系统调用的抽象接口,从LibCore.java中可以看出它是通过Linux这个类实现的
http://androidxref.com/9.0.0_r3/xref/libcore/luni/src/main/java/libcore/io/Linux.java#53
48public final class Linux implements Os {
49 Linux() { }
53 public native InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException;
http://androidxref.com/9.0.0_r3/xref/libcore/luni/src/main/java/libcore/io/BlockGuardOs.java#164
40/**
41 * Informs BlockGuard of any activity it should be aware of.
42 */
43public class BlockGuardOs extends ForwardingOs {
44 public BlockGuardOs(Os os) {
45 super(os);
46 }
164 @Override public InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException {
165 // With AI_NUMERICHOST flag set, the node must a numerical network address, therefore no
166 // host address lookups will be performed. In this case, it is fine to perform on main
167 // thread.
168 boolean isNumericHost = (hints.ai_flags & AI_NUMERICHOST) != 0;
169 if (!isNumericHost) {
170 BlockGuard.getThreadPolicy().onNetwork();
171 }
172 return os.android_getaddrinfo(node, hints, netId);
173 }
再找OS类
http://androidxref.com/9.0.0_r3/xref/libcore/luni/src/main/java/libcore/io/Os.java#50
47public interface Os {
50 public InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException;
参考
得知Linux.java通过JNI (libcore_io_Linux.cpp)调用linux的posix API,那么知道了,C层的实现都在libcore_io_Linux.cpp中,咱们来看下。
http://androidxref.com/9.0.0_r3/xref/libcore/luni/src/main/native/libcore_io_Linux.cpp#1244
1244static jobjectArray Linux_android_getaddrinfo(JNIEnv* env, jobject, jstring javaNode,
1245 jobject javaHints, jint netId) {
1246 ScopedUtfChars node(env, javaNode);
1247 if (node.c_str() == NULL) {
1248 return NULL;
1249 }
1250
1251 static jfieldID flagsFid = env->GetFieldID(JniConstants::structAddrinfoClass, "ai_flags", "I");
1252 static jfieldID familyFid = env->GetFieldID(JniConstants::structAddrinfoClass, "ai_family", "I");
1253 static jfieldID socktypeFid = env->GetFieldID(JniConstants::structAddrinfoClass, "ai_socktype", "I");
1254 static jfieldID protocolFid = env->GetFieldID(JniConstants::structAddrinfoClass, "ai_protocol", "I");
1255
1256 addrinfo hints;
1257 memset(&hints, 0, sizeof(hints));
1258 hints.ai_flags = env->GetIntField(javaHints, flagsFid);
1259 hints.ai_family = env->GetIntField(javaHints, familyFid);
1260 hints.ai_socktype = env->GetIntField(javaHints, socktypeFid);
1261 hints.ai_protocol = env->GetIntField(javaHints, protocolFid);
1262
1263 addrinfo* addressList = NULL;
1264 errno = 0;
1265 int rc = android_getaddrinfofornet(node.c_str(), NULL, &hints, netId, 0, &addressList);
1266 std::unique_ptr addressListDeleter(addressList);
1267 if (rc != 0) {
1268 throwGaiException(env, "android_getaddrinfo", rc);
1269 return NULL;
1270 }
1271
1272 // Count results so we know how to size the output array.
1273 int addressCount = 0;
1274 for (addrinfo* ai = addressList; ai != NULL; ai = ai->ai_next) {
1275 if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) {
1276 ++addressCount;
1277 } else {
1278 ALOGE("android_getaddrinfo unexpected ai_family %i", ai->ai_family);
1279 }
1280 }
1281 if (addressCount == 0) {
1282 return NULL;
1283 }
1284
1285 // Prepare output array.
1286 jobjectArray result = env->NewObjectArray(addressCount, JniConstants::inetAddressClass, NULL);
1287 if (result == NULL) {
1288 return NULL;
1289 }
1290
1291 // Examine returned addresses one by one, save them in the output array.
1292 int index = 0;
1293 for (addrinfo* ai = addressList; ai != NULL; ai = ai->ai_next) {
1294 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) {
1295 // Unknown address family. Skip this address.
1296 ALOGE("android_getaddrinfo unexpected ai_family %i", ai->ai_family);
1297 continue;
1298 }
1299
1300 // Convert each IP address into a Java byte array.
1301 sockaddr_storage& address = *reinterpret_cast(ai->ai_addr);
1302 ScopedLocalRef inetAddress(env, sockaddrToInetAddress(env, address, NULL));
1303 if (inetAddress.get() == NULL) {
1304 return NULL;
1305 }
1306 env->SetObjectArrayElement(result, index, inetAddress.get());
1307 ++index;
1308 }
1309 return result;
1310}
调用android_getaddrinfofornet()
http://androidxref.com/9.0.0_r3/xref/libcore/luni/src/main/native/Portability.h#28
28static inline int android_getaddrinfofornet(const char* hostname, const char* servname,
29 const struct addrinfo* hints, unsigned /*netid*/, unsigned /*mark*/, struct addrinfo** res) {
30 return getaddrinfo(hostname, servname, hints, res);
31}
最终调用到bionic/libc/dns/net/getaddrinfo.c
http://androidxref.com/9.0.0_r3/xref/bionic/libc/dns/net/getaddrinfo.c#564
562__BIONIC_WEAK_FOR_NATIVE_BRIDGE
563int
564getaddrinfo(const char *hostname, const char *servname,
565 const struct addrinfo *hints, struct addrinfo **res)
566{
567 return android_getaddrinfofornet(hostname, servname, hints, NETID_UNSET, MARK_UNSET, res);
568}
570__BIONIC_WEAK_FOR_NATIVE_BRIDGE
571int
572android_getaddrinfofornet(const char *hostname, const char *servname,
573 const struct addrinfo *hints, unsigned netid, unsigned mark, struct addrinfo **res)
574{
575 struct android_net_context netcontext = {
576 .app_netid = netid,
577 .app_mark = mark,
578 .dns_netid = netid,
579 .dns_mark = mark,
580 .uid = NET_CONTEXT_INVALID_UID,
581 };
582 return android_getaddrinfofornetcontext(hostname, servname, hints, &netcontext, res);
583}
584
585__BIONIC_WEAK_FOR_NATIVE_BRIDGE
586int
587android_getaddrinfofornetcontext(const char *hostname, const char *servname,
588 const struct addrinfo *hints, const struct android_net_context *netcontext,
589 struct addrinfo **res)
590{
591 struct addrinfo sentinel;
592 struct addrinfo *cur;
593 int error = 0;
594 struct addrinfo ai;
595 struct addrinfo ai0;
596 struct addrinfo *pai;
597 const struct explore *ex;
598
599 /* hostname is allowed to be NULL */
600 /* servname is allowed to be NULL */
601 /* hints is allowed to be NULL */
602 assert(res != NULL);
603 assert(netcontext != NULL);
604 memset(&sentinel, 0, sizeof(sentinel));
605 cur = &sentinel;
606 pai = &ai;
607 pai->ai_flags = 0;
608 pai->ai_family = PF_UNSPEC;
609 pai->ai_socktype = ANY;
610 pai->ai_protocol = ANY;
611 pai->ai_addrlen = 0;
612 pai->ai_canonname = NULL;
613 pai->ai_addr = NULL;
614 pai->ai_next = NULL;
615
616 if (hostname == NULL && servname == NULL)
617 return EAI_NONAME;
618 if (hints) {
619 /* error check for hints */
620 if (hints->ai_addrlen || hints->ai_canonname ||
621 hints->ai_addr || hints->ai_next)
622 ERR(EAI_BADHINTS); /* xxx */
623 if (hints->ai_flags & ~AI_MASK)
624 ERR(EAI_BADFLAGS);
625 switch (hints->ai_family) {
626 case PF_UNSPEC:
627 case PF_INET:
628#ifdef INET6
629 case PF_INET6:
630#endif
631 break;
632 default:
633 ERR(EAI_FAMILY);
634 }
635 memcpy(pai, hints, sizeof(*pai));
636
637 /*
638 * if both socktype/protocol are specified, check if they
639 * are meaningful combination.
640 */
641 if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
642 for (ex = explore; ex->e_af >= 0; ex++) {
643 if (pai->ai_family != ex->e_af)
644 continue;
645 if (ex->e_socktype == ANY)
646 continue;
647 if (ex->e_protocol == ANY)
648 continue;
649 if (pai->ai_socktype == ex->e_socktype
650 && pai->ai_protocol != ex->e_protocol) {
651 ERR(EAI_BADHINTS);
652 }
653 }
654 }
655 }
656
657 /*
658 * check for special cases. (1) numeric servname is disallowed if
659 * socktype/protocol are left unspecified. (2) servname is disallowed
660 * for raw and other inet{,6} sockets.
661 */
662 if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
663#ifdef PF_INET6
664 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
665#endif
666 ) {
667 ai0 = *pai; /* backup *pai */
668
669 if (pai->ai_family == PF_UNSPEC) {
670#ifdef PF_INET6
671 pai->ai_family = PF_INET6;
672#else
673 pai->ai_family = PF_INET;
674#endif
675 }
676 error = get_portmatch(pai, servname);
677 if (error)
678 ERR(error);
679
680 *pai = ai0;
681 }
682
683 ai0 = *pai;
684
685 /* NULL hostname, or numeric hostname */
686 for (ex = explore; ex->e_af >= 0; ex++) {
687 *pai = ai0;
688
689 /* PF_UNSPEC entries are prepared for DNS queries only */
690 if (ex->e_af == PF_UNSPEC)
691 continue;
692
693 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
694 continue;
695 if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
696 continue;
697 if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
698 continue;
699
700 if (pai->ai_family == PF_UNSPEC)
701 pai->ai_family = ex->e_af;
702 if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
703 pai->ai_socktype = ex->e_socktype;
704 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
705 pai->ai_protocol = ex->e_protocol;
706
707 if (hostname == NULL)
708 error = explore_null(pai, servname, &cur->ai_next);
709 else
710 error = explore_numeric_scope(pai, hostname, servname,
711 &cur->ai_next);
712
713 if (error)
714 goto free;
715
716 while (cur->ai_next)
717 cur = cur->ai_next;
718 }
719
720 /*
721 * XXX
722 * If numeric representation of AF1 can be interpreted as FQDN
723 * representation of AF2, we need to think again about the code below.
724 */
725 if (sentinel.ai_next)
726 goto good;
727
728 if (hostname == NULL)
729 ERR(EAI_NODATA);
730 if (pai->ai_flags & AI_NUMERICHOST)
731 ERR(EAI_NONAME);
732
733#if defined(__ANDROID__)
734 int gai_error = android_getaddrinfo_proxy(
735 hostname, servname, hints, res, netcontext->app_netid);
736 if (gai_error != EAI_SYSTEM) {
737 return gai_error;
738 }
739#endif
740
741 /*
742 * hostname as alphabetical name.
743 * we would like to prefer AF_INET6 than AF_INET, so we'll make a
744 * outer loop by AFs.
745 */
746 for (ex = explore; ex->e_af >= 0; ex++) {
747 *pai = ai0;
748
749 /* require exact match for family field */
750 if (pai->ai_family != ex->e_af)
751 continue;
752
753 if (!MATCH(pai->ai_socktype, ex->e_socktype,
754 WILD_SOCKTYPE(ex))) {
755 continue;
756 }
757 if (!MATCH(pai->ai_protocol, ex->e_protocol,
758 WILD_PROTOCOL(ex))) {
759 continue;
760 }
761
762 if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
763 pai->ai_socktype = ex->e_socktype;
764 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
765 pai->ai_protocol = ex->e_protocol;
766
767 error = explore_fqdn(
768 pai, hostname, servname, &cur->ai_next, netcontext);
769
770 while (cur && cur->ai_next)
771 cur = cur->ai_next;
772 }
773
774 /* XXX */
775 if (sentinel.ai_next)
776 error = 0;
777
778 if (error)
779 goto free;
780 if (error == 0) {
781 if (sentinel.ai_next) {
782 good:
783 *res = sentinel.ai_next;
784 return SUCCESS;
785 } else
786 error = EAI_FAIL;
787 }
788 free:
789 bad:
790 if (sentinel.ai_next)
791 freeaddrinfo(sentinel.ai_next);
792 *res = NULL;
793 return error;
794}