概述
本文为《深入理解Android Wi-Fi、NFC和GPS卷》读书笔记,Android源码为Android 5.1
Netd进程由init进程根据init.rc的对应配置项而启动:
android-5.1/system/core/rootdir/init.rc
service netd /system/bin/netd
class main
socket netd stream 0660 root system
socket dnsproxyd stream 0660 root inet
socket mdns stream 0660 root system
socket fwmarkd stream 0660 root inet
Netd启动时将创建四个TCP监听socket,其名称分别是netd、dnsproxyd、mdns和fwmarkd。
Framework 层中的 NetworkManagementService 和 NsdService 将分别和netd及mdns监听socket建立链接并交互。
每一个调用和域名解析相关的socket API(如 getaddrinfo 或 gethostbyname 等)的进程都会借由 dnsproxyd 监听 socket 与 netd 建立链接。
下面开始分析Netd进程。
android-5.1/system/netd/server/main.cpp
int main() {
CommandListener *cl;
NetlinkManager *nm;
DnsProxyListener *dpl;
MDnsSdListener *mdnsl;
FwmarkServer* fwmarkServer;
ALOGI("Netd 1.0 starting");
remove_pid_file();
//为Netd进程屏蔽SIGPIPE信号
blockSigpipe();
//创建NetlinkManager
if (!(nm = NetlinkManager::Instance())) {
ALOGE("Unable to create NetlinkManager");
exit(1);
};
//创建CommandListener,它将创建名为netd的监听socket
cl = new CommandListener();
//设置NetlinkManager的消息发送者(Broadcaster)为CommandListener
nm->setBroadcaster((SocketListener *) cl);
//启动NetlinkManager
if (nm->start()) {
ALOGE("Unable to start NetlinkManager (%s)", strerror(errno));
exit(1);
}
// Set local DNS mode, to prevent bionic from proxying
// back to this service, recursively.
//为本Netd设置环境变量 ANDROID_DNS_MODE 为local
setenv("ANDROID_DNS_MODE", "local", 1);
//创建 DnsProxyListener,它将创建名为 dnsproxyd 的监听socket
dpl = new DnsProxyListener(CommandListener::sNetCtrl);
if (dpl->startListener()) {
ALOGE("Unable to start DnsProxyListener (%s)", strerror(errno));
exit(1);
}
//创建 MDnsSdListener并启动监听,它将创建名为mdns的监听socket
mdnsl = new MDnsSdListener();
if (mdnsl->startListener()) {
ALOGE("Unable to start MDnsSdListener (%s)", strerror(errno));
exit(1);
}
//创建 FwmarkServer并启动监听,它将创建名为fwmarkd的监听
fwmarkServer = new FwmarkServer(CommandListener::sNetCtrl);
if (fwmarkServer->startListener()) {
ALOGE("Unable to start FwmarkServer (%s)", strerror(errno));
exit(1);
}
/*
* Now that we're up, we can respond to commands
*/
if (cl->startListener()) {
ALOGE("Unable to start CommandListener (%s)", strerror(errno));
exit(1);
}
bool wrote_pid = write_pid_file();
while(1) {
sleep(30); // 30 sec
if (!wrote_pid) {
wrote_pid = write_pid_file();
}
}
ALOGI("Netd exiting");
remove_pid_file();
exit(0);
}
Netd的main函数主要是创建几个重要成员并启动相应的工作,这四个重要成员分别如下:
NetlinkManager:接收并处理来自Kernel的UEvent消息。这些消息经NetlinkManager解析后将借助它的Broadcaster(也就是代码中为NetlinkManager设置的CommandListener)发送给Framework层的 NetworkManagementService。
CommandListener、DnsProxyListener、MDnsSDListener、FwmarkServer:分别创建名为netd、dnsproxyd、mdns、fwmarkServer的监听socket
NetlinkManager分析
NetlinkManager(以后简称NM)主要负责接收并解析来自Kernel的UEvent消息。其核心代码在start函数中,如下所示:
int NetlinkManager::start() {
//创建接收 NETLINK_KOBJECT_UEVENT 消息的socket,其值保存在mUeventSock中
//其中, NETLINK_FORMAT_ASCII 代表UEvent消息的内容为 ASCII字符串
if ((mUeventHandler = setupSocket(&mUeventSock, NETLINK_KOBJECT_UEVENT,
0xffffffff, NetlinkListener::NETLINK_FORMAT_ASCII)) == NULL) {
return -1;
}
//创建接收 RTMGRP_LINK 消息的socket,其值保存在 mRouteSock 中
//其中, NETLINK_FORMAT_BINARY 代表 UEvent 消息的类型为结构体,故需要进行二进制解析
if ((mRouteHandler = setupSocket(&mRouteSock, NETLINK_ROUTE,
RTMGRP_LINK |
RTMGRP_IPV4_IFADDR |
RTMGRP_IPV6_IFADDR |
RTMGRP_IPV6_ROUTE |
(1 << (RTNLGRP_ND_USEROPT - 1)),
NetlinkListener::NETLINK_FORMAT_BINARY)) == NULL) {
return -1;
}
//创建接收 NETLINK_NFLOG 消息的socket,其值保存在 mQuotaSock 中
if ((mQuotaHandler = setupSocket(&mQuotaSock, NETLINK_NFLOG,
NFLOG_QUOTA_GROUP, NetlinkListener::NETLINK_FORMAT_BINARY)) == NULL) {
ALOGE("Unable to open quota2 logging socket");
// TODO: return -1 once the emulator gets a new kernel.
}
return 0;
}
NM的start函数主要是向Kernel注册三个用于接收UEvent事件的socket,这三个UEvent分别对应于以下内容
NETLINK_KOBJECT_UEVENT: 代表 kobject 事件,由于这些事件包含的信息由ASCII字符串表述,故上述代码中使用了 NETLINK_FORMAT_ASCII。 它表示将采用字符串解析的方法去解析接收到的UEvent 消息。 kobject 一般用来通知内核中某个模块的加载或卸载。对于NM来说,其关注的是 /sys/class/net下相应模块的加载或卸载消息。
NETLINK_ROUTE:代表Kernel中routing或link改变时对应的消息。 NETLINK_ROUTE 包含很多子项,上述代码中使用了 RTMGRP_LINK 项。二者结合起来使用,表示NM希望收到网络链路断开或接通时对应的UEvent消息。由于对应UEvent消息内部封装了 nlmsghdr 等相关结构体,故上述代码使用了 NETLINK_FORMAT_BINARY来指示解析 UEvent消息时将使用二进制的解析方法。
NETLINK_NFLOG:和2.3.6节介绍的带宽控制有关。Netd中的带宽控制可以设置一个预警值,当网络数据超过一定字节数就会触发Kernel发送一个警告。该功能属于iptables 的扩展项。值得指出的是,上述代码中有关 NETLINK_NFLOG 相关socket的设置并非所有 Kernel版本都支持。同时, NFLOG_QUOTA_GROUP 的值是直接定义在 NetlinkManager.cpp中的,而非和其他类似系统定义一样定义在系统头文件中,这也表明 NFLOG_QUOTA_GROUP 的功能比较新。
NetlinkHandler接收到的UEvent消息会转换成一个NetlinkEvent对象。NetlinkEvent对象封装了对 UEvent消息的解析方法。对于 NETLINK_FORMAT_ASCII类型,其 parseAsciiNetlinkMessage函数会被调用,而对于 NETLINK_FORMAT_BINARY类型,其 parseBinaryNetlinkMessage 函数会被调用。
NM处理流程的输入为一个解析后的 NetlinkEvent对象。NM完成相应工作后,其处理结果将经由 mBroadcaster对象传递给 Framework层的接收者,也就是 NetworkManagementService。
CommandListener 从 FrameworkListener派生,而 FrameworkListener 内部有一个数组 mCommands,用来存储注册到 FrameworkListener中的命令处理对象。
下面简单了解 NetlinkHandler 的 onEvent 函数:
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
const char *subsys = evt->getSubsystem();
if (!subsys) {
ALOGW("No subsystem found in netlink event");
return;
}
//处理对应 NETLINK_KOBJECT_UEVENT和 NETLINK_ROUTE 的消息
if (!strcmp(subsys, "net")) {
int action = evt->getAction();
const char *iface = evt->findParam("INTERFACE");//查找消息中携带的网络设备名
if (action == evt->NlActionAdd) {
notifyInterfaceAdded(iface); //添加NIC(Network Interface Card)的消息
} else if (action == evt->NlActionRemove) {
notifyInterfaceRemoved(iface); //NIC被移除的消息
} else if (action == evt->NlActionChange) {
evt->dump();
notifyInterfaceChanged("nana", true); //NIC变化消息
} else if (action == evt->NlActionLinkUp) { //下面两个消息来自 NETLINK_ROUTE
notifyInterfaceLinkChanged(iface, true); //链路启用(类此插网线)
} else if (action == evt->NlActionLinkDown) {
notifyInterfaceLinkChanged(iface, false); //链路断开(类似拔网线)
} else if (action == evt->NlActionAddressUpdated ||
action == evt->NlActionAddressRemoved) {
const char *address = evt->findParam("ADDRESS");
const char *flags = evt->findParam("FLAGS");
const char *scope = evt->findParam("SCOPE");
if (action == evt->NlActionAddressRemoved && iface && address) {
int resetMask = strchr(address, ':') ? RESET_IPV6_ADDRESSES : RESET_IPV4_ADDRESSES;
resetMask |= RESET_IGNORE_INTERFACE_ADDRESS;
if (int ret = ifc_reset_connections(iface, resetMask)) {
ALOGE("ifc_reset_connections failed on iface %s for address %s (%s)", iface,
address, strerror(ret));
}
}
if (iface && flags && scope) {
notifyAddressChanged(action, address, iface, flags, scope);
}
} else if (action == evt->NlActionRdnss) {
const char *lifetime = evt->findParam("LIFETIME");
const char *servers = evt->findParam("SERVERS");
if (lifetime && servers) {
notifyInterfaceDnsServers(iface, lifetime, servers);
}
} else if (action == evt->NlActionRouteUpdated ||
action == evt->NlActionRouteRemoved) {
const char *route = evt->findParam("ROUTE");
const char *gateway = evt->findParam("GATEWAY");
const char *iface = evt->findParam("INTERFACE");
if (route && (gateway || iface)) {
notifyRouteChange(action, route, gateway, iface);
}
}
} else if (!strcmp(subsys, "qlog")) { //对应 NETLINK_NFLOG
const char *alertName = evt->findParam("ALERT_NAME");
const char *iface = evt->findParam("INTERFACE");
notifyQuotaLimitReached(alertName, iface); //当数据量超过预警值,则会收到该通知
} else if (!strcmp(subsys, "xt_idletimer")) {//这和后文的idletimer有关,用于跟踪某个 NIC的工作状态,即idle或active,检测时间按秒计算
const char *label = evt->findParam("INTERFACE");
const char *state = evt->findParam("STATE");
const char *timestamp = evt->findParam("TIME_NS");
if (state)
notifyInterfaceClassActivity(label, !strcmp("active", state), timestamp);
#if !LOG_NDEBUG
} else if (strcmp(subsys, "platform") && strcmp(subsys, "backlight")) {
/* It is not a VSYNC or a backlight event */
ALOGV("unexpected event from subsystem %s", subsys);
#endif
}
}
由上边代码可知, NETLINK_KOBJECT_UEVENT和 NETLINK_ROUTE 主要反映网络设备的事件和状态,包括NIC的添加、删除和修改,以及链路的连接状态等。 NETLINK_NFLOG 用于反映设置的log是否超过配额。另外,上边代码中还处理了 xt_idletimer 的 uevent 消息,它和后文介绍的 IdleTimerCmd 有关,主要用来监视网络设备的收发工作状态。当对应设备工作或空闲时间超过设置的监控时间后, Kernel将会发送携带其状态(idle或active)的UEvent消息。
NM创建 NetlinkHandler 后,工作便转交给 NetlinkHandler来完成,而每个 NetlinkHandler对象均会单独创建一个线程用于接收 socket 消息。当 Kernel 发送 UEvent 消息后, NetlinkHandler便从select调用中返回,然后调用其 onDataAvailable 函数,该函数内部会创建一个 NetlinkEvent 对象。 NetlinkEvent 对象根据 socket 创建时指定的解析类型去解析来自 Kernel 的UEvent消息。 最终NetlinkHandler 的 onEvent 将被调用,不同的UEvent消息将在此函数中进行分类处理。 NetlinkHandler 最终将处理结果经由 NM 内部变量 mBroadcaster 转发给 NetworkManagementService。
Netd 中的第二个重要成员是 CommandListener(以后简称CL),其主要作用是接收来自 Framework 层 NetworkManageService 的命令。从角色来看,CL仅是一个Listener 。它在收到命令后,只是将它们转交给对应的命令处理对象去处理。 CL 内部定义了许多命令,而这些命令都有较深的背景知识。
CL定义了11个和网络相关的Command 类。这些类均从 NetdCommand 派生。 CL 还定义了11个控制类, 这些控制类将和命令类共同完成相应的命令处理工作。
CL创建时,需要注册自己支持的命令类:
构造函数:
android-5.1/system/netd/server/CommandListener.cpp
CommandListener::CommandListener() :
FrameworkListener("netd", true) {
registerCmd(new InterfaceCmd());//注册11个命令类对象
registerCmd(new IpFwdCmd());
registerCmd(new TetherCmd());
registerCmd(new NatCmd());
registerCmd(new ListTtysCmd());
registerCmd(new PppdCmd());
registerCmd(new SoftapCmd());
registerCmd(new BandwidthControlCmd());
registerCmd(new IdletimerControlCmd());
registerCmd(new ResolverCmd());
registerCmd(new FirewallCmd());
registerCmd(new ClatdCmd());
registerCmd(new NetworkCommand());
//创建对应的控制类对象
if (!sNetCtrl)
sNetCtrl = new NetworkController();
if (!sTetherCtrl)
sTetherCtrl = new TetherController();
if (!sNatCtrl)
sNatCtrl = new NatController();
if (!sPppCtrl)
sPppCtrl = new PppController();
if (!sSoftapCtrl)
sSoftapCtrl = new SoftapController();
if (!sBandwidthCtrl)
sBandwidthCtrl = new BandwidthController();
if (!sIdletimerCtrl)
sIdletimerCtrl = new IdletimerController();
if (!sResolverCtrl)
sResolverCtrl = new ResolverController();
if (!sFirewallCtrl)
sFirewallCtrl = new FirewallController();
if (!sInterfaceCtrl)
sInterfaceCtrl = new InterfaceController();
if (!sClatdCtrl)
sClatdCtrl = new ClatdController(sNetCtrl);
/*
* This is the only time we touch top-level chains in iptables; controllers
* should only mutate rules inside of their children chains, as created by
* the constants above.
*
* Modules should never ACCEPT packets (except in well-justified cases);
* they should instead defer to any remaining modules using RETURN, or
* otherwise DROP/REJECT.
*/
// Create chains for children modules
//初始化 iptables 中的各个Table 及相应 Chain 和 Rules
createChildChains(V4V6, "filter", "INPUT", FILTER_INPUT);
createChildChains(V4V6, "filter", "FORWARD", FILTER_FORWARD);
createChildChains(V4V6, "filter", "OUTPUT", FILTER_OUTPUT);
createChildChains(V4V6, "raw", "PREROUTING", RAW_PREROUTING);
createChildChains(V4V6, "mangle", "POSTROUTING", MANGLE_POSTROUTING);
createChildChains(V4, "mangle", "FORWARD", MANGLE_FORWARD);
createChildChains(V4, "nat", "PREROUTING", NAT_PREROUTING);
createChildChains(V4, "nat", "POSTROUTING", NAT_POSTROUTING);
// Let each module setup their child chains
//netd允许OEM厂商可自定义一些规则,这些规则在 /system/bin/oem-iptables-init.sh文件中保存
setupOemIptablesHook();
/* When enabled, DROPs all packets except those matching rules. */
//初始化 iptables中的一些chain,以及初始化路由表
sFirewallCtrl->setupIptablesHooks();
/* Does DROPs in FORWARD by default */
sNatCtrl->setupIptablesHooks();
/*
* Does REJECT in INPUT, OUTPUT. Does counting also.
* No DROP/REJECT allowed later in netfilter-flow hook order.
*/
sBandwidthCtrl->setupIptablesHooks();
/*
* Counts in nat: PREROUTING, POSTROUTING.
* No DROP/REJECT allowed later in netfilter-flow hook order.
*/
sIdletimerCtrl->setupIptablesHooks();
//初始化时,Netd将禁止带宽控制功能
sBandwidthCtrl->enableBandwidthControl(false);
if (int ret = RouteController::Init(NetworkController::LOCAL_NET_ID)) {
ALOGE("failed to initialize RouteController (%s)", strerror(-ret));
}
}
由于 CL 的间接基类也是 SocketListener,所以其工作流程和 NetlinkHandler 类似。
CL构造函数的后半部分工作主要是利用iptables等工具创建较多的Chain和Rule,以及对某些命令控制对象进行初始化。
getaddrinfo 函数分析
android-5.1/bionic/libc/dns/net/getaddrinfo.c
int
getaddrinfo(const char *hostname, const char *servname,
const struct addrinfo *hints, struct addrinfo **res)
{
//Android平台的特殊定制
return android_getaddrinfofornet(hostname, servname, hints, NETID_UNSET, MARK_UNSET, res);
}
Android平台的 getaddrinfo 会调用其定制的 android_getaddrinfofornet 函数完成一些特殊操作:
int
android_getaddrinfofornet(const char *hostname, const char *servname,
const struct addrinfo *hints, unsigned netid, unsigned mark, struct addrinfo **res)
{
struct addrinfo sentinel;
struct addrinfo *cur;
int error = 0;
struct addrinfo ai;
struct addrinfo ai0;
struct addrinfo *pai;
const struct explore *ex;
//取 ANDROID_DNS_MODE 环境变量
//只有android-5.1/system/netd/server/main.cpp中设置了此变量:setenv("ANDROID_DNS_MODE", "local", 1);
const char* cache_mode = getenv("ANDROID_DNS_MODE");
/* hostname is allowed to be NULL */
/* servname is allowed to be NULL */
/* hints is allowed to be NULL */
assert(res != NULL);
memset(&sentinel, 0, sizeof(sentinel));
cur = &sentinel;
pai = &ai;
pai->ai_flags = 0;
pai->ai_family = PF_UNSPEC;
pai->ai_socktype = ANY;
pai->ai_protocol = ANY;
pai->ai_addrlen = 0;
pai->ai_canonname = NULL;
pai->ai_addr = NULL;
pai->ai_next = NULL;
if (hostname == NULL && servname == NULL)
return EAI_NONAME;
if (hints) {
/* error check for hints */
if (hints->ai_addrlen || hints->ai_canonname ||
hints->ai_addr || hints->ai_next)
ERR(EAI_BADHINTS); /* xxx */
if (hints->ai_flags & ~AI_MASK)
ERR(EAI_BADFLAGS);
switch (hints->ai_family) {
case PF_UNSPEC:
case PF_INET:
#ifdef INET6
case PF_INET6:
#endif
break;
default:
ERR(EAI_FAMILY);
}
memcpy(pai, hints, sizeof(*pai));
/*
* if both socktype/protocol are specified, check if they
* are meaningful combination.
*/
if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
for (ex = explore; ex->e_af >= 0; ex++) {
if (pai->ai_family != ex->e_af)
continue;
if (ex->e_socktype == ANY)
continue;
if (ex->e_protocol == ANY)
continue;
if (pai->ai_socktype == ex->e_socktype
&& pai->ai_protocol != ex->e_protocol) {
ERR(EAI_BADHINTS);
}
}
}
}
/*
* check for special cases. (1) numeric servname is disallowed if
* socktype/protocol are left unspecified. (2) servname is disallowed
* for raw and other inet{,6} sockets.
*/
if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
#ifdef PF_INET6
|| MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
#endif
) {
ai0 = *pai; /* backup *pai */
if (pai->ai_family == PF_UNSPEC) {
#ifdef PF_INET6
pai->ai_family = PF_INET6;
#else
pai->ai_family = PF_INET;
#endif
}
error = get_portmatch(pai, servname);
if (error)
ERR(error);
*pai = ai0;
}
ai0 = *pai;
/* NULL hostname, or numeric hostname */
for (ex = explore; ex->e_af >= 0; ex++) {
*pai = ai0;
/* PF_UNSPEC entries are prepared for DNS queries only */
if (ex->e_af == PF_UNSPEC)
continue;
if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
continue;
if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
continue;
if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
continue;
if (pai->ai_family == PF_UNSPEC)
pai->ai_family = ex->e_af;
if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
pai->ai_socktype = ex->e_socktype;
if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
pai->ai_protocol = ex->e_protocol;
if (hostname == NULL)
error = explore_null(pai, servname, &cur->ai_next);
else
error = explore_numeric_scope(pai, hostname, servname,
&cur->ai_next);
if (error)
goto free;
while (cur->ai_next)
cur = cur->ai_next;
}
/*
* XXX
* If numeric representation of AF1 can be interpreted as FQDN
* representation of AF2, we need to think again about the code below.
*/
if (sentinel.ai_next)
goto good;
if (hostname == NULL)
ERR(EAI_NODATA);
if (pai->ai_flags & AI_NUMERICHOST)
ERR(EAI_NONAME);
/*
* BEGIN ANDROID CHANGES; proxying to the cache
*/
//如果是Netd进程调用,则判断不成立,因为两个都返回0
//如果非Netd进程调用,则判断成立
if (cache_mode == NULL || strcmp(cache_mode, "local") != 0) {
// we're not the proxy - pass the request to them
return android_getaddrinfo_proxy(hostname, servname, hints, res, netid);
}
/*
* hostname as alphabetical name.
* we would like to prefer AF_INET6 than AF_INET, so we'll make a
* outer loop by AFs.
*/
for (ex = explore; ex->e_af >= 0; ex++) {
*pai = ai0;
/* require exact match for family field */
if (pai->ai_family != ex->e_af)
continue;
if (!MATCH(pai->ai_socktype, ex->e_socktype,
WILD_SOCKTYPE(ex))) {
continue;
}
if (!MATCH(pai->ai_protocol, ex->e_protocol,
WILD_PROTOCOL(ex))) {
continue;
}
if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
pai->ai_socktype = ex->e_socktype;
if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
pai->ai_protocol = ex->e_protocol;
error = explore_fqdn(pai, hostname, servname,
&cur->ai_next, netid, mark);
while (cur && cur->ai_next)
cur = cur->ai_next;
}
/* XXX */
if (sentinel.ai_next)
error = 0;
if (error)
goto free;
if (error == 0) {
if (sentinel.ai_next) {
good:
*res = sentinel.ai_next;
return SUCCESS;
} else
error = EAI_FAIL;
}
free:
bad:
if (sentinel.ai_next)
freeaddrinfo(sentinel.ai_next);
*res = NULL;
return error;
}
非Netd进程调用时,会执行函数 android_getaddrinfo_proxy
static int
android_getaddrinfo_proxy(
const char *hostname, const char *servname,
const struct addrinfo *hints, struct addrinfo **res, unsigned netid)
{
int sock;
const int one = 1;
struct sockaddr_un proxy_addr;
FILE* proxy = NULL;
int success = 0;
// Clear this at start, as we use its non-NULLness later (in the
// error path) to decide if we have to free up any memory we
// allocated in the process (before failing).
*res = NULL;
// Bogus things we can't serialize. Don't use the proxy. These will fail - let them.
if ((hostname != NULL &&
strcspn(hostname, " nrt^'"") != strlen(hostname)) ||
(servname != NULL &&
strcspn(servname, " nrt^'"") != strlen(servname))) {
return EAI_NODATA;
}
//建立和Netd中 DnsProxyListener 的连接,将请求转发给它去执行
sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (sock < 0) {
return EAI_NODATA;
}
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
memset(&proxy_addr, 0, sizeof(proxy_addr));
proxy_addr.sun_family = AF_UNIX;
strlcpy(proxy_addr.sun_path, "/dev/socket/dnsproxyd",
sizeof(proxy_addr.sun_path));
if (TEMP_FAILURE_RETRY(connect(sock,
(const struct sockaddr*) &proxy_addr,
sizeof(proxy_addr))) != 0) {
close(sock);
return EAI_NODATA;
}
netid = __netdClientDispatch.netIdForResolv(netid);
// Send the request.
//发送请求,处理回复等
proxy = fdopen(sock, "r+");
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;
}
// literal NULL byte at end, required by FrameworkListener
if (fputc(0, proxy) == EOF ||
fflush(proxy) != 0) {
goto exit;
}
char buf[4];
// read result code for gethostbyaddr
if (fread(buf, 1, sizeof(buf), proxy) != sizeof(buf)) {
goto exit;
}
int result_code = (int)strtol(buf, NULL, 10);
// verify the code itself
if (result_code != DnsProxyQueryResult ) {
fread(buf, 1, sizeof(buf), proxy);
goto exit;
}
struct addrinfo* ai = NULL;
struct addrinfo** nextres = res;
while (1) {
uint32_t addrinfo_len;
if (fread(&addrinfo_len, sizeof(addrinfo_len),
1, proxy) != 1) {
break;
}
addrinfo_len = ntohl(addrinfo_len);
if (addrinfo_len == 0) {
success = 1;
break;
}
if (addrinfo_len < sizeof(struct addrinfo)) {
break;
}
struct addrinfo* ai = calloc(1, addrinfo_len +
sizeof(struct sockaddr_storage));
if (ai == NULL) {
break;
}
if (fread(ai, addrinfo_len, 1, proxy) != 1) {
// Error; fall through.
break;
}
// Zero out the pointer fields we copied which aren't
// valid in this address space.
ai->ai_addr = NULL;
ai->ai_canonname = NULL;
ai->ai_next = NULL;
// struct sockaddr
uint32_t addr_len;
if (fread(&addr_len, sizeof(addr_len), 1, proxy) != 1) {
break;
}
addr_len = ntohl(addr_len);
if (addr_len != 0) {
if (addr_len > sizeof(struct sockaddr_storage)) {
// Bogus; too big.
break;
}
struct sockaddr* addr = (struct sockaddr*)(ai + 1);
if (fread(addr, addr_len, 1, proxy) != 1) {
break;
}
ai->ai_addr = addr;
}
// cannonname
uint32_t name_len;
if (fread(&name_len, sizeof(name_len), 1, proxy) != 1) {
break;
}
name_len = ntohl(name_len);
if (name_len != 0) {
ai->ai_canonname = (char*) malloc(name_len);
if (fread(ai->ai_canonname, name_len, 1, proxy) != 1) {
break;
}
if (ai->ai_canonname[name_len - 1] != '