Loading res_cache.cpp +51 −59 Original line number Diff line number Diff line Loading @@ -984,9 +984,10 @@ struct NetConfig { dns_event_subsampling_map = resolv_get_dns_event_subsampling_map(); } int nameserverCount() { return nameserverSockAddrs.size(); } const unsigned netid; std::unique_ptr<Cache> cache; int nscount = 0; std::vector<std::string> nameservers; std::vector<IPSockAddr> nameserverSockAddrs; int revision_id = 0; // # times the nameservers have been replaced Loading Loading @@ -1442,7 +1443,7 @@ static void res_cache_clear_stats_locked(NetConfig* netconfig); bool resolv_has_nameservers(unsigned netid) { std::lock_guard guard(cache_mutex); NetConfig* info = find_netconfig_locked(netid); return (info != nullptr) && (info->nscount > 0); return (info != nullptr) && (info->nameserverCount() > 0); } int resolv_create_cache_for_net(unsigned netid) { Loading Loading @@ -1603,7 +1604,6 @@ int resolv_set_nameservers( << ", addr = " << netconfig->nameservers[i]; } netconfig->nameserverSockAddrs = std::move(ipSockAddrs); netconfig->nscount = numservers; } else { if (netconfig->params.max_samples != old_max_samples) { // If the maximum number of samples changes, the overhead of keeping the most recent Loading Loading @@ -1655,7 +1655,6 @@ static bool resolv_is_nameservers_equal(const std::vector<std::string>& oldServe } static void free_nameservers_locked(NetConfig* netconfig) { netconfig->nscount = 0; netconfig->nameservers.clear(); netconfig->nameserverSockAddrs.clear(); res_cache_clear_stats_locked(netconfig); Loading @@ -1671,21 +1670,7 @@ void resolv_populate_res_for_net(ResState* statp) { NetConfig* info = find_netconfig_locked(statp->netid); if (info == nullptr) return; // TODO: Convert nsaddrs[] to c++ container and remove the size-checking. const int serverNum = std::min(MAXNS, static_cast<int>(info->nameserverSockAddrs.size())); for (int nserv = 0; nserv < serverNum; nserv++) { sockaddr_storage ss = info->nameserverSockAddrs.at(nserv); if (auto sockaddr_len = sockaddrSize(ss); sockaddr_len != 0) { memcpy(&statp->nsaddrs[nserv], &ss, sockaddr_len); } else { LOG(WARNING) << __func__ << ": can't get sa_len from " << info->nameserverSockAddrs.at(nserv); } } statp->nscount = serverNum; statp->nsaddrs = info->nameserverSockAddrs; statp->search_domains = info->search_domains; statp->tc_mode = info->tc_mode; } Loading Loading @@ -1725,42 +1710,32 @@ int android_net_res_stats_get_info_for_net(unsigned netid, int* nscount, char domains[MAXDNSRCH][MAXDNSRCHPATH], res_params* params, struct res_stats stats[MAXNS], int* wait_for_pending_req_timeout_count) { int revision_id = -1; std::lock_guard guard(cache_mutex); NetConfig* info = find_netconfig_locked(netid); if (info) { if (info->nscount > MAXNS) { LOG(INFO) << __func__ << ": nscount " << info->nscount << " > MAXNS " << MAXNS; errno = EFAULT; return -1; } int i; *nscount = info->nscount; if (!info) return -1; // It shouldn't happen, but just in case of buffer overflow. if (info->nscount != static_cast<int>(info->nameserverSockAddrs.size())) { LOG(INFO) << __func__ << ": nscount " << info->nscount << " != " << info->nameserverSockAddrs.size(); const int num = info->nameserverCount(); if (num > MAXNS) { LOG(INFO) << __func__ << ": nscount " << num << " > MAXNS " << MAXNS; errno = EFAULT; return -1; } for (i = 0; i < info->nscount; i++) { servers[i] = info->nameserverSockAddrs.at(i); for (int i = 0; i < num; i++) { servers[i] = info->nameserverSockAddrs[i]; stats[i] = info->nsstats[i]; } for (i = 0; i < static_cast<int>(info->search_domains.size()); i++) { for (size_t i = 0; i < info->search_domains.size(); i++) { strlcpy(domains[i], info->search_domains[i].c_str(), MAXDNSRCHPATH); } *dcount = i; *nscount = num; *dcount = static_cast<int>(info->search_domains.size()); *params = info->params; revision_id = info->revision_id; *wait_for_pending_req_timeout_count = info->wait_for_pending_req_timeout_count; } return revision_id; return info->revision_id; } std::vector<std::string> resolv_cache_dump_subsampling_map(unsigned netid) { Loading Loading @@ -1799,30 +1774,47 @@ uint32_t resolv_cache_get_subsampling_denom(unsigned netid, int return_code) { return denom; } int resolv_cache_get_resolver_stats(unsigned netid, res_params* params, res_stats stats[MAXNS]) { int resolv_cache_get_resolver_stats(unsigned netid, res_params* params, res_stats stats[MAXNS], const std::vector<IPSockAddr>& serverSockAddrs) { std::lock_guard guard(cache_mutex); NetConfig* info = find_netconfig_locked(netid); if (info) { memcpy(stats, info->nsstats, sizeof(info->nsstats)); *params = info->params; return info->revision_id; } if (!info) return -1; for (size_t i = 0; i < serverSockAddrs.size(); i++) { for (size_t j = 0; j < info->nameserverSockAddrs.size(); j++) { // Should never happen. Just in case because of the fix-sized array |stats|. if (j >= MAXNS) { LOG(WARNING) << __func__ << ": unexpected size " << j; return -1; } void resolv_cache_add_resolver_stats_sample(unsigned netid, int revision_id, const sockaddr* sa, // It's possible that the server is not found, e.g. when a new list of nameservers // is updated to the NetConfig just after this look up thread being populated. // Keep the server valid as-is (by means of keeping stats[i] unset), but we should // think about if there's a better way. if (info->nameserverSockAddrs[j] == serverSockAddrs[i]) { stats[i] = info->nsstats[j]; break; } } } *params = info->params; return info->revision_id; } void resolv_cache_add_resolver_stats_sample(unsigned netid, int revision_id, const IPSockAddr& serverSockAddr, const res_sample& sample, int max_samples) { if (max_samples <= 0 || sa == nullptr) return; if (max_samples <= 0) return; std::lock_guard guard(cache_mutex); NetConfig* info = find_netconfig_locked(netid); if (info && info->revision_id == revision_id) { const int serverNum = std::min(MAXNS, static_cast<int>(info->nameserverSockAddrs.size())); const IPSockAddr ipsa = IPSockAddr::toIPSockAddr(*sa); for (int ns = 0; ns < serverNum; ns++) { if (ipsa == info->nameserverSockAddrs.at(ns)) { if (serverSockAddr == info->nameserverSockAddrs[ns]) { res_cache_add_stats_sample_locked(&info->nsstats[ns], sample, max_samples); return; } Loading res_init.cpp +0 −10 Original line number Diff line number Diff line Loading @@ -97,17 +97,7 @@ void res_init(ResState* statp, const struct android_net_context* _Nonnull netcon statp->netid = netcontext->dns_netid; statp->uid = netcontext->uid; statp->pid = netcontext->pid; statp->nscount = 1; statp->id = arc4random_uniform(65536); // The following dummy initialization is probably useless because // it's overwritten later by resolv_populate_res_for_net(). // TODO: check if it's safe to remove. const sockaddr_union u{ .sin.sin_addr.s_addr = INADDR_ANY, .sin.sin_family = AF_INET, .sin.sin_port = htons(NAMESERVER_PORT), }; memcpy(&statp->nsaddrs, &u, sizeof(u)); for (auto& sock : statp->nssocks) { sock.reset(); Loading res_send.cpp +49 −44 Original line number Diff line number Diff line Loading @@ -138,11 +138,13 @@ using android::netdutils::Stopwatch; static DnsTlsDispatcher sDnsTlsDispatcher; static struct sockaddr* get_nsaddr(res_state, size_t); static int send_vc(res_state, res_params* params, const uint8_t*, int, uint8_t*, int, int*, int, time_t*, int*, int*); static int send_dg(res_state, res_params* params, const uint8_t*, int, uint8_t*, int, int*, int, int*, int*, time_t*, int*, int*); static int send_vc(res_state statp, res_params* params, const uint8_t* buf, int buflen, uint8_t* ans, int anssiz, int* terrno, size_t ns, time_t* at, int* rcode, int* delay); static int send_dg(res_state statp, res_params* params, const uint8_t* buf, int buflen, uint8_t* ans, int anssiz, int* terrno, size_t ns, int* v_circuit, int* gotsomewhere, time_t* at, int* rcode, int* delay); static void dump_error(const char*, const struct sockaddr*, int); static int sock_eq(struct sockaddr*, struct sockaddr*); Loading Loading @@ -288,13 +290,13 @@ static void res_set_usable_server(int selectedServer, int nscount, bool usable_s static bool res_ourserver_p(res_state statp, const sockaddr* sa) { const sockaddr_in *inp, *srv; const sockaddr_in6 *in6p, *srv6; int ns; switch (sa->sa_family) { case AF_INET: inp = (const struct sockaddr_in*) (const void*) sa; for (ns = 0; ns < statp->nscount; ns++) { srv = (struct sockaddr_in*) (void*) get_nsaddr(statp, (size_t) ns); for (const IPSockAddr& ipsa : statp->nsaddrs) { sockaddr_storage ss = ipsa; srv = reinterpret_cast<sockaddr_in*>(&ss); if (srv->sin_family == inp->sin_family && srv->sin_port == inp->sin_port && (srv->sin_addr.s_addr == INADDR_ANY || srv->sin_addr.s_addr == inp->sin_addr.s_addr)) Loading @@ -303,8 +305,9 @@ static bool res_ourserver_p(res_state statp, const sockaddr* sa) { break; case AF_INET6: in6p = (const struct sockaddr_in6*) (const void*) sa; for (ns = 0; ns < statp->nscount; ns++) { srv6 = (struct sockaddr_in6*) (void*) get_nsaddr(statp, (size_t) ns); for (const IPSockAddr& ipsa : statp->nsaddrs) { sockaddr_storage ss = ipsa; srv6 = reinterpret_cast<sockaddr_in6*>(&ss); if (srv6->sin6_family == in6p->sin6_family && srv6->sin6_port == in6p->sin6_port && #ifdef HAVE_SIN6_SCOPE_ID (srv6->sin6_scope_id == 0 || srv6->sin6_scope_id == in6p->sin6_scope_id) && Loading Loading @@ -427,7 +430,7 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int // data so the normal resolve path can do its thing resolv_populate_res_for_net(statp); } if (statp->nscount == 0) { if (statp->nameserverCount() == 0) { // We have no nameservers configured, so there's no point trying. // Tell the cache the query failed, or any retries and anyone else asking the same // question will block for PENDING_REQUEST_TIMEOUT seconds instead of failing fast. Loading Loading @@ -457,9 +460,9 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int } } res_stats stats[MAXNS]; res_stats stats[MAXNS]{}; res_params params; int revision_id = resolv_cache_get_resolver_stats(statp->netid, ¶ms, stats); int revision_id = resolv_cache_get_resolver_stats(statp->netid, ¶ms, stats, statp->nsaddrs); if (revision_id < 0) { // TODO: Remove errno once callers stop using it errno = ESRCH; Loading @@ -467,14 +470,14 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int } bool usable_servers[MAXNS]; int usableServersCount = android_net_res_stats_get_usable_servers( ¶ms, stats, statp->nscount, usable_servers); ¶ms, stats, statp->nameserverCount(), usable_servers); if ((flags & ANDROID_RESOLV_NO_RETRY) && usableServersCount > 1) { auto hp = reinterpret_cast<const HEADER*>(buf); // Select a random server based on the query id int selectedServer = (hp->id % usableServersCount) + 1; res_set_usable_server(selectedServer, statp->nscount, usable_servers); res_set_usable_server(selectedServer, statp->nameserverCount(), usable_servers); } // Send request, RETRY times, or until successful. Loading @@ -484,20 +487,15 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int int terrno = ETIMEDOUT; for (int attempt = 0; attempt < retryTimes; ++attempt) { for (int ns = 0; ns < statp->nscount; ++ns) { for (size_t ns = 0; ns < statp->nsaddrs.size(); ++ns) { if (!usable_servers[ns]) continue; *rcode = RCODE_INTERNAL_ERROR; // Get server addr const sockaddr* nsap = get_nsaddr(statp, ns); const int nsaplen = sockaddrSize(nsap); static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; char abuf[NI_MAXHOST]; if (getnameinfo(nsap, (socklen_t)nsaplen, abuf, sizeof(abuf), NULL, 0, niflags) == 0) const IPSockAddr& serverSockAddr = statp->nsaddrs[ns]; LOG(DEBUG) << __func__ << ": Querying server (# " << ns + 1 << ") address = " << abuf; << ") address = " << serverSockAddr.toString(); ::android::net::Protocol query_proto = useTcp ? PROTO_TCP : PROTO_UDP; time_t now = 0; Loading Loading @@ -533,7 +531,7 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int dnsQueryEvent->set_cache_hit(static_cast<CacheStatus>(cache_status)); dnsQueryEvent->set_latency_micros(saturate_cast<int32_t>(queryStopwatch.timeTakenUs())); dnsQueryEvent->set_dns_server_index(ns); dnsQueryEvent->set_ip_version(ipFamilyToIPVersion(nsap->sa_family)); dnsQueryEvent->set_ip_version(ipFamilyToIPVersion(serverSockAddr.family())); dnsQueryEvent->set_retry_times(retry_count_for_event); dnsQueryEvent->set_rcode(static_cast<NsRcode>(*rcode)); dnsQueryEvent->set_protocol(query_proto); Loading @@ -544,10 +542,10 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int // SERVFAIL or times out) do not unduly affect the stats. if (shouldRecordStats) { res_sample sample; _res_stats_set_sample(&sample, now, *rcode, delay); resolv_cache_add_resolver_stats_sample(statp->netid, revision_id, nsap, sample, params.max_samples); resolv_stats_add(statp->netid, IPSockAddr::toIPSockAddr(*nsap), dnsQueryEvent); res_stats_set_sample(&sample, now, *rcode, delay); resolv_cache_add_resolver_stats_sample(statp->netid, revision_id, serverSockAddr, sample, params.max_samples); resolv_stats_add(statp->netid, serverSockAddr, dnsQueryEvent); } if (resplen == 0) continue; Loading Loading @@ -582,12 +580,6 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int return -terrno; } /* Private */ static struct sockaddr* get_nsaddr(res_state statp, size_t n) { return (struct sockaddr*)(void*)&statp->nsaddrs[n]; } static struct timespec get_timeout(res_state statp, const res_params* params, const int ns) { int msec; // Legacy algorithm which scales the timeout by nameserver number. Loading @@ -595,7 +587,7 @@ static struct timespec get_timeout(res_state statp, const res_params* params, co // This has no effect with 1 or 2 nameservers msec = params->base_timeout_msec << ns; if (ns > 0) { msec /= statp->nscount; msec /= statp->nameserverCount(); } // For safety, don't allow OEMs and experiments to configure a timeout shorter than 1s. if (msec < 1000) { Loading @@ -610,7 +602,7 @@ static struct timespec get_timeout(res_state statp, const res_params* params, co } static int send_vc(res_state statp, res_params* params, const uint8_t* buf, int buflen, uint8_t* ans, int anssiz, int* terrno, int ns, time_t* at, int* rcode, uint8_t* ans, int anssiz, int* terrno, size_t ns, time_t* at, int* rcode, int* delay) { *at = time(NULL); *delay = 0; Loading @@ -623,7 +615,14 @@ static int send_vc(res_state statp, res_params* params, const uint8_t* buf, int LOG(INFO) << __func__ << ": using send_vc"; nsap = get_nsaddr(statp, (size_t) ns); // It should never happen, but just in case. if (ns >= statp->nsaddrs.size()) { LOG(ERROR) << __func__ << ": Out-of-bound indexing: " << ns; return -1; } sockaddr_storage ss = statp->nsaddrs[ns]; nsap = reinterpret_cast<sockaddr*>(&ss); nsaplen = sockaddrSize(nsap); connreset = 0; Loading Loading @@ -804,7 +803,7 @@ read_len: */ if (resplen > 0) { struct timespec done = evNowTime(); *delay = _res_stats_calculate_rtt(&done, &now); *delay = res_stats_calculate_rtt(&done, &now); *rcode = anhp->rcode; } return (resplen); Loading Loading @@ -897,12 +896,18 @@ bool ignoreInvalidAnswer(res_state statp, const sockaddr_storage& from, const ui } static int send_dg(res_state statp, res_params* params, const uint8_t* buf, int buflen, uint8_t* ans, int anssiz, int* terrno, int ns, int* v_circuit, int* gotsomewhere, time_t* at, int* rcode, int* delay) { uint8_t* ans, int anssiz, int* terrno, size_t ns, int* v_circuit, int* gotsomewhere, time_t* at, int* rcode, int* delay) { // It should never happen, but just in case. if (ns >= statp->nsaddrs.size()) { LOG(ERROR) << __func__ << ": Out-of-bound indexing: " << ns; return -1; } *at = time(nullptr); *delay = 0; const sockaddr* nsap = get_nsaddr(statp, (size_t)ns); const sockaddr_storage ss = statp->nsaddrs[ns]; const sockaddr* nsap = reinterpret_cast<const sockaddr*>(&ss); const int nsaplen = sockaddrSize(nsap); if (statp->nssocks[ns] == -1) { Loading Loading @@ -1007,7 +1012,7 @@ static int send_dg(res_state statp, res_params* params, const uint8_t* buf, int } timespec done = evNowTime(); *delay = _res_stats_calculate_rtt(&done, &now); *delay = res_stats_calculate_rtt(&done, &now); if (anhp->rcode == SERVFAIL || anhp->rcode == NOTIMP || anhp->rcode == REFUSED) { LOG(DEBUG) << __func__ << ": server rejected query:"; res_pquery(ans, (resplen > anssiz) ? anssiz : resplen); Loading res_stats.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -24,7 +24,7 @@ #include "stats.h" // Calculate the round-trip-time from start time t0 and end time t1. int _res_stats_calculate_rtt(const timespec* t1, const timespec* t0) { int res_stats_calculate_rtt(const timespec* t1, const timespec* t0) { // Divide ns by one million to get ms, multiply s by thousand to get ms (obvious) long ms0 = t0->tv_sec * 1000 + t0->tv_nsec / 1000000; long ms1 = t1->tv_sec * 1000 + t1->tv_nsec / 1000000; Loading @@ -32,7 +32,7 @@ int _res_stats_calculate_rtt(const timespec* t1, const timespec* t0) { } // Create a sample for calculating server reachability statistics. void _res_stats_set_sample(res_sample* sample, time_t now, int rcode, int rtt) { void res_stats_set_sample(res_sample* sample, time_t now, int rcode, int rtt) { LOG(INFO) << __func__ << ": rcode = " << rcode << ", sec = " << rtt; sample->at = now; sample->rcode = rcode; Loading resolv_cache.h +15 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ #include "ResolverStats.h" #include "params.h" #include "stats.h" // Sets the name server addresses to the provided ResState. // The name servers are retrieved from the cache which is associated Loading Loading @@ -115,3 +116,17 @@ void resolv_stats_dump(android::netdutils::DumpWriter& dw, unsigned netid); void resolv_oem_options_dump(android::netdutils::DumpWriter& dw, unsigned netid); const char* tc_mode_to_str(const int mode); /* Retrieve a local copy of the stats for the given netid. The buffer must have space for * MAXNS __resolver_stats. Returns the revision id of the resolvers used. */ int resolv_cache_get_resolver_stats( unsigned netid, res_params* params, res_stats stats[MAXNS], const std::vector<android::netdutils::IPSockAddr>& serverSockAddrs); /* Add a sample to the shared struct for the given netid and server, provided that the * revision_id of the stored servers has not changed. */ void resolv_cache_add_resolver_stats_sample(unsigned netid, int revision_id, const android::netdutils::IPSockAddr& serverSockAddr, const res_sample& sample, int max_samples); Loading
res_cache.cpp +51 −59 Original line number Diff line number Diff line Loading @@ -984,9 +984,10 @@ struct NetConfig { dns_event_subsampling_map = resolv_get_dns_event_subsampling_map(); } int nameserverCount() { return nameserverSockAddrs.size(); } const unsigned netid; std::unique_ptr<Cache> cache; int nscount = 0; std::vector<std::string> nameservers; std::vector<IPSockAddr> nameserverSockAddrs; int revision_id = 0; // # times the nameservers have been replaced Loading Loading @@ -1442,7 +1443,7 @@ static void res_cache_clear_stats_locked(NetConfig* netconfig); bool resolv_has_nameservers(unsigned netid) { std::lock_guard guard(cache_mutex); NetConfig* info = find_netconfig_locked(netid); return (info != nullptr) && (info->nscount > 0); return (info != nullptr) && (info->nameserverCount() > 0); } int resolv_create_cache_for_net(unsigned netid) { Loading Loading @@ -1603,7 +1604,6 @@ int resolv_set_nameservers( << ", addr = " << netconfig->nameservers[i]; } netconfig->nameserverSockAddrs = std::move(ipSockAddrs); netconfig->nscount = numservers; } else { if (netconfig->params.max_samples != old_max_samples) { // If the maximum number of samples changes, the overhead of keeping the most recent Loading Loading @@ -1655,7 +1655,6 @@ static bool resolv_is_nameservers_equal(const std::vector<std::string>& oldServe } static void free_nameservers_locked(NetConfig* netconfig) { netconfig->nscount = 0; netconfig->nameservers.clear(); netconfig->nameserverSockAddrs.clear(); res_cache_clear_stats_locked(netconfig); Loading @@ -1671,21 +1670,7 @@ void resolv_populate_res_for_net(ResState* statp) { NetConfig* info = find_netconfig_locked(statp->netid); if (info == nullptr) return; // TODO: Convert nsaddrs[] to c++ container and remove the size-checking. const int serverNum = std::min(MAXNS, static_cast<int>(info->nameserverSockAddrs.size())); for (int nserv = 0; nserv < serverNum; nserv++) { sockaddr_storage ss = info->nameserverSockAddrs.at(nserv); if (auto sockaddr_len = sockaddrSize(ss); sockaddr_len != 0) { memcpy(&statp->nsaddrs[nserv], &ss, sockaddr_len); } else { LOG(WARNING) << __func__ << ": can't get sa_len from " << info->nameserverSockAddrs.at(nserv); } } statp->nscount = serverNum; statp->nsaddrs = info->nameserverSockAddrs; statp->search_domains = info->search_domains; statp->tc_mode = info->tc_mode; } Loading Loading @@ -1725,42 +1710,32 @@ int android_net_res_stats_get_info_for_net(unsigned netid, int* nscount, char domains[MAXDNSRCH][MAXDNSRCHPATH], res_params* params, struct res_stats stats[MAXNS], int* wait_for_pending_req_timeout_count) { int revision_id = -1; std::lock_guard guard(cache_mutex); NetConfig* info = find_netconfig_locked(netid); if (info) { if (info->nscount > MAXNS) { LOG(INFO) << __func__ << ": nscount " << info->nscount << " > MAXNS " << MAXNS; errno = EFAULT; return -1; } int i; *nscount = info->nscount; if (!info) return -1; // It shouldn't happen, but just in case of buffer overflow. if (info->nscount != static_cast<int>(info->nameserverSockAddrs.size())) { LOG(INFO) << __func__ << ": nscount " << info->nscount << " != " << info->nameserverSockAddrs.size(); const int num = info->nameserverCount(); if (num > MAXNS) { LOG(INFO) << __func__ << ": nscount " << num << " > MAXNS " << MAXNS; errno = EFAULT; return -1; } for (i = 0; i < info->nscount; i++) { servers[i] = info->nameserverSockAddrs.at(i); for (int i = 0; i < num; i++) { servers[i] = info->nameserverSockAddrs[i]; stats[i] = info->nsstats[i]; } for (i = 0; i < static_cast<int>(info->search_domains.size()); i++) { for (size_t i = 0; i < info->search_domains.size(); i++) { strlcpy(domains[i], info->search_domains[i].c_str(), MAXDNSRCHPATH); } *dcount = i; *nscount = num; *dcount = static_cast<int>(info->search_domains.size()); *params = info->params; revision_id = info->revision_id; *wait_for_pending_req_timeout_count = info->wait_for_pending_req_timeout_count; } return revision_id; return info->revision_id; } std::vector<std::string> resolv_cache_dump_subsampling_map(unsigned netid) { Loading Loading @@ -1799,30 +1774,47 @@ uint32_t resolv_cache_get_subsampling_denom(unsigned netid, int return_code) { return denom; } int resolv_cache_get_resolver_stats(unsigned netid, res_params* params, res_stats stats[MAXNS]) { int resolv_cache_get_resolver_stats(unsigned netid, res_params* params, res_stats stats[MAXNS], const std::vector<IPSockAddr>& serverSockAddrs) { std::lock_guard guard(cache_mutex); NetConfig* info = find_netconfig_locked(netid); if (info) { memcpy(stats, info->nsstats, sizeof(info->nsstats)); *params = info->params; return info->revision_id; } if (!info) return -1; for (size_t i = 0; i < serverSockAddrs.size(); i++) { for (size_t j = 0; j < info->nameserverSockAddrs.size(); j++) { // Should never happen. Just in case because of the fix-sized array |stats|. if (j >= MAXNS) { LOG(WARNING) << __func__ << ": unexpected size " << j; return -1; } void resolv_cache_add_resolver_stats_sample(unsigned netid, int revision_id, const sockaddr* sa, // It's possible that the server is not found, e.g. when a new list of nameservers // is updated to the NetConfig just after this look up thread being populated. // Keep the server valid as-is (by means of keeping stats[i] unset), but we should // think about if there's a better way. if (info->nameserverSockAddrs[j] == serverSockAddrs[i]) { stats[i] = info->nsstats[j]; break; } } } *params = info->params; return info->revision_id; } void resolv_cache_add_resolver_stats_sample(unsigned netid, int revision_id, const IPSockAddr& serverSockAddr, const res_sample& sample, int max_samples) { if (max_samples <= 0 || sa == nullptr) return; if (max_samples <= 0) return; std::lock_guard guard(cache_mutex); NetConfig* info = find_netconfig_locked(netid); if (info && info->revision_id == revision_id) { const int serverNum = std::min(MAXNS, static_cast<int>(info->nameserverSockAddrs.size())); const IPSockAddr ipsa = IPSockAddr::toIPSockAddr(*sa); for (int ns = 0; ns < serverNum; ns++) { if (ipsa == info->nameserverSockAddrs.at(ns)) { if (serverSockAddr == info->nameserverSockAddrs[ns]) { res_cache_add_stats_sample_locked(&info->nsstats[ns], sample, max_samples); return; } Loading
res_init.cpp +0 −10 Original line number Diff line number Diff line Loading @@ -97,17 +97,7 @@ void res_init(ResState* statp, const struct android_net_context* _Nonnull netcon statp->netid = netcontext->dns_netid; statp->uid = netcontext->uid; statp->pid = netcontext->pid; statp->nscount = 1; statp->id = arc4random_uniform(65536); // The following dummy initialization is probably useless because // it's overwritten later by resolv_populate_res_for_net(). // TODO: check if it's safe to remove. const sockaddr_union u{ .sin.sin_addr.s_addr = INADDR_ANY, .sin.sin_family = AF_INET, .sin.sin_port = htons(NAMESERVER_PORT), }; memcpy(&statp->nsaddrs, &u, sizeof(u)); for (auto& sock : statp->nssocks) { sock.reset(); Loading
res_send.cpp +49 −44 Original line number Diff line number Diff line Loading @@ -138,11 +138,13 @@ using android::netdutils::Stopwatch; static DnsTlsDispatcher sDnsTlsDispatcher; static struct sockaddr* get_nsaddr(res_state, size_t); static int send_vc(res_state, res_params* params, const uint8_t*, int, uint8_t*, int, int*, int, time_t*, int*, int*); static int send_dg(res_state, res_params* params, const uint8_t*, int, uint8_t*, int, int*, int, int*, int*, time_t*, int*, int*); static int send_vc(res_state statp, res_params* params, const uint8_t* buf, int buflen, uint8_t* ans, int anssiz, int* terrno, size_t ns, time_t* at, int* rcode, int* delay); static int send_dg(res_state statp, res_params* params, const uint8_t* buf, int buflen, uint8_t* ans, int anssiz, int* terrno, size_t ns, int* v_circuit, int* gotsomewhere, time_t* at, int* rcode, int* delay); static void dump_error(const char*, const struct sockaddr*, int); static int sock_eq(struct sockaddr*, struct sockaddr*); Loading Loading @@ -288,13 +290,13 @@ static void res_set_usable_server(int selectedServer, int nscount, bool usable_s static bool res_ourserver_p(res_state statp, const sockaddr* sa) { const sockaddr_in *inp, *srv; const sockaddr_in6 *in6p, *srv6; int ns; switch (sa->sa_family) { case AF_INET: inp = (const struct sockaddr_in*) (const void*) sa; for (ns = 0; ns < statp->nscount; ns++) { srv = (struct sockaddr_in*) (void*) get_nsaddr(statp, (size_t) ns); for (const IPSockAddr& ipsa : statp->nsaddrs) { sockaddr_storage ss = ipsa; srv = reinterpret_cast<sockaddr_in*>(&ss); if (srv->sin_family == inp->sin_family && srv->sin_port == inp->sin_port && (srv->sin_addr.s_addr == INADDR_ANY || srv->sin_addr.s_addr == inp->sin_addr.s_addr)) Loading @@ -303,8 +305,9 @@ static bool res_ourserver_p(res_state statp, const sockaddr* sa) { break; case AF_INET6: in6p = (const struct sockaddr_in6*) (const void*) sa; for (ns = 0; ns < statp->nscount; ns++) { srv6 = (struct sockaddr_in6*) (void*) get_nsaddr(statp, (size_t) ns); for (const IPSockAddr& ipsa : statp->nsaddrs) { sockaddr_storage ss = ipsa; srv6 = reinterpret_cast<sockaddr_in6*>(&ss); if (srv6->sin6_family == in6p->sin6_family && srv6->sin6_port == in6p->sin6_port && #ifdef HAVE_SIN6_SCOPE_ID (srv6->sin6_scope_id == 0 || srv6->sin6_scope_id == in6p->sin6_scope_id) && Loading Loading @@ -427,7 +430,7 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int // data so the normal resolve path can do its thing resolv_populate_res_for_net(statp); } if (statp->nscount == 0) { if (statp->nameserverCount() == 0) { // We have no nameservers configured, so there's no point trying. // Tell the cache the query failed, or any retries and anyone else asking the same // question will block for PENDING_REQUEST_TIMEOUT seconds instead of failing fast. Loading Loading @@ -457,9 +460,9 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int } } res_stats stats[MAXNS]; res_stats stats[MAXNS]{}; res_params params; int revision_id = resolv_cache_get_resolver_stats(statp->netid, ¶ms, stats); int revision_id = resolv_cache_get_resolver_stats(statp->netid, ¶ms, stats, statp->nsaddrs); if (revision_id < 0) { // TODO: Remove errno once callers stop using it errno = ESRCH; Loading @@ -467,14 +470,14 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int } bool usable_servers[MAXNS]; int usableServersCount = android_net_res_stats_get_usable_servers( ¶ms, stats, statp->nscount, usable_servers); ¶ms, stats, statp->nameserverCount(), usable_servers); if ((flags & ANDROID_RESOLV_NO_RETRY) && usableServersCount > 1) { auto hp = reinterpret_cast<const HEADER*>(buf); // Select a random server based on the query id int selectedServer = (hp->id % usableServersCount) + 1; res_set_usable_server(selectedServer, statp->nscount, usable_servers); res_set_usable_server(selectedServer, statp->nameserverCount(), usable_servers); } // Send request, RETRY times, or until successful. Loading @@ -484,20 +487,15 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int int terrno = ETIMEDOUT; for (int attempt = 0; attempt < retryTimes; ++attempt) { for (int ns = 0; ns < statp->nscount; ++ns) { for (size_t ns = 0; ns < statp->nsaddrs.size(); ++ns) { if (!usable_servers[ns]) continue; *rcode = RCODE_INTERNAL_ERROR; // Get server addr const sockaddr* nsap = get_nsaddr(statp, ns); const int nsaplen = sockaddrSize(nsap); static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; char abuf[NI_MAXHOST]; if (getnameinfo(nsap, (socklen_t)nsaplen, abuf, sizeof(abuf), NULL, 0, niflags) == 0) const IPSockAddr& serverSockAddr = statp->nsaddrs[ns]; LOG(DEBUG) << __func__ << ": Querying server (# " << ns + 1 << ") address = " << abuf; << ") address = " << serverSockAddr.toString(); ::android::net::Protocol query_proto = useTcp ? PROTO_TCP : PROTO_UDP; time_t now = 0; Loading Loading @@ -533,7 +531,7 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int dnsQueryEvent->set_cache_hit(static_cast<CacheStatus>(cache_status)); dnsQueryEvent->set_latency_micros(saturate_cast<int32_t>(queryStopwatch.timeTakenUs())); dnsQueryEvent->set_dns_server_index(ns); dnsQueryEvent->set_ip_version(ipFamilyToIPVersion(nsap->sa_family)); dnsQueryEvent->set_ip_version(ipFamilyToIPVersion(serverSockAddr.family())); dnsQueryEvent->set_retry_times(retry_count_for_event); dnsQueryEvent->set_rcode(static_cast<NsRcode>(*rcode)); dnsQueryEvent->set_protocol(query_proto); Loading @@ -544,10 +542,10 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int // SERVFAIL or times out) do not unduly affect the stats. if (shouldRecordStats) { res_sample sample; _res_stats_set_sample(&sample, now, *rcode, delay); resolv_cache_add_resolver_stats_sample(statp->netid, revision_id, nsap, sample, params.max_samples); resolv_stats_add(statp->netid, IPSockAddr::toIPSockAddr(*nsap), dnsQueryEvent); res_stats_set_sample(&sample, now, *rcode, delay); resolv_cache_add_resolver_stats_sample(statp->netid, revision_id, serverSockAddr, sample, params.max_samples); resolv_stats_add(statp->netid, serverSockAddr, dnsQueryEvent); } if (resplen == 0) continue; Loading Loading @@ -582,12 +580,6 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int return -terrno; } /* Private */ static struct sockaddr* get_nsaddr(res_state statp, size_t n) { return (struct sockaddr*)(void*)&statp->nsaddrs[n]; } static struct timespec get_timeout(res_state statp, const res_params* params, const int ns) { int msec; // Legacy algorithm which scales the timeout by nameserver number. Loading @@ -595,7 +587,7 @@ static struct timespec get_timeout(res_state statp, const res_params* params, co // This has no effect with 1 or 2 nameservers msec = params->base_timeout_msec << ns; if (ns > 0) { msec /= statp->nscount; msec /= statp->nameserverCount(); } // For safety, don't allow OEMs and experiments to configure a timeout shorter than 1s. if (msec < 1000) { Loading @@ -610,7 +602,7 @@ static struct timespec get_timeout(res_state statp, const res_params* params, co } static int send_vc(res_state statp, res_params* params, const uint8_t* buf, int buflen, uint8_t* ans, int anssiz, int* terrno, int ns, time_t* at, int* rcode, uint8_t* ans, int anssiz, int* terrno, size_t ns, time_t* at, int* rcode, int* delay) { *at = time(NULL); *delay = 0; Loading @@ -623,7 +615,14 @@ static int send_vc(res_state statp, res_params* params, const uint8_t* buf, int LOG(INFO) << __func__ << ": using send_vc"; nsap = get_nsaddr(statp, (size_t) ns); // It should never happen, but just in case. if (ns >= statp->nsaddrs.size()) { LOG(ERROR) << __func__ << ": Out-of-bound indexing: " << ns; return -1; } sockaddr_storage ss = statp->nsaddrs[ns]; nsap = reinterpret_cast<sockaddr*>(&ss); nsaplen = sockaddrSize(nsap); connreset = 0; Loading Loading @@ -804,7 +803,7 @@ read_len: */ if (resplen > 0) { struct timespec done = evNowTime(); *delay = _res_stats_calculate_rtt(&done, &now); *delay = res_stats_calculate_rtt(&done, &now); *rcode = anhp->rcode; } return (resplen); Loading Loading @@ -897,12 +896,18 @@ bool ignoreInvalidAnswer(res_state statp, const sockaddr_storage& from, const ui } static int send_dg(res_state statp, res_params* params, const uint8_t* buf, int buflen, uint8_t* ans, int anssiz, int* terrno, int ns, int* v_circuit, int* gotsomewhere, time_t* at, int* rcode, int* delay) { uint8_t* ans, int anssiz, int* terrno, size_t ns, int* v_circuit, int* gotsomewhere, time_t* at, int* rcode, int* delay) { // It should never happen, but just in case. if (ns >= statp->nsaddrs.size()) { LOG(ERROR) << __func__ << ": Out-of-bound indexing: " << ns; return -1; } *at = time(nullptr); *delay = 0; const sockaddr* nsap = get_nsaddr(statp, (size_t)ns); const sockaddr_storage ss = statp->nsaddrs[ns]; const sockaddr* nsap = reinterpret_cast<const sockaddr*>(&ss); const int nsaplen = sockaddrSize(nsap); if (statp->nssocks[ns] == -1) { Loading Loading @@ -1007,7 +1012,7 @@ static int send_dg(res_state statp, res_params* params, const uint8_t* buf, int } timespec done = evNowTime(); *delay = _res_stats_calculate_rtt(&done, &now); *delay = res_stats_calculate_rtt(&done, &now); if (anhp->rcode == SERVFAIL || anhp->rcode == NOTIMP || anhp->rcode == REFUSED) { LOG(DEBUG) << __func__ << ": server rejected query:"; res_pquery(ans, (resplen > anssiz) ? anssiz : resplen); Loading
res_stats.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -24,7 +24,7 @@ #include "stats.h" // Calculate the round-trip-time from start time t0 and end time t1. int _res_stats_calculate_rtt(const timespec* t1, const timespec* t0) { int res_stats_calculate_rtt(const timespec* t1, const timespec* t0) { // Divide ns by one million to get ms, multiply s by thousand to get ms (obvious) long ms0 = t0->tv_sec * 1000 + t0->tv_nsec / 1000000; long ms1 = t1->tv_sec * 1000 + t1->tv_nsec / 1000000; Loading @@ -32,7 +32,7 @@ int _res_stats_calculate_rtt(const timespec* t1, const timespec* t0) { } // Create a sample for calculating server reachability statistics. void _res_stats_set_sample(res_sample* sample, time_t now, int rcode, int rtt) { void res_stats_set_sample(res_sample* sample, time_t now, int rcode, int rtt) { LOG(INFO) << __func__ << ": rcode = " << rcode << ", sec = " << rtt; sample->at = now; sample->rcode = rcode; Loading
resolv_cache.h +15 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ #include "ResolverStats.h" #include "params.h" #include "stats.h" // Sets the name server addresses to the provided ResState. // The name servers are retrieved from the cache which is associated Loading Loading @@ -115,3 +116,17 @@ void resolv_stats_dump(android::netdutils::DumpWriter& dw, unsigned netid); void resolv_oem_options_dump(android::netdutils::DumpWriter& dw, unsigned netid); const char* tc_mode_to_str(const int mode); /* Retrieve a local copy of the stats for the given netid. The buffer must have space for * MAXNS __resolver_stats. Returns the revision id of the resolvers used. */ int resolv_cache_get_resolver_stats( unsigned netid, res_params* params, res_stats stats[MAXNS], const std::vector<android::netdutils::IPSockAddr>& serverSockAddrs); /* Add a sample to the shared struct for the given netid and server, provided that the * revision_id of the stored servers has not changed. */ void resolv_cache_add_resolver_stats_sample(unsigned netid, int revision_id, const android::netdutils::IPSockAddr& serverSockAddr, const res_sample& sample, int max_samples);