Android DNS Resolver

DNS 解析器(DNS Resolver)

DNS 解析器模块可保护用户免受 DNS 拦截和配置更新攻击,并改进了 DNS 解析的网络性能。此模块包含用于实现 DNS 桩解析器的代码,该解析器可将 www.google.com 等名称转换为 IP 地址(例如 2001:db8::1)。DNS 桩解析器支持 Java API 元素(如 InetAddress#getAllByName 和 Network#getAllByName)以及原生网络功能,且可发送和接收 DNS 查询以及缓存结果。

Android 10 中的变化

在搭载 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;

参考

  • android 从java到C层文件读取流程
  • 深入理解Android的file.exists()

得知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}

 

你可能感兴趣的:(网络协议)