Dns-Reslover 初始化
init 进程启动后,解析 init.rc,启动了 netd
- //system/netd/server/main.cpp
- bool initDnsResolver() {
- ResolverNetdCallbacks callbacks = {
- .check_calling_permission = &checkCallingPermissionCallback,
- .get_network_context = &getNetworkContextCallback,
- .log = &logCallback,
- .tagSocket = &tagSocketCallback,
- .evaluate_domain_name = &evaluateDomainNameCallback,
- };
- return resolv_init(&callbacks);
- }
- int main(){
- //初始化配置,初始化必要的类
- if (!initDnsResolver()) {
- ALOGE("Unable to init resolver");
- exit(1);
- }
- //注册,启动MDnsService,NetdNativeService,NetdHwService等服务,生存Binder对象供客户调用
- }
复制代码 netd 启动过程中初始化了 Dns-Reslover。初始化过程调用了 initReslover,构造了解析器的回调函数,调用 resolv_init 具体进行初始化。
- bool resolv_init(const ResolverNetdCallbacks* callbacks) {
- //..
- android::net::gDnsResolv = android::net::DnsResolver::getInstance();
- return android::net::gDnsResolv->start();
- }
复制代码 resolv_init 中初始化 Dns 日志系统设置,设置解析器回调函数。接着预备启动Dns-Reslover服务。
Dns-Reslover 启动
- //packages/modules/DnsResolver/DnsResolver.cpp
- bool DnsResolver::start() {
- if (!verifyCallbacks()) {
- LOG(ERROR) << __func__ << ": Callback verification failed";
- return false;
- }
- if (mDnsProxyListener.startListener()) {
- PLOG(ERROR) << __func__ << ": Unable to start DnsProxyListener";
- return false;
- }
- binder_status_t ret;
- if ((ret = DnsResolverService::start()) != STATUS_OK) {
- LOG(ERROR) << __func__ << ": Unable to start DnsResolverService: " << ret;
- return false;
- }
- return true;
- }
复制代码 DnsReslover 启动分为三步,首先检查回调函数是否有效,然后启动 DnsProxyListener 监听Dns解析请求,然后启动DnsReslover 服务。
DnsProxyListener 启动
- //system/core/libsysutils/src/SocketListener.cpp
- int SocketListener::startListener(int backlog) {
-
- if (mListen && listen(mSock, backlog) < 0) {//mListen==true
- SLOGE("Unable to listen on socket (%s)", strerror(errno));
- return -1;
- } else if (!mListen)
- mClients[mSock] = new SocketClient(mSock, false, mUseCmdNum);
-
- if (pipe2(mCtrlPipe, O_CLOEXEC)) {
- SLOGE("pipe failed (%s)", strerror(errno));
- return -1;
- }
- if (pthread_create(&mThread, nullptr, SocketListener::threadStart, this)) {
- SLOGE("pthread_create (%s)", strerror(errno));
- return -1;
- }
- return 0;
- }
复制代码 创建一个监听 socket,创建一个线程间的通信管道。创建一个监听线程,专门处置惩罚解析请求。
- //system/core/libsysutils/src/SocketListener.cpp
- void *SocketListener::threadStart(void *obj) {
- SocketListener *me = reinterpret_cast<SocketListener *>(obj);
- me->runListener();
- pthread_exit(nullptr);
- return nullptr;
- }
- void SocketListener::runListener() {
- while (true) {
- //...
- for (SocketClient* c : pending) {
- // Process it, if false is returned, remove from the map
- SLOGV("processing fd %d", c->getSocket());
- if (!onDataAvailable(c)) {
- release(c, false);
- }
- c->decRef();
- }
- }
- }
复制代码 线程中处置惩罚监听线程,管道和 client 上的全部事件,将有数据到达的 client 挂在一个链表上,依次处置惩罚到达的数据。
DnsResloverService启动
- //packages/modules/DnsResolver/DnsResolverService.cpp
- binder_status_t DnsResolverService::start() {
- std::shared_ptr<DnsResolverService> resolverService =
- ::ndk::SharedRefBase::make<DnsResolverService>();
- binder_status_t status =
- AServiceManager_addService(resolverService->asBinder().get(), getServiceName());
- if (status != STATUS_OK) {
- return status;
- }
- ABinderProcess_startThreadPool();
- return STATUS_OK;
- }
复制代码 服务注册到 Binder 服务管理中,可供其他进程调用。启动 Binder 进程的线程池,以便处置惩罚来自客户端的请求。
Dns 查询
1 来自上层的DNS请求
1 Getaddrinfo
1.1 下发请求
- //libcore/ojluni/src/main/java/java/net/InetAddress.java
- public static InetAddress getByName(String host)
- throws UnknownHostException {
- // Android-changed: Rewritten on the top of Libcore.os.
- return impl.lookupAllHostAddr(host, NETID_UNSET)[0];
- }
复制代码 步伐调用 InetAddress 类中的 getByName 方法来获取一个主机名的 IP 地址。getByName 内部调用到Inet6AddressImpl 中的 lookupAllHostAddr 方法。InetAdress类中另有一些其他方法内部都调用了 Inet6AddressImpl.lookupAllHostAddr,这些方法都是以下的流程。
- //libcore/ojluni/src/main/java/java/net/Inet6AddressImpl.java
- public InetAddress[] lookupAllHostAddr(String host, int netId) throws UnknownHostException {
- //如果已经是IP地址,直接return
- //...
- return lookupHostByName(host, netId);
- }
- private static InetAddress[] lookupHostByName(String host, int netId)
- throws UnknownHostException {
- //...
- StructAddrinfo hints = new StructAddrinfo();
- hints.ai_flags = AI_ADDRCONFIG;
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- InetAddress[] addresses = Libcore.os.android_getaddrinfo(host, hints, netId);
- //...
- return addresses;
- }
复制代码 如果已经是IP地址,直接 return。接下来去cahce中查找,找不到再调用到 Libcore.os 中的 android_getaddrinfo JNI 方法。Libcore 中的全部的 JNI 方法定义在这个文件中:libcore/luni/src/main/java/libcore/io/Linux.java 。实现如下:
- //libcore/luni/src/main/native/libcore_io_Linux.cpp
- static jobjectArray Linux_android_getaddrinfo(JNIEnv* env, jobject, jstring javaNode,
- jobject javaHints, jint netId) {
- ScopedUtfChars node(env, javaNode);
- //...
- addrinfo* addressList = NULL;
- errno = 0;
- int rc = android_getaddrinfofornet(node.c_str(), NULL, &hints, netId, 0, &addressList);
- //...
- // Prepare output array.
- }
复制代码 其中调用了 android_getaddrinfofornet 方法,实现 Dns 解析。
- //bionic/libc/dns/net/getaddrinfo.c
- int android_getaddrinfofornet(const char *hostname, const char *servname,
- const struct addrinfo *hints, unsigned netid, unsigned mark, struct addrinfo **res)
- {
- struct android_net_context netcontext = {
- .app_netid = netid,
- .app_mark = mark,
- .dns_netid = netid,
- .dns_mark = mark,
- .uid = NET_CONTEXT_INVALID_UID,
- };
- return android_getaddrinfofornetcontext(hostname, servname, hints, &netcontext, res);
- }
- int android_getaddrinfofornetcontext(const char *hostname, const char *servname,
- const struct addrinfo *hints, const struct android_net_context *netcontext,
- struct addrinfo **res)
- {
- #if defined(__ANDROID__)
- int gai_error = android_getaddrinfo_proxy(
- hostname, servname, hints, res, netcontext->app_netid);
- if (gai_error != EAI_SYSTEM) {
- return gai_error;
- }
- #endif
- //...
- }
复制代码 android_getaddrinfofornet 调用android_getaddrinfofornetcontext,而android_getaddrinfofornetcontext调用了 android_getaddrinfo_proxy 去连接到 DnsProxyListener ,并构造一个 getaddrinfo 命令下发。接下来具体看一下 android_getaddrinfo_proxy。
- //bionic/libc/dns/net/getaddrinfo.c
- static int android_getaddrinfo_proxy(
- const char *hostname, const char *servname,
- const struct addrinfo *hints, struct addrinfo **res, unsigned netid)
- {
- //...
- FILE* proxy = fdopen(__netdClientDispatch.dnsOpenProxy(), "r+");
- if (proxy == NULL) {
- return EAI_SYSTEM;
- }
- netid = __netdClientDispatch.netIdForResolv(netid);
- // Send the request.
- if (fprintf(proxy, "getaddrinfo %s %s %d %d %d %d %u",
- hostname == NULL ? "^" : hostname,
- servname == NULL ? "^" : servname,
- hints == NULL ? -1 : hints->ai_flags,
- hints == NULL ? -1 : hints->ai_family,
- hints == NULL ? -1 : hints->ai_socktype,
- hints == NULL ? -1 : hints->ai_protocol,
- netid) < 0) {
- goto exit;
- }
- //...
- //receive result
- }
复制代码 重要是在构造命令,连接DnsProxyListener,发送死令并接受请求。再看一下 __netdClientDispatch.dnsOpenProxy的实现
- //bionic/libc/bionic/NetdClient.cpp
- template <typename FunctionType>
- static void netdClientInitFunction(void* handle, const char* symbol, FunctionType* function) {
- typedef void (*InitFunctionType)(FunctionType*);
- InitFunctionType initFunction = reinterpret_cast<InitFunctionType>(dlsym(handle, symbol));
- if (initFunction != nullptr) {
- initFunction(function);
- }
- }
- static void netdClientInitImpl() {
- //...
- void* handle = dlopen("libnetd_client.so", RTLD_NOW);
- //...Init其他函数
- netdClientInitFunction(handle, "netdClientInitDnsOpenProxy",
- &__netdClientDispatch.dnsOpenProxy);
- }
复制代码 dlopen打开的libnetd_client.so定义在netd进程中:
- //system/netd/client/Android.bp
- cc_library {
- name: "libnetd_client",
- //...
- }
复制代码 dlsym函数获取了libnetd_client.so中的netdClientInitDnsOpenProxy函数地址,其代码实现如下所示:
- extern "C" void netdClientInitDnsOpenProxy(DnsOpenProxyType* function) {
- if (function) {
- *function = dns_open_proxy;
- }
- }
复制代码 将 NetdClient.dns_open_proxy 的地址赋给 __netdClientDispatch.dnsOpenProxy 。
- int dns_open_proxy() {
- ....
- const auto socketFunc = libcSocket ? libcSocket : socket;
- int s = socketFunc(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
- if (s == -1) {
- return -1;
- }
- const int one = 1;
- setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
-
- static const struct sockaddr_un proxy_addr = {
- .sun_family = AF_UNIX,
- .sun_path = "/dev/socket/dnsproxyd",
- };
- const auto connectFunc = libcConnect ? libcConnect : connect;
- if (TEMP_FAILURE_RETRY(
- connectFunc(s, (const struct sockaddr*) &proxy_addr, sizeof(proxy_addr))) != 0) {
- // Store the errno for connect because we only care about why we can't connect to dnsproxyd
- int storedErrno = errno;
- close(s);
- errno = storedErrno;
- return -1;
- }
- return s;
- }
复制代码 作为客户端打开 /dev/socket/dnsproxyd 并连接。通过这个 Unix 域套接字,上层和 netd 之间通信,实现 DNS 解析。
1.2 处置惩罚请求
- //system/core/libsysutils/src/SocketListener.cpp
- void SocketListener::runListener() {
- while (true) {
- //...
- for (SocketClient* c : pending) {
- // Process it, if false is returned, remove from the map
- SLOGV("processing fd %d", c->getSocket());
- if (!onDataAvailable(c)) {
- release(c, false);
- }
- c->decRef();
- }
- }
- }
复制代码 DnsProxyListener 监听到来自客户的 Dns 解析请求,于是调用 onDataAvailable 来处置惩罚客户数据。
- //system/core/libsysutils/src/FrameworkListener.cpp
- bool FrameworkListener::onDataAvailable(SocketClient *c) {
- char buffer[CMD_BUF_SIZE];
- int len;
- len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));
- //...
- for (i = 0; i < len; i++) {
- if (buffer[i] == '\0') {
- //...
- dispatchCommand(c, buffer + offset);
- offset = i + 1;
- }
- }
- //...
- }
复制代码 读取客户数据,及从上层送下来的 Dns 解析命令,处置惩罚这些命令字符串。
- //system/core/libsysutils/src/FrameworkListener.cpp
- void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
- int argc = 0;
- char *argv[FrameworkListener::CMD_ARGS_MAX];
- //
- while(*p) {
- //处理字符串
- } 90,1 53%
- *q = '\0';
- if (argc >= CMD_ARGS_MAX)
- goto overflow;
- argv[argc++] = strdup(tmp);
- //...
- for (auto* c : mCommands) {
- if (!strcmp(argv[0], c->getCommand())) {
- if (c->runCommand(cli, argc, argv)) {
- SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
- }
- }
- }
- //...
- }
-
复制代码 找到注册过的命令中跟此命令相匹配的一个,此处是 GetAddrInfoCmd ,实行。
- //packages/modules/DnsResolver/DnsProxyListener.cpp
- int DnsProxyListener::GetAddrInfoCmd::runCommand(SocketClient* cli, int argc, char** argv) {
- logArguments(argc, argv);
- //...
- (new GetAddrInfoHandler(cli, name, service, move(hints), netcontext))->spawn();
- return 0;
- }
复制代码 解析命令参数,设置 getaddrinfo 的相关参数,创建一个 handler 线程,专门处置惩罚 Dns 解析。
- //packages/modules/DnsResolver/DnsProxyListener.cpp
- void DnsProxyListener::GetAddrInfoHandler::run() {
- //...
- if (queryLimiter.start(uid)) {
- const char* host = mHost.starts_with('^') ? nullptr : mHost.c_str();
- const char* service = mService.starts_with('^') ? nullptr : mService.c_str();
- if (evaluate_domain_name(mNetContext, host)) {
- rv = resolv_getaddrinfo(host, service, mHints.get(), &mNetContext, &result, &event);
- } else {
- rv = EAI_SYSTEM;
- }
- queryLimiter.finish(uid);
- } else {
- rv = EAI_MEMORY;
- LOG(ERROR) << "GetAddrInfoHandler::run: from UID " << uid
- << ", max concurrent queries reached";
- }
- doDns64Synthesis(&rv, &result, &event);
- //...
- bool success = true;
- if (rv) {
- success = !mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, &rv, sizeof(rv));
- } else {
- success = !mClient->sendCode(ResponseCode::DnsProxyQueryResult);
- addrinfo* ai = result;
- while (ai && success) {
- success = sendBE32(mClient, 1) && sendaddrinfo(mClient, ai);
- ai = ai->ai_next;
- }
- success = success && sendBE32(mClient, 0);
- }
- //...
- freeaddrinfo(result);
- }
复制代码 以上代码解析 IP 地址,并生存在 result 中,解析效果大概涉及到转换成 IPv4。将解析到的效果发送给 Client。具体的解析函数为 resolv_getaddrinfo。
- //packages/modules/DnsResolver/getaddrinfo.cpp
- int resolv_getaddrinfo(const char* _Nonnull hostname, const char* servname, const addrinfo* hints,
- const android_net_context* _Nonnull netcontext, addrinfo** _Nonnull res,
- NetworkDnsEventReported* _Nonnull event) {
- //...
- addrinfo ai = hints ? *hints : addrinfo{};
- addrinfo sentinel = {};
- addrinfo* cur = &sentinel;
- for (const Explore& ex : explore_options) {
- //...
- addrinfo tmp = ai;
- //..
- error = explore_fqdn(&tmp, hostname, servname, &cur->ai_next, netcontext, event);
- while (cur->ai_next) cur = cur->ai_next;
- }
- //...
- if ((*res = sentinel.ai_next)) return 0;
- //...
- }
复制代码 根据不同的解析选项解析出全部的 addr 并返回。
- //packages/modules/DnsResolver/getaddrinfo.cpp
- static int explore_fqdn(const addrinfo* pai, const char* hostname, const char* servname,
- addrinfo** res, const android_net_context* netcontext,
- NetworkDnsEventReported* event) {
- //...
- if ((error = get_portmatch(pai, servname))) return error;
- if (!files_getaddrinfo(netcontext->dns_netid, hostname, pai, &result)) {
- error = dns_getaddrinfo(hostname, pai, netcontext, &result, event);
- }
- //...
- for (addrinfo* cur = result; cur; cur = cur->ai_next) {
- // canonname should be filled already
- if ((error = get_port(cur, servname, 0))) {
- freeaddrinfo(result);
- return error;
- }
- }
- *res = result;
- return 0;
- }
复制代码 从文件(files_getaddrinfo)大概Dns服务器(dns_getaddrinfo)中获取域名解析效果,并填充端口信息。
- int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int anssiz, int* rcode,
- uint32_t flags, std::chrono::milliseconds sleepTimeMs) {
- //...
- ResolvCacheStatus cache_status =
- resolv_cache_lookup(statp->netid, buf, buflen, ans, anssiz, &anslen, flags);
- const int32_t cacheLatencyUs = saturate_cast<int32_t>(cacheStopwatch.timeTakenUs());
- if (cache_status == RESOLV_CACHE_FOUND) {
- //cache里成功找到,return
- } else if (cache_status != RESOLV_CACHE_UNSUPPORTED) {
- //配置resolver
- }
- // DoT
- if (!(statp->netcontext_flags & NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS)) {
- bool fallback = false; 420,5 33%
- int resplen = res_tls_send(statp, Slice(const_cast<uint8_t*>(buf), buflen),
- Slice(ans, anssiz), rcode, &fallback);
- //return
- }
- //...
- for (int attempt = 0; attempt < retryTimes; ++attempt) {
- for (size_t ns = 0; ns < statp->nsaddrs.size(); ++ns) {
- if (!usable_servers[ns]) continue;
- if (useTcp) {
- // TCP; at most one attempt per server.
- attempt = retryTimes;
- resplen = send_vc(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns,
- &query_time, rcode, &delay);
- } else {
- // UDP
- resplen = send_dg(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, &actualNs,
- &useTcp, &gotsomewhere, &query_time, rcode, &delay);
- //...
- }
- //...
- if (cache_status == RESOLV_CACHE_NOTFOUND) {
- resolv_cache_add(statp->netid, buf, buflen, ans, resplen);
- }
- statp->closeSockets();
- return (resplen);
- }
- }
- //...
- return -terrno;
- }
复制代码 dns_getaddrinfo 一直调用到 res_nsend,首先查找 cache,如果没有的话就正式向设置好的一些Dns服务器去请求Dns解析。首先从 resoler_state 中查找到可用的服务器信息,然后依次向这些服务器发起 Dns 请求。可以利用 TCP 大概 UDP。
2 Resnsend
2.1 下发请求
- //packages/modules/Connectivity/framework/src/android/net/DnsResolver.java
- public void query(@Nullable Network network, @NonNull String domain,
- @QueryType int nsType, @QueryFlag int flags,
- @NonNull @CallbackExecutor Executor executor,
- @Nullable CancellationSignal cancellationSignal,
- @NonNull Callback<? super List<InetAddress>> callback) {
- //...
- queryNetwork = (network != null) ? network : getDnsNetwork();
- queryfd = resNetworkQuery(queryNetwork.getNetIdForResolv(), domain, CLASS_IN, nsType,
- flags);
- //...
- }
复制代码 应用调用 DnsResolver. query 方法开始一次 Dns 解析过程。调用 JNI 接口 resNetworkQuery 向下层发送Dns解析请求。
- //packages/modules/Connectivity/framework/src/android/net/NetworkUtils.java
- private static native FileDescriptor resNetworkQuery(
- long netHandle, String dname, int nsClass, int nsType, int flags) throws ErrnoException;
- //packages/modules/Connectivity/framework/jni/android_net_NetworkUtils.cpp
- static jobject android_net_utils_resNetworkQuery(JNIEnv *env, jobject thiz, jlong netHandle,
- jstring dname, jint ns_class, jint ns_type, jint flags) {
- //...
- int fd = android_res_nquery(netHandle, queryname, ns_class, ns_type, flags);
- //...
- return jniCreateFileDescriptor(env, fd);
- }
- //frameworks/base/native/android/net.c
- int android_res_nquery(net_handle_t network, const char *dname,
- int ns_class, int ns_type, enum ResNsendFlags flags) {
- //...
- return resNetworkQuery(netid, dname, ns_class, ns_type, flags);
- }
- //system/netd/client/NetdClient.cpp
- extern "C" int resNetworkQuery(unsigned netId, const char* dname, int ns_class, int ns_type,
- uint32_t flags) {
- std::vector<uint8_t> buf(MAX_CMD_SIZE, 0);
- int len = res_mkquery(ns_o_query, dname, ns_class, ns_type, nullptr, 0, nullptr, buf.data(),
- MAX_CMD_SIZE);
- return resNetworkSend(netId, buf.data(), len, flags);
- }
复制代码 经过一系列调用,终极调用到 resNetworkQuery 函数。在其中根据参数构造了 query 请求。
- //system/netd/client/NetdClient.cpp
- extern "C" int resNetworkSend(unsigned netId, const uint8_t* msg, size_t msglen, uint32_t flags) {
- // Encode
- netId = getNetworkForResolv(netId);
- const std::string cmd = "resnsend " + std::to_string(netId) + " " + std::to_string(flags) +
- " " + encodedQuery + '\0';
- //error process
- int fd = dns_open_proxy();
- //error process
- ssize_t rc = sendData(fd, cmd.c_str(), cmd.size());
- //error process
- shutdown(fd, SHUT_WR);
- return fd;
- }
复制代码 resNetworkQuery 调用了 resNetworkSend 完成了终极的 query 请求的发送。先将 query 构造成一个下发的命令,接着连接 DnsProxyLIstener,然后将 cmd 发送到 DnsProxyListener ,由 netd 来处置惩罚这个命令。
2.2 处置惩罚请求
与 getaddrinfo 大致类似,只不过 ResnsendCmd 调用了 resolv_resnend,而这个函数直接调用 res_nsend。
3 gethostbyaddr
3.1 下发请求
- //libcore/ojluni/src/main/java/java/net/InetAddress.java
- public String getHostName() {
- // Android-changed: Remove SecurityManager check.
- if (holder().getHostName() == null) {
- holder().hostName = InetAddress.getHostFromNameService(this);
- }
- return holder().getHostName();
- }
- private static String getHostFromNameService(InetAddress addr) {
- String host = null;
- host = nameService.getHostByAddr(addr.getAddress());
- //...
- return host;
- }
- private static final NameService nameService = new NameService() {
- public InetAddress[] lookupAllHostAddr(String host, int netId)
- throws UnknownHostException {
- return impl.lookupAllHostAddr(host, netId);
- }
- public String getHostByAddr(byte[] addr)
- throws UnknownHostException {
- return impl.getHostByAddr(addr);
- }
- };
复制代码 步伐调用 InetAddress 类中的 getHostName 方法来获取一个 IP 地址对应的主机名。getHostName 内部调用到Inet6AddressImpl 中的 getHostByAddr 方法。InetAdress类中另有一些其他方法内部都调用了 Inet6AddressImpl.getHostByAddr,这些方法都是以下的流程。
- //libcore/ojluni/src/main/java/java/net/Inet6AddressImpl.java
- public String getHostByAddr(byte[] addr) throws UnknownHostException {
- BlockGuard.getThreadPolicy().onNetwork();
- return getHostByAddr0(addr);
- }
- private String getHostByAddr0(byte[] addr) throws UnknownHostException {
- InetAddress hostaddr = InetAddress.getByAddress(addr);
- try {
- return Libcore.os.getnameinfo(hostaddr, NI_NAMEREQD);
- } catch (GaiException e) {
- UnknownHostException uhe = new UnknownHostException(hostaddr.toString());
- uhe.initCause(e);
- throw uhe;
- }
- }
复制代码 其中再次调用到 Libcore.os 中的 getnameinfo JNI 方法。Libcore 中的全部的 JNI 方法定义在这个文件中:libcore/luni/src/main/java/libcore/io/Linux.java 。实现如下:
- //libcore/luni/src/main/native/libcore_io_Linux.cpp
- static jstring Linux_getnameinfo(JNIEnv* env, jobject, jobject javaAddress, jint flags) {
- sockaddr_storage ss;
- socklen_t sa_len;
- if (!inetAddressToSockaddrVerbatim(env, javaAddress, 0, ss, sa_len)) {
- return NULL;
- }
- char buf[NI_MAXHOST]; // NI_MAXHOST is longer than INET6_ADDRSTRLEN.
- errno = 0;
- int rc = getnameinfo(reinterpret_cast<sockaddr*>(&ss), sa_len, buf, sizeof(buf), NULL, 0, flags);
- if (rc != 0) {
- throwGaiException(env, "getnameinfo", rc);
- return NULL;
- }
- return env->NewStringUTF(buf);
- }
- //bionic/libc/dns/net/getnameinfo.c
- int getnameinfo(const struct sockaddr* sa, socklen_t salen, char* host, size_t hostlen,
- char* serv, size_t servlen, int flags)
- {
- return android_getnameinfofornet(sa, salen, host, hostlen, serv, servlen, flags,
- NETID_UNSET, MARK_UNSET);
- }
- int android_getnameinfofornet(const struct sockaddr* sa, socklen_t salen, char* host,
- size_t hostlen, char* serv, size_t servlen, int flags, unsigned netid,
- unsigned mark)
- {
- switch (sa->sa_family) {
- case AF_INET:
- case AF_INET6:
- return getnameinfo_inet(sa, salen, host, hostlen,
- serv, servlen, flags, netid, mark);
- case AF_LOCAL://从sa中读就行
- return getnameinfo_local(sa, salen, host, hostlen,
- serv, servlen, flags);
- default:
- return EAI_FAMILY;
- }
- }
- static int getnameinfo_inet(const struct sockaddr* sa, socklen_t salen,
- char *host, socklen_t hostlen,
- char *serv, socklen_t servlen,
- int flags, unsigned netid, unsigned mark)
- {
- //...
- const struct android_net_context netcontext = { .app_netid = netid, .app_mark = mark };
- hp = android_gethostbyaddrfornetcontext_proxy(addr, afd->a_addrlen, afd->a_af, &netcontext);
- //...
- }
复制代码 一直调用到 getnameinfo_inet 函数,真正去发送 gethostbyaddr 的请求。android_gethostbyaddrfornetcontext_proxy 向 DnsProxyListener 发送请求并返回一个 host 信息的结构体。
- //bionic/libc/dns/net/gethnamaddr.c
- static struct hostent* android_gethostbyaddrfornetcontext_proxy_internal(const void* addr, socklen_t len, int af,
- struct hostent *hp, char *hbuf, size_t hbuflen, int *he,
- const struct android_net_context *netcontext)
- {
- FILE* proxy = fdopen(__netdClientDispatch.dnsOpenProxy(), "r+");
- //...
- //send
- if (fprintf(proxy, "gethostbyaddr %s %d %d %u",
- addrStr, len, af, netid) < 0) {
- fclose(proxy);
- return NULL;
- }
- //...
- ///receive
- struct hostent *result = android_read_hostent(proxy, hp, hbuf, hbuflen, he);
- fclose(proxy);
- return result;
- }
复制代码 android_gethostbyaddrfornetcontext_proxy 中调用到 android_gethostbyaddrfornetcontext_proxy_internal。android_gethostbyaddrfornetcontext_proxy_internal 中连接到 DnsProxyListener,并通过 printf
发送了一个 gethostbyaddr 命令。
3.2 处置惩罚请求
- //packages/modules/DnsResolver/gethnamaddr.cpp
- int resolv_gethostbyaddr(const void* addr, socklen_t len, int af, hostent* hp, char* buf,
- size_t buflen, const struct android_net_context* netcontext,
- hostent** result, NetworkDnsEventReported* event) {
- //...
- if (_hf_gethtbyaddr(uaddr, len, af, &info)) {
- int error = dns_gethtbyaddr(uaddr, len, af, netcontext, &info, event);
- if (error != 0) return error;
- }
- *result = hp;
- return 0;
- }
- //packages/modules/DnsResolver/gethnamaddr.cpp
- static int dns_gethtbyaddr(const unsigned char* uaddr, int len, int af,
- const android_net_context* netcontext, getnamaddr* info,
- NetworkDnsEventReported* event) {
- //...
- n = res_nquery(&res, qbuf, C_IN, T_PTR, buf->buf, (int)sizeof(buf->buf), &he);
- }
- //packages/modules/DnsResolver/res_query.cpp
- int res_nquery(res_state statp, const char* name, // domain name
- int cl, int type, // class and type of query
- uint8_t* answer, // buffer to put answer
- int anslen, // size of answer buffer
- int* herrno) // legacy and extended h_errno
- // NETD_RESOLV_H_ERRNO_EXT_*
- {
- //...
- n = res_nmkquery(QUERY, name, cl, type, /*data=*/nullptr, 0, buf, sizeof(buf),
- statp->netcontext_flags);
- //...
- n = res_nsend(statp, buf, n, answer, anslen, &rcode, 0);
复制代码 GethostbyaddrCmd 中调用了 resolv_gethostbyaddr,其中先在本地文件解析,然后利用Dns解析。在Dns解析过程中还是利用了 res_nsend。接下来流程都是一样的。
2 作为AP,接受STA的dns请求
Tethering 进入 TetherModeAliveState 状态是 enter 中 调用了 turnOnMainTetherSettings。
- //packages/modules/Connectivity/Tethering/src/com/android/networkstack/tethering/Tethering.java
- protected boolean turnOnMainTetherSettings() {
- final TetheringConfiguration cfg = mConfig;
- try {
- mNetd.ipfwdEnableForwarding(TAG);
- } catch (RemoteException | ServiceSpecificException e) {
- mLog.e(e);
- transitionTo(mSetIpForwardingEnabledErrorState);
- return false;
- }
- // TODO: Randomize DHCPv4 ranges, especially in hotspot mode.
- // Legacy DHCP server is disabled if passed an empty ranges array
- final String[] dhcpRanges = cfg.enableLegacyDhcpServer
- ? cfg.legacyDhcpRanges : new String[0];
- try {
- NetdUtils.tetherStart(mNetd, true /** usingLegacyDnsProxy */, dhcpRanges);
- } catch (RemoteException | ServiceSpecificException e) {
- try {
- // Stop and retry.
- mNetd.tetherStop();
- NetdUtils.tetherStart(mNetd, true /** usingLegacyDnsProxy */, dhcpRanges);
- } catch (RemoteException | ServiceSpecificException ee) {
- mLog.e(ee);
- transitionTo(mStartTetheringErrorState);
- return false;
- }
- }
- mLog.log("SET main tether settings: ON");
- return true;
- }
复制代码 调用 NetdUtils 中的 tetherStart 方法,传入参数 usingLegacyDnsProxy = true,这里的意思是通过 Dnsmasq 来处置惩罚Dns 请求,而 dhcpRanges = null,所以倒霉用 Dnsmasq 来处置惩罚 DHCP 请求。tetherStart 中调用到了 Netd 服务中的 tetherStartWithConfiguration 方法。tetherStartWithConfiguration 的具体实现是 Netd 内部的 tetherController 来实现的。其中开启了 Dnsmasq 进程用以处置惩罚 DNS 请求。
3 res_nsend 具体实现
DnsPacket
http://c.biancheng.net/view/6457.html
Dns设置得到
1 来自上层的DNS请求
ConnectivityService内部有两个Handler:NetworkStateTrackerHandler,InternalHandler。
1.InternalHandler
收到**EVENT_PRIVATE_DNS_SETTINGS_CHANGED消息,调用handlePrivateDnsSettingsChanged**
->handlePerNetworkPrivateDnsConfig->updatePrivateDns->updateDnses。
onNetworkMonitorCreated被触发后收到EVENT_REGISTER_NETWORK_AGENT消息,调用handleRegisterNetworkAgent->updateNetworkInfo
->handlePerNetworkPrivateDnsConfig->updatePrivateDns->updateDnses。
onPrivateDnsValidationEvent被触发收到EVENT_PRIVATE_DNS_VALIDATION_UPDATE消息,调用handlePrivateDnsValidationUpdate****->handleUpdateLinkProperties->updateLinkProperties->updateDnses。
2.NetworkStateTrackerHandler
收到***NetworkAgent.EVENT_NETWORK_INFO_CHANGED消息,调用maybeHandleNetworkAgentMessage***
->updateNetworkInfo->handlePerNetworkPrivateDnsConfig->updatePrivateDns->updateDnses。
收到**EVENT_PRIVATE_DNS_CONFIG_RESOLVED消息,maybeHandleNetworkMonitorMessage**
->****updatePrivateDns->updateDnses。
收到**NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGE,maybeHandleNetworkAgentMessage**
->handleUpdateLinkProperties->updateLinkProperties->updateDnses。
收到**EVENT_CAPPORT_DATA_CHANGED消息,调用maybeHandleNetworkMonitorMessage->** **handleCapportApiDataUpdate->handleUpdateLinkProperties->updateLinkProperties->updateDnses。**
2 来自其他设备的DNS请求
- //packages/modules/Connectivity/Tethering/src/com/android/networkstack/tethering/Tethering.java
- public void enter() {
- //...
- if (upstreamWanted()) {
- mUpstreamWanted = true;
- mOffload.start();
- chooseUpstreamType(true);
- mTryCell = false;
- }
- //...
- }
复制代码 之前的流程与 NAT 部分相同,调用到 chooseUpstreamType。经过一系列调用,终极调用到 setDnsForwarders。
- //packages/modules/Connectivity/Tethering/src/com/android/networkstack/tethering/Tethering.java
- protected void setDnsForwarders(final Network network, final LinkProperties lp) {
- // TODO: Set v4 and/or v6 DNS per available connectivity.
- final Collection<InetAddress> dnses = lp.getDnsServers();
- // TODO: Properly support the absence of DNS servers.
- final String[] dnsServers;
- if (dnses != null && !dnses.isEmpty()) {
- dnsServers = new String[dnses.size()];
- int i = 0;
- for (InetAddress dns : dnses) {
- dnsServers[i++] = dns.getHostAddress();
- }
- } else {
- dnsServers = mConfig.defaultIPv4DNS;
- }
- final int netId = (network != null) ? network.getNetId() : NETID_UNSET;
- try {
- mNetd.tetherDnsSet(netId, dnsServers);
- mLog.log(String.format(
- "SET DNS forwarders: network=%s dnsServers=%s",
- network, Arrays.toString(dnsServers)));
- } catch (RemoteException | ServiceSpecificException e) {
- // TODO: Investigate how this can fail and what exactly
- // happens if/when such failures occur.
- mLog.e("setting DNS forwarders failed, " + e);
- transitionTo(mSetDnsForwardersErrorState);
- }
- }
复制代码 其中调用了 Netd服务的 tetherDnsSet 方法,进行Dns的设置。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |