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。
收到**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。
收到***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的配置。