Loading getaddrinfo.cpp +138 −28 Original line number Diff line number Diff line Loading @@ -53,6 +53,8 @@ #include <sys/un.h> #include <unistd.h> #include <future> #include <android-base/logging.h> #include "netd_resolv/resolv.h" Loading @@ -61,6 +63,7 @@ #include "res_init.h" #include "resolv_cache.h" #include "resolv_private.h" #include "util.h" #define ANY 0 Loading Loading @@ -1573,6 +1576,137 @@ static bool files_getaddrinfo(const size_t netid, const char* name, const addrin /* resolver logic */ namespace { constexpr int SLEEP_TIME_MS = 2; int getHerrnoFromRcode(int rcode) { switch (rcode) { // Not defined in RFC. case RCODE_TIMEOUT: // DNS metrics monitors DNS query timeout. return NETD_RESOLV_H_ERRNO_EXT_TIMEOUT; // extended h_errno. // Defined in RFC 1035 section 4.1.1. case NXDOMAIN: return HOST_NOT_FOUND; case SERVFAIL: return TRY_AGAIN; case NOERROR: return NO_DATA; case FORMERR: case NOTIMP: case REFUSED: default: return NO_RECOVERY; } } struct QueryResult { int ancount; int rcode; int herrno; NetworkDnsEventReported event; }; QueryResult doQuery(const char* name, res_target* t, res_state res) { HEADER* hp = (HEADER*)(void*)t->answer.data(); hp->rcode = NOERROR; // default const int cl = t->qclass; const int type = t->qtype; const int anslen = t->answer.size(); LOG(DEBUG) << __func__ << ": (" << cl << ", " << type << ")"; uint8_t buf[MAXPACKET]; int n = res_nmkquery(QUERY, name, cl, type, /*data=*/nullptr, /*datalen=*/0, buf, sizeof(buf), res->netcontext_flags); if (n > 0 && (res->netcontext_flags & (NET_CONTEXT_FLAG_USE_DNS_OVER_TLS | NET_CONTEXT_FLAG_USE_EDNS))) { n = res_nopt(res, n, buf, sizeof(buf), anslen); } NetworkDnsEventReported event; if (n <= 0) { LOG(ERROR) << __func__ << ": res_nmkquery failed"; return {0, -1, NO_RECOVERY, event}; return { .ancount = 0, .rcode = -1, .herrno = NO_RECOVERY, .event = event, }; } ResState res_temp = fromResState(*res, &event); int rcode = NOERROR; n = res_nsend(&res_temp, buf, n, t->answer.data(), anslen, &rcode, 0); if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { // if the query choked with EDNS0, retry without EDNS0 if ((res_temp.netcontext_flags & (NET_CONTEXT_FLAG_USE_DNS_OVER_TLS | NET_CONTEXT_FLAG_USE_EDNS)) && (res_temp._flags & RES_F_EDNS0ERR)) { LOG(DEBUG) << __func__ << ": retry without EDNS0"; n = res_nmkquery(QUERY, name, cl, type, /*data=*/nullptr, /*datalen=*/0, buf, sizeof(buf), res->netcontext_flags); n = res_nsend(&res_temp, buf, n, t->answer.data(), anslen, &rcode, 0); } } LOG(DEBUG) << __func__ << ": rcode=" << hp->rcode << ", ancount=" << ntohs(hp->ancount); t->n = n; return { .ancount = ntohs(hp->ancount), .rcode = rcode, .event = event, }; } } // namespace static int res_queryN_parallel(const char* name, res_target* target, res_state res, int* herrno) { std::vector<std::future<QueryResult>> results; results.reserve(2); for (res_target* t = target; t; t = t->next) { results.emplace_back(std::async(std::launch::async, doQuery, name, t, res)); // Avoiding gateways drop packets if queries are sent too close together if (t->next) usleep(SLEEP_TIME_MS * 1000); } int ancount = 0; int rcode = 0; for (auto& f : results) { const QueryResult& r = f.get(); if (r.herrno == NO_RECOVERY) { *herrno = r.herrno; return -1; } res->event->MergeFrom(r.event); ancount += r.ancount; rcode = r.rcode; } if (ancount == 0) { *herrno = getHerrnoFromRcode(rcode); return -1; } return ancount; } static int res_queryN_wrapper(const char* name, res_target* target, res_state res, int* herrno) { const bool parallel_lookup = getExperimentFlagInt("parallel_lookup", 0); if (parallel_lookup) return res_queryN_parallel(name, target, res, herrno); return res_queryN(name, target, res, herrno); } /* * Formulate a normal query, send, and await answer. * Returned answer is placed in supplied buffer "answer". Loading Loading @@ -1647,29 +1781,7 @@ static int res_queryN(const char* name, res_target* target, res_state res, int* } if (ancount == 0) { switch (rcode) { // Not defined in RFC. case RCODE_TIMEOUT: // DNS metrics monitors DNS query timeout. *herrno = NETD_RESOLV_H_ERRNO_EXT_TIMEOUT; // extended h_errno. break; // Defined in RFC 1035 section 4.1.1. case NXDOMAIN: *herrno = HOST_NOT_FOUND; break; case SERVFAIL: *herrno = TRY_AGAIN; break; case NOERROR: *herrno = NO_DATA; break; case FORMERR: case NOTIMP: case REFUSED: default: *herrno = NO_RECOVERY; break; } *herrno = getHerrnoFromRcode(rcode); return -1; } return ancount; Loading Loading @@ -1795,10 +1907,8 @@ static int res_searchN(const char* name, res_target* target, res_state res, int* return -1; } /* * Perform a call on res_query on the concatenation of name and domain, * removing a trailing dot from name if domain is NULL. */ // Perform a call on res_query on the concatenation of name and domain, // removing a trailing dot from name if domain is NULL. static int res_querydomainN(const char* name, const char* domain, res_target* target, res_state res, int* herrno) { char nbuf[MAXDNAME]; Loading Loading @@ -1828,5 +1938,5 @@ static int res_querydomainN(const char* name, const char* domain, res_target* ta } snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain); } return res_queryN(longname, target, res, herrno); return res_queryN_wrapper(longname, target, res, herrno); } res_init.cpp +23 −0 Original line number Diff line number Diff line Loading @@ -91,6 +91,7 @@ #include "netd_resolv/resolv.h" #include "resolv_private.h" #include "stats.pb.h" void res_init(ResState* statp, const struct android_net_context* _Nonnull netcontext, android::net::NetworkDnsEventReported* _Nonnull event) { Loading @@ -108,3 +109,25 @@ void res_init(ResState* statp, const struct android_net_context* _Nonnull netcon statp->event = event; statp->netcontext_flags = netcontext->flags; } // TODO: Have some proper constructors for ResState instead of this method and res_init(). ResState fromResState(const ResState& other, android::net::NetworkDnsEventReported* event) { ResState resOutput; resOutput.netid = other.netid; resOutput.uid = other.uid; resOutput.pid = other.pid; resOutput.id = other.id; resOutput.nsaddrs = other.nsaddrs; for (auto& sock : resOutput.nssocks) { sock.reset(); } resOutput.ndots = other.ndots; resOutput._mark = other._mark; resOutput.tcp_nssock.reset(); resOutput.event = event; resOutput.netcontext_flags = other.netcontext_flags; return resOutput; } res_init.h +2 −0 Original line number Diff line number Diff line Loading @@ -16,7 +16,9 @@ #pragma once #include "resolv_private.h" #include "stats.pb.h" // TODO: make this a constructor for ResState void res_init(ResState* res, const struct android_net_context* netcontext, android::net::NetworkDnsEventReported* event); ResState fromResState(const ResState& other, android::net::NetworkDnsEventReported* event); res_send.cpp +163 −101 Original line number Diff line number Diff line Loading @@ -95,6 +95,7 @@ #include <unistd.h> #include <android-base/logging.h> #include <android-base/result.h> #include <android/multinetwork.h> // ResNsendFlags #include <netdutils/Slice.h> Loading @@ -114,6 +115,8 @@ #include "util.h" // TODO: use the namespace something like android::netd_resolv for libnetd_resolv using android::base::ErrnoError; using android::base::Result; using android::net::CacheStatus; using android::net::DnsQueryEvent; using android::net::DnsTlsDispatcher; Loading Loading @@ -142,7 +145,7 @@ static int send_vc(res_state statp, res_params* params, const uint8_t* buf, int 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, 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); Loading Loading @@ -286,21 +289,23 @@ static void res_set_usable_server(int selectedServer, int nscount, bool usable_s } } // Looks up the nameserver address in res.nsaddrs[], returns true if found, otherwise false. static bool res_ourserver_p(res_state statp, const sockaddr* sa) { // Looks up the nameserver address in res.nsaddrs[], returns the ns number if found, otherwise -1. static int res_ourserver_p(res_state statp, const sockaddr* sa) { const sockaddr_in *inp, *srv; const sockaddr_in6 *in6p, *srv6; int ns = 0; switch (sa->sa_family) { case AF_INET: inp = (const struct sockaddr_in*) (const void*) sa; 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)) return true; return ns; ++ns; } break; case AF_INET6: Loading @@ -314,13 +319,14 @@ static bool res_ourserver_p(res_state statp, const sockaddr* sa) { #endif (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) || IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr))) return true; return ns; ++ns; } break; default: break; } return false; return -1; } /* int Loading Loading @@ -498,18 +504,19 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int << ") address = " << serverSockAddr.toString(); ::android::net::Protocol query_proto = useTcp ? PROTO_TCP : PROTO_UDP; time_t now = 0; time_t query_time = 0; int delay = 0; bool fallbackTCP = false; const bool shouldRecordStats = (attempt == 0); int resplen; Stopwatch queryStopwatch; int retry_count_for_event = 0; size_t actualNs = ns; if (useTcp) { // TCP; at most one attempt per server. attempt = retryTimes; resplen = send_vc(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &now, rcode, &delay); resplen = send_vc(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &query_time, rcode, &delay); if (buflen <= PACKETSZ && resplen <= 0 && statp->tc_mode == aidl::android::net::IDnsResolver::TC_MODE_UDP_TCP) { Loading @@ -520,18 +527,24 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int LOG(INFO) << __func__ << ": used send_vc " << resplen; } else { // UDP resplen = send_dg(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &useTcp, &gotsomewhere, &now, rcode, &delay); resplen = send_dg(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, &actualNs, &useTcp, &gotsomewhere, &query_time, rcode, &delay); fallbackTCP = useTcp ? true : false; retry_count_for_event = attempt; LOG(INFO) << __func__ << ": used send_dg " << resplen; } const IPSockAddr& receivedServerAddr = statp->nsaddrs[actualNs]; DnsQueryEvent* dnsQueryEvent = addDnsQueryEvent(statp->event); 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(serverSockAddr.family())); // When |retryTimes| > 1, we cannot actually know the correct latency value if we // received the answer from the previous server. So temporarily set the latency as -1 if // that condition happened. // TODO: make the latency value accurate. dnsQueryEvent->set_latency_micros( (actualNs == ns) ? saturate_cast<int32_t>(queryStopwatch.timeTakenUs()) : -1); dnsQueryEvent->set_dns_server_index(actualNs); dnsQueryEvent->set_ip_version(ipFamilyToIPVersion(receivedServerAddr.family())); dnsQueryEvent->set_retry_times(retry_count_for_event); dnsQueryEvent->set_rcode(static_cast<NsRcode>(*rcode)); dnsQueryEvent->set_protocol(query_proto); Loading @@ -542,10 +555,13 @@ 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); res_stats_set_sample(&sample, query_time, *rcode, delay); // KeepListening UDP mechanism is incompatible with usable_servers of legacy stats, // so keep the old logic for now. // TODO: Replace usable_servers of legacy stats with new one. resolv_cache_add_resolver_stats_sample(statp->netid, revision_id, serverSockAddr, sample, params.max_samples); resolv_stats_add(statp->netid, serverSockAddr, dnsQueryEvent); resolv_stats_add(statp->netid, receivedServerAddr, dnsQueryEvent); } if (resplen == 0) continue; Loading Loading @@ -629,7 +645,7 @@ static int send_vc(res_state statp, res_params* params, const uint8_t* buf, int same_ns: truncating = 0; struct timespec now = evNowTime(); struct timespec start_time = evNowTime(); /* Are we still talking to whom we want to talk to? */ if (statp->tcp_nssock >= 0 && (statp->_flags & RES_F_VC) != 0) { Loading Loading @@ -803,7 +819,7 @@ read_len: */ if (resplen > 0) { struct timespec done = evNowTime(); *delay = res_stats_calculate_rtt(&done, &now); *delay = res_stats_calculate_rtt(&done, &start_time); *rcode = anhp->rcode; } return (resplen); Loading Loading @@ -873,8 +889,53 @@ retry: return n; } static std::vector<pollfd> extractUdpFdset(res_state statp, const short events = POLLIN) { std::vector<pollfd> fdset(statp->nsaddrs.size()); for (size_t i = 0; i < statp->nsaddrs.size(); ++i) { fdset[i] = {.fd = statp->nssocks[i], .events = events}; } return fdset; } static Result<std::vector<int>> udpRetryingPoll(res_state statp, const timespec* finish) { for (;;) { LOG(DEBUG) << __func__ << ": poll"; timespec start_time = evNowTime(); timespec timeout = (evCmpTime(*finish, start_time) > 0) ? evSubTime(*finish, start_time) : evConsTime(0L, 0L); std::vector<pollfd> fdset = extractUdpFdset(statp); const int n = ppoll(fdset.data(), fdset.size(), &timeout, /*sigmask=*/nullptr); if (n <= 0) { if (errno == EINTR && n < 0) continue; if (n == 0) errno = ETIMEDOUT; PLOG(INFO) << __func__ << ": failed"; return ErrnoError(); } std::vector<int> fdsToRead; for (const auto& pollfd : fdset) { if (pollfd.revents & (POLLIN | POLLERR)) { fdsToRead.push_back(pollfd.fd); } } LOG(DEBUG) << __func__ << ": " << " returning fd size: " << fdsToRead.size(); return fdsToRead; } } static Result<std::vector<int>> udpRetryingPollWrapper(res_state statp, int ns, const timespec* finish) { const bool keepListeningUdp = getExperimentFlagInt("keep_listening_udp", 0); if (keepListeningUdp) return udpRetryingPoll(statp, finish); if (int n = retrying_poll(statp->nssocks[ns], POLLIN, finish); n <= 0) { return ErrnoError(); } return std::vector<int>{statp->nssocks[ns]}; } bool ignoreInvalidAnswer(res_state statp, const sockaddr_storage& from, const uint8_t* buf, int buflen, uint8_t* ans, int anssiz) { int buflen, uint8_t* ans, int anssiz, int* receivedFromNs) { const HEADER* hp = (const HEADER*)(const void*)buf; HEADER* anhp = (HEADER*)(void*)ans; if (hp->id != anhp->id) { Loading @@ -882,7 +943,7 @@ bool ignoreInvalidAnswer(res_state statp, const sockaddr_storage& from, const ui LOG(DEBUG) << __func__ << ": old answer:"; return true; } if (!res_ourserver_p(statp, (sockaddr*)(void*)&from)) { if (*receivedFromNs = res_ourserver_p(statp, (sockaddr*)(void*)&from); *receivedFromNs < 0) { // response from wrong server? ignore it. LOG(DEBUG) << __func__ << ": not our server:"; return true; Loading @@ -896,23 +957,23 @@ 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, size_t ns, int* v_circuit, 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()) { if (*ns >= statp->nsaddrs.size()) { LOG(ERROR) << __func__ << ": Out-of-bound indexing: " << ns; return -1; } *at = time(nullptr); *delay = 0; const sockaddr_storage ss = statp->nsaddrs[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) { statp->nssocks[ns].reset(socket(nsap->sa_family, SOCK_DGRAM | SOCK_CLOEXEC, 0)); if (statp->nssocks[ns] < 0) { if (statp->nssocks[*ns] == -1) { statp->nssocks[*ns].reset(socket(nsap->sa_family, SOCK_DGRAM | SOCK_CLOEXEC, 0)); if (statp->nssocks[*ns] < 0) { switch (errno) { case EPROTONOSUPPORT: case EPFNOSUPPORT: Loading @@ -926,9 +987,9 @@ static int send_dg(res_state statp, res_params* params, const uint8_t* buf, int } } resolv_tag_socket(statp->nssocks[ns], statp->uid, statp->pid); resolv_tag_socket(statp->nssocks[*ns], statp->uid, statp->pid); if (statp->_mark != MARK_UNSET) { if (setsockopt(statp->nssocks[ns], SOL_SOCKET, SO_MARK, &(statp->_mark), if (setsockopt(statp->nssocks[*ns], SOL_SOCKET, SO_MARK, &(statp->_mark), sizeof(statp->_mark)) < 0) { statp->closeSockets(); return -1; Loading @@ -938,62 +999,64 @@ static int send_dg(res_state statp, res_params* params, const uint8_t* buf, int // on the next socket operation when the server responds with an // ICMP port-unreachable error. This way we can detect the absence of // a nameserver without timing out. if (random_bind(statp->nssocks[ns], nsap->sa_family) < 0) { if (random_bind(statp->nssocks[*ns], nsap->sa_family) < 0) { dump_error("bind(dg)", nsap, nsaplen); statp->closeSockets(); return (0); } if (connect(statp->nssocks[ns], nsap, (socklen_t)nsaplen) < 0) { if (connect(statp->nssocks[*ns], nsap, (socklen_t)nsaplen) < 0) { dump_error("connect(dg)", nsap, nsaplen); statp->closeSockets(); return (0); } LOG(DEBUG) << __func__ << ": new DG socket"; } if (send(statp->nssocks[ns], (const char*)buf, (size_t)buflen, 0) != buflen) { if (send(statp->nssocks[*ns], (const char*)buf, (size_t)buflen, 0) != buflen) { PLOG(DEBUG) << __func__ << ": send: "; statp->closeSockets(); return 0; } timespec timeout = get_timeout(statp, params, ns); timespec now = evNowTime(); timespec finish = evAddTime(now, timeout); timespec timeout = get_timeout(statp, params, *ns); timespec start_time = evNowTime(); timespec finish = evAddTime(start_time, timeout); for (;;) { // Wait for reply. int n = retrying_poll(statp->nssocks[ns], POLLIN, &finish); if (n == 0) { *rcode = RCODE_TIMEOUT; LOG(DEBUG) << __func__ << ": timeout"; *gotsomewhere = 1; auto result = udpRetryingPollWrapper(statp, *ns, &finish); if (!result.has_value()) { const bool isTimeout = (result.error().code() == ETIMEDOUT); *rcode = (isTimeout) ? RCODE_TIMEOUT : *rcode; *gotsomewhere = (isTimeout) ? 1 : *gotsomewhere; // Leave the UDP sockets open on timeout so we can keep listening for // a late response from this server while retrying on the next server. if (!isTimeout) statp->closeSockets(); LOG(DEBUG) << __func__ << ": " << (isTimeout) ? "timeout" : "poll"; return 0; } if (n < 0) { PLOG(DEBUG) << __func__ << ": poll: "; statp->closeSockets(); return 0; } errno = 0; bool needRetry = false; for (int fd : result.value()) { needRetry = false; sockaddr_storage from; socklen_t fromlen = sizeof(from); int resplen = recvfrom(statp->nssocks[ns], (char*)ans, (size_t)anssiz, 0, (sockaddr*)(void*)&from, &fromlen); int resplen = recvfrom(fd, (char*)ans, (size_t)anssiz, 0, (sockaddr*)(void*)&from, &fromlen); if (resplen <= 0) { PLOG(DEBUG) << __func__ << ": recvfrom: "; statp->closeSockets(); return 0; continue; } *gotsomewhere = 1; if (resplen < HFIXEDSZ) { // Undersized message. LOG(DEBUG) << __func__ << ": undersized: " << resplen; *terrno = EMSGSIZE; statp->closeSockets(); return 0; continue; } if (ignoreInvalidAnswer(statp, from, buf, buflen, ans, anssiz)) { int receivedFromNs = *ns; if (needRetry = ignoreInvalidAnswer(statp, from, buf, buflen, ans, anssiz, &receivedFromNs); needRetry) { res_pquery(ans, (resplen > anssiz) ? anssiz : resplen); continue; } Loading @@ -1007,34 +1070,33 @@ static int send_dg(res_state statp, res_params* params, const uint8_t* buf, int res_pquery(ans, (resplen > anssiz) ? anssiz : resplen); // record the error statp->_flags |= RES_F_EDNS0ERR; statp->closeSockets(); return 0; continue; } timespec done = evNowTime(); *delay = res_stats_calculate_rtt(&done, &now); *delay = res_stats_calculate_rtt(&done, &start_time); if (anhp->rcode == SERVFAIL || anhp->rcode == NOTIMP || anhp->rcode == REFUSED) { LOG(DEBUG) << __func__ << ": server rejected query:"; res_pquery(ans, (resplen > anssiz) ? anssiz : resplen); statp->closeSockets(); *rcode = anhp->rcode; return 0; continue; } if (anhp->tc) { // To get the rest of answer, // use TCP with same server. LOG(DEBUG) << __func__ << ": truncated answer"; *v_circuit = 1; statp->closeSockets(); return 1; } // All is well, or the error is fatal. Signal that the // next nameserver ought not be tried. if (resplen > 0) { *rcode = anhp->rcode; } *ns = receivedFromNs; return resplen; } if (!needRetry) return 0; } } static void dump_error(const char* str, const struct sockaddr* address, int alen) { Loading tests/dns_responder/dns_responder.cpp +7 −1 Original line number Diff line number Diff line Loading @@ -27,9 +27,10 @@ #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> #include <set> #include <chrono> #include <iostream> #include <set> #include <vector> #define LOG_TAG "DNSResponder" Loading Loading @@ -515,6 +516,10 @@ void DNSResponder::setResponseProbability(double response_probability) { setResponseProbability(response_probability, IPPROTO_UDP); } void DNSResponder::setResponseDelayMs(unsigned timeMs) { response_delayed_ms_ = timeMs; } // Set response probability on specific protocol. It's caller's duty to ensure that the |protocol| // can be supported by DNSResponder. void DNSResponder::setResponseProbability(double response_probability, int protocol) { Loading Loading @@ -1102,6 +1107,7 @@ void DNSResponder::handleQuery(int protocol) { size_t response_len = sizeof(response); // TODO: check whether sending malformed packets to DnsResponder if (handleDNSRequest(buffer, len, protocol, response, &response_len) && response_len > 0) { std::this_thread::sleep_for(std::chrono::milliseconds(response_delayed_ms_)); // place wait_for after handleDNSRequest() so we can check the number of queries in // test case before it got responded. std::unique_lock guard(cv_mutex_for_deferred_resp_); Loading Loading
getaddrinfo.cpp +138 −28 Original line number Diff line number Diff line Loading @@ -53,6 +53,8 @@ #include <sys/un.h> #include <unistd.h> #include <future> #include <android-base/logging.h> #include "netd_resolv/resolv.h" Loading @@ -61,6 +63,7 @@ #include "res_init.h" #include "resolv_cache.h" #include "resolv_private.h" #include "util.h" #define ANY 0 Loading Loading @@ -1573,6 +1576,137 @@ static bool files_getaddrinfo(const size_t netid, const char* name, const addrin /* resolver logic */ namespace { constexpr int SLEEP_TIME_MS = 2; int getHerrnoFromRcode(int rcode) { switch (rcode) { // Not defined in RFC. case RCODE_TIMEOUT: // DNS metrics monitors DNS query timeout. return NETD_RESOLV_H_ERRNO_EXT_TIMEOUT; // extended h_errno. // Defined in RFC 1035 section 4.1.1. case NXDOMAIN: return HOST_NOT_FOUND; case SERVFAIL: return TRY_AGAIN; case NOERROR: return NO_DATA; case FORMERR: case NOTIMP: case REFUSED: default: return NO_RECOVERY; } } struct QueryResult { int ancount; int rcode; int herrno; NetworkDnsEventReported event; }; QueryResult doQuery(const char* name, res_target* t, res_state res) { HEADER* hp = (HEADER*)(void*)t->answer.data(); hp->rcode = NOERROR; // default const int cl = t->qclass; const int type = t->qtype; const int anslen = t->answer.size(); LOG(DEBUG) << __func__ << ": (" << cl << ", " << type << ")"; uint8_t buf[MAXPACKET]; int n = res_nmkquery(QUERY, name, cl, type, /*data=*/nullptr, /*datalen=*/0, buf, sizeof(buf), res->netcontext_flags); if (n > 0 && (res->netcontext_flags & (NET_CONTEXT_FLAG_USE_DNS_OVER_TLS | NET_CONTEXT_FLAG_USE_EDNS))) { n = res_nopt(res, n, buf, sizeof(buf), anslen); } NetworkDnsEventReported event; if (n <= 0) { LOG(ERROR) << __func__ << ": res_nmkquery failed"; return {0, -1, NO_RECOVERY, event}; return { .ancount = 0, .rcode = -1, .herrno = NO_RECOVERY, .event = event, }; } ResState res_temp = fromResState(*res, &event); int rcode = NOERROR; n = res_nsend(&res_temp, buf, n, t->answer.data(), anslen, &rcode, 0); if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { // if the query choked with EDNS0, retry without EDNS0 if ((res_temp.netcontext_flags & (NET_CONTEXT_FLAG_USE_DNS_OVER_TLS | NET_CONTEXT_FLAG_USE_EDNS)) && (res_temp._flags & RES_F_EDNS0ERR)) { LOG(DEBUG) << __func__ << ": retry without EDNS0"; n = res_nmkquery(QUERY, name, cl, type, /*data=*/nullptr, /*datalen=*/0, buf, sizeof(buf), res->netcontext_flags); n = res_nsend(&res_temp, buf, n, t->answer.data(), anslen, &rcode, 0); } } LOG(DEBUG) << __func__ << ": rcode=" << hp->rcode << ", ancount=" << ntohs(hp->ancount); t->n = n; return { .ancount = ntohs(hp->ancount), .rcode = rcode, .event = event, }; } } // namespace static int res_queryN_parallel(const char* name, res_target* target, res_state res, int* herrno) { std::vector<std::future<QueryResult>> results; results.reserve(2); for (res_target* t = target; t; t = t->next) { results.emplace_back(std::async(std::launch::async, doQuery, name, t, res)); // Avoiding gateways drop packets if queries are sent too close together if (t->next) usleep(SLEEP_TIME_MS * 1000); } int ancount = 0; int rcode = 0; for (auto& f : results) { const QueryResult& r = f.get(); if (r.herrno == NO_RECOVERY) { *herrno = r.herrno; return -1; } res->event->MergeFrom(r.event); ancount += r.ancount; rcode = r.rcode; } if (ancount == 0) { *herrno = getHerrnoFromRcode(rcode); return -1; } return ancount; } static int res_queryN_wrapper(const char* name, res_target* target, res_state res, int* herrno) { const bool parallel_lookup = getExperimentFlagInt("parallel_lookup", 0); if (parallel_lookup) return res_queryN_parallel(name, target, res, herrno); return res_queryN(name, target, res, herrno); } /* * Formulate a normal query, send, and await answer. * Returned answer is placed in supplied buffer "answer". Loading Loading @@ -1647,29 +1781,7 @@ static int res_queryN(const char* name, res_target* target, res_state res, int* } if (ancount == 0) { switch (rcode) { // Not defined in RFC. case RCODE_TIMEOUT: // DNS metrics monitors DNS query timeout. *herrno = NETD_RESOLV_H_ERRNO_EXT_TIMEOUT; // extended h_errno. break; // Defined in RFC 1035 section 4.1.1. case NXDOMAIN: *herrno = HOST_NOT_FOUND; break; case SERVFAIL: *herrno = TRY_AGAIN; break; case NOERROR: *herrno = NO_DATA; break; case FORMERR: case NOTIMP: case REFUSED: default: *herrno = NO_RECOVERY; break; } *herrno = getHerrnoFromRcode(rcode); return -1; } return ancount; Loading Loading @@ -1795,10 +1907,8 @@ static int res_searchN(const char* name, res_target* target, res_state res, int* return -1; } /* * Perform a call on res_query on the concatenation of name and domain, * removing a trailing dot from name if domain is NULL. */ // Perform a call on res_query on the concatenation of name and domain, // removing a trailing dot from name if domain is NULL. static int res_querydomainN(const char* name, const char* domain, res_target* target, res_state res, int* herrno) { char nbuf[MAXDNAME]; Loading Loading @@ -1828,5 +1938,5 @@ static int res_querydomainN(const char* name, const char* domain, res_target* ta } snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain); } return res_queryN(longname, target, res, herrno); return res_queryN_wrapper(longname, target, res, herrno); }
res_init.cpp +23 −0 Original line number Diff line number Diff line Loading @@ -91,6 +91,7 @@ #include "netd_resolv/resolv.h" #include "resolv_private.h" #include "stats.pb.h" void res_init(ResState* statp, const struct android_net_context* _Nonnull netcontext, android::net::NetworkDnsEventReported* _Nonnull event) { Loading @@ -108,3 +109,25 @@ void res_init(ResState* statp, const struct android_net_context* _Nonnull netcon statp->event = event; statp->netcontext_flags = netcontext->flags; } // TODO: Have some proper constructors for ResState instead of this method and res_init(). ResState fromResState(const ResState& other, android::net::NetworkDnsEventReported* event) { ResState resOutput; resOutput.netid = other.netid; resOutput.uid = other.uid; resOutput.pid = other.pid; resOutput.id = other.id; resOutput.nsaddrs = other.nsaddrs; for (auto& sock : resOutput.nssocks) { sock.reset(); } resOutput.ndots = other.ndots; resOutput._mark = other._mark; resOutput.tcp_nssock.reset(); resOutput.event = event; resOutput.netcontext_flags = other.netcontext_flags; return resOutput; }
res_init.h +2 −0 Original line number Diff line number Diff line Loading @@ -16,7 +16,9 @@ #pragma once #include "resolv_private.h" #include "stats.pb.h" // TODO: make this a constructor for ResState void res_init(ResState* res, const struct android_net_context* netcontext, android::net::NetworkDnsEventReported* event); ResState fromResState(const ResState& other, android::net::NetworkDnsEventReported* event);
res_send.cpp +163 −101 Original line number Diff line number Diff line Loading @@ -95,6 +95,7 @@ #include <unistd.h> #include <android-base/logging.h> #include <android-base/result.h> #include <android/multinetwork.h> // ResNsendFlags #include <netdutils/Slice.h> Loading @@ -114,6 +115,8 @@ #include "util.h" // TODO: use the namespace something like android::netd_resolv for libnetd_resolv using android::base::ErrnoError; using android::base::Result; using android::net::CacheStatus; using android::net::DnsQueryEvent; using android::net::DnsTlsDispatcher; Loading Loading @@ -142,7 +145,7 @@ static int send_vc(res_state statp, res_params* params, const uint8_t* buf, int 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, 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); Loading Loading @@ -286,21 +289,23 @@ static void res_set_usable_server(int selectedServer, int nscount, bool usable_s } } // Looks up the nameserver address in res.nsaddrs[], returns true if found, otherwise false. static bool res_ourserver_p(res_state statp, const sockaddr* sa) { // Looks up the nameserver address in res.nsaddrs[], returns the ns number if found, otherwise -1. static int res_ourserver_p(res_state statp, const sockaddr* sa) { const sockaddr_in *inp, *srv; const sockaddr_in6 *in6p, *srv6; int ns = 0; switch (sa->sa_family) { case AF_INET: inp = (const struct sockaddr_in*) (const void*) sa; 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)) return true; return ns; ++ns; } break; case AF_INET6: Loading @@ -314,13 +319,14 @@ static bool res_ourserver_p(res_state statp, const sockaddr* sa) { #endif (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) || IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr))) return true; return ns; ++ns; } break; default: break; } return false; return -1; } /* int Loading Loading @@ -498,18 +504,19 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int << ") address = " << serverSockAddr.toString(); ::android::net::Protocol query_proto = useTcp ? PROTO_TCP : PROTO_UDP; time_t now = 0; time_t query_time = 0; int delay = 0; bool fallbackTCP = false; const bool shouldRecordStats = (attempt == 0); int resplen; Stopwatch queryStopwatch; int retry_count_for_event = 0; size_t actualNs = ns; if (useTcp) { // TCP; at most one attempt per server. attempt = retryTimes; resplen = send_vc(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &now, rcode, &delay); resplen = send_vc(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &query_time, rcode, &delay); if (buflen <= PACKETSZ && resplen <= 0 && statp->tc_mode == aidl::android::net::IDnsResolver::TC_MODE_UDP_TCP) { Loading @@ -520,18 +527,24 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int LOG(INFO) << __func__ << ": used send_vc " << resplen; } else { // UDP resplen = send_dg(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &useTcp, &gotsomewhere, &now, rcode, &delay); resplen = send_dg(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, &actualNs, &useTcp, &gotsomewhere, &query_time, rcode, &delay); fallbackTCP = useTcp ? true : false; retry_count_for_event = attempt; LOG(INFO) << __func__ << ": used send_dg " << resplen; } const IPSockAddr& receivedServerAddr = statp->nsaddrs[actualNs]; DnsQueryEvent* dnsQueryEvent = addDnsQueryEvent(statp->event); 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(serverSockAddr.family())); // When |retryTimes| > 1, we cannot actually know the correct latency value if we // received the answer from the previous server. So temporarily set the latency as -1 if // that condition happened. // TODO: make the latency value accurate. dnsQueryEvent->set_latency_micros( (actualNs == ns) ? saturate_cast<int32_t>(queryStopwatch.timeTakenUs()) : -1); dnsQueryEvent->set_dns_server_index(actualNs); dnsQueryEvent->set_ip_version(ipFamilyToIPVersion(receivedServerAddr.family())); dnsQueryEvent->set_retry_times(retry_count_for_event); dnsQueryEvent->set_rcode(static_cast<NsRcode>(*rcode)); dnsQueryEvent->set_protocol(query_proto); Loading @@ -542,10 +555,13 @@ 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); res_stats_set_sample(&sample, query_time, *rcode, delay); // KeepListening UDP mechanism is incompatible with usable_servers of legacy stats, // so keep the old logic for now. // TODO: Replace usable_servers of legacy stats with new one. resolv_cache_add_resolver_stats_sample(statp->netid, revision_id, serverSockAddr, sample, params.max_samples); resolv_stats_add(statp->netid, serverSockAddr, dnsQueryEvent); resolv_stats_add(statp->netid, receivedServerAddr, dnsQueryEvent); } if (resplen == 0) continue; Loading Loading @@ -629,7 +645,7 @@ static int send_vc(res_state statp, res_params* params, const uint8_t* buf, int same_ns: truncating = 0; struct timespec now = evNowTime(); struct timespec start_time = evNowTime(); /* Are we still talking to whom we want to talk to? */ if (statp->tcp_nssock >= 0 && (statp->_flags & RES_F_VC) != 0) { Loading Loading @@ -803,7 +819,7 @@ read_len: */ if (resplen > 0) { struct timespec done = evNowTime(); *delay = res_stats_calculate_rtt(&done, &now); *delay = res_stats_calculate_rtt(&done, &start_time); *rcode = anhp->rcode; } return (resplen); Loading Loading @@ -873,8 +889,53 @@ retry: return n; } static std::vector<pollfd> extractUdpFdset(res_state statp, const short events = POLLIN) { std::vector<pollfd> fdset(statp->nsaddrs.size()); for (size_t i = 0; i < statp->nsaddrs.size(); ++i) { fdset[i] = {.fd = statp->nssocks[i], .events = events}; } return fdset; } static Result<std::vector<int>> udpRetryingPoll(res_state statp, const timespec* finish) { for (;;) { LOG(DEBUG) << __func__ << ": poll"; timespec start_time = evNowTime(); timespec timeout = (evCmpTime(*finish, start_time) > 0) ? evSubTime(*finish, start_time) : evConsTime(0L, 0L); std::vector<pollfd> fdset = extractUdpFdset(statp); const int n = ppoll(fdset.data(), fdset.size(), &timeout, /*sigmask=*/nullptr); if (n <= 0) { if (errno == EINTR && n < 0) continue; if (n == 0) errno = ETIMEDOUT; PLOG(INFO) << __func__ << ": failed"; return ErrnoError(); } std::vector<int> fdsToRead; for (const auto& pollfd : fdset) { if (pollfd.revents & (POLLIN | POLLERR)) { fdsToRead.push_back(pollfd.fd); } } LOG(DEBUG) << __func__ << ": " << " returning fd size: " << fdsToRead.size(); return fdsToRead; } } static Result<std::vector<int>> udpRetryingPollWrapper(res_state statp, int ns, const timespec* finish) { const bool keepListeningUdp = getExperimentFlagInt("keep_listening_udp", 0); if (keepListeningUdp) return udpRetryingPoll(statp, finish); if (int n = retrying_poll(statp->nssocks[ns], POLLIN, finish); n <= 0) { return ErrnoError(); } return std::vector<int>{statp->nssocks[ns]}; } bool ignoreInvalidAnswer(res_state statp, const sockaddr_storage& from, const uint8_t* buf, int buflen, uint8_t* ans, int anssiz) { int buflen, uint8_t* ans, int anssiz, int* receivedFromNs) { const HEADER* hp = (const HEADER*)(const void*)buf; HEADER* anhp = (HEADER*)(void*)ans; if (hp->id != anhp->id) { Loading @@ -882,7 +943,7 @@ bool ignoreInvalidAnswer(res_state statp, const sockaddr_storage& from, const ui LOG(DEBUG) << __func__ << ": old answer:"; return true; } if (!res_ourserver_p(statp, (sockaddr*)(void*)&from)) { if (*receivedFromNs = res_ourserver_p(statp, (sockaddr*)(void*)&from); *receivedFromNs < 0) { // response from wrong server? ignore it. LOG(DEBUG) << __func__ << ": not our server:"; return true; Loading @@ -896,23 +957,23 @@ 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, size_t ns, int* v_circuit, 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()) { if (*ns >= statp->nsaddrs.size()) { LOG(ERROR) << __func__ << ": Out-of-bound indexing: " << ns; return -1; } *at = time(nullptr); *delay = 0; const sockaddr_storage ss = statp->nsaddrs[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) { statp->nssocks[ns].reset(socket(nsap->sa_family, SOCK_DGRAM | SOCK_CLOEXEC, 0)); if (statp->nssocks[ns] < 0) { if (statp->nssocks[*ns] == -1) { statp->nssocks[*ns].reset(socket(nsap->sa_family, SOCK_DGRAM | SOCK_CLOEXEC, 0)); if (statp->nssocks[*ns] < 0) { switch (errno) { case EPROTONOSUPPORT: case EPFNOSUPPORT: Loading @@ -926,9 +987,9 @@ static int send_dg(res_state statp, res_params* params, const uint8_t* buf, int } } resolv_tag_socket(statp->nssocks[ns], statp->uid, statp->pid); resolv_tag_socket(statp->nssocks[*ns], statp->uid, statp->pid); if (statp->_mark != MARK_UNSET) { if (setsockopt(statp->nssocks[ns], SOL_SOCKET, SO_MARK, &(statp->_mark), if (setsockopt(statp->nssocks[*ns], SOL_SOCKET, SO_MARK, &(statp->_mark), sizeof(statp->_mark)) < 0) { statp->closeSockets(); return -1; Loading @@ -938,62 +999,64 @@ static int send_dg(res_state statp, res_params* params, const uint8_t* buf, int // on the next socket operation when the server responds with an // ICMP port-unreachable error. This way we can detect the absence of // a nameserver without timing out. if (random_bind(statp->nssocks[ns], nsap->sa_family) < 0) { if (random_bind(statp->nssocks[*ns], nsap->sa_family) < 0) { dump_error("bind(dg)", nsap, nsaplen); statp->closeSockets(); return (0); } if (connect(statp->nssocks[ns], nsap, (socklen_t)nsaplen) < 0) { if (connect(statp->nssocks[*ns], nsap, (socklen_t)nsaplen) < 0) { dump_error("connect(dg)", nsap, nsaplen); statp->closeSockets(); return (0); } LOG(DEBUG) << __func__ << ": new DG socket"; } if (send(statp->nssocks[ns], (const char*)buf, (size_t)buflen, 0) != buflen) { if (send(statp->nssocks[*ns], (const char*)buf, (size_t)buflen, 0) != buflen) { PLOG(DEBUG) << __func__ << ": send: "; statp->closeSockets(); return 0; } timespec timeout = get_timeout(statp, params, ns); timespec now = evNowTime(); timespec finish = evAddTime(now, timeout); timespec timeout = get_timeout(statp, params, *ns); timespec start_time = evNowTime(); timespec finish = evAddTime(start_time, timeout); for (;;) { // Wait for reply. int n = retrying_poll(statp->nssocks[ns], POLLIN, &finish); if (n == 0) { *rcode = RCODE_TIMEOUT; LOG(DEBUG) << __func__ << ": timeout"; *gotsomewhere = 1; auto result = udpRetryingPollWrapper(statp, *ns, &finish); if (!result.has_value()) { const bool isTimeout = (result.error().code() == ETIMEDOUT); *rcode = (isTimeout) ? RCODE_TIMEOUT : *rcode; *gotsomewhere = (isTimeout) ? 1 : *gotsomewhere; // Leave the UDP sockets open on timeout so we can keep listening for // a late response from this server while retrying on the next server. if (!isTimeout) statp->closeSockets(); LOG(DEBUG) << __func__ << ": " << (isTimeout) ? "timeout" : "poll"; return 0; } if (n < 0) { PLOG(DEBUG) << __func__ << ": poll: "; statp->closeSockets(); return 0; } errno = 0; bool needRetry = false; for (int fd : result.value()) { needRetry = false; sockaddr_storage from; socklen_t fromlen = sizeof(from); int resplen = recvfrom(statp->nssocks[ns], (char*)ans, (size_t)anssiz, 0, (sockaddr*)(void*)&from, &fromlen); int resplen = recvfrom(fd, (char*)ans, (size_t)anssiz, 0, (sockaddr*)(void*)&from, &fromlen); if (resplen <= 0) { PLOG(DEBUG) << __func__ << ": recvfrom: "; statp->closeSockets(); return 0; continue; } *gotsomewhere = 1; if (resplen < HFIXEDSZ) { // Undersized message. LOG(DEBUG) << __func__ << ": undersized: " << resplen; *terrno = EMSGSIZE; statp->closeSockets(); return 0; continue; } if (ignoreInvalidAnswer(statp, from, buf, buflen, ans, anssiz)) { int receivedFromNs = *ns; if (needRetry = ignoreInvalidAnswer(statp, from, buf, buflen, ans, anssiz, &receivedFromNs); needRetry) { res_pquery(ans, (resplen > anssiz) ? anssiz : resplen); continue; } Loading @@ -1007,34 +1070,33 @@ static int send_dg(res_state statp, res_params* params, const uint8_t* buf, int res_pquery(ans, (resplen > anssiz) ? anssiz : resplen); // record the error statp->_flags |= RES_F_EDNS0ERR; statp->closeSockets(); return 0; continue; } timespec done = evNowTime(); *delay = res_stats_calculate_rtt(&done, &now); *delay = res_stats_calculate_rtt(&done, &start_time); if (anhp->rcode == SERVFAIL || anhp->rcode == NOTIMP || anhp->rcode == REFUSED) { LOG(DEBUG) << __func__ << ": server rejected query:"; res_pquery(ans, (resplen > anssiz) ? anssiz : resplen); statp->closeSockets(); *rcode = anhp->rcode; return 0; continue; } if (anhp->tc) { // To get the rest of answer, // use TCP with same server. LOG(DEBUG) << __func__ << ": truncated answer"; *v_circuit = 1; statp->closeSockets(); return 1; } // All is well, or the error is fatal. Signal that the // next nameserver ought not be tried. if (resplen > 0) { *rcode = anhp->rcode; } *ns = receivedFromNs; return resplen; } if (!needRetry) return 0; } } static void dump_error(const char* str, const struct sockaddr* address, int alen) { Loading
tests/dns_responder/dns_responder.cpp +7 −1 Original line number Diff line number Diff line Loading @@ -27,9 +27,10 @@ #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> #include <set> #include <chrono> #include <iostream> #include <set> #include <vector> #define LOG_TAG "DNSResponder" Loading Loading @@ -515,6 +516,10 @@ void DNSResponder::setResponseProbability(double response_probability) { setResponseProbability(response_probability, IPPROTO_UDP); } void DNSResponder::setResponseDelayMs(unsigned timeMs) { response_delayed_ms_ = timeMs; } // Set response probability on specific protocol. It's caller's duty to ensure that the |protocol| // can be supported by DNSResponder. void DNSResponder::setResponseProbability(double response_probability, int protocol) { Loading Loading @@ -1102,6 +1107,7 @@ void DNSResponder::handleQuery(int protocol) { size_t response_len = sizeof(response); // TODO: check whether sending malformed packets to DnsResponder if (handleDNSRequest(buffer, len, protocol, response, &response_len) && response_len > 0) { std::this_thread::sleep_for(std::chrono::milliseconds(response_delayed_ms_)); // place wait_for after handleDNSRequest() so we can check the number of queries in // test case before it got responded. std::unique_lock guard(cv_mutex_for_deferred_resp_); Loading