【Android】(十三) DNS-Resolver

打印 上一主题 下一主题

主题 1024|帖子 1024|积分 3072

Dns-Reslover 初始化

init 进程启动后,解析 init.rc,启动了 netd
  1. //system/netd/server/main.cpp
  2. bool initDnsResolver() {
  3.     ResolverNetdCallbacks callbacks = {
  4.         .check_calling_permission = &checkCallingPermissionCallback,
  5.         .get_network_context = &getNetworkContextCallback,
  6.         .log = &logCallback,
  7.         .tagSocket = &tagSocketCallback,
  8.         .evaluate_domain_name = &evaluateDomainNameCallback,
  9.     };
  10.     return resolv_init(&callbacks);
  11. }
  12. int main(){
  13.     //初始化配置,初始化必要的类
  14.     if (!initDnsResolver()) {
  15.         ALOGE("Unable to init resolver");
  16.         exit(1);
  17.     }
  18.     //注册,启动MDnsService,NetdNativeService,NetdHwService等服务,生存Binder对象供客户调用
  19. }
复制代码
netd 启动过程中初始化了 Dns-Reslover。初始化过程调用了 initReslover,构造了解析器的回调函数,调用 resolv_init 具体进行初始化。
  1. bool resolv_init(const ResolverNetdCallbacks* callbacks) {
  2.     //..
  3.     android::net::gDnsResolv = android::net::DnsResolver::getInstance();
  4.     return android::net::gDnsResolv->start();
  5. }
复制代码
resolv_init 中初始化 Dns 日志系统设置,设置解析器回调函数。接着预备启动Dns-Reslover服务。
Dns-Reslover 启动

  1. //packages/modules/DnsResolver/DnsResolver.cpp
  2. bool DnsResolver::start() {
  3.     if (!verifyCallbacks()) {
  4.         LOG(ERROR) << __func__ << ": Callback verification failed";
  5.         return false;
  6.     }
  7.     if (mDnsProxyListener.startListener()) {
  8.         PLOG(ERROR) << __func__ << ": Unable to start DnsProxyListener";
  9.         return false;
  10.     }
  11.     binder_status_t ret;
  12.     if ((ret = DnsResolverService::start()) != STATUS_OK) {
  13.         LOG(ERROR) << __func__ << ": Unable to start DnsResolverService: " << ret;
  14.         return false;
  15.     }
  16.     return true;
  17. }
复制代码
DnsReslover 启动分为三步,首先检查回调函数是否有效,然后启动 DnsProxyListener 监听Dns解析请求,然后启动DnsReslover 服务。
DnsProxyListener 启动

  1. //system/core/libsysutils/src/SocketListener.cpp
  2. int SocketListener::startListener(int backlog) {
  3.    
  4.     if (mListen && listen(mSock, backlog) < 0) {//mListen==true
  5.         SLOGE("Unable to listen on socket (%s)", strerror(errno));
  6.         return -1;
  7.     } else if (!mListen)
  8.         mClients[mSock] = new SocketClient(mSock, false, mUseCmdNum);
  9.    
  10.     if (pipe2(mCtrlPipe, O_CLOEXEC)) {
  11.         SLOGE("pipe failed (%s)", strerror(errno));
  12.         return -1;
  13.     }
  14.     if (pthread_create(&mThread, nullptr, SocketListener::threadStart, this)) {
  15.         SLOGE("pthread_create (%s)", strerror(errno));
  16.         return -1;
  17.     }
  18.     return 0;
  19. }
复制代码
创建一个监听 socket,创建一个线程间的通信管道。创建一个监听线程,专门处置惩罚解析请求。
  1. //system/core/libsysutils/src/SocketListener.cpp
  2. void *SocketListener::threadStart(void *obj) {
  3.     SocketListener *me = reinterpret_cast<SocketListener *>(obj);
  4.     me->runListener();
  5.     pthread_exit(nullptr);
  6.     return nullptr;
  7. }
  8. void SocketListener::runListener() {
  9.     while (true) {
  10.         //...
  11.         for (SocketClient* c : pending) {
  12.             // Process it, if false is returned, remove from the map
  13.             SLOGV("processing fd %d", c->getSocket());
  14.             if (!onDataAvailable(c)) {
  15.                 release(c, false);
  16.             }
  17.             c->decRef();
  18.         }
  19.     }
  20. }
复制代码
线程中处置惩罚监听线程,管道和 client 上的全部事件,将有数据到达的 client 挂在一个链表上,依次处置惩罚到达的数据。
DnsResloverService启动

  1. //packages/modules/DnsResolver/DnsResolverService.cpp
  2. binder_status_t DnsResolverService::start() {
  3.     std::shared_ptr<DnsResolverService> resolverService =
  4.             ::ndk::SharedRefBase::make<DnsResolverService>();
  5.     binder_status_t status =
  6.             AServiceManager_addService(resolverService->asBinder().get(), getServiceName());
  7.     if (status != STATUS_OK) {
  8.         return status;
  9.     }
  10.     ABinderProcess_startThreadPool();
  11.     return STATUS_OK;
  12. }
复制代码
服务注册到 Binder 服务管理中,可供其他进程调用。启动 Binder 进程的线程池,以便处置惩罚来自客户端的请求。
Dns 查询

1 来自上层的DNS请求

1 Getaddrinfo

1.1 下发请求


  1. //libcore/ojluni/src/main/java/java/net/InetAddress.java
  2. public static InetAddress getByName(String host)
  3.     throws UnknownHostException {
  4.     // Android-changed: Rewritten on the top of Libcore.os.
  5.     return impl.lookupAllHostAddr(host, NETID_UNSET)[0];
  6. }
复制代码
步伐调用 InetAddress 类中的 getByName 方法来获取一个主机名的 IP 地址。getByName 内部调用到Inet6AddressImpl 中的 lookupAllHostAddr 方法。InetAdress类中另有一些其他方法内部都调用了 Inet6AddressImpl.lookupAllHostAddr,这些方法都是以下的流程。
  1. //libcore/ojluni/src/main/java/java/net/Inet6AddressImpl.java
  2. public InetAddress[] lookupAllHostAddr(String host, int netId) throws UnknownHostException {
  3.     //如果已经是IP地址,直接return
  4.     //...
  5.     return lookupHostByName(host, netId);
  6. }
  7. private static InetAddress[] lookupHostByName(String host, int netId)
  8.         throws UnknownHostException {
  9.     //...
  10.     StructAddrinfo hints = new StructAddrinfo();
  11.     hints.ai_flags = AI_ADDRCONFIG;
  12.     hints.ai_family = AF_UNSPEC;
  13.     hints.ai_socktype = SOCK_STREAM;
  14.     InetAddress[] addresses = Libcore.os.android_getaddrinfo(host, hints, netId);
  15.     //...
  16.     return addresses;
  17. }
复制代码
如果已经是IP地址,直接 return。接下来去cahce中查找,找不到再调用到 Libcore.os 中的 android_getaddrinfo JNI 方法。Libcore 中的全部的 JNI 方法定义在这个文件中:libcore/luni/src/main/java/libcore/io/Linux.java 。实现如下:
  1. //libcore/luni/src/main/native/libcore_io_Linux.cpp
  2. static jobjectArray Linux_android_getaddrinfo(JNIEnv* env, jobject, jstring javaNode,
  3.         jobject javaHints, jint netId) {
  4.     ScopedUtfChars node(env, javaNode);
  5.     //...
  6.     addrinfo* addressList = NULL;
  7.     errno = 0;
  8.     int rc = android_getaddrinfofornet(node.c_str(), NULL, &hints, netId, 0, &addressList);
  9.     //...
  10.     // Prepare output array.
  11. }
复制代码
其中调用了 android_getaddrinfofornet 方法,实现 Dns 解析。
  1. //bionic/libc/dns/net/getaddrinfo.c
  2. int android_getaddrinfofornet(const char *hostname, const char *servname,
  3.     const struct addrinfo *hints, unsigned netid, unsigned mark, struct addrinfo **res)
  4. {
  5.         struct android_net_context netcontext = {
  6.                 .app_netid = netid,
  7.                 .app_mark = mark,
  8.                 .dns_netid = netid,
  9.                 .dns_mark = mark,
  10.                 .uid = NET_CONTEXT_INVALID_UID,
  11.         };
  12.         return android_getaddrinfofornetcontext(hostname, servname, hints, &netcontext, res);
  13. }
  14. int android_getaddrinfofornetcontext(const char *hostname, const char *servname,
  15.     const struct addrinfo *hints, const struct android_net_context *netcontext,
  16.     struct addrinfo **res)
  17. {
  18. #if defined(__ANDROID__)
  19.     int gai_error = android_getaddrinfo_proxy(
  20.             hostname, servname, hints, res, netcontext->app_netid);
  21.     if (gai_error != EAI_SYSTEM) {
  22.             return gai_error;
  23.     }
  24. #endif
  25.     //...
  26. }
复制代码
android_getaddrinfofornet 调用android_getaddrinfofornetcontext,而android_getaddrinfofornetcontext调用了 android_getaddrinfo_proxy 去连接到 DnsProxyListener ,并构造一个 getaddrinfo 命令下发。接下来具体看一下 android_getaddrinfo_proxy。
  1. //bionic/libc/dns/net/getaddrinfo.c
  2. static int android_getaddrinfo_proxy(
  3.     const char *hostname, const char *servname,
  4.     const struct addrinfo *hints, struct addrinfo **res, unsigned netid)
  5. {
  6.         //...
  7.         FILE* proxy = fdopen(__netdClientDispatch.dnsOpenProxy(), "r+");
  8.         if (proxy == NULL) {
  9.                 return EAI_SYSTEM;
  10.         }
  11.         netid = __netdClientDispatch.netIdForResolv(netid);
  12.         // Send the request.
  13.         if (fprintf(proxy, "getaddrinfo %s %s %d %d %d %d %u",
  14.                     hostname == NULL ? "^" : hostname,
  15.                     servname == NULL ? "^" : servname,
  16.                     hints == NULL ? -1 : hints->ai_flags,
  17.                     hints == NULL ? -1 : hints->ai_family,
  18.                     hints == NULL ? -1 : hints->ai_socktype,
  19.                     hints == NULL ? -1 : hints->ai_protocol,
  20.                     netid) < 0) {
  21.                 goto exit;
  22.         }
  23.         //...
  24.         //receive result
  25. }
复制代码
重要是在构造命令,连接DnsProxyListener,发送死令并接受请求。再看一下 __netdClientDispatch.dnsOpenProxy的实现
  1. //bionic/libc/bionic/NetdClient.cpp
  2. template <typename FunctionType>
  3. static void netdClientInitFunction(void* handle, const char* symbol, FunctionType* function) {
  4.     typedef void (*InitFunctionType)(FunctionType*);
  5.     InitFunctionType initFunction = reinterpret_cast<InitFunctionType>(dlsym(handle, symbol));
  6.     if (initFunction != nullptr) {
  7.         initFunction(function);
  8.     }
  9. }
  10. static void netdClientInitImpl() {
  11.     //...
  12.     void* handle = dlopen("libnetd_client.so", RTLD_NOW);
  13.     //...Init其他函数
  14.     netdClientInitFunction(handle, "netdClientInitDnsOpenProxy",
  15.                            &__netdClientDispatch.dnsOpenProxy);
  16. }
复制代码
dlopen打开的libnetd_client.so定义在netd进程中:
  1. //system/netd/client/Android.bp
  2. cc_library {
  3.     name: "libnetd_client",
  4.     //...
  5. }
复制代码
dlsym函数获取了libnetd_client.so中的netdClientInitDnsOpenProxy函数地址,其代码实现如下所示:
  1. extern "C" void netdClientInitDnsOpenProxy(DnsOpenProxyType* function) {
  2.     if (function) {
  3.         *function = dns_open_proxy;
  4.     }
  5. }
复制代码
将 NetdClient.dns_open_proxy 的地址赋给 __netdClientDispatch.dnsOpenProxy 。
  1. int dns_open_proxy() {
  2.     ....
  3.     const auto socketFunc = libcSocket ? libcSocket : socket;
  4.     int s = socketFunc(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
  5.     if (s == -1) {
  6.         return -1;
  7.     }
  8.     const int one = 1;
  9.     setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
  10.    
  11.     static const struct sockaddr_un proxy_addr = {
  12.             .sun_family = AF_UNIX,
  13.             .sun_path = "/dev/socket/dnsproxyd",
  14.     };
  15.     const auto connectFunc = libcConnect ? libcConnect : connect;
  16.     if (TEMP_FAILURE_RETRY(
  17.                 connectFunc(s, (const struct sockaddr*) &proxy_addr, sizeof(proxy_addr))) != 0) {
  18.         // Store the errno for connect because we only care about why we can't connect to dnsproxyd
  19.         int storedErrno = errno;
  20.         close(s);
  21.         errno = storedErrno;
  22.         return -1;
  23.     }
  24.     return s;
  25. }
复制代码
作为客户端打开 /dev/socket/dnsproxyd 并连接。通过这个 Unix 域套接字,上层和 netd 之间通信,实现 DNS 解析。
1.2 处置惩罚请求


  1. //system/core/libsysutils/src/SocketListener.cpp
  2. void SocketListener::runListener() {
  3.     while (true) {
  4.         //...
  5.         for (SocketClient* c : pending) {
  6.             // Process it, if false is returned, remove from the map
  7.             SLOGV("processing fd %d", c->getSocket());
  8.             if (!onDataAvailable(c)) {
  9.                 release(c, false);
  10.             }
  11.             c->decRef();
  12.         }
  13.     }
  14. }
复制代码
DnsProxyListener 监听到来自客户的 Dns 解析请求,于是调用 onDataAvailable 来处置惩罚客户数据。
  1. //system/core/libsysutils/src/FrameworkListener.cpp
  2. bool FrameworkListener::onDataAvailable(SocketClient *c) {
  3.     char buffer[CMD_BUF_SIZE];
  4.     int len;
  5.     len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));
  6.     //...
  7.     for (i = 0; i < len; i++) {
  8.         if (buffer[i] == '\0') {
  9.             //...
  10.             dispatchCommand(c, buffer + offset);
  11.             offset = i + 1;
  12.         }
  13.     }
  14.     //...
  15. }
复制代码
读取客户数据,及从上层送下来的 Dns 解析命令,处置惩罚这些命令字符串。
  1. //system/core/libsysutils/src/FrameworkListener.cpp
  2. void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
  3.     int argc = 0;
  4.     char *argv[FrameworkListener::CMD_ARGS_MAX];
  5.     //
  6.     while(*p) {
  7.         //处理字符串
  8.     }                                                                                                                                                                                     90,1          53%
  9.     *q = '\0';
  10.     if (argc >= CMD_ARGS_MAX)
  11.         goto overflow;
  12.     argv[argc++] = strdup(tmp);
  13.     //...
  14.     for (auto* c : mCommands) {
  15.         if (!strcmp(argv[0], c->getCommand())) {
  16.             if (c->runCommand(cli, argc, argv)) {
  17.                 SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
  18.             }
  19.         }
  20.     }
  21.     //...
  22. }
  23.                
复制代码
找到注册过的命令中跟此命令相匹配的一个,此处是 GetAddrInfoCmd ,实行。
  1. //packages/modules/DnsResolver/DnsProxyListener.cpp
  2. int DnsProxyListener::GetAddrInfoCmd::runCommand(SocketClient* cli, int argc, char** argv) {
  3.     logArguments(argc, argv);
  4.     //...
  5.     (new GetAddrInfoHandler(cli, name, service, move(hints), netcontext))->spawn();
  6.     return 0;
  7. }
复制代码
解析命令参数,设置 getaddrinfo 的相关参数,创建一个 handler 线程,专门处置惩罚 Dns 解析。
  1. //packages/modules/DnsResolver/DnsProxyListener.cpp
  2. void DnsProxyListener::GetAddrInfoHandler::run() {
  3.     //...
  4.     if (queryLimiter.start(uid)) {
  5.         const char* host = mHost.starts_with('^') ? nullptr : mHost.c_str();
  6.         const char* service = mService.starts_with('^') ? nullptr : mService.c_str();
  7.         if (evaluate_domain_name(mNetContext, host)) {
  8.             rv = resolv_getaddrinfo(host, service, mHints.get(), &mNetContext, &result, &event);
  9.         } else {
  10.             rv = EAI_SYSTEM;
  11.         }
  12.         queryLimiter.finish(uid);
  13.     } else {
  14.         rv = EAI_MEMORY;
  15.         LOG(ERROR) << "GetAddrInfoHandler::run: from UID " << uid
  16.                    << ", max concurrent queries reached";
  17.     }
  18.     doDns64Synthesis(&rv, &result, &event);
  19.     //...
  20.     bool success = true;
  21.     if (rv) {
  22.         success = !mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, &rv, sizeof(rv));
  23.     } else {
  24.         success = !mClient->sendCode(ResponseCode::DnsProxyQueryResult);
  25.         addrinfo* ai = result;
  26.         while (ai && success) {
  27.             success = sendBE32(mClient, 1) && sendaddrinfo(mClient, ai);
  28.             ai = ai->ai_next;
  29.         }
  30.         success = success && sendBE32(mClient, 0);
  31.     }
  32.     //...
  33.     freeaddrinfo(result);
  34. }
复制代码
以上代码解析 IP 地址,并生存在 result 中,解析效果大概涉及到转换成 IPv4。将解析到的效果发送给 Client。具体的解析函数为 resolv_getaddrinfo。
  1. //packages/modules/DnsResolver/getaddrinfo.cpp
  2. int resolv_getaddrinfo(const char* _Nonnull hostname, const char* servname, const addrinfo* hints,
  3.                        const android_net_context* _Nonnull netcontext, addrinfo** _Nonnull res,
  4.                        NetworkDnsEventReported* _Nonnull event) {
  5.     //...
  6.     addrinfo ai = hints ? *hints : addrinfo{};
  7.     addrinfo sentinel = {};
  8.     addrinfo* cur = &sentinel;
  9.     for (const Explore& ex : explore_options) {
  10.         //...
  11.         addrinfo tmp = ai;
  12.         //..
  13.         error = explore_fqdn(&tmp, hostname, servname, &cur->ai_next, netcontext, event);
  14.         while (cur->ai_next) cur = cur->ai_next;
  15.     }
  16.     //...
  17.     if ((*res = sentinel.ai_next)) return 0;
  18.     //...
  19. }
复制代码
根据不同的解析选项解析出全部的 addr 并返回。
  1. //packages/modules/DnsResolver/getaddrinfo.cpp
  2. static int explore_fqdn(const addrinfo* pai, const char* hostname, const char* servname,
  3.                         addrinfo** res, const android_net_context* netcontext,
  4.                         NetworkDnsEventReported* event) {
  5.     //...
  6.     if ((error = get_portmatch(pai, servname))) return error;
  7.     if (!files_getaddrinfo(netcontext->dns_netid, hostname, pai, &result)) {
  8.         error = dns_getaddrinfo(hostname, pai, netcontext, &result, event);
  9.     }
  10.     //...
  11.     for (addrinfo* cur = result; cur; cur = cur->ai_next) {
  12.         // canonname should be filled already
  13.         if ((error = get_port(cur, servname, 0))) {
  14.             freeaddrinfo(result);
  15.             return error;
  16.         }
  17.     }
  18.     *res = result;
  19.     return 0;
  20. }
复制代码
从文件(files_getaddrinfo)大概Dns服务器(dns_getaddrinfo)中获取域名解析效果,并填充端口信息。
  1. int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int anssiz, int* rcode,
  2.               uint32_t flags, std::chrono::milliseconds sleepTimeMs) {
  3.     //...
  4.     ResolvCacheStatus cache_status =
  5.             resolv_cache_lookup(statp->netid, buf, buflen, ans, anssiz, &anslen, flags);
  6.     const int32_t cacheLatencyUs = saturate_cast<int32_t>(cacheStopwatch.timeTakenUs());
  7.     if (cache_status == RESOLV_CACHE_FOUND) {
  8.         //cache里成功找到,return
  9.     } else if (cache_status != RESOLV_CACHE_UNSUPPORTED) {
  10.         //配置resolver
  11.     }
  12.     // DoT
  13.     if (!(statp->netcontext_flags & NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS)) {
  14.         bool fallback = false;                                                                                                                                                                               420,5         33%
  15.         int resplen = res_tls_send(statp, Slice(const_cast<uint8_t*>(buf), buflen),
  16.                                    Slice(ans, anssiz), rcode, &fallback);
  17.         //return
  18.     }
  19.     //...
  20.     for (int attempt = 0; attempt < retryTimes; ++attempt) {
  21.         for (size_t ns = 0; ns < statp->nsaddrs.size(); ++ns) {
  22.             if (!usable_servers[ns]) continue;
  23.             if (useTcp) {
  24.                 // TCP; at most one attempt per server.
  25.                 attempt = retryTimes;
  26.                 resplen = send_vc(statp, &params, buf, buflen, ans, anssiz, &terrno, ns,
  27.                                   &query_time, rcode, &delay);
  28.             } else {
  29.                 // UDP
  30.                 resplen = send_dg(statp, &params, buf, buflen, ans, anssiz, &terrno, &actualNs,
  31.                                   &useTcp, &gotsomewhere, &query_time, rcode, &delay);
  32.                 //...
  33.             }
  34.             //...
  35.             if (cache_status == RESOLV_CACHE_NOTFOUND) {
  36.                 resolv_cache_add(statp->netid, buf, buflen, ans, resplen);
  37.             }
  38.             statp->closeSockets();
  39.             return (resplen);
  40.         }
  41.     }
  42.     //...
  43.     return -terrno;
  44. }
复制代码
dns_getaddrinfo 一直调用到 res_nsend,首先查找 cache,如果没有的话就正式向设置好的一些Dns服务器去请求Dns解析。首先从 resoler_state 中查找到可用的服务器信息,然后依次向这些服务器发起 Dns 请求。可以利用 TCP 大概 UDP。
2 Resnsend

2.1 下发请求

  1. //packages/modules/Connectivity/framework/src/android/net/DnsResolver.java
  2. public void query(@Nullable Network network, @NonNull String domain,
  3.         @QueryType int nsType, @QueryFlag int flags,
  4.         @NonNull @CallbackExecutor Executor executor,
  5.         @Nullable CancellationSignal cancellationSignal,
  6.         @NonNull Callback<? super List<InetAddress>> callback) {
  7.     //...
  8.     queryNetwork = (network != null) ? network : getDnsNetwork();
  9.     queryfd = resNetworkQuery(queryNetwork.getNetIdForResolv(), domain, CLASS_IN, nsType,
  10.             flags);
  11.     //...
  12. }
复制代码
应用调用 DnsResolver. query 方法开始一次 Dns 解析过程。调用 JNI 接口 resNetworkQuery 向下层发送Dns解析请求。
  1. //packages/modules/Connectivity/framework/src/android/net/NetworkUtils.java
  2. private static native FileDescriptor resNetworkQuery(
  3.             long netHandle, String dname, int nsClass, int nsType, int flags) throws ErrnoException;
  4. //packages/modules/Connectivity/framework/jni/android_net_NetworkUtils.cpp
  5. static jobject android_net_utils_resNetworkQuery(JNIEnv *env, jobject thiz, jlong netHandle,
  6.         jstring dname, jint ns_class, jint ns_type, jint flags) {
  7.     //...
  8.     int fd = android_res_nquery(netHandle, queryname, ns_class, ns_type, flags);
  9.     //...
  10.     return jniCreateFileDescriptor(env, fd);
  11. }
  12. //frameworks/base/native/android/net.c
  13. int android_res_nquery(net_handle_t network, const char *dname,
  14.         int ns_class, int ns_type, enum ResNsendFlags flags) {
  15.     //...
  16.     return resNetworkQuery(netid, dname, ns_class, ns_type, flags);
  17. }
  18. //system/netd/client/NetdClient.cpp
  19. extern "C" int resNetworkQuery(unsigned netId, const char* dname, int ns_class, int ns_type,
  20.                                uint32_t flags) {
  21.     std::vector<uint8_t> buf(MAX_CMD_SIZE, 0);
  22.     int len = res_mkquery(ns_o_query, dname, ns_class, ns_type, nullptr, 0, nullptr, buf.data(),
  23.                           MAX_CMD_SIZE);
  24.     return resNetworkSend(netId, buf.data(), len, flags);
  25. }
复制代码
经过一系列调用,终极调用到 resNetworkQuery 函数。在其中根据参数构造了 query 请求。
  1. //system/netd/client/NetdClient.cpp
  2. extern "C" int resNetworkSend(unsigned netId, const uint8_t* msg, size_t msglen, uint32_t flags) {
  3.     // Encode
  4.     netId = getNetworkForResolv(netId);
  5.     const std::string cmd = "resnsend " + std::to_string(netId) + " " + std::to_string(flags) +
  6.                             " " + encodedQuery + '\0';
  7.     //error process
  8.     int fd = dns_open_proxy();
  9.     //error process
  10.     ssize_t rc = sendData(fd, cmd.c_str(), cmd.size());
  11.     //error process
  12.     shutdown(fd, SHUT_WR);
  13.     return fd;
  14. }
复制代码
resNetworkQuery 调用了 resNetworkSend 完成了终极的 query 请求的发送。先将 query 构造成一个下发的命令,接着连接 DnsProxyLIstener,然后将 cmd 发送到 DnsProxyListener ,由 netd 来处置惩罚这个命令。
2.2 处置惩罚请求

与 getaddrinfo 大致类似,只不过 ResnsendCmd 调用了 resolv_resnend,而这个函数直接调用 res_nsend。
3 gethostbyaddr

3.1 下发请求

  1. //libcore/ojluni/src/main/java/java/net/InetAddress.java
  2. public String getHostName() {
  3.     // Android-changed: Remove SecurityManager check.
  4.     if (holder().getHostName() == null) {
  5.         holder().hostName = InetAddress.getHostFromNameService(this);
  6.     }
  7.     return holder().getHostName();
  8. }
  9. private static String getHostFromNameService(InetAddress addr) {
  10.     String host = null;
  11.     host = nameService.getHostByAddr(addr.getAddress());
  12.     //...
  13.     return host;
  14. }
  15. private static final NameService nameService = new NameService() {
  16.     public InetAddress[] lookupAllHostAddr(String host, int netId)
  17.             throws UnknownHostException {
  18.         return impl.lookupAllHostAddr(host, netId);
  19.     }
  20.     public String getHostByAddr(byte[] addr)
  21.             throws UnknownHostException {
  22.         return impl.getHostByAddr(addr);
  23.     }
  24. };
复制代码
步伐调用 InetAddress 类中的 getHostName 方法来获取一个 IP 地址对应的主机名。getHostName 内部调用到Inet6AddressImpl 中的 getHostByAddr 方法。InetAdress类中另有一些其他方法内部都调用了 Inet6AddressImpl.getHostByAddr,这些方法都是以下的流程。
  1. //libcore/ojluni/src/main/java/java/net/Inet6AddressImpl.java
  2. public String getHostByAddr(byte[] addr) throws UnknownHostException {
  3.     BlockGuard.getThreadPolicy().onNetwork();
  4.     return getHostByAddr0(addr);
  5. }
  6. private String getHostByAddr0(byte[] addr) throws UnknownHostException {
  7.     InetAddress hostaddr = InetAddress.getByAddress(addr);
  8.     try {
  9.         return Libcore.os.getnameinfo(hostaddr, NI_NAMEREQD);
  10.     } catch (GaiException e) {
  11.         UnknownHostException uhe = new UnknownHostException(hostaddr.toString());
  12.         uhe.initCause(e);
  13.         throw uhe;
  14.     }
  15. }
复制代码
其中再次调用到 Libcore.os 中的 getnameinfo JNI 方法。Libcore 中的全部的 JNI 方法定义在这个文件中:libcore/luni/src/main/java/libcore/io/Linux.java 。实现如下:
  1. //libcore/luni/src/main/native/libcore_io_Linux.cpp
  2. static jstring Linux_getnameinfo(JNIEnv* env, jobject, jobject javaAddress, jint flags) {
  3.     sockaddr_storage ss;
  4.     socklen_t sa_len;
  5.     if (!inetAddressToSockaddrVerbatim(env, javaAddress, 0, ss, sa_len)) {
  6.         return NULL;
  7.     }
  8.     char buf[NI_MAXHOST]; // NI_MAXHOST is longer than INET6_ADDRSTRLEN.
  9.     errno = 0;
  10.     int rc = getnameinfo(reinterpret_cast<sockaddr*>(&ss), sa_len, buf, sizeof(buf), NULL, 0, flags);
  11.     if (rc != 0) {
  12.         throwGaiException(env, "getnameinfo", rc);
  13.         return NULL;
  14.     }
  15.     return env->NewStringUTF(buf);
  16. }
  17. //bionic/libc/dns/net/getnameinfo.c
  18. int getnameinfo(const struct sockaddr* sa, socklen_t salen, char* host, size_t hostlen,
  19.                 char* serv, size_t servlen, int flags)
  20. {
  21.         return android_getnameinfofornet(sa, salen, host, hostlen, serv, servlen, flags,
  22.                         NETID_UNSET, MARK_UNSET);
  23. }
  24. int android_getnameinfofornet(const struct sockaddr* sa, socklen_t salen, char* host,
  25.                 size_t hostlen, char* serv, size_t servlen, int flags, unsigned netid,
  26.                 unsigned mark)
  27. {
  28.         switch (sa->sa_family) {
  29.         case AF_INET:
  30.         case AF_INET6:
  31.                 return getnameinfo_inet(sa, salen, host, hostlen,
  32.                                 serv, servlen, flags, netid, mark);
  33.         case AF_LOCAL://从sa中读就行
  34.                 return getnameinfo_local(sa, salen, host, hostlen,
  35.                     serv, servlen, flags);
  36.         default:
  37.                 return EAI_FAMILY;
  38.         }
  39. }
  40. static int getnameinfo_inet(const struct sockaddr* sa, socklen_t salen,
  41.        char *host, socklen_t hostlen,
  42.        char *serv, socklen_t servlen,
  43.        int flags, unsigned netid, unsigned mark)
  44. {
  45.     //...
  46.     const struct android_net_context netcontext = { .app_netid = netid, .app_mark = mark };
  47.     hp = android_gethostbyaddrfornetcontext_proxy(addr, afd->a_addrlen, afd->a_af, &netcontext);
  48.     //...
  49. }
复制代码
一直调用到 getnameinfo_inet 函数,真正去发送 gethostbyaddr 的请求。android_gethostbyaddrfornetcontext_proxy 向 DnsProxyListener 发送请求并返回一个 host 信息的结构体。
  1. //bionic/libc/dns/net/gethnamaddr.c
  2. static struct hostent* android_gethostbyaddrfornetcontext_proxy_internal(const void* addr, socklen_t len, int af,
  3.                              struct hostent *hp, char *hbuf, size_t hbuflen, int *he,
  4.                              const struct android_net_context *netcontext)
  5. {
  6.         FILE* proxy = fdopen(__netdClientDispatch.dnsOpenProxy(), "r+");
  7.         //...
  8.         //send
  9.         if (fprintf(proxy, "gethostbyaddr %s %d %d %u",
  10.                         addrStr, len, af, netid) < 0) {
  11.                 fclose(proxy);
  12.                 return NULL;
  13.         }
  14.         //...
  15.         ///receive
  16.         struct hostent *result = android_read_hostent(proxy, hp, hbuf, hbuflen, he);
  17.         fclose(proxy);
  18.         return result;
  19. }
复制代码
android_gethostbyaddrfornetcontext_proxy 中调用到 android_gethostbyaddrfornetcontext_proxy_internal。android_gethostbyaddrfornetcontext_proxy_internal 中连接到 DnsProxyListener,并通过 printf
发送了一个 gethostbyaddr 命令。
3.2 处置惩罚请求

  1. //packages/modules/DnsResolver/gethnamaddr.cpp
  2. int resolv_gethostbyaddr(const void* addr, socklen_t len, int af, hostent* hp, char* buf,
  3.                          size_t buflen, const struct android_net_context* netcontext,
  4.                          hostent** result, NetworkDnsEventReported* event) {
  5.     //...
  6.     if (_hf_gethtbyaddr(uaddr, len, af, &info)) {
  7.         int error = dns_gethtbyaddr(uaddr, len, af, netcontext, &info, event);
  8.         if (error != 0) return error;
  9.     }
  10.     *result = hp;
  11.     return 0;
  12. }
  13. //packages/modules/DnsResolver/gethnamaddr.cpp
  14. static int dns_gethtbyaddr(const unsigned char* uaddr, int len, int af,
  15.                            const android_net_context* netcontext, getnamaddr* info,
  16.                            NetworkDnsEventReported* event) {
  17.     //...
  18.     n = res_nquery(&res, qbuf, C_IN, T_PTR, buf->buf, (int)sizeof(buf->buf), &he);
  19. }
  20. //packages/modules/DnsResolver/res_query.cpp
  21. int res_nquery(res_state statp, const char* name,  // domain name
  22.                int cl, int type,                   // class and type of query
  23.                uint8_t* answer,                    // buffer to put answer
  24.                int anslen,                         // size of answer buffer
  25.                int* herrno)                        // legacy and extended h_errno
  26.                                                    // NETD_RESOLV_H_ERRNO_EXT_*
  27. {
  28.     //...
  29.     n = res_nmkquery(QUERY, name, cl, type, /*data=*/nullptr, 0, buf, sizeof(buf),
  30.                      statp->netcontext_flags);
  31.     //...
  32.     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。
  1. //packages/modules/Connectivity/Tethering/src/com/android/networkstack/tethering/Tethering.java
  2. protected boolean turnOnMainTetherSettings() {
  3.     final TetheringConfiguration cfg = mConfig;
  4.     try {
  5.         mNetd.ipfwdEnableForwarding(TAG);
  6.     } catch (RemoteException | ServiceSpecificException e) {
  7.         mLog.e(e);
  8.         transitionTo(mSetIpForwardingEnabledErrorState);
  9.         return false;
  10.     }
  11.     // TODO: Randomize DHCPv4 ranges, especially in hotspot mode.
  12.     // Legacy DHCP server is disabled if passed an empty ranges array
  13.     final String[] dhcpRanges = cfg.enableLegacyDhcpServer
  14.             ? cfg.legacyDhcpRanges : new String[0];
  15.     try {
  16.         NetdUtils.tetherStart(mNetd, true /** usingLegacyDnsProxy */, dhcpRanges);
  17.     } catch (RemoteException | ServiceSpecificException e) {
  18.         try {
  19.             // Stop and retry.
  20.             mNetd.tetherStop();
  21.             NetdUtils.tetherStart(mNetd, true /** usingLegacyDnsProxy */, dhcpRanges);
  22.         } catch (RemoteException | ServiceSpecificException ee) {
  23.             mLog.e(ee);
  24.             transitionTo(mStartTetheringErrorState);
  25.             return false;
  26.         }
  27.     }
  28.     mLog.log("SET main tether settings: ON");
  29.     return true;
  30. }
复制代码
调用 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:NetworkStateTrackerHandlerInternalHandler
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_CHANGEmaybeHandleNetworkAgentMessage**
->handleUpdateLinkProperties->updateLinkProperties->updateDnses
收到**EVENT_CAPPORT_DATA_CHANGED消息,调用maybeHandleNetworkMonitorMessage->** **handleCapportApiDataUpdate->handleUpdateLinkProperties->updateLinkProperties->updateDnses**
2 来自其他设备的DNS请求

  1. //packages/modules/Connectivity/Tethering/src/com/android/networkstack/tethering/Tethering.java
  2. public void enter() {
  3.     //...
  4.     if (upstreamWanted()) {
  5.         mUpstreamWanted = true;
  6.         mOffload.start();
  7.         chooseUpstreamType(true);
  8.         mTryCell = false;
  9.     }
  10.     //...
  11. }
复制代码
之前的流程与 NAT 部分相同,调用到 chooseUpstreamType。经过一系列调用,终极调用到 setDnsForwarders。
  1. //packages/modules/Connectivity/Tethering/src/com/android/networkstack/tethering/Tethering.java
  2. protected void setDnsForwarders(final Network network, final LinkProperties lp) {
  3.     // TODO: Set v4 and/or v6 DNS per available connectivity.
  4.     final Collection<InetAddress> dnses = lp.getDnsServers();
  5.     // TODO: Properly support the absence of DNS servers.
  6.     final String[] dnsServers;
  7.     if (dnses != null && !dnses.isEmpty()) {
  8.         dnsServers = new String[dnses.size()];
  9.         int i = 0;
  10.         for (InetAddress dns : dnses) {
  11.             dnsServers[i++] = dns.getHostAddress();
  12.         }
  13.     } else {
  14.         dnsServers = mConfig.defaultIPv4DNS;
  15.     }
  16.     final int netId = (network != null) ? network.getNetId() : NETID_UNSET;
  17.     try {
  18.         mNetd.tetherDnsSet(netId, dnsServers);
  19.         mLog.log(String.format(
  20.                 "SET DNS forwarders: network=%s dnsServers=%s",
  21.                 network, Arrays.toString(dnsServers)));
  22.     } catch (RemoteException | ServiceSpecificException e) {
  23.         // TODO: Investigate how this can fail and what exactly
  24.         // happens if/when such failures occur.
  25.         mLog.e("setting DNS forwarders failed, " + e);
  26.         transitionTo(mSetDnsForwardersErrorState);
  27.     }
  28. }
复制代码
其中调用了 Netd服务的 tetherDnsSet 方法,进行Dns的设置。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

愛在花開的季節

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表