#include <dirent.h>
#include <errno.h>
#include <linux/if.h>
+#include <math.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#define DBG 0
#define VDBG 0
+#include <chrono>
+
#include <cutils/log.h>
+#include <binder/IServiceManager.h>
+#include <utils/String16.h>
#include <sysutils/SocketClient.h>
#include "Fwmark.h"
#include "NetdConstants.h"
#include "NetworkController.h"
#include "ResponseCode.h"
+#include "Stopwatch.h"
+#include "android/net/metrics/INetdEventListener.h"
+
+using android::String16;
+using android::interface_cast;
+using android::net::metrics::INetdEventListener;
DnsProxyListener::DnsProxyListener(const NetworkController* netCtrl) :
FrameworkListener("dnsproxyd"), mNetCtrl(netCtrl) {
registerCmd(new GetHostByNameCmd(this));
}
-DnsProxyListener::GetAddrInfoHandler::GetAddrInfoHandler(SocketClient *c,
- char* host,
- char* service,
- struct addrinfo* hints,
- unsigned netId,
- uint32_t mark)
+DnsProxyListener::GetAddrInfoHandler::GetAddrInfoHandler(
+ SocketClient *c, char* host, char* service, struct addrinfo* hints,
+ const struct android_net_context& netcontext,
+ const android::sp<android::net::metrics::INetdEventListener>& netdEventListener)
: mClient(c),
mHost(host),
mService(service),
mHints(hints),
- mNetId(netId),
- mMark(mark) {
+ mNetContext(netcontext),
+ mNetdEventListener(netdEventListener) {
}
DnsProxyListener::GetAddrInfoHandler::~GetAddrInfoHandler() {
return NULL;
}
+android::sp<INetdEventListener> DnsProxyListener::getNetdEventListener() {
+ if (mNetdEventListener == nullptr) {
+ // Use checkService instead of getService because getService waits for 5 seconds for the
+ // service to become available. The DNS resolver inside netd is started much earlier in the
+ // boot sequence than the framework DNS listener, and we don't want to delay all DNS lookups
+ // for 5 seconds until the DNS listener starts up.
+ android::sp<android::IBinder> b = android::defaultServiceManager()->checkService(
+ android::String16("netd_listener"));
+ if (b != nullptr) {
+ mNetdEventListener = interface_cast<INetdEventListener>(b);
+ }
+ }
+ // If the DNS listener service is dead, the binder call will just return an error, which should
+ // be fine because the only impact is that we can't log DNS events. In any case, this should
+ // only happen if the system server is going down, which means it will shortly be taking us down
+ // with it.
+ return mNetdEventListener;
+}
+
+static bool sendBE32(SocketClient* c, uint32_t data) {
+ uint32_t be_data = htonl(data);
+ return c->sendData(&be_data, sizeof(be_data)) == 0;
+}
+
// Sends 4 bytes of big-endian length, followed by the data.
// Returns true on success.
-static bool sendLenAndData(SocketClient *c, const int len, const void* data) {
- uint32_t len_be = htonl(len);
- return c->sendData(&len_be, 4) == 0 &&
- (len == 0 || c->sendData(data, len) == 0);
+static bool sendLenAndData(SocketClient* c, const int len, const void* data) {
+ return sendBE32(c, len) && (len == 0 || c->sendData(data, len) == 0);
}
// Returns true on success
return success;
}
+static bool sendaddrinfo(SocketClient* c, struct addrinfo* ai) {
+ // struct addrinfo {
+ // int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */
+ // int ai_family; /* PF_xxx */
+ // int ai_socktype; /* SOCK_xxx */
+ // int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+ // socklen_t ai_addrlen; /* length of ai_addr */
+ // char *ai_canonname; /* canonical name for hostname */
+ // struct sockaddr *ai_addr; /* binary address */
+ // struct addrinfo *ai_next; /* next structure in linked list */
+ // };
+
+ // Write the struct piece by piece because we might be a 64-bit netd
+ // talking to a 32-bit process.
+ bool success =
+ sendBE32(c, ai->ai_flags) &&
+ sendBE32(c, ai->ai_family) &&
+ sendBE32(c, ai->ai_socktype) &&
+ sendBE32(c, ai->ai_protocol);
+ if (!success) {
+ return false;
+ }
+
+ // ai_addrlen and ai_addr.
+ if (!sendLenAndData(c, ai->ai_addrlen, ai->ai_addr)) {
+ return false;
+ }
+
+ // strlen(ai_canonname) and ai_canonname.
+ if (!sendLenAndData(c, ai->ai_canonname ? strlen(ai->ai_canonname) + 1 : 0, ai->ai_canonname)) {
+ return false;
+ }
+
+ return true;
+}
+
void DnsProxyListener::GetAddrInfoHandler::run() {
if (DBG) {
- ALOGD("GetAddrInfoHandler, now for %s / %s / %u / %u", mHost, mService, mNetId, mMark);
+ ALOGD("GetAddrInfoHandler, now for %s / %s / {%u,%u,%u,%u,%u}", mHost, mService,
+ mNetContext.app_netid, mNetContext.app_mark,
+ mNetContext.dns_netid, mNetContext.dns_mark,
+ mNetContext.uid);
}
struct addrinfo* result = NULL;
- uint32_t rv = android_getaddrinfofornet(mHost, mService, mHints, mNetId, mMark, &result);
+ Stopwatch s;
+ uint32_t rv = android_getaddrinfofornetcontext(mHost, mService, mHints, &mNetContext, &result);
+ const int latencyMs = lround(s.timeTaken());
+
if (rv) {
// getaddrinfo failed
mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, &rv, sizeof(rv));
bool success = !mClient->sendCode(ResponseCode::DnsProxyQueryResult);
struct addrinfo* ai = result;
while (ai && success) {
- success = sendLenAndData(mClient, sizeof(struct addrinfo), ai)
- && sendLenAndData(mClient, ai->ai_addrlen, ai->ai_addr)
- && sendLenAndData(mClient,
- ai->ai_canonname ? strlen(ai->ai_canonname) + 1 : 0,
- ai->ai_canonname);
+ success = sendBE32(mClient, 1) && sendaddrinfo(mClient, ai);
ai = ai->ai_next;
}
- success = success && sendLenAndData(mClient, 0, "");
+ success = success && sendBE32(mClient, 0);
if (!success) {
ALOGW("Error writing DNS result to client");
}
freeaddrinfo(result);
}
mClient->decRef();
+ if (mNetdEventListener != nullptr) {
+ mNetdEventListener->onDnsEvent(mNetContext.dns_netid,
+ INetdEventListener::EVENT_GETADDRINFO, (int32_t) rv,
+ latencyMs);
+ }
}
-DnsProxyListener::GetAddrInfoCmd::GetAddrInfoCmd(const DnsProxyListener* dnsProxyListener) :
+DnsProxyListener::GetAddrInfoCmd::GetAddrInfoCmd(DnsProxyListener* dnsProxyListener) :
NetdCommand("getaddrinfo"),
mDnsProxyListener(dnsProxyListener) {
}
unsigned netId = strtoul(argv[7], NULL, 10);
uid_t uid = cli->getUid();
- uint32_t mark = mDnsProxyListener->mNetCtrl->getNetworkForDns(&netId, uid);
+ struct android_net_context netcontext;
+ mDnsProxyListener->mNetCtrl->getNetworkContext(netId, uid, &netcontext);
if (ai_flags != -1 || ai_family != -1 ||
ai_socktype != -1 || ai_protocol != -1) {
hints->ai_family = ai_family;
hints->ai_socktype = ai_socktype;
hints->ai_protocol = ai_protocol;
-
- // Only implement AI_ADDRCONFIG if application is using default network since our
- // implementation only works on the default network.
- if ((hints->ai_flags & AI_ADDRCONFIG) &&
- netId != mDnsProxyListener->mNetCtrl->getDefaultNetwork()) {
- hints->ai_flags &= ~AI_ADDRCONFIG;
- }
}
if (DBG) {
- ALOGD("GetAddrInfoHandler for %s / %s / %u / %d / %u",
+ ALOGD("GetAddrInfoHandler for %s / %s / {%u,%u,%u,%u,%u}",
name ? name : "[nullhost]",
service ? service : "[nullservice]",
- netId, uid, mark);
+ netcontext.app_netid, netcontext.app_mark,
+ netcontext.dns_netid, netcontext.dns_mark,
+ netcontext.uid);
}
cli->incRef();
DnsProxyListener::GetAddrInfoHandler* handler =
- new DnsProxyListener::GetAddrInfoHandler(cli, name, service, hints, netId, mark);
+ new DnsProxyListener::GetAddrInfoHandler(cli, name, service, hints, netcontext,
+ mDnsProxyListener->getNetdEventListener());
handler->start();
return 0;
/*******************************************************
* GetHostByName *
*******************************************************/
-DnsProxyListener::GetHostByNameCmd::GetHostByNameCmd(const DnsProxyListener* dnsProxyListener) :
+DnsProxyListener::GetHostByNameCmd::GetHostByNameCmd(DnsProxyListener* dnsProxyListener) :
NetdCommand("gethostbyname"),
mDnsProxyListener(dnsProxyListener) {
}
cli->incRef();
DnsProxyListener::GetHostByNameHandler* handler =
- new DnsProxyListener::GetHostByNameHandler(cli, name, af, netId, mark);
+ new DnsProxyListener::GetHostByNameHandler(cli, name, af, netId, mark,
+ mDnsProxyListener->getNetdEventListener());
handler->start();
return 0;
}
-DnsProxyListener::GetHostByNameHandler::GetHostByNameHandler(SocketClient* c,
- char* name,
- int af,
- unsigned netId,
- uint32_t mark)
+DnsProxyListener::GetHostByNameHandler::GetHostByNameHandler(
+ SocketClient* c, char* name, int af, unsigned netId, uint32_t mark,
+ const android::sp<android::net::metrics::INetdEventListener>& netdEventListener)
: mClient(c),
mName(name),
mAf(af),
mNetId(netId),
- mMark(mark) {
+ mMark(mark),
+ mNetdEventListener(netdEventListener) {
}
DnsProxyListener::GetHostByNameHandler::~GetHostByNameHandler() {
ALOGD("DnsProxyListener::GetHostByNameHandler::run\n");
}
- struct hostent* hp;
-
- hp = android_gethostbynamefornet(mName, mAf, mNetId, mMark);
+ Stopwatch s;
+ struct hostent* hp = android_gethostbynamefornet(mName, mAf, mNetId, mMark);
+ const int latencyMs = lround(s.timeTaken());
if (DBG) {
ALOGD("GetHostByNameHandler::run gethostbyname errno: %s hp->h_name = %s, name_len = %zu\n",
ALOGW("GetHostByNameHandler: Error writing DNS result to client\n");
}
mClient->decRef();
+
+ if (mNetdEventListener != nullptr) {
+ mNetdEventListener->onDnsEvent(mNetId, INetdEventListener::EVENT_GETHOSTBYNAME,
+ h_errno, latencyMs);
+ }
}