Loading res_send.cpp +67 −108 Original line number Original line Diff line number Diff line Loading @@ -397,24 +397,20 @@ static DnsQueryEvent* addDnsQueryEvent(NetworkDnsEventReported* event) { int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int anssiz, int* rcode, int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int anssiz, int* rcode, uint32_t flags) { uint32_t flags) { int gotsomewhere, terrno, v_circuit, resplen, n; LOG(DEBUG) << __func__; ResolvCacheStatus cache_status = RESOLV_CACHE_UNSUPPORTED; // Should not happen if (anssiz < HFIXEDSZ) { if (anssiz < HFIXEDSZ) { // TODO: Remove errno once callers stop using it // TODO: Remove errno once callers stop using it errno = EINVAL; errno = EINVAL; return -EINVAL; return -EINVAL; } } LOG(DEBUG) << __func__; res_pquery(buf, buflen); res_pquery(buf, buflen); v_circuit = buflen > PACKETSZ; gotsomewhere = 0; terrno = ETIMEDOUT; int anslen = 0; int anslen = 0; Stopwatch cacheStopwatch; Stopwatch cacheStopwatch; cache_status = resolv_cache_lookup(statp->netid, buf, buflen, ans, anssiz, &anslen, flags); ResolvCacheStatus cache_status = resolv_cache_lookup(statp->netid, buf, buflen, ans, anssiz, &anslen, flags); const int32_t cacheLatencyUs = saturate_cast<int32_t>(cacheStopwatch.timeTakenUs()); const int32_t cacheLatencyUs = saturate_cast<int32_t>(cacheStopwatch.timeTakenUs()); if (cache_status == RESOLV_CACHE_FOUND) { if (cache_status == RESOLV_CACHE_FOUND) { HEADER* hp = (HEADER*)(void*)ans; HEADER* hp = (HEADER*)(void*)ans; Loading Loading @@ -442,8 +438,8 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int // DoT // DoT if (!(statp->netcontext_flags & NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS)) { if (!(statp->netcontext_flags & NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS)) { bool fallback = false; bool fallback = false; resplen = res_tls_send(statp, Slice(const_cast<uint8_t*>(buf), buflen), Slice(ans, anssiz), int resplen = res_tls_send(statp, Slice(const_cast<uint8_t*>(buf), buflen), rcode, &fallback); Slice(ans, anssiz), rcode, &fallback); if (resplen > 0) { if (resplen > 0) { LOG(DEBUG) << __func__ << ": got answer from DoT"; LOG(DEBUG) << __func__ << ": got answer from DoT"; res_pquery(ans, resplen); res_pquery(ans, resplen); Loading @@ -454,7 +450,7 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int } } if (!fallback) { if (!fallback) { _resolv_cache_query_failed(statp->netid, buf, buflen, flags); _resolv_cache_query_failed(statp->netid, buf, buflen, flags); return -terrno; return -ETIMEDOUT; } } } } Loading @@ -478,90 +474,62 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int res_set_usable_server(selectedServer, statp->nscount, usable_servers); res_set_usable_server(selectedServer, statp->nscount, usable_servers); } } /* // Send request, RETRY times, or until successful. * Send request, RETRY times, or until successful. */ int retryTimes = (flags & ANDROID_RESOLV_NO_RETRY) ? 1 : params.retry_count; int retryTimes = (flags & ANDROID_RESOLV_NO_RETRY) ? 1 : params.retry_count; int useTcp = buflen > PACKETSZ; int gotsomewhere = 0; int terrno = ETIMEDOUT; for (int attempt = 0; attempt < retryTimes; ++attempt) { for (int attempt = 0; attempt < retryTimes; ++attempt) { for (int ns = 0; ns < statp->nscount; ++ns) { for (int ns = 0; ns < statp->nscount; ns++) { if (!usable_servers[ns]) continue; if (!usable_servers[ns]) continue; int nsaplen; time_t now = 0; int delay = 0; *rcode = RCODE_INTERNAL_ERROR; *rcode = RCODE_INTERNAL_ERROR; // Get server addr const sockaddr* nsap = get_nsaddr(statp, ns); const sockaddr* nsap = get_nsaddr(statp, ns); nsaplen = sockaddrSize(nsap); const int nsaplen = sockaddrSize(nsap); same_ns: static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; char abuf[NI_MAXHOST]; char abuf[NI_MAXHOST]; DnsQueryEvent* dnsQueryEvent = addDnsQueryEvent(statp->event); dnsQueryEvent->set_cache_hit(static_cast<CacheStatus>(cache_status)); if (getnameinfo(nsap, (socklen_t)nsaplen, abuf, sizeof(abuf), NULL, 0, niflags) == 0) if (getnameinfo(nsap, (socklen_t)nsaplen, abuf, sizeof(abuf), NULL, 0, niflags) == 0) LOG(DEBUG) << __func__ << ": Querying server (# " << ns + 1 LOG(DEBUG) << __func__ << ": Querying server (# " << ns + 1 << ") address = " << abuf; << ") address = " << abuf; ::android::net::Protocol query_proto = useTcp ? PROTO_TCP : PROTO_UDP; time_t now = 0; int delay = 0; bool fallbackTCP = false; const bool shouldRecordStats = (attempt == 0); int resplen; Stopwatch queryStopwatch; Stopwatch queryStopwatch; if (v_circuit) { if (useTcp) { /* Use VC; at most one attempt per server. */ // TCP; at most one attempt per server. bool shouldRecordStats = (attempt == 0); attempt = retryTimes; attempt = retryTimes; resplen = send_vc(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &now, n = send_vc(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &now, rcode, rcode, &delay); &delay); 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_retry_times(attempt); dnsQueryEvent->set_rcode(static_cast<NsRcode>(*rcode)); dnsQueryEvent->set_protocol(PROTO_TCP); dnsQueryEvent->set_type(getQueryType(buf, buflen)); /* * Only record stats the first time we try a query. This ensures that * queries that deterministically fail (e.g., a name that always returns * 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); } LOG(INFO) << __func__ << ": used send_vc " << n; if (n < 0) { _resolv_cache_query_failed(statp->netid, buf, buflen, flags); res_nclose(statp); return -terrno; }; if (n == 0) goto next_ns; resplen = n; } else { } else { /* Use datagrams. */ // UDP LOG(INFO) << __func__ << ": using send_dg"; resplen = send_dg(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &useTcp, n = send_dg(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &v_circuit, &gotsomewhere, &now, rcode, &delay); &gotsomewhere, &now, rcode, &delay); fallbackTCP = useTcp ? true : false; } LOG(INFO) << __func__ << ": used send_" << ((useTcp) ? "vc " : "dg ") << resplen; dnsQueryEvent->set_latency_micros( DnsQueryEvent* dnsQueryEvent = addDnsQueryEvent(statp->event); saturate_cast<int32_t>(queryStopwatch.timeTakenUs())); 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_dns_server_index(ns); dnsQueryEvent->set_ip_version(ipFamilyToIPVersion(nsap->sa_family)); dnsQueryEvent->set_ip_version(ipFamilyToIPVersion(nsap->sa_family)); dnsQueryEvent->set_retry_times(attempt); dnsQueryEvent->set_retry_times(attempt); dnsQueryEvent->set_rcode(static_cast<NsRcode>(*rcode)); dnsQueryEvent->set_rcode(static_cast<NsRcode>(*rcode)); dnsQueryEvent->set_protocol(PROTO_UDP); dnsQueryEvent->set_protocol(query_proto); dnsQueryEvent->set_type(getQueryType(buf, buflen)); dnsQueryEvent->set_type(getQueryType(buf, buflen)); /* Only record stats the first time we try a query. See above. */ // Only record stats the first time we try a query. This ensures that if (attempt == 0) { // queries that deterministically fail (e.g., a name that always returns // SERVFAIL or times out) do not unduly affect the stats. if (shouldRecordStats) { res_sample sample; res_sample sample; _res_stats_set_sample(&sample, now, *rcode, delay); _res_stats_set_sample(&sample, now, *rcode, delay); resolv_cache_add_resolver_stats_sample(statp->netid, revision_id, nsap, sample, resolv_cache_add_resolver_stats_sample(statp->netid, revision_id, nsap, sample, Loading @@ -569,17 +537,16 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int resolv_stats_add(statp->netid, IPSockAddr::toIPSockAddr(*nsap), dnsQueryEvent); resolv_stats_add(statp->netid, IPSockAddr::toIPSockAddr(*nsap), dnsQueryEvent); } } LOG(INFO) << __func__ << ": used send_dg " << n; if (resplen == 0) continue; if (fallbackTCP) { if (n < 0) { ns--; continue; } if (resplen < 0) { _resolv_cache_query_failed(statp->netid, buf, buflen, flags); _resolv_cache_query_failed(statp->netid, buf, buflen, flags); res_nclose(statp); res_nclose(statp); return -terrno; return -terrno; }; }; if (n == 0) goto next_ns; if (v_circuit) goto same_ns; resplen = n; } LOG(DEBUG) << __func__ << ": got answer:"; LOG(DEBUG) << __func__ << ": got answer:"; res_pquery(ans, (resplen > anssiz) ? anssiz : resplen); res_pquery(ans, (resplen > anssiz) ? anssiz : resplen); Loading @@ -589,23 +556,15 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int } } res_nclose(statp); res_nclose(statp); return (resplen); return (resplen); next_ns:; } // for each ns } // for each ns } // for each retry } // for each retry res_nclose(statp); res_nclose(statp); if (!v_circuit) { terrno = useTcp ? terrno : gotsomewhere ? ETIMEDOUT : ECONNREFUSED; if (!gotsomewhere) { // TODO: Remove errno once callers stop using it errno = ECONNREFUSED; /* no nameservers found */ terrno = ECONNREFUSED; } else { // TODO: Remove errno once callers stop using it // TODO: Remove errno once callers stop using it errno = ETIMEDOUT; /* no answer obtained */ errno = useTcp ? terrno terrno = ETIMEDOUT; : gotsomewhere ? ETIMEDOUT /* no answer obtained */ } : ECONNREFUSED /* no nameservers found */; } else { errno = terrno; } _resolv_cache_query_failed(statp->netid, buf, buflen, flags); _resolv_cache_query_failed(statp->netid, buf, buflen, flags); return -terrno; return -terrno; } } Loading Loading
res_send.cpp +67 −108 Original line number Original line Diff line number Diff line Loading @@ -397,24 +397,20 @@ static DnsQueryEvent* addDnsQueryEvent(NetworkDnsEventReported* event) { int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int anssiz, int* rcode, int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int anssiz, int* rcode, uint32_t flags) { uint32_t flags) { int gotsomewhere, terrno, v_circuit, resplen, n; LOG(DEBUG) << __func__; ResolvCacheStatus cache_status = RESOLV_CACHE_UNSUPPORTED; // Should not happen if (anssiz < HFIXEDSZ) { if (anssiz < HFIXEDSZ) { // TODO: Remove errno once callers stop using it // TODO: Remove errno once callers stop using it errno = EINVAL; errno = EINVAL; return -EINVAL; return -EINVAL; } } LOG(DEBUG) << __func__; res_pquery(buf, buflen); res_pquery(buf, buflen); v_circuit = buflen > PACKETSZ; gotsomewhere = 0; terrno = ETIMEDOUT; int anslen = 0; int anslen = 0; Stopwatch cacheStopwatch; Stopwatch cacheStopwatch; cache_status = resolv_cache_lookup(statp->netid, buf, buflen, ans, anssiz, &anslen, flags); ResolvCacheStatus cache_status = resolv_cache_lookup(statp->netid, buf, buflen, ans, anssiz, &anslen, flags); const int32_t cacheLatencyUs = saturate_cast<int32_t>(cacheStopwatch.timeTakenUs()); const int32_t cacheLatencyUs = saturate_cast<int32_t>(cacheStopwatch.timeTakenUs()); if (cache_status == RESOLV_CACHE_FOUND) { if (cache_status == RESOLV_CACHE_FOUND) { HEADER* hp = (HEADER*)(void*)ans; HEADER* hp = (HEADER*)(void*)ans; Loading Loading @@ -442,8 +438,8 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int // DoT // DoT if (!(statp->netcontext_flags & NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS)) { if (!(statp->netcontext_flags & NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS)) { bool fallback = false; bool fallback = false; resplen = res_tls_send(statp, Slice(const_cast<uint8_t*>(buf), buflen), Slice(ans, anssiz), int resplen = res_tls_send(statp, Slice(const_cast<uint8_t*>(buf), buflen), rcode, &fallback); Slice(ans, anssiz), rcode, &fallback); if (resplen > 0) { if (resplen > 0) { LOG(DEBUG) << __func__ << ": got answer from DoT"; LOG(DEBUG) << __func__ << ": got answer from DoT"; res_pquery(ans, resplen); res_pquery(ans, resplen); Loading @@ -454,7 +450,7 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int } } if (!fallback) { if (!fallback) { _resolv_cache_query_failed(statp->netid, buf, buflen, flags); _resolv_cache_query_failed(statp->netid, buf, buflen, flags); return -terrno; return -ETIMEDOUT; } } } } Loading @@ -478,90 +474,62 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int res_set_usable_server(selectedServer, statp->nscount, usable_servers); res_set_usable_server(selectedServer, statp->nscount, usable_servers); } } /* // Send request, RETRY times, or until successful. * Send request, RETRY times, or until successful. */ int retryTimes = (flags & ANDROID_RESOLV_NO_RETRY) ? 1 : params.retry_count; int retryTimes = (flags & ANDROID_RESOLV_NO_RETRY) ? 1 : params.retry_count; int useTcp = buflen > PACKETSZ; int gotsomewhere = 0; int terrno = ETIMEDOUT; for (int attempt = 0; attempt < retryTimes; ++attempt) { for (int attempt = 0; attempt < retryTimes; ++attempt) { for (int ns = 0; ns < statp->nscount; ++ns) { for (int ns = 0; ns < statp->nscount; ns++) { if (!usable_servers[ns]) continue; if (!usable_servers[ns]) continue; int nsaplen; time_t now = 0; int delay = 0; *rcode = RCODE_INTERNAL_ERROR; *rcode = RCODE_INTERNAL_ERROR; // Get server addr const sockaddr* nsap = get_nsaddr(statp, ns); const sockaddr* nsap = get_nsaddr(statp, ns); nsaplen = sockaddrSize(nsap); const int nsaplen = sockaddrSize(nsap); same_ns: static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; char abuf[NI_MAXHOST]; char abuf[NI_MAXHOST]; DnsQueryEvent* dnsQueryEvent = addDnsQueryEvent(statp->event); dnsQueryEvent->set_cache_hit(static_cast<CacheStatus>(cache_status)); if (getnameinfo(nsap, (socklen_t)nsaplen, abuf, sizeof(abuf), NULL, 0, niflags) == 0) if (getnameinfo(nsap, (socklen_t)nsaplen, abuf, sizeof(abuf), NULL, 0, niflags) == 0) LOG(DEBUG) << __func__ << ": Querying server (# " << ns + 1 LOG(DEBUG) << __func__ << ": Querying server (# " << ns + 1 << ") address = " << abuf; << ") address = " << abuf; ::android::net::Protocol query_proto = useTcp ? PROTO_TCP : PROTO_UDP; time_t now = 0; int delay = 0; bool fallbackTCP = false; const bool shouldRecordStats = (attempt == 0); int resplen; Stopwatch queryStopwatch; Stopwatch queryStopwatch; if (v_circuit) { if (useTcp) { /* Use VC; at most one attempt per server. */ // TCP; at most one attempt per server. bool shouldRecordStats = (attempt == 0); attempt = retryTimes; attempt = retryTimes; resplen = send_vc(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &now, n = send_vc(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &now, rcode, rcode, &delay); &delay); 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_retry_times(attempt); dnsQueryEvent->set_rcode(static_cast<NsRcode>(*rcode)); dnsQueryEvent->set_protocol(PROTO_TCP); dnsQueryEvent->set_type(getQueryType(buf, buflen)); /* * Only record stats the first time we try a query. This ensures that * queries that deterministically fail (e.g., a name that always returns * 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); } LOG(INFO) << __func__ << ": used send_vc " << n; if (n < 0) { _resolv_cache_query_failed(statp->netid, buf, buflen, flags); res_nclose(statp); return -terrno; }; if (n == 0) goto next_ns; resplen = n; } else { } else { /* Use datagrams. */ // UDP LOG(INFO) << __func__ << ": using send_dg"; resplen = send_dg(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &useTcp, n = send_dg(statp, ¶ms, buf, buflen, ans, anssiz, &terrno, ns, &v_circuit, &gotsomewhere, &now, rcode, &delay); &gotsomewhere, &now, rcode, &delay); fallbackTCP = useTcp ? true : false; } LOG(INFO) << __func__ << ": used send_" << ((useTcp) ? "vc " : "dg ") << resplen; dnsQueryEvent->set_latency_micros( DnsQueryEvent* dnsQueryEvent = addDnsQueryEvent(statp->event); saturate_cast<int32_t>(queryStopwatch.timeTakenUs())); 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_dns_server_index(ns); dnsQueryEvent->set_ip_version(ipFamilyToIPVersion(nsap->sa_family)); dnsQueryEvent->set_ip_version(ipFamilyToIPVersion(nsap->sa_family)); dnsQueryEvent->set_retry_times(attempt); dnsQueryEvent->set_retry_times(attempt); dnsQueryEvent->set_rcode(static_cast<NsRcode>(*rcode)); dnsQueryEvent->set_rcode(static_cast<NsRcode>(*rcode)); dnsQueryEvent->set_protocol(PROTO_UDP); dnsQueryEvent->set_protocol(query_proto); dnsQueryEvent->set_type(getQueryType(buf, buflen)); dnsQueryEvent->set_type(getQueryType(buf, buflen)); /* Only record stats the first time we try a query. See above. */ // Only record stats the first time we try a query. This ensures that if (attempt == 0) { // queries that deterministically fail (e.g., a name that always returns // SERVFAIL or times out) do not unduly affect the stats. if (shouldRecordStats) { res_sample sample; res_sample sample; _res_stats_set_sample(&sample, now, *rcode, delay); _res_stats_set_sample(&sample, now, *rcode, delay); resolv_cache_add_resolver_stats_sample(statp->netid, revision_id, nsap, sample, resolv_cache_add_resolver_stats_sample(statp->netid, revision_id, nsap, sample, Loading @@ -569,17 +537,16 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int resolv_stats_add(statp->netid, IPSockAddr::toIPSockAddr(*nsap), dnsQueryEvent); resolv_stats_add(statp->netid, IPSockAddr::toIPSockAddr(*nsap), dnsQueryEvent); } } LOG(INFO) << __func__ << ": used send_dg " << n; if (resplen == 0) continue; if (fallbackTCP) { if (n < 0) { ns--; continue; } if (resplen < 0) { _resolv_cache_query_failed(statp->netid, buf, buflen, flags); _resolv_cache_query_failed(statp->netid, buf, buflen, flags); res_nclose(statp); res_nclose(statp); return -terrno; return -terrno; }; }; if (n == 0) goto next_ns; if (v_circuit) goto same_ns; resplen = n; } LOG(DEBUG) << __func__ << ": got answer:"; LOG(DEBUG) << __func__ << ": got answer:"; res_pquery(ans, (resplen > anssiz) ? anssiz : resplen); res_pquery(ans, (resplen > anssiz) ? anssiz : resplen); Loading @@ -589,23 +556,15 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int } } res_nclose(statp); res_nclose(statp); return (resplen); return (resplen); next_ns:; } // for each ns } // for each ns } // for each retry } // for each retry res_nclose(statp); res_nclose(statp); if (!v_circuit) { terrno = useTcp ? terrno : gotsomewhere ? ETIMEDOUT : ECONNREFUSED; if (!gotsomewhere) { // TODO: Remove errno once callers stop using it errno = ECONNREFUSED; /* no nameservers found */ terrno = ECONNREFUSED; } else { // TODO: Remove errno once callers stop using it // TODO: Remove errno once callers stop using it errno = ETIMEDOUT; /* no answer obtained */ errno = useTcp ? terrno terrno = ETIMEDOUT; : gotsomewhere ? ETIMEDOUT /* no answer obtained */ } : ECONNREFUSED /* no nameservers found */; } else { errno = terrno; } _resolv_cache_query_failed(statp->netid, buf, buflen, flags); _resolv_cache_query_failed(statp->netid, buf, buflen, flags); return -terrno; return -terrno; } } Loading