Merge "Fix fortify_fatal issue during DNSServiceProcessResult()"
diff --git a/Android.bp b/Android.bp
index 64831b8..32e719b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -11,9 +11,9 @@
// Override -Wno-error=implicit-fallthrough from soong
"-Werror=implicit-fallthrough",
"-Wnullable-to-nonnull-conversion",
+ "-Wsign-compare",
"-Wthread-safety",
"-Wunused-parameter",
- "-Wsign-compare",
],
tidy: true,
tidy_checks: [
diff --git a/client/FwmarkClient.cpp b/client/FwmarkClient.cpp
index 9435528..ed1459c 100644
--- a/client/FwmarkClient.cpp
+++ b/client/FwmarkClient.cpp
@@ -25,7 +25,7 @@
#include <sys/un.h>
#include <unistd.h>
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+#include <iterator>
namespace {
@@ -94,7 +94,7 @@
msghdr message;
memset(&message, 0, sizeof(message));
message.msg_iov = iov;
- message.msg_iovlen = ARRAY_SIZE(iov);
+ message.msg_iovlen = std::size(iov);
union {
cmsghdr cmh;
diff --git a/client/NetdClient.cpp b/client/NetdClient.cpp
index 68aa3c3..5586347 100644
--- a/client/NetdClient.cpp
+++ b/client/NetdClient.cpp
@@ -385,15 +385,16 @@
return FwmarkClient().send(&command, -1, nullptr);
}
-extern "C" int resNetworkQuery(unsigned netId, const char* dname, int ns_class, int ns_type) {
+extern "C" int resNetworkQuery(unsigned netId, const char* dname, int ns_class, int ns_type,
+ uint32_t flags) {
std::vector<uint8_t> buf(MAX_CMD_SIZE, 0);
int len = res_mkquery(ns_o_query, dname, ns_class, ns_type, nullptr, 0, nullptr, buf.data(),
MAX_CMD_SIZE);
- return resNetworkSend(netId, buf.data(), len);
+ return resNetworkSend(netId, buf.data(), len, flags);
}
-extern "C" int resNetworkSend(unsigned netId, const uint8_t* msg, size_t msglen) {
+extern "C" int resNetworkSend(unsigned netId, const uint8_t* msg, size_t msglen, uint32_t) {
// Encode
// Base 64 encodes every 3 bytes into 4 characters, but then adds padding to the next
// multiple of 4 and a \0
diff --git a/include/NetdClient.h b/include/NetdClient.h
index c361802..7d7a0e8 100644
--- a/include/NetdClient.h
+++ b/include/NetdClient.h
@@ -49,11 +49,11 @@
int deleteTagData(uint32_t tag, uid_t uid);
-int resNetworkQuery(unsigned netId, const char* dname, int classType, int type);
+int resNetworkQuery(unsigned netId, const char* dname, int classType, int type, uint32_t flags);
int resNetworkResult(int query_fd, int* rcode, uint8_t* answer, size_t anslen);
-int resNetworkSend(unsigned netId, const uint8_t* msg, size_t msglen);
+int resNetworkSend(unsigned netId, const uint8_t* msg, size_t msglen, uint32_t flags);
void resNetworkCancel(int nsend_fd);
__END_DECLS
diff --git a/libnetdbpf/include/netdbpf/bpf_shared.h b/libnetdbpf/include/netdbpf/bpf_shared.h
index bffb1a1..f824e08 100644
--- a/libnetdbpf/include/netdbpf/bpf_shared.h
+++ b/libnetdbpf/include/netdbpf/bpf_shared.h
@@ -55,38 +55,23 @@
#define BPF_PATH "/sys/fs/bpf"
-#define BPF_EGRESS_PROG_PATH BPF_PATH "/egress_prog"
-#define BPF_INGRESS_PROG_PATH BPF_PATH "/ingress_prog"
-#define XT_BPF_INGRESS_PROG_PATH BPF_PATH "/xt_bpf_ingress_prog"
-#define XT_BPF_EGRESS_PROG_PATH BPF_PATH "/xt_bpf_egress_prog"
-#define XT_BPF_WHITELIST_PROG_PATH BPF_PATH "/xt_bpf_whitelist_prog"
-#define XT_BPF_BLACKLIST_PROG_PATH BPF_PATH "/xt_bpf_blacklist_prog"
+#define BPF_EGRESS_PROG_PATH BPF_PATH "/prog_netd_cgroupskb_egress_stats"
+#define BPF_INGRESS_PROG_PATH BPF_PATH "/prog_netd_cgroupskb_ingress_stats"
+#define XT_BPF_INGRESS_PROG_PATH BPF_PATH "/prog_netd_skfilter_ingress_xtbpf"
+#define XT_BPF_EGRESS_PROG_PATH BPF_PATH "/prog_netd_skfilter_egress_xtbpf"
+#define XT_BPF_WHITELIST_PROG_PATH BPF_PATH "/prog_netd_skfilter_whitelist_xtbpf"
+#define XT_BPF_BLACKLIST_PROG_PATH BPF_PATH "/prog_netd_skfilter_blacklist_xtbpf"
-#define COOKIE_TAG_MAP_PATH BPF_PATH "/traffic_cookie_tag_map"
-#define UID_COUNTERSET_MAP_PATH BPF_PATH "/traffic_uid_counterset_map"
-#define APP_UID_STATS_MAP_PATH BPF_PATH "/traffic_app_uid_stats_map"
-#define UID_STATS_MAP_PATH BPF_PATH "/traffic_uid_stats_map"
-#define TAG_STATS_MAP_PATH BPF_PATH "/traffic_tag_stats_map"
-#define IFACE_INDEX_NAME_MAP_PATH BPF_PATH "/traffic_iface_index_name_map"
-#define IFACE_STATS_MAP_PATH BPF_PATH "/traffic_iface_stats_map"
-#define CONFIGURATION_MAP_PATH BPF_PATH "/traffic_configuration_map"
-#define UID_OWNER_MAP_PATH BPF_PATH "/traffic_uid_owner_map"
-
-#define BPF_CGROUP_INGRESS_PROG_NAME "cgroup_ingress_prog"
-#define BPF_CGROUP_EGRESS_PROG_NAME "cgroup_egress_prog"
-#define XT_BPF_INGRESS_PROG_NAME "xt_ingress_prog"
-#define XT_BPF_EGRESS_PROG_NAME "xt_egress_prog"
-#define XT_BPF_WHITELIST_PROG_NAME "xt_whitelist_prog"
-#define XT_BPF_BLACKLIST_PROG_NAME "xt_blacklist_prog"
-
-#define COOKIE_TAG_MAP 0xbfceaaffffffffff
-#define UID_COUNTERSET_MAP 0xbfdceeafffffffff
-#define APP_UID_STATS_MAP 0xbfa1daafffffffff
-#define UID_STATS_MAP 0xbfdaafffffffffff
-#define TAG_STATS_MAP 0xbfaaafffffffffff
-#define IFACE_STATS_MAP 0xbf1faceaafffffff
-#define CONFIGURATION_MAP 0Xbfc0fa0affffffff
-#define UID_OWNER_MAP 0xbfbad1d1daffffff
+#define COOKIE_TAG_MAP_PATH BPF_PATH "/map_netd_cookie_tag_map"
+#define UID_COUNTERSET_MAP_PATH BPF_PATH "/map_netd_uid_counterset_map"
+#define APP_UID_STATS_MAP_PATH BPF_PATH "/map_netd_app_uid_stats_map"
+#define UID_STATS_MAP_PATH BPF_PATH "/map_netd_uid_stats_map"
+#define TAG_STATS_MAP_PATH BPF_PATH "/map_netd_tag_stats_map"
+#define IFACE_INDEX_NAME_MAP_PATH BPF_PATH "/map_netd_iface_index_name_map"
+#define IFACE_STATS_MAP_PATH BPF_PATH "/map_netd_iface_stats_map"
+#define CONFIGURATION_MAP_PATH BPF_PATH "/map_netd_configuration_map"
+#define UID_OWNER_MAP_PATH BPF_PATH "/map_netd_uid_owner_map"
+#define UID_PERMISSION_MAP_PATH BPF_PATH "/map_netd_uid_permission_map"
enum UidOwnerMatchType {
NO_MATCH,
diff --git a/libnetdutils/InternetAddressesTest.cpp b/libnetdutils/InternetAddressesTest.cpp
index 59d8210..2129ca7 100644
--- a/libnetdutils/InternetAddressesTest.cpp
+++ b/libnetdutils/InternetAddressesTest.cpp
@@ -383,24 +383,22 @@
{"2001:db8:cafe:d00d::", 46, "2001:db8:cafc::"},
};
- int totalTests = 0;
- for (unsigned int i = 0; i < arraysize(testExpectations); i++, totalTests++) {
+ for (const auto& expectation : testExpectations) {
IPAddress ip;
- EXPECT_TRUE(IPAddress::forString(testExpectations[i].ip, &ip))
- << "Failed to parse IP address " << testExpectations[i].ip;
+ EXPECT_TRUE(IPAddress::forString(expectation.ip, &ip))
+ << "Failed to parse IP address " << expectation.ip;
IPAddress ipTruncated;
- EXPECT_TRUE(IPAddress::forString(testExpectations[i].ipTruncated, &ipTruncated))
- << "Failed to parse IP address " << testExpectations[i].ipTruncated;
+ EXPECT_TRUE(IPAddress::forString(expectation.ipTruncated, &ipTruncated))
+ << "Failed to parse IP address " << expectation.ipTruncated;
- IPPrefix prefix(ip, testExpectations[i].cidrLen);
+ IPPrefix prefix(ip, expectation.cidrLen);
- EXPECT_EQ(testExpectations[i].cidrLen, prefix.length())
- << "Unexpected cidrLen " << testExpectations[i].cidrLen;
+ EXPECT_EQ(expectation.cidrLen, prefix.length())
+ << "Unexpected cidrLen " << expectation.cidrLen;
EXPECT_EQ(ipTruncated, prefix.ip())
<< "Unexpected IP truncation: " << prefix.ip() << ", expected: " << ipTruncated;
}
- EXPECT_EQ(static_cast<int>(arraysize(testExpectations)), totalTests);
}
TEST(IPPrefixTest, GamutOfOperators) {
diff --git a/resolv/PrivateDnsConfiguration.cpp b/resolv/PrivateDnsConfiguration.cpp
index 616662e..b262a2f 100644
--- a/resolv/PrivateDnsConfiguration.cpp
+++ b/resolv/PrivateDnsConfiguration.cpp
@@ -26,15 +26,15 @@
#include "netdutils/BackoffSequence.h"
int resolv_set_private_dns_for_net(unsigned netid, uint32_t mark, const char** servers,
- const unsigned numServers, const char* tlsName,
- const uint8_t** fingerprints, const unsigned numFingerprint) {
+ const int numServers, const char* tlsName,
+ const uint8_t** fingerprints, const int numFingerprint) {
std::vector<std::string> tlsServers;
- for (unsigned i = 0; i < numServers; i++) {
+ for (int i = 0; i < numServers; i++) {
tlsServers.push_back(std::string(servers[i]));
}
std::set<std::vector<uint8_t>> tlsFingerprints;
- for (unsigned i = 0; i < numFingerprint; i++) {
+ for (int i = 0; i < numFingerprint; i++) {
// Each fingerprint stored are 32(SHA256_SIZE) bytes long.
tlsFingerprints.emplace(std::vector<uint8_t>(fingerprints[i], fingerprints[i] + 32));
}
@@ -194,7 +194,7 @@
const auto netPair = mPrivateDnsTransports.find(netId);
if (netPair != mPrivateDnsTransports.end()) {
- status->numServers = netPair->second.size();
+ status->numServers = static_cast<int>(netPair->second.size());
int count = 0;
for (const auto& serverPair : netPair->second) {
status->serverStatus[count].ss = serverPair.first.ss;
diff --git a/resolv/getaddrinfo.cpp b/resolv/getaddrinfo.cpp
index 45c3792..860eb98 100644
--- a/resolv/getaddrinfo.cpp
+++ b/resolv/getaddrinfo.cpp
@@ -134,7 +134,8 @@
static const struct afd* find_afd(int);
static int ip6_str2scopeid(const char*, struct sockaddr_in6*, u_int32_t*);
-static struct addrinfo* getanswer(const querybuf*, int, const char*, int, const struct addrinfo*);
+static struct addrinfo* getanswer(const querybuf*, int, const char*, int, const struct addrinfo*,
+ int* herrno);
static int dns_getaddrinfo(const char* name, const addrinfo* pai,
const android_net_context* netcontext, addrinfo** rv);
static void _sethtent(FILE**);
@@ -143,10 +144,10 @@
static bool files_getaddrinfo(const char* name, const addrinfo* pai, addrinfo** res);
static int _find_src_addr(const struct sockaddr*, struct sockaddr*, unsigned, uid_t);
-static int res_queryN(const char* name, res_target* target, res_state res, int* ai_error);
-static int res_searchN(const char* name, res_target* target, res_state res, int* ai_error);
+static int res_queryN(const char* name, res_target* target, res_state res, int* herrno);
+static int res_searchN(const char* name, res_target* target, res_state res, int* herrno);
static int res_querydomainN(const char* name, const char* domain, res_target* target, res_state res,
- int* ai_error);
+ int* herrno);
const char* const ai_errlist[] = {
"Success",
@@ -820,13 +821,13 @@
#define BOUNDS_CHECK(ptr, count) \
do { \
if (eom - (ptr) < (count)) { \
- h_errno = NO_RECOVERY; \
+ *herrno = NO_RECOVERY; \
return NULL; \
} \
} while (0)
static struct addrinfo* getanswer(const querybuf* answer, int anslen, const char* qname, int qtype,
- const struct addrinfo* pai) {
+ const struct addrinfo* pai, int* herrno) {
struct addrinfo sentinel = {};
struct addrinfo *cur;
struct addrinfo ai;
@@ -871,12 +872,12 @@
cp = answer->buf;
BOUNDED_INCR(HFIXEDSZ);
if (qdcount != 1) {
- h_errno = NO_RECOVERY;
+ *herrno = NO_RECOVERY;
return (NULL);
}
n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
if ((n < 0) || !(*name_ok)(bp)) {
- h_errno = NO_RECOVERY;
+ *herrno = NO_RECOVERY;
return (NULL);
}
BOUNDED_INCR(n + QFIXEDSZ);
@@ -887,7 +888,7 @@
*/
n = strlen(bp) + 1; /* for the \0 */
if (n >= MAXHOSTNAMELEN) {
- h_errno = NO_RECOVERY;
+ *herrno = NO_RECOVERY;
return (NULL);
}
canonname = bp;
@@ -1003,11 +1004,11 @@
(void) get_canonname(pai, sentinel.ai_next, qname);
else
(void) get_canonname(pai, sentinel.ai_next, canonname);
- h_errno = NETDB_SUCCESS;
+ *herrno = NETDB_SUCCESS;
return sentinel.ai_next;
}
- h_errno = NO_RECOVERY;
+ *herrno = NO_RECOVERY;
return NULL;
}
@@ -1391,13 +1392,11 @@
querybuf* buf = (querybuf*) malloc(sizeof(*buf));
if (buf == NULL) {
- h_errno = NETDB_INTERNAL;
return EAI_MEMORY;
}
querybuf* buf2 = (querybuf*) malloc(sizeof(*buf2));
if (buf2 == NULL) {
free(buf);
- h_errno = NETDB_INTERNAL;
return EAI_MEMORY;
}
@@ -1466,26 +1465,26 @@
*/
res_setnetcontext(res, netcontext);
- // Pass ai_error to catch more detailed errors rather than EAI_NODATA.
- int ai_error = EAI_NODATA;
- if (res_searchN(name, &q, res, &ai_error) < 0) {
+ int herrno = NETDB_INTERNAL;
+ if (res_searchN(name, &q, res, &herrno) < 0) {
free(buf);
free(buf2);
- return ai_error; // TODO: Decode error from h_errno like we do below
+ // Pass herrno to catch more detailed errors rather than EAI_NODATA.
+ return herrnoToAiErrno(herrno);
}
- ai = getanswer(buf, q.n, q.name, q.qtype, pai);
+ ai = getanswer(buf, q.n, q.name, q.qtype, pai, &herrno);
if (ai) {
cur->ai_next = ai;
while (cur && cur->ai_next) cur = cur->ai_next;
}
if (q.next) {
- ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai);
+ ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai, &herrno);
if (ai) cur->ai_next = ai;
}
free(buf);
free(buf2);
if (sentinel.ai_next == NULL) {
- return herrnoToAiError(h_errno);
+ return herrnoToAiErrno(herrno);
}
_rfc6724_sort(&sentinel, netcontext->app_mark, netcontext->uid);
@@ -1586,11 +1585,11 @@
* Perform preliminary check of answer, returning success only
* if no error is indicated and the answer count is nonzero.
* Return the size of the response on success, -1 on error.
- * Error number is left in h_errno.
+ * Error number is left in *herrno.
*
* Caller must parse answer and determine whether it answers the question.
*/
-static int res_queryN(const char* name, res_target* target, res_state res, int* ai_error) {
+static int res_queryN(const char* name, res_target* target, res_state res, int* herrno) {
u_char buf[MAXPACKET];
HEADER* hp;
int n;
@@ -1632,15 +1631,15 @@
#ifdef DEBUG
if (res->options & RES_DEBUG) printf(";; res_nquery: mkquery failed\n");
#endif
- h_errno = NO_RECOVERY;
+ *herrno = NO_RECOVERY;
return n;
}
n = res_nsend(res, buf, n, answer, anslen, &rcode);
- *ai_error = rcodeToAiError(rcode);
-
if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
- rcode = hp->rcode; /* record most recent error */
+ // Record rcode from DNS response header only if no timeout.
+ // Keep rcode timeout for reporting later if any.
+ if (rcode != RCODE_TIMEOUT) rcode = hp->rcode; /* record most recent error */
/* if the query choked with EDNS0, retry without EDNS0 */
if ((res->options & (RES_USE_EDNS0 | RES_USE_DNSSEC)) != 0 &&
((oflags ^ res->_flags) & RES_F_EDNS0ERR) != 0) {
@@ -1664,20 +1663,26 @@
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:
- h_errno = HOST_NOT_FOUND;
+ *herrno = HOST_NOT_FOUND;
break;
case SERVFAIL:
- h_errno = TRY_AGAIN;
+ *herrno = TRY_AGAIN;
break;
case NOERROR:
- h_errno = NO_DATA;
+ *herrno = NO_DATA;
break;
case FORMERR:
case NOTIMP:
case REFUSED:
default:
- h_errno = NO_RECOVERY;
+ *herrno = NO_RECOVERY;
break;
}
return -1;
@@ -1689,9 +1694,9 @@
* Formulate a normal query, send, and retrieve answer in supplied buffer.
* Return the size of the response on success, -1 on error.
* If enabled, implement search rules until answer or unrecoverable failure
- * is detected. Error code, if any, is left in h_errno.
+ * is detected. Error code, if any, is left in *herrno.
*/
-static int res_searchN(const char* name, res_target* target, res_state res, int* ai_error) {
+static int res_searchN(const char* name, res_target* target, res_state res, int* herrno) {
const char *cp, *const *domain;
HEADER* hp;
u_int dots;
@@ -1704,7 +1709,7 @@
hp = (HEADER*) (void*) target->answer; /*XXX*/
errno = 0;
- h_errno = HOST_NOT_FOUND; /* default, if we never query */
+ *herrno = HOST_NOT_FOUND; /* default, if we never query */
dots = 0;
for (cp = name; *cp; cp++) dots += (*cp == '.');
trailing_dot = 0;
@@ -1716,9 +1721,9 @@
*/
saved_herrno = -1;
if (dots >= res->ndots) {
- ret = res_querydomainN(name, NULL, target, res, ai_error);
+ ret = res_querydomainN(name, NULL, target, res, herrno);
if (ret > 0) return (ret);
- saved_herrno = h_errno;
+ saved_herrno = *herrno;
tried_as_is++;
}
@@ -1739,7 +1744,7 @@
_resolv_populate_res_for_net(res);
for (domain = (const char* const*) res->dnsrch; *domain && !done; domain++) {
- ret = res_querydomainN(name, *domain, target, res, ai_error);
+ ret = res_querydomainN(name, *domain, target, res, herrno);
if (ret > 0) return ret;
/*
@@ -1756,11 +1761,11 @@
* fully-qualified.
*/
if (errno == ECONNREFUSED) {
- h_errno = TRY_AGAIN;
+ *herrno = TRY_AGAIN;
return -1;
}
- switch (h_errno) {
+ switch (*herrno) {
case NO_DATA:
got_nodata++;
[[fallthrough]];
@@ -1792,7 +1797,7 @@
* name or whether it ends with a dot.
*/
if (!tried_as_is) {
- ret = res_querydomainN(name, NULL, target, res, ai_error);
+ ret = res_querydomainN(name, NULL, target, res, herrno);
if (ret > 0) return ret;
}
@@ -1805,11 +1810,11 @@
* the last DNSRCH we did.
*/
if (saved_herrno != -1)
- h_errno = saved_herrno;
+ *herrno = saved_herrno;
else if (got_nodata)
- h_errno = NO_DATA;
+ *herrno = NO_DATA;
else if (got_servfail)
- h_errno = TRY_AGAIN;
+ *herrno = TRY_AGAIN;
return -1;
}
@@ -1818,7 +1823,7 @@
* 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* ai_error) {
+ int* herrno) {
char nbuf[MAXDNAME];
const char* longname = nbuf;
size_t n, d;
@@ -1837,7 +1842,7 @@
*/
n = strlen(name);
if (n + 1 > sizeof(nbuf)) {
- h_errno = NO_RECOVERY;
+ *herrno = NO_RECOVERY;
return -1;
}
if (n > 0 && name[--n] == '.') {
@@ -1849,10 +1854,10 @@
n = strlen(name);
d = strlen(domain);
if (n + 1 + d + 1 > sizeof(nbuf)) {
- h_errno = NO_RECOVERY;
+ *herrno = NO_RECOVERY;
return -1;
}
snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
}
- return res_queryN(longname, target, res, ai_error);
+ return res_queryN(longname, target, res, herrno);
}
diff --git a/resolv/gethnamaddr.cpp b/resolv/gethnamaddr.cpp
index 53abe12..b8609eb 100644
--- a/resolv/gethnamaddr.cpp
+++ b/resolv/gethnamaddr.cpp
@@ -135,20 +135,20 @@
static void pad_v4v6_hostent(struct hostent* hp, char** bpp, char* ep);
static void addrsort(char**, int, res_state);
-static bool _dns_gethtbyaddr(const unsigned char* uaddr, int len, int af,
- const android_net_context* netcontext, getnamaddr* info);
+static int _dns_gethtbyaddr(const unsigned char* uaddr, int len, int af,
+ const android_net_context* netcontext, getnamaddr* info);
static int _dns_gethtbyname(const char* name, int af, getnamaddr* info);
static int gethostbyname_internal(const char* name, int af, res_state res, hostent* hp, char* hbuf,
- size_t hbuflen, int* errorp,
- const android_net_context* netcontext);
+ size_t hbuflen, const android_net_context* netcontext);
static int gethostbyname_internal_real(const char* name, int af, res_state res, hostent* hp,
- char* buf, size_t buflen, int* he);
-static struct hostent* android_gethostbyaddrfornetcontext_proxy_internal(
- const void*, socklen_t, int, struct hostent*, char*, size_t, int*,
- const struct android_net_context*);
-static struct hostent* android_gethostbyaddrfornetcontext_proxy(
- const void* addr, socklen_t len, int af, const struct android_net_context* netcontext);
+ char* buf, size_t buflen);
+static int android_gethostbyaddrfornetcontext_proxy_internal(const void*, socklen_t, int,
+ struct hostent*, char*, size_t,
+ const struct android_net_context*);
+static int android_gethostbyaddrfornetcontext_proxy(const void* addr, socklen_t len, int af,
+ const struct android_net_context* netcontext,
+ hostent** hp);
#ifdef DEBUG
static void debugprintf(const char* msg, res_state res, ...) {
@@ -470,7 +470,7 @@
}
static int gethostbyname_internal_real(const char* name, int af, res_state res, hostent* hp,
- char* buf, size_t buflen, int* he) {
+ char* buf, size_t buflen) {
getnamaddr info;
size_t size;
@@ -484,7 +484,6 @@
size = NS_IN6ADDRSZ;
break;
default:
- *he = NETDB_INTERNAL;
errno = EAFNOSUPPORT;
return EAI_FAMILY;
}
@@ -526,24 +525,19 @@
}
}
- *he = NETDB_INTERNAL;
info.hp = hp;
info.buf = buf;
info.buflen = buflen;
- info.he = he;
- if (!_hf_gethtbyname2(name, af, &info)) {
+ if (_hf_gethtbyname2(name, af, &info)) {
int error = _dns_gethtbyname(name, af, &info);
if (error != 0) {
return error;
}
}
- *he = NETDB_SUCCESS;
return 0;
nospc:
- *he = NETDB_INTERNAL;
errno = ENOSPC;
- // Bad arguments
- return EAI_FAIL;
+ return EAI_MEMORY;
fake:
HENT_ARRAY(hp->h_addr_list, 1, buf, buflen);
HENT_ARRAY(hp->h_aliases, 0, buf, buflen);
@@ -552,7 +546,6 @@
if (size > buflen) goto nospc;
if (inet_pton(af, name, buf) <= 0) {
- *he = HOST_NOT_FOUND;
return EAI_NODATA;
}
hp->h_addr_list[0] = buf;
@@ -561,21 +554,19 @@
buflen -= size;
HENT_SCOPY(hp->h_name, name, buf, buflen);
if (res->options & RES_USE_INET6) map_v4v6_hostent(hp, &buf, buf + buflen);
- *he = NETDB_SUCCESS;
return 0;
}
// very similar in proxy-ness to android_getaddrinfo_proxy
static int gethostbyname_internal(const char* name, int af, res_state res, hostent* hp, char* hbuf,
- size_t hbuflen, int* errorp,
- const android_net_context* netcontext) {
+ size_t hbuflen, const android_net_context* netcontext) {
res_setnetcontext(res, netcontext);
- return gethostbyname_internal_real(name, af, res, hp, hbuf, hbuflen, errorp);
+ return gethostbyname_internal_real(name, af, res, hp, hbuf, hbuflen);
}
-static struct hostent* android_gethostbyaddrfornetcontext_real(
- const void* addr, socklen_t len, int af, struct hostent* hp, char* buf, size_t buflen,
- int* he, const struct android_net_context* netcontext) {
+static int android_gethostbyaddrfornetcontext_real(const void* addr, socklen_t len, int af,
+ struct hostent* hp, char* buf, size_t buflen,
+ const struct android_net_context* netcontext) {
const u_char* uaddr = (const u_char*) addr;
socklen_t size;
struct getnamaddr info;
@@ -585,8 +576,7 @@
if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
(IN6_IS_ADDR_LINKLOCAL((const struct in6_addr*) addr) ||
IN6_IS_ADDR_SITELOCAL((const struct in6_addr*) addr))) {
- *he = HOST_NOT_FOUND;
- return NULL;
+ return EAI_NODATA;
}
if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
(IN6_IS_ADDR_V4MAPPED((const struct in6_addr*) addr) ||
@@ -606,33 +596,29 @@
break;
default:
errno = EAFNOSUPPORT;
- *he = NETDB_INTERNAL;
- return NULL;
+ return EAI_FAMILY;
}
if (size != len) {
errno = EINVAL;
- *he = NETDB_INTERNAL;
- return NULL;
+ // TODO: Consider to remap error code without relying on errno.
+ return EAI_SYSTEM;
}
info.hp = hp;
info.buf = buf;
info.buflen = buflen;
- info.he = he;
- *he = NETDB_INTERNAL;
- if (!_hf_gethtbyaddr(uaddr, len, af, &info)) {
- if (!_dns_gethtbyaddr(uaddr, len, af, netcontext, &info)) {
- return NULL;
+ if (_hf_gethtbyaddr(uaddr, len, af, &info)) {
+ int error = _dns_gethtbyaddr(uaddr, len, af, netcontext, &info);
+ if (error != 0) {
+ return error;
}
}
- *he = NETDB_SUCCESS;
- return hp;
+ return 0;
}
-static struct hostent* android_gethostbyaddrfornetcontext_proxy_internal(
+static int android_gethostbyaddrfornetcontext_proxy_internal(
const void* addr, socklen_t len, int af, struct hostent* hp, char* hbuf, size_t hbuflen,
- int* he, const struct android_net_context* netcontext) {
- return android_gethostbyaddrfornetcontext_real(addr, len, af, hp, hbuf, hbuflen, he,
- netcontext);
+ const struct android_net_context* netcontext) {
+ return android_gethostbyaddrfornetcontext_real(addr, len, af, hp, hbuf, hbuflen, netcontext);
}
struct hostent* netbsd_gethostent_r(FILE* hf, struct hostent* hent, char* buf, size_t buflen,
@@ -864,7 +850,6 @@
}
querybuf* buf = (querybuf*) malloc(sizeof(querybuf));
if (buf == NULL) {
- *info->he = NETDB_INTERNAL;
return EAI_MEMORY;
}
res = res_get_state();
@@ -873,30 +858,24 @@
return EAI_MEMORY;
}
- int ai_error = EAI_NODATA;
- n = res_nsearch(res, name, C_IN, type, buf->buf, (int) sizeof(buf->buf), &ai_error);
+ int herrno = NETDB_INTERNAL;
+ n = res_nsearch(res, name, C_IN, type, buf->buf, (int) sizeof(buf->buf), &herrno);
if (n < 0) {
free(buf);
debugprintf("res_nsearch failed (%d)\n", res, n);
-
- // If server responds empty answer with rcode NOERROR, adjust the error so netd will
- // get the nulltpr hp.
- // TODO: Adjust the error closed to res_nsend instead of here after h_errno is removed.
- if (ai_error == 0) {
- return herrnoToAiError(h_errno);
- }
- return ai_error;
+ // Pass herrno to catch more detailed errors rather than EAI_NODATA.
+ return herrnoToAiErrno(herrno);
}
- hp = getanswer(buf, n, name, type, res, info->hp, info->buf, info->buflen, info->he);
+ hp = getanswer(buf, n, name, type, res, info->hp, info->buf, info->buflen, &herrno);
free(buf);
if (hp == NULL) {
- return herrnoToAiError(h_errno);
+ return herrnoToAiErrno(herrno);
}
return 0;
}
-static bool _dns_gethtbyaddr(const unsigned char* uaddr, int len, int af,
- const android_net_context* netcontext, getnamaddr* info) {
+static int _dns_gethtbyaddr(const unsigned char* uaddr, int len, int af,
+ const android_net_context* netcontext, getnamaddr* info) {
char qbuf[MAXDNAME + 1], *qp, *ep;
int n;
struct hostent* hp;
@@ -921,41 +900,40 @@
if (advance > 0 && qp + advance < ep)
qp += advance;
else {
- *info->he = NETDB_INTERNAL;
- return false;
+ // TODO: Consider to remap error code without relying on errno.
+ return EAI_SYSTEM;
}
}
if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) {
- *info->he = NETDB_INTERNAL;
- return false;
+ // TODO: Consider to remap error code without relying on errno.
+ return EAI_SYSTEM;
}
break;
default:
- return false;
+ return EAI_FAMILY;
}
querybuf* buf = (querybuf*) malloc(sizeof(querybuf));
if (buf == NULL) {
- *info->he = NETDB_INTERNAL;
- return false;
+ return EAI_MEMORY;
}
res = res_get_state();
if (res == NULL) {
free(buf);
- return false;
+ return EAI_MEMORY;
}
res_setnetcontext(res, netcontext);
- int ai_error = 0;
- n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, (int) sizeof(buf->buf), &ai_error);
+ int herrno = NETDB_INTERNAL;
+ n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, (int) sizeof(buf->buf), &herrno);
if (n < 0) {
free(buf);
debugprintf("res_nquery failed (%d)\n", res, n);
- return false;
+ return herrnoToAiErrno(herrno);
}
- hp = getanswer(buf, n, qbuf, T_PTR, res, info->hp, info->buf, info->buflen, info->he);
+ hp = getanswer(buf, n, qbuf, T_PTR, res, info->hp, info->buf, info->buflen, &herrno);
free(buf);
if (hp == NULL) {
- return false;
+ return herrnoToAiErrno(herrno);
}
char* bf = (char*) (hp->h_addr_list + 2);
@@ -978,13 +956,11 @@
memcpy(bf + NS_INADDRSZ, NAT64_PAD, sizeof(NAT64_PAD));
}
- *info->he = NETDB_SUCCESS;
- return true;
+ return 0;
nospc:
errno = ENOSPC;
- *info->he = NETDB_INTERNAL;
- return false;
+ return EAI_MEMORY;
}
/*
@@ -998,45 +974,45 @@
if (res == NULL) return EAI_MEMORY;
res_static* rs = res_get_static(); // For thread-safety.
error = gethostbyname_internal(name, af, res, &rs->host, rs->hostbuf, sizeof(rs->hostbuf),
- &h_errno, netcontext);
+ netcontext);
if (error == 0) {
*hp = &rs->host;
}
return error;
}
-struct hostent* android_gethostbyaddrfornetcontext(const void* addr, socklen_t len, int af,
- const struct android_net_context* netcontext) {
- return android_gethostbyaddrfornetcontext_proxy(addr, len, af, netcontext);
+int android_gethostbyaddrfornetcontext(const void* addr, socklen_t len, int af,
+ const struct android_net_context* netcontext, hostent** hp) {
+ return android_gethostbyaddrfornetcontext_proxy(addr, len, af, netcontext, hp);
}
-static struct hostent* android_gethostbyaddrfornetcontext_proxy(
- const void* addr, socklen_t len, int af, const struct android_net_context* netcontext) {
+static int android_gethostbyaddrfornetcontext_proxy(const void* addr, socklen_t len, int af,
+ const struct android_net_context* netcontext,
+ hostent** hp) {
struct res_static* rs = res_get_static(); // For thread-safety.
- return android_gethostbyaddrfornetcontext_proxy_internal(
- addr, len, af, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &h_errno, netcontext);
+ int error = android_gethostbyaddrfornetcontext_proxy_internal(
+ addr, len, af, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), netcontext);
+ if (error == 0) *hp = &rs->host;
+ return error;
}
-int herrnoToAiError(int herror) {
- switch (herror) {
- case HOST_NOT_FOUND:
+int herrnoToAiErrno(int herrno) {
+ switch (herrno) {
+ // extended h_errno
+ case NETD_RESOLV_H_ERRNO_EXT_TIMEOUT:
+ return NETD_RESOLV_TIMEOUT;
+ // legacy h_errno
+ case NETDB_SUCCESS:
+ return 0;
+ case HOST_NOT_FOUND: // TODO: Perhaps convert HOST_NOT_FOUND to EAI_NONAME instead
+ case NO_DATA: // NO_ADDRESS
return EAI_NODATA;
case TRY_AGAIN:
return EAI_AGAIN;
+ case NETDB_INTERNAL:
+ return EAI_SYSTEM; // see errno for detail
+ case NO_RECOVERY:
default:
return EAI_FAIL;
}
-}
-
-int rcodeToAiError(int rcode) {
- // Catch the two cases (success, timeout). For other cases, just set it EAI_NODATA
- // as EAI_NODATA is returned in dns_getaddrinfo() when res_searchN() returns -1.
- switch (rcode) {
- case NOERROR:
- return 0;
- case RCODE_TIMEOUT:
- return NETD_RESOLV_TIMEOUT;
- default:
- return EAI_NODATA;
- }
-}
+}
\ No newline at end of file
diff --git a/resolv/hostent.h b/resolv/hostent.h
index 892ed88..4f6a33b 100644
--- a/resolv/hostent.h
+++ b/resolv/hostent.h
@@ -38,12 +38,11 @@
struct hostent* hp;
char* buf;
size_t buflen;
- int* he;
};
// /etc/hosts lookup
-bool _hf_gethtbyaddr(const unsigned char* uaddr, int len, int af, getnamaddr* info);
-hostent* _hf_gethtbyname2(const char* name, int af, getnamaddr* info);
+int _hf_gethtbyaddr(const unsigned char* uaddr, int len, int af, getnamaddr* info);
+int _hf_gethtbyname2(const char* name, int af, getnamaddr* info);
hostent* netbsd_gethostent_r(FILE*, struct hostent*, char*, size_t, int*);
// Reserved padding for remapping IPv4 address to NAT64 synthesis IPv6 address
diff --git a/resolv/include/netd_resolv/resolv.h b/resolv/include/netd_resolv/resolv.h
index f50744c..e30f31a 100644
--- a/resolv/include/netd_resolv/resolv.h
+++ b/resolv/include/netd_resolv/resolv.h
@@ -91,7 +91,7 @@
struct ExternalPrivateDnsStatus {
PrivateDnsMode mode;
- unsigned numServers;
+ int numServers;
struct PrivateDnsInfo {
sockaddr_storage ss;
const char* hostname;
@@ -102,8 +102,8 @@
typedef void (*private_dns_validated_callback)(unsigned netid, const char* server,
const char* hostname, bool success);
-LIBNETD_RESOLV_PUBLIC hostent* android_gethostbyaddrfornetcontext(const void*, socklen_t, int,
- const android_net_context*);
+LIBNETD_RESOLV_PUBLIC int android_gethostbyaddrfornetcontext(const void*, socklen_t, int,
+ const android_net_context*, hostent**);
LIBNETD_RESOLV_PUBLIC int android_gethostbynamefornetcontext(const char*, int,
const android_net_context*, hostent**);
LIBNETD_RESOLV_PUBLIC int android_getaddrinfofornetcontext(const char*, const char*,
@@ -119,15 +119,14 @@
// Set name servers for a network
LIBNETD_RESOLV_PUBLIC int resolv_set_nameservers_for_net(unsigned netid, const char** servers,
- unsigned numservers, const char* domains,
+ int numservers, const char* domains,
const __res_params* params);
LIBNETD_RESOLV_PUBLIC int resolv_set_private_dns_for_net(unsigned netid, uint32_t mark,
- const char** servers,
- const unsigned numServers,
+ const char** servers, int numServers,
const char* tlsName,
const uint8_t** fingerprints,
- const unsigned numFingerprints);
+ int numFingerprints);
LIBNETD_RESOLV_PUBLIC void resolv_delete_private_dns_for_net(unsigned netid);
diff --git a/resolv/include/netd_resolv/resolv_stub.h b/resolv/include/netd_resolv/resolv_stub.h
index a2462bd..fddabcf 100644
--- a/resolv/include/netd_resolv/resolv_stub.h
+++ b/resolv/include/netd_resolv/resolv_stub.h
@@ -37,8 +37,8 @@
int (*android_getaddrinfofornetcontext)(const char*, const char*, const addrinfo*,
const android_net_context*, addrinfo**);
- hostent* (*android_gethostbyaddrfornetcontext)(const void*, socklen_t, int,
- const android_net_context*);
+ int (*android_gethostbyaddrfornetcontext)(const void*, socklen_t, int,
+ const android_net_context*, hostent**);
int (*android_gethostbynamefornetcontext)(const char*, int, const android_net_context*,
hostent**);
diff --git a/resolv/libnetd_resolv_test.cpp b/resolv/libnetd_resolv_test.cpp
index 683dd21..2bd27fd 100644
--- a/resolv/libnetd_resolv_test.cpp
+++ b/resolv/libnetd_resolv_test.cpp
@@ -19,6 +19,7 @@
#include <gtest/gtest.h>
#include <android-base/stringprintf.h>
+#include <arpa/inet.h>
#include <netdb.h>
#include "dns_responder.h"
@@ -45,6 +46,15 @@
resolv_set_nameservers_for_net(TEST_NETID, nullptr, 0, "", nullptr);
}
+ static std::string ToString(const hostent* he) {
+ if (he == nullptr) return "<null>";
+ char buffer[INET6_ADDRSTRLEN];
+ if (!inet_ntop(he->h_addrtype, he->h_addr_list[0], buffer, sizeof(buffer))) {
+ return "<invalid>";
+ }
+ return buffer;
+ }
+
static std::string ToString(const addrinfo* ai) {
if (!ai) return "<null>";
for (const auto* aip = ai; aip != nullptr; aip = aip->ai_next) {
@@ -76,27 +86,27 @@
.max_samples = 8,
.base_timeout_msec = 100,
};
-};
-
-class GetAddrInfoForNetContextTest : public TestBase {};
-
-TEST_F(GetAddrInfoForNetContextTest, InvalidParameters) {
- struct addrinfo* result = nullptr;
- const android_net_context netcontext = {
- .app_netid = NETID_UNSET,
+ const android_net_context mNetcontext = {
+ .app_netid = TEST_NETID,
.app_mark = MARK_UNSET,
- .dns_netid = NETID_UNSET,
+ .dns_netid = TEST_NETID,
.dns_mark = MARK_UNSET,
.uid = NET_CONTEXT_INVALID_UID,
};
+};
+class GetAddrInfoForNetContextTest : public TestBase {};
+class GetHostByNameForNetContextTest : public TestBase {};
+
+TEST_F(GetAddrInfoForNetContextTest, InvalidParameters) {
// Both null "netcontext" and null "res" of android_getaddrinfofornetcontext() are not tested
// here because they are checked by assert() without returning any error number.
// Invalid hostname and servname.
// Both hostname and servname are null pointers. Expect error number EAI_NONAME.
+ struct addrinfo* result = nullptr;
int rv = android_getaddrinfofornetcontext(nullptr /*hostname*/, nullptr /*servname*/,
- nullptr /*hints*/, &netcontext, &result);
+ nullptr /*hints*/, &mNetcontext, &result);
EXPECT_EQ(EAI_NONAME, rv);
if (result) {
freeaddrinfo(result);
@@ -151,7 +161,7 @@
};
rv = android_getaddrinfofornetcontext("localhost", nullptr /*servname*/, &hints,
- &netcontext, &result);
+ &mNetcontext, &result);
EXPECT_EQ(config.expected_errorno, rv);
if (result) {
@@ -162,14 +172,6 @@
}
TEST_F(GetAddrInfoForNetContextTest, InvalidParameters_Family) {
- const android_net_context netcontext = {
- .app_netid = NETID_UNSET,
- .app_mark = MARK_UNSET,
- .dns_netid = NETID_UNSET,
- .dns_mark = MARK_UNSET,
- .uid = NET_CONTEXT_INVALID_UID,
- };
-
for (int family = 0; family < AF_MAX; ++family) {
if (family == AF_UNSPEC || family == AF_INET || family == AF_INET6) {
continue; // skip supported family
@@ -182,7 +184,7 @@
};
int rv = android_getaddrinfofornetcontext("localhost", nullptr /*servname*/, &hints,
- &netcontext, &result);
+ &mNetcontext, &result);
EXPECT_EQ(EAI_FAMILY, rv);
if (result) freeaddrinfo(result);
@@ -190,14 +192,6 @@
}
TEST_F(GetAddrInfoForNetContextTest, InvalidParameters_MeaningfulSocktypeAndProtocolCombination) {
- const android_net_context netcontext = {
- .app_netid = NETID_UNSET,
- .app_mark = MARK_UNSET,
- .dns_netid = NETID_UNSET,
- .dns_mark = MARK_UNSET,
- .uid = NET_CONTEXT_INVALID_UID,
- };
-
static const int families[] = {PF_INET, PF_INET6, PF_UNSPEC};
// Skip to test socket type SOCK_RAW in meaningful combination (explore_options[]) of
// system\netd\resolv\getaddrinfo.cpp. In explore_options[], the socket type SOCK_RAW always
@@ -237,7 +231,7 @@
};
int rv = android_getaddrinfofornetcontext("localhost", nullptr /*servname*/, &hints,
- &netcontext, &result);
+ &mNetcontext, &result);
EXPECT_EQ(EAI_BADHINTS, rv);
if (result) freeaddrinfo(result);
@@ -247,13 +241,6 @@
}
TEST_F(GetAddrInfoForNetContextTest, InvalidParameters_PortNameAndNumber) {
- const android_net_context netcontext = {
- .app_netid = NETID_UNSET,
- .app_mark = MARK_UNSET,
- .dns_netid = NETID_UNSET,
- .dns_mark = MARK_UNSET,
- .uid = NET_CONTEXT_INVALID_UID,
- };
constexpr char http_portno[] = "80";
constexpr char invalid_portno[] = "65536"; // out of valid port range from 0 to 65535
constexpr char http_portname[] = "http";
@@ -326,22 +313,18 @@
};
struct addrinfo* result = nullptr;
- int rv = android_getaddrinfofornetcontext("localhost", config.servname, &hints, &netcontext,
- &result);
+ int rv = android_getaddrinfofornetcontext("localhost", config.servname, &hints,
+ &mNetcontext, &result);
EXPECT_EQ(config.expected_errorno, rv);
if (result) freeaddrinfo(result);
}
}
-// Blocked by aosp/816674 which causes wrong error code EAI_FAIL (4) but EAI_NODATA (7).
-// TODO: fix aosp/816674 and add testcases AlphabeticalHostname_NoData back.
-/*
TEST_F(GetAddrInfoForNetContextTest, AlphabeticalHostname_NoData) {
constexpr char listen_addr[] = "127.0.0.3";
constexpr char listen_srv[] = "53";
constexpr char v4_host_name[] = "v4only.example.com.";
- constexpr char nonexistent_host_name[] = "nonexistent.example.com.";
test::DNSResponder dns(listen_addr, listen_srv, 250, ns_rcode::ns_r_servfail);
dns.addMapping(v4_host_name, ns_type::ns_t_a, "1.2.3.3");
ASSERT_TRUE(dns.startServer());
@@ -351,37 +334,16 @@
mDefaultSearchDomains, &mDefaultParams_Binder));
dns.clearQueries();
- struct addrinfo* result = nullptr;
- const android_net_context netcontext = {
- .app_netid = TEST_NETID,
- .app_mark = MARK_UNSET,
- .dns_netid = TEST_NETID,
- .dns_mark = MARK_UNSET,
- .uid = NET_CONTEXT_INVALID_UID,
- };
-
- // Query nonexistent hostname.
- int rv =
- android_getaddrinfofornetcontext("nonexistent", nullptr, nullptr, &netcontext, &result);
- EXPECT_LE(1U, GetNumQueries(dns, nonexistent_host_name));
- EXPECT_TRUE(result == nullptr);
- EXPECT_EQ(EAI_NODATA, rv);
-
- if (result) {
- freeaddrinfo(result);
- result = nullptr;
- }
-
// Want AAAA answer but DNS server has A answer only.
+ struct addrinfo* result = nullptr;
const addrinfo hints = {.ai_family = AF_INET6};
- rv = android_getaddrinfofornetcontext("v4only", nullptr, &hints, &netcontext, &result);
+ int rv = android_getaddrinfofornetcontext("v4only", nullptr, &hints, &mNetcontext, &result);
EXPECT_LE(1U, GetNumQueries(dns, v4_host_name));
EXPECT_TRUE(result == nullptr);
EXPECT_EQ(EAI_NODATA, rv);
if (result) freeaddrinfo(result);
}
-*/
TEST_F(GetAddrInfoForNetContextTest, AlphabeticalHostname) {
constexpr char listen_addr[] = "127.0.0.3";
@@ -399,14 +361,6 @@
sizeof(servers) / sizeof(servers[0]),
mDefaultSearchDomains, &mDefaultParams_Binder));
- const android_net_context netcontext = {
- .app_netid = TEST_NETID,
- .app_mark = MARK_UNSET,
- .dns_netid = TEST_NETID,
- .dns_mark = MARK_UNSET,
- .uid = NET_CONTEXT_INVALID_UID,
- };
-
static const struct TestConfig {
int ai_family;
const std::string expected_addr;
@@ -421,7 +375,8 @@
struct addrinfo* result = nullptr;
const struct addrinfo hints = {.ai_family = config.ai_family};
- int rv = android_getaddrinfofornetcontext("sawadee", nullptr, &hints, &netcontext, &result);
+ int rv =
+ android_getaddrinfofornetcontext("sawadee", nullptr, &hints, &mNetcontext, &result);
EXPECT_EQ(0, rv);
EXPECT_TRUE(result != nullptr);
EXPECT_EQ(1U, GetNumQueries(dns, host_name));
@@ -436,28 +391,27 @@
constexpr char listen_srv[] = "53";
constexpr char host_name[] = "hello.example.com.";
- const android_net_context netcontext = {
- .app_netid = TEST_NETID,
- .app_mark = MARK_UNSET,
- .dns_netid = TEST_NETID,
- .dns_mark = MARK_UNSET,
- .uid = NET_CONTEXT_INVALID_UID,
+ static const struct TestConfig {
+ ns_rcode rcode;
+ int expected_errorno; // expected result
+
+ // Only test failure RCODE [1..5] in RFC 1035 section 4.1.1 and skip successful RCODE 0
+ // which means no error.
+ } testConfigs[]{
+ // clang-format off
+ {ns_rcode::ns_r_formerr, EAI_FAIL},
+ {ns_rcode::ns_r_servfail, EAI_AGAIN},
+ {ns_rcode::ns_r_nxdomain, EAI_NODATA},
+ {ns_rcode::ns_r_notimpl, EAI_FAIL},
+ {ns_rcode::ns_r_refused, EAI_FAIL},
+ // clang-format on
};
- // Only test failure RCODE [1..5] in RFC 1035 section 4.1.1 and skip successful RCODE 0 which
- // means no error.
- // clang-format off
- static const ns_rcode rcodes[] = {ns_rcode::ns_r_formerr,
- ns_rcode::ns_r_servfail,
- ns_rcode::ns_r_nxdomain,
- ns_rcode::ns_r_notimpl,
- ns_rcode::ns_r_refused};
- // clang-format on
+ for (const auto& config : testConfigs) {
+ SCOPED_TRACE(StringPrintf("rcode: %d", config.rcode));
- for (const auto& rcode : rcodes) {
- SCOPED_TRACE(StringPrintf("rcode: %d", rcode));
-
- test::DNSResponder dns(listen_addr, listen_srv, 250, rcode /*response specific rcode*/);
+ test::DNSResponder dns(listen_addr, listen_srv, 250,
+ config.rcode /*response specific rcode*/);
dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.4");
dns.setResponseProbability(0.0); // always ignore requests and response preset rcode
ASSERT_TRUE(dns.startServer());
@@ -468,8 +422,9 @@
struct addrinfo* result = nullptr;
const struct addrinfo hints = {.ai_family = AF_UNSPEC};
- int rv = android_getaddrinfofornetcontext(host_name, nullptr, &hints, &netcontext, &result);
- EXPECT_EQ(EAI_NODATA, rv);
+ int rv =
+ android_getaddrinfofornetcontext(host_name, nullptr, &hints, &mNetcontext, &result);
+ EXPECT_EQ(config.expected_errorno, rv);
if (result) freeaddrinfo(result);
}
@@ -490,26 +445,140 @@
mDefaultSearchDomains, &mDefaultParams_Binder));
struct addrinfo* result = nullptr;
- const android_net_context netcontext = {
- .app_netid = TEST_NETID,
- .app_mark = MARK_UNSET,
- .dns_netid = TEST_NETID,
- .dns_mark = MARK_UNSET,
- .uid = NET_CONTEXT_INVALID_UID,
- };
-
const struct addrinfo hints = {.ai_family = AF_UNSPEC};
- int rv = android_getaddrinfofornetcontext("hello", nullptr, &hints, &netcontext, &result);
+ int rv = android_getaddrinfofornetcontext("hello", nullptr, &hints, &mNetcontext, &result);
EXPECT_EQ(NETD_RESOLV_TIMEOUT, rv);
if (result) freeaddrinfo(result);
}
-// Local host file function (files_getaddrinfo) is not tested because it only returns a boolean
-// (success or failure) without any error number.
+TEST_F(GetHostByNameForNetContextTest, AlphabeticalHostname) {
+ constexpr char listen_addr[] = "127.0.0.3";
+ constexpr char listen_srv[] = "53";
+ constexpr char host_name[] = "jiababuei.example.com.";
+ constexpr char v4addr[] = "1.2.3.4";
+ constexpr char v6addr[] = "::1.2.3.4";
-// TODO: Add test NULL hostname, or numeric hostname for android_getaddrinfofornetcontext
-// TODO: Add test for android_gethostbyaddrfornetcontext and android_gethostbynamefornetcontext.
+ test::DNSResponder dns(listen_addr, listen_srv, 250, ns_rcode::ns_r_servfail);
+ dns.addMapping(host_name, ns_type::ns_t_a, v4addr);
+ dns.addMapping(host_name, ns_type::ns_t_aaaa, v6addr);
+ ASSERT_TRUE(dns.startServer());
+ const char* servers[] = {listen_addr};
+ ASSERT_EQ(0, resolv_set_nameservers_for_net(TEST_NETID, servers,
+ sizeof(servers) / sizeof(servers[0]),
+ mDefaultSearchDomains, &mDefaultParams_Binder));
+
+ static const struct TestConfig {
+ int ai_family;
+ const std::string expected_addr;
+ } testConfigs[]{
+ {AF_INET, v4addr},
+ {AF_INET6, v6addr},
+ };
+
+ for (const auto& config : testConfigs) {
+ SCOPED_TRACE(StringPrintf("family: %d", config.ai_family));
+ dns.clearQueries();
+
+ struct hostent* hp = nullptr;
+ int rv = android_gethostbynamefornetcontext("jiababuei", config.ai_family, &mNetcontext,
+ &hp);
+ EXPECT_EQ(0, rv);
+ EXPECT_TRUE(hp != nullptr);
+ EXPECT_EQ(1U, GetNumQueries(dns, host_name));
+ EXPECT_EQ(config.expected_addr, ToString(hp));
+ }
+}
+
+TEST_F(GetHostByNameForNetContextTest, NoData) {
+ constexpr char listen_addr[] = "127.0.0.3";
+ constexpr char listen_srv[] = "53";
+ constexpr char v4_host_name[] = "v4only.example.com.";
+ test::DNSResponder dns(listen_addr, listen_srv, 250, ns_rcode::ns_r_servfail);
+ dns.addMapping(v4_host_name, ns_type::ns_t_a, "1.2.3.3");
+ ASSERT_TRUE(dns.startServer());
+ const char* servers[] = {listen_addr};
+ ASSERT_EQ(0, resolv_set_nameservers_for_net(TEST_NETID, servers,
+ sizeof(servers) / sizeof(servers[0]),
+ mDefaultSearchDomains, &mDefaultParams_Binder));
+ dns.clearQueries();
+
+ // Want AAAA answer but DNS server has A answer only.
+ struct hostent* hp = nullptr;
+ int rv = android_gethostbynamefornetcontext("v4only", AF_INET6, &mNetcontext, &hp);
+ EXPECT_LE(1U, GetNumQueries(dns, v4_host_name));
+ EXPECT_TRUE(hp == nullptr);
+ EXPECT_EQ(EAI_NODATA, rv);
+}
+
+TEST_F(GetHostByNameForNetContextTest, ServerResponseError) {
+ constexpr char listen_addr[] = "127.0.0.3";
+ constexpr char listen_srv[] = "53";
+ constexpr char host_name[] = "hello.example.com.";
+
+ static const struct TestConfig {
+ ns_rcode rcode;
+ int expected_errorno; // expected result
+
+ // Only test failure RCODE [1..5] in RFC 1035 section 4.1.1 and skip successful RCODE 0
+ // which means no error. Note that the return error codes aren't mapped by rcode in the
+ // test case SERVFAIL, NOTIMP and REFUSED. See the comment of res_nsend()
+ // in system\netd\resolv\res_query.cpp for more detail.
+ } testConfigs[]{
+ // clang-format off
+ {ns_rcode::ns_r_formerr, EAI_FAIL},
+ {ns_rcode::ns_r_servfail, EAI_AGAIN}, // Not mapped by rcode.
+ {ns_rcode::ns_r_nxdomain, EAI_NODATA},
+ {ns_rcode::ns_r_notimpl, EAI_AGAIN}, // Not mapped by rcode.
+ {ns_rcode::ns_r_refused, EAI_AGAIN}, // Not mapped by rcode.
+ // clang-format on
+ };
+
+ for (const auto& config : testConfigs) {
+ SCOPED_TRACE(StringPrintf("rcode: %d", config.rcode));
+
+ test::DNSResponder dns(listen_addr, listen_srv, 250,
+ config.rcode /*response specific rcode*/);
+ dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.4");
+ dns.setResponseProbability(0.0); // always ignore requests and response preset rcode
+ ASSERT_TRUE(dns.startServer());
+ const char* servers[] = {listen_addr};
+ ASSERT_EQ(0, resolv_set_nameservers_for_net(TEST_NETID, servers,
+ sizeof(servers) / sizeof(servers[0]),
+ mDefaultSearchDomains, &mDefaultParams_Binder));
+
+ struct hostent* hp = nullptr;
+ int rv = android_gethostbynamefornetcontext(host_name, AF_INET, &mNetcontext, &hp);
+ EXPECT_TRUE(hp == nullptr);
+ EXPECT_EQ(config.expected_errorno, rv);
+ }
+}
+
+// TODO: Add private DNS server timeout test.
+TEST_F(GetHostByNameForNetContextTest, ServerTimeout) {
+ constexpr char listen_addr[] = "127.0.0.3";
+ constexpr char listen_srv[] = "53";
+ constexpr char host_name[] = "hello.example.com.";
+ test::DNSResponder dns(listen_addr, listen_srv, 250, static_cast<ns_rcode>(-1) /*no response*/);
+ dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.4");
+ dns.setResponseProbability(0.0); // always ignore requests and don't response
+ ASSERT_TRUE(dns.startServer());
+ const char* servers[] = {listen_addr};
+ ASSERT_EQ(0, resolv_set_nameservers_for_net(TEST_NETID, servers,
+ sizeof(servers) / sizeof(servers[0]),
+ mDefaultSearchDomains, &mDefaultParams_Binder));
+
+ struct hostent* hp = nullptr;
+ int rv = android_gethostbynamefornetcontext(host_name, AF_INET, &mNetcontext, &hp);
+ EXPECT_EQ(NETD_RESOLV_TIMEOUT, rv);
+}
+
+// Note that local host file function, files_getaddrinfo(), of android_getaddrinfofornetcontext()
+// is not tested because it only returns a boolean (success or failure) without any error number.
+
+// TODO: Add test NULL hostname, or numeric hostname for android_getaddrinfofornetcontext.
+// TODO: Add test invalid parameters for android_gethostbynamefornetcontext.
+// TODO: Add test for android_gethostbyaddrfornetcontext.
} // end of namespace net
} // end of namespace android
diff --git a/resolv/res_cache.cpp b/resolv/res_cache.cpp
index fd1a324..60a60df 100644
--- a/resolv/res_cache.cpp
+++ b/resolv/res_cache.cpp
@@ -1729,7 +1729,7 @@
params->base_timeout_msec = 0; // 0 = legacy algorithm
}
-int resolv_set_nameservers_for_net(unsigned netid, const char** servers, unsigned numservers,
+int resolv_set_nameservers_for_net(unsigned netid, const char** servers, const int numservers,
const char* domains, const __res_params* params) {
char* cp;
int* offset;
@@ -1744,13 +1744,13 @@
// As a side effect this also reduces the time the lock is kept.
char sbuf[NI_MAXSERV];
snprintf(sbuf, sizeof(sbuf), "%u", NAMESERVER_PORT);
- for (unsigned i = 0; i < numservers; i++) {
+ for (int i = 0; i < numservers; i++) {
// The addrinfo structures allocated here are freed in free_nameservers_locked().
const addrinfo hints = {
.ai_family = AF_UNSPEC, .ai_socktype = SOCK_DGRAM, .ai_flags = AI_NUMERICHOST};
int rt = getaddrinfo_numeric(servers[i], sbuf, hints, &nsaddrinfo[i]);
if (rt != 0) {
- for (unsigned j = 0; j < i; j++) {
+ for (int j = 0; j < i; j++) {
freeaddrinfo(nsaddrinfo[j]);
}
VLOG << __func__ << ": getaddrinfo_numeric(" << servers[i]
@@ -1778,8 +1778,7 @@
if (!resolv_is_nameservers_equal_locked(cache_info, servers, numservers)) {
// free current before adding new
free_nameservers_locked(cache_info);
- unsigned i;
- for (i = 0; i < numservers; i++) {
+ for (int i = 0; i < numservers; i++) {
cache_info->nsaddrinfo[i] = nsaddrinfo[i];
cache_info->nameservers[i] = strdup(servers[i]);
VLOG << __func__ << ": netid = " << netid << ", addr = " << servers[i];
@@ -1804,7 +1803,7 @@
res_cache_clear_stats_locked(cache_info);
++cache_info->revision_id;
}
- for (unsigned j = 0; j < numservers; j++) {
+ for (int j = 0; j < numservers; j++) {
freeaddrinfo(nsaddrinfo[j]);
}
}
diff --git a/resolv/res_query.cpp b/resolv/res_query.cpp
index 6faa504..f81b33e 100644
--- a/resolv/res_query.cpp
+++ b/resolv/res_query.cpp
@@ -103,7 +103,7 @@
* Perform preliminary check of answer, returning success only
* if no error is indicated and the answer count is nonzero.
* Return the size of the response on success, -1 on error.
- * Error number is left in H_ERRNO.
+ * Error number is left in *herrno.
*
* Caller must parse answer and determine whether it answers the question.
*/
@@ -111,7 +111,8 @@
int cl, int type, // class and type of query
u_char* answer, // buffer to put answer
int anslen, // size of answer buffer
- int* ai_error) // error will be set based on rcode
+ int* herrno) // legacy and extended h_errno
+ // NETD_RESOLV_H_ERRNO_EXT_*
{
u_char buf[MAXPACKET];
HEADER* hp = (HEADER*) (void*) answer;
@@ -136,11 +137,10 @@
#ifdef DEBUG
if (statp->options & RES_DEBUG) printf(";; res_query: mkquery failed\n");
#endif
- RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ *herrno = NO_RECOVERY;
return n;
}
n = res_nsend(statp, buf, n, answer, anslen, &rcode);
- *ai_error = rcodeToAiError(rcode);
if (n < 0) {
/* if the query choked with EDNS0, retry without EDNS0 */
if ((statp->options & (RES_USE_EDNS0 | RES_USE_DNSSEC)) != 0U &&
@@ -152,7 +152,28 @@
#ifdef DEBUG
if (statp->options & RES_DEBUG) printf(";; res_query: send error\n");
#endif
- RES_SET_H_ERRNO(statp, TRY_AGAIN);
+ // Note that rcodes SERVFAIL, NOTIMP, REFUSED may cause res_nquery() to return a general
+ // error code EAI_AGAIN, but mapping the error code from rcode as res_queryN() does for
+ // getaddrinfo(). Different rcodes trigger different behaviors:
+ //
+ // - SERVFAIL, NOTIMP, REFUSED
+ // These result in send_dg() returning 0, causing res_nsend() to try the next
+ // nameserver. After all nameservers failed, res_nsend() returns -ETIMEDOUT, causing
+ // res_nquery() to return EAI_AGAIN here regardless of the rcode from the DNS response.
+ //
+ // - NXDOMAIN, FORMERR
+ // These rcodes may cause res_nsend() to return successfully (i.e. the result is a
+ // positive integer). In this case, res_nquery() returns error number by referring
+ // the rcode from the DNS response.
+ switch (rcode) {
+ case RCODE_TIMEOUT: // Not defined in RFC.
+ // DNS metrics monitors DNS query timeout.
+ *herrno = NETD_RESOLV_H_ERRNO_EXT_TIMEOUT; // extended h_errno.
+ break;
+ default:
+ *herrno = TRY_AGAIN;
+ break;
+ }
return n;
}
@@ -164,19 +185,19 @@
#endif
switch (hp->rcode) {
case NXDOMAIN:
- RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
+ *herrno = HOST_NOT_FOUND;
break;
case SERVFAIL:
- RES_SET_H_ERRNO(statp, TRY_AGAIN);
+ *herrno = TRY_AGAIN;
break;
case NOERROR:
- RES_SET_H_ERRNO(statp, NO_DATA);
+ *herrno = NO_DATA;
break;
case FORMERR:
case NOTIMP:
case REFUSED:
default:
- RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ *herrno = NO_RECOVERY;
break;
}
return -1;
@@ -188,13 +209,14 @@
* Formulate a normal query, send, and retrieve answer in supplied buffer.
* Return the size of the response on success, -1 on error.
* If enabled, implement search rules until answer or unrecoverable failure
- * is detected. Error code, if any, is left in H_ERRNO.
+ * is detected. Error code, if any, is left in *herrno.
*/
int res_nsearch(res_state statp, const char* name, /* domain name */
int cl, int type, /* class and type of query */
u_char* answer, /* buffer to put answer */
int anslen, /* size of answer */
- int* ai_error) /* error will be set based on rcode*/
+ int* herrno) /* legacy and extended
+ h_errno NETD_RESOLV_H_ERRNO_EXT_* */
{
const char *cp, *const *domain;
HEADER* hp = (HEADER*) (void*) answer;
@@ -205,7 +227,7 @@
int searched = 0;
errno = 0;
- RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); /* True if we never query. */
+ *herrno = HOST_NOT_FOUND; /* True if we never query. */
dots = 0;
for (cp = name; *cp != '\0'; cp++) dots += (*cp == '.');
@@ -219,9 +241,9 @@
*/
saved_herrno = -1;
if (dots >= statp->ndots || trailing_dot) {
- ret = res_nquerydomain(statp, name, NULL, cl, type, answer, anslen, ai_error);
+ ret = res_nquerydomain(statp, name, NULL, cl, type, answer, anslen, herrno);
if (ret > 0 || trailing_dot) return ret;
- saved_herrno = statp->res_h_errno;
+ saved_herrno = *herrno;
tried_as_is++;
}
@@ -250,7 +272,7 @@
if (domain[0][0] == '\0' || (domain[0][0] == '.' && domain[0][1] == '\0'))
root_on_list++;
- ret = res_nquerydomain(statp, name, *domain, cl, type, answer, anslen, ai_error);
+ ret = res_nquerydomain(statp, name, *domain, cl, type, answer, anslen, herrno);
if (ret > 0) return ret;
/*
@@ -267,11 +289,11 @@
* fully-qualified.
*/
if (errno == ECONNREFUSED) {
- RES_SET_H_ERRNO(statp, TRY_AGAIN);
+ *herrno = TRY_AGAIN;
return -1;
}
- switch (statp->res_h_errno) {
+ switch (*herrno) {
case NO_DATA:
got_nodata++;
break;
@@ -303,7 +325,7 @@
*/
if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0U) &&
!(tried_as_is || root_on_list)) {
- ret = res_nquerydomain(statp, name, NULL, cl, type, answer, anslen, ai_error);
+ ret = res_nquerydomain(statp, name, NULL, cl, type, answer, anslen, herrno);
if (ret > 0) return ret;
}
@@ -315,11 +337,11 @@
* the last DNSRCH we did.
*/
if (saved_herrno != -1)
- RES_SET_H_ERRNO(statp, saved_herrno);
+ *herrno = saved_herrno;
else if (got_nodata)
- RES_SET_H_ERRNO(statp, NO_DATA);
+ *herrno = NO_DATA;
else if (got_servfail)
- RES_SET_H_ERRNO(statp, TRY_AGAIN);
+ *herrno = TRY_AGAIN;
return -1;
}
@@ -331,7 +353,7 @@
int type, /* class and type of query */
u_char* answer, /* buffer to put answer */
int anslen, /* size of answer */
- int* ai_error) /* error will be set based on rcode*/
+ int* herrno) /* legacy and extended h_errno NETD_RESOLV_H_ERRNO_EXT_* */
{
char nbuf[MAXDNAME];
const char* longname = nbuf;
@@ -349,7 +371,7 @@
*/
n = strlen(name);
if (n >= MAXDNAME) {
- RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ *herrno = NO_RECOVERY;
return -1;
}
n--;
@@ -362,10 +384,10 @@
n = strlen(name);
d = strlen(domain);
if (n + d + 1 >= MAXDNAME) {
- RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ *herrno = NO_RECOVERY;
return -1;
}
snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
}
- return res_nquery(statp, longname, cl, type, answer, anslen, ai_error);
+ return res_nquery(statp, longname, cl, type, answer, anslen, herrno);
}
diff --git a/resolv/res_state.cpp b/resolv/res_state.cpp
index 325bb6e..26febff 100644
--- a/resolv/res_state.cpp
+++ b/resolv/res_state.cpp
@@ -43,7 +43,6 @@
#include "resolv_private.h"
typedef struct {
- int _h_errno;
// TODO: Have one __res_state per network so we don't have to repopulate frequently.
struct __res_state _nres[1];
struct res_static _rstatic[1];
@@ -53,7 +52,6 @@
_res_thread* rt = (_res_thread*) calloc(1, sizeof(*rt));
if (rt) {
- rt->_h_errno = 0;
memset(rt->_rstatic, 0, sizeof rt->_rstatic);
}
return rt;
@@ -119,13 +117,6 @@
struct __res_state _nres;
-int* __get_h_errno(void) {
- _res_thread* rt = res_thread_get();
- static int panic = NETDB_INTERNAL;
-
- return rt ? &rt->_h_errno : &panic;
-}
-
res_state res_get_state(void) {
_res_thread* rt = res_thread_get();
diff --git a/resolv/resolv_private.h b/resolv/resolv_private.h
index bd48660..18e5886 100644
--- a/resolv/resolv_private.h
+++ b/resolv/resolv_private.h
@@ -71,27 +71,6 @@
#define MAXHOSTNAMELEN 256
/*
- * This used to be defined in res_query.c, now it's in herror.c.
- * [XXX no it's not. It's in irs/irs_data.c]
- * It was
- * never extern'd by any *.h file before it was placed here. For thread
- * aware programs, the last h_errno value set is stored in res->h_errno.
- *
- * XXX: There doesn't seem to be a good reason for exposing RES_SET_H_ERRNO
- * (and __h_errno_set) to the public via <resolv.h>.
- * XXX: __h_errno_set is really part of IRS, not part of the resolver.
- * If somebody wants to build and use a resolver that doesn't use IRS,
- * what do they do? Perhaps something like
- * #ifdef WANT_IRS
- * # define RES_SET_H_ERRNO(r,x) __h_errno_set(r,x)
- * #else
- * # define RES_SET_H_ERRNO(r,x) (h_errno = (r)->res_h_errno = (x))
- * #endif
- */
-
-#define RES_SET_H_ERRNO(r, x) (h_errno = (r)->res_h_errno = (x))
-
-/*
* Global defines and variables for resolver stub.
*/
#define MAXDFLSRCH 3 /* # default domain levels to try */
@@ -126,7 +105,6 @@
struct in_addr addr;
uint32_t mask;
} sort_list[MAXRESOLVSORT];
- int res_h_errno; /* last one set for this context */
unsigned _mark; /* If non-0 SET_MARK to _mark on all request sockets */
int _vcsock; /* PRIVATE: for res_send VC i/o */
u_int _flags; /* PRIVATE: see below */
@@ -233,6 +211,16 @@
#define RES_PRF_TRUNC 0x00008000
/* 0x00010000 */
+/*
+ * Error code extending h_errno codes defined in bionic/libc/include/netdb.h.
+ *
+ * This error code, including legacy h_errno, is returned from res_nquery(), res_nsearch(),
+ * res_nquerydomain(), res_queryN(), res_searchN() and res_querydomainN() for DNS metrics.
+ *
+ * TODO: Consider mapping legacy and extended h_errno into a unified resolver error code mapping.
+ */
+#define NETD_RESOLV_H_ERRNO_EXT_TIMEOUT RCODE_TIMEOUT
+
extern const char* const _res_opcodes[];
/* Things involving an internal (static) resolver context. */
@@ -280,9 +268,6 @@
addrinfo** result);
// Helper function for converting h_errno to the error codes visible to netd
-int herrnoToAiError(int herrno);
-
-// Helper function for converting rcode to the error codes visible to netd
-int rcodeToAiError(int rcode);
+int herrnoToAiErrno(int herrno);
#endif // NETD_RESOLV_PRIVATE_H
diff --git a/resolv/resolver_test.cpp b/resolv/resolver_test.cpp
index d0c0ba5..5c5d833 100644
--- a/resolv/resolver_test.cpp
+++ b/resolv/resolver_test.cpp
@@ -140,7 +140,7 @@
std::vector<int32_t> stats32;
auto rv = mNetdSrv->getResolverInfo(TEST_NETID, servers, domains, tlsServers, ¶ms32,
&stats32);
- if (!rv.isOk() || params32.size() != INetd::RESOLVER_PARAMS_COUNT) {
+ if (!rv.isOk() || params32.size() != static_cast<size_t>(INetd::RESOLVER_PARAMS_COUNT)) {
return false;
}
*params = __res_params {
@@ -456,10 +456,10 @@
INetd::RESOLVER_PARAMS_MAX_SAMPLES,
INetd::RESOLVER_PARAMS_BASE_TIMEOUT_MSEC,
};
- int size = static_cast<int>(params_offsets.size());
+ const int size = static_cast<int>(params_offsets.size());
EXPECT_EQ(size, INetd::RESOLVER_PARAMS_COUNT);
std::sort(params_offsets.begin(), params_offsets.end());
- for (int i = 0 ; i < size ; ++i) {
+ for (int i = 0; i < size; ++i) {
EXPECT_EQ(params_offsets[i], i);
}
}
@@ -479,8 +479,8 @@
ASSERT_TRUE(SetResolversForNetwork(servers, domains, mDefaultParams_Binder));
const hostent* result = gethostbyname(mapping.host.c_str());
- size_t total_queries = std::accumulate(dns.begin(), dns.end(), 0,
- [this, &mapping](size_t total, auto& d) {
+ const size_t total_queries =
+ std::accumulate(dns.begin(), dns.end(), 0, [this, &mapping](size_t total, auto& d) {
return total + GetNumQueriesForType(*d, ns_type::ns_t_a, mapping.entry.c_str());
});
@@ -696,7 +696,7 @@
// for the next sample_lifetime seconds.
// TODO: This approach is implementation-dependent, change once metrics reporting is available.
addrinfo hints = {.ai_family = AF_INET6};
- for (int i = 0 ; i < sample_count ; ++i) {
+ for (int i = 0; i < sample_count; ++i) {
std::string domain = StringPrintf("nonexistent%d", i);
ScopedAddrinfo result = safe_getaddrinfo(domain.c_str(), nullptr, &hints);
}
@@ -1636,8 +1636,8 @@
ASSERT_TRUE(SetResolversForNetwork(servers, mDefaultSearchDomains, mDefaultParams_Binder));
dns.clearQueries();
- int fd1 = resNetworkQuery(TEST_NETID, "howdy.example.com", 1, 1); // Type A 1
- int fd2 = resNetworkQuery(TEST_NETID, "howdy.example.com", 1, 28); // Type AAAA 28
+ int fd1 = resNetworkQuery(TEST_NETID, "howdy.example.com", 1, 1, 0); // Type A 1
+ int fd2 = resNetworkQuery(TEST_NETID, "howdy.example.com", 1, 28, 0); // Type AAAA 28
EXPECT_TRUE(fd1 != -1);
EXPECT_TRUE(fd2 != -1);
@@ -1654,8 +1654,8 @@
EXPECT_EQ(2U, GetNumQueries(dns, host_name));
// Re-query verify cache works
- fd1 = resNetworkQuery(TEST_NETID, "howdy.example.com", 1, 1); // Type A 1
- fd2 = resNetworkQuery(TEST_NETID, "howdy.example.com", 1, 28); // Type AAAA 28
+ fd1 = resNetworkQuery(TEST_NETID, "howdy.example.com", 1, 1, 0); // Type A 1
+ fd2 = resNetworkQuery(TEST_NETID, "howdy.example.com", 1, 28, 0); // Type AAAA 28
EXPECT_TRUE(fd1 != -1);
EXPECT_TRUE(fd2 != -1);
@@ -1698,7 +1698,7 @@
for (auto& td : kTestData) {
SCOPED_TRACE(td.dname);
- td.fd = resNetworkQuery(TEST_NETID, td.dname, 1, td.queryType);
+ td.fd = resNetworkQuery(TEST_NETID, td.dname, 1, td.queryType, 0);
EXPECT_TRUE(td.fd != -1);
}
@@ -1733,17 +1733,17 @@
{
std::unique_lock lk(cvMutex);
// A 1 AAAA 28
- fd1 = resNetworkQuery(TEST_NETID, "howdy.example.com", 1, 28);
+ fd1 = resNetworkQuery(TEST_NETID, "howdy.example.com", 1, 28, 0);
EXPECT_TRUE(fd1 != -1);
EXPECT_EQ(std::cv_status::no_timeout, cv.wait_for(lk, std::chrono::seconds(1)));
}
dns.setResponseProbability(0.0);
- int fd2 = resNetworkQuery(TEST_NETID, "howdy.example.com", 1, 1);
+ int fd2 = resNetworkQuery(TEST_NETID, "howdy.example.com", 1, 1, 0);
EXPECT_TRUE(fd2 != -1);
- int fd3 = resNetworkQuery(TEST_NETID, "howdy.example.com", 1, 1);
+ int fd3 = resNetworkQuery(TEST_NETID, "howdy.example.com", 1, 1, 0);
EXPECT_TRUE(fd3 != -1);
uint8_t buf[MAXPACKET] = {};
@@ -1760,7 +1760,7 @@
dns.setResponseProbability(1.0);
- int fd4 = resNetworkQuery(TEST_NETID, "howdy.example.com", 1, 1);
+ int fd4 = resNetworkQuery(TEST_NETID, "howdy.example.com", 1, 1, 0);
EXPECT_TRUE(fd4 != -1);
memset(buf, 0, MAXPACKET);
@@ -2035,9 +2035,6 @@
EXPECT_EQ(result_str, "1.2.3.4");
}
-// blocked by aosp/816674 which causes wrong error code EAI_FAIL (4) but EAI_NODATA (7).
-// TODO: fix aosp/816674 and add testcases GetAddrInfo_Dns64QuerySpecified back.
-/*
TEST_F(ResolverTest, GetAddrInfo_Dns64QuerySpecified) {
constexpr char listen_addr[] = "::1";
constexpr char listen_srv[] = "53";
@@ -2073,7 +2070,6 @@
result_str = ToString(result);
EXPECT_EQ(result_str, "1.2.3.4");
}
-*/
TEST_F(ResolverTest, GetAddrInfo_Dns64QueryUnspecifiedV6) {
constexpr char listen_addr[] = "::1";
@@ -2657,11 +2653,6 @@
EXPECT_EQ(result_str, host_name);
}
-// blocked by aosp/816674 which causes wrong error code EAI_FAIL (4) but EAI_NODATA (7).
-// TODO:
-// 1. fix aosp/816674 and add testcases GetHostByName2_Dns64Synthesize back.
-// 2. Manual test gethostbyname2 synthesis for IPv4 address which comes from host file.
-/*
TEST_F(ResolverTest, GetHostByName2_Dns64Synthesize) {
constexpr char dns64_name[] = "ipv4only.arpa.";
constexpr char host_name[] = "ipv4only.example.com.";
@@ -2686,7 +2677,6 @@
std::string result_str = ToString(result);
EXPECT_EQ(result_str, "64:ff9b::102:304");
}
-*/
TEST_F(ResolverTest, GetHostByName2_DnsQueryWithHavingNat64Prefix) {
constexpr char dns64_name[] = "ipv4only.arpa.";
diff --git a/resolv/sethostent.cpp b/resolv/sethostent.cpp
index 7c5b905..49cc236 100644
--- a/resolv/sethostent.cpp
+++ b/resolv/sethostent.cpp
@@ -61,7 +61,7 @@
}
}
-hostent* _hf_gethtbyname2(const char* name, int af, getnamaddr* info) {
+int _hf_gethtbyname2(const char* name, int af, getnamaddr* info) {
struct hostent *hp, hent;
char *buf, *ptr;
size_t len, num, i;
@@ -72,13 +72,12 @@
sethostent_r(&hf);
if (hf == NULL) {
errno = EINVAL;
- *info->he = NETDB_INTERNAL;
- return NULL;
+ // TODO: Consider to remap error code without relying on errno.
+ return EAI_SYSTEM;
}
if ((ptr = buf = (char*) malloc(len = info->buflen)) == NULL) {
- *info->he = NETDB_INTERNAL;
- return NULL;
+ return EAI_MEMORY;
}
hent.h_name = NULL;
@@ -90,9 +89,10 @@
info->hp->h_addrtype = af;
info->hp->h_length = 0;
- hp = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen, info->he);
+ int herrno;
+ hp = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen, &herrno);
if (hp == NULL) {
- if (*info->he == NETDB_INTERNAL && errno == ENOSPC) {
+ if (herrno == NETDB_INTERNAL && errno == ENOSPC) {
goto nospc; // glibc compatibility.
}
break;
@@ -127,9 +127,11 @@
endhostent_r(&hf);
if (num == 0) {
- *info->he = HOST_NOT_FOUND;
free(buf);
- return NULL;
+ // TODO: Perhaps convert HOST_NOT_FOUND to EAI_NONAME instead.
+ // The original return error number is h_errno HOST_NOT_FOUND which was converted to
+ // EAI_NODATA.
+ return EAI_NODATA;
}
hp = info->hp;
@@ -160,33 +162,35 @@
hp->h_aliases[anum] = NULL;
free(buf);
- return hp;
+ return 0;
nospc:
- *info->he = NETDB_INTERNAL;
free(buf);
errno = ENOSPC;
- return NULL;
+ return EAI_MEMORY;
}
-bool _hf_gethtbyaddr(const unsigned char* uaddr, int len, int af, getnamaddr* info) {
+int _hf_gethtbyaddr(const unsigned char* uaddr, int len, int af, getnamaddr* info) {
info->hp->h_length = len;
info->hp->h_addrtype = af;
FILE* hf = NULL;
sethostent_r(&hf);
if (hf == NULL) {
- *info->he = NETDB_INTERNAL;
- return false;
+ // TODO: Consider to remap error code without relying on errno.
+ return EAI_SYSTEM;
}
struct hostent* hp;
- while ((hp = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen, info->he)) != NULL)
+ int herrno;
+ while ((hp = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen, &herrno)) != NULL)
if (!memcmp(hp->h_addr_list[0], uaddr, (size_t) hp->h_length)) break;
endhostent_r(&hf);
if (hp == NULL) {
- if (errno == ENOSPC) return false; // glibc compatibility.
- *info->he = HOST_NOT_FOUND;
- return false;
+ if (errno == ENOSPC) return EAI_MEMORY; // glibc compatibility.
+ // TODO: Perhaps convert HOST_NOT_FOUND to EAI_NONAME instead.
+ // The original return error number is h_errno HOST_NOT_FOUND which was converted to
+ // EAI_NODATA.
+ return EAI_NODATA;
}
- return true;
+ return 0;
}
diff --git a/server/DnsProxyListener.cpp b/server/DnsProxyListener.cpp
index 73a1e2a..ef36438 100644
--- a/server/DnsProxyListener.cpp
+++ b/server/DnsProxyListener.cpp
@@ -126,7 +126,7 @@
RESOLV_STUB.resolv_get_private_dns_status_for_net(dns_netid, &privateDnsStatus);
switch (static_cast<PrivateDnsMode>(privateDnsStatus.mode)) {
case PrivateDnsMode::OPPORTUNISTIC:
- for (unsigned i = 0; i < privateDnsStatus.numServers; i++) {
+ for (int i = 0; i < privateDnsStatus.numServers; i++) {
if (privateDnsStatus.serverStatus[i].validation == Validation::success) {
return true;
}
@@ -171,11 +171,11 @@
}
}
-void addIpAddrWithinLimit(std::vector<android::String16>* ip_addrs, const sockaddr* addr,
+void addIpAddrWithinLimit(std::vector<std::string>* ip_addrs, const sockaddr* addr,
socklen_t addrlen);
-int extractIpAddressAnswers(const uint8_t* answer, size_t anslen, int ipType,
- std::vector<String16>* ip_addrs) {
+int extractResNsendAnswers(const uint8_t* answer, size_t anslen, int ipType,
+ std::vector<std::string>* ip_addrs) {
int total_ip_addr_count = 0;
ns_msg handle;
if (ns_initparse((const uint8_t*) answer, anslen, &handle) < 0) {
@@ -194,9 +194,8 @@
addIpAddrWithinLimit(ip_addrs, (sockaddr*) &sin, sizeof(sin));
total_ip_addr_count++;
} else if (ipType == ns_t_aaaa) {
- struct in6_addr in6;
- memcpy(&in6, rdata, IN6ADDRSZ);
- sockaddr_in6 sin6 = {.sin6_family = AF_INET6, .sin6_addr = in6};
+ sockaddr_in6 sin6 = {.sin6_family = AF_INET6};
+ memcpy(&sin6.sin6_addr, rdata, sizeof(sin6.sin6_addr));
addIpAddrWithinLimit(ip_addrs, (sockaddr*) &sin6, sizeof(sin6));
total_ip_addr_count++;
}
@@ -205,6 +204,65 @@
return total_ip_addr_count;
}
+int extractGetaddrinfoAnswers(const addrinfo* result, std::vector<std::string>* ip_addrs) {
+ int total_ip_addr_count = 0;
+ if (result == nullptr) {
+ return 0;
+ }
+ for (const addrinfo* ai = result; ai; ai = ai->ai_next) {
+ sockaddr* ai_addr = ai->ai_addr;
+ if (ai_addr) {
+ addIpAddrWithinLimit(ip_addrs, ai_addr, ai->ai_addrlen);
+ total_ip_addr_count++;
+ }
+ }
+ return total_ip_addr_count;
+}
+
+int extractGethostbynameAnswers(const hostent* hp, std::vector<std::string>* ip_addrs) {
+ int total_ip_addr_count = 0;
+ if (hp == nullptr) {
+ return 0;
+ }
+ if (hp->h_addrtype == AF_INET) {
+ in_addr** list = (in_addr**) hp->h_addr_list;
+ for (int i = 0; list[i] != nullptr; i++) {
+ sockaddr_in sin = {.sin_family = AF_INET, .sin_addr = *list[i]};
+ addIpAddrWithinLimit(ip_addrs, (sockaddr*) &sin, sizeof(sin));
+ total_ip_addr_count++;
+ }
+ } else if (hp->h_addrtype == AF_INET6) {
+ in6_addr** list = (in6_addr**) hp->h_addr_list;
+ for (int i = 0; list[i] != nullptr; i++) {
+ sockaddr_in6 sin6 = {.sin6_family = AF_INET6, .sin6_addr = *list[i]};
+ addIpAddrWithinLimit(ip_addrs, (sockaddr*) &sin6, sizeof(sin6));
+ total_ip_addr_count++;
+ }
+ }
+ return total_ip_addr_count;
+}
+
+int rcodeToAiError(int rcode) {
+ switch (rcode) {
+ case NOERROR:
+ return 0;
+ case RCODE_TIMEOUT:
+ return NETD_RESOLV_TIMEOUT;
+ default:
+ return EAI_NODATA;
+ }
+}
+
+int resNSendToAiError(int err, int rcode) {
+ if (err > 0) {
+ return rcodeToAiError(rcode);
+ }
+ if (err == -ETIMEDOUT) {
+ return NETD_RESOLV_TIMEOUT;
+ }
+ return EAI_SYSTEM;
+}
+
template <typename IntegralType>
bool simpleStrtoul(const char* input, IntegralType* output, int base = 10) {
char* endPtr;
@@ -232,6 +290,29 @@
return true;
}
+void reportDnsInfoAll(int reportingLevel, int eventType, const android_net_context& netContext,
+ int latencyMs, int returnCode, const std::string& query_name,
+ const std::vector<std::string>& ip_addrs = {}, int total_ip_addr_count = 0) {
+ const auto listener = gCtls->eventReporter.getNetdEventListener();
+ if (!listener) return;
+
+ switch (reportingLevel) {
+ case INetdEventListener::REPORTING_LEVEL_NONE:
+ // Skip reporting.
+ break;
+ case INetdEventListener::REPORTING_LEVEL_METRICS:
+ // Metrics reporting is on. Send metrics.
+ listener->onDnsEvent(netContext.dns_netid, eventType, returnCode, latencyMs, "", {}, -1,
+ -1);
+ break;
+ case INetdEventListener::REPORTING_LEVEL_FULL:
+ // Full event info reporting is on. Send full info.
+ listener->onDnsEvent(netContext.dns_netid, eventType, returnCode, latencyMs, query_name,
+ ip_addrs, total_ip_addr_count, netContext.uid);
+ break;
+ }
+}
+
bool onlyIPv4Answers(const struct addrinfo* res) {
// Null addrinfo pointer isn't checked because the caller doesn't pass null pointer.
@@ -408,18 +489,16 @@
registerCmd(new ResNSendCommand(this));
}
-DnsProxyListener::GetAddrInfoHandler::GetAddrInfoHandler(
- SocketClient *c, char* host, char* service, struct addrinfo* hints,
- const android_net_context& netcontext, const int reportingLevel,
- const android::sp<android::net::metrics::INetdEventListener>& netdEventListener)
- : mClient(c),
- mHost(host),
- mService(service),
- mHints(hints),
- mNetContext(netcontext),
- mReportingLevel(reportingLevel),
- mNetdEventListener(netdEventListener) {
-}
+DnsProxyListener::GetAddrInfoHandler::GetAddrInfoHandler(SocketClient* c, char* host, char* service,
+ addrinfo* hints,
+ const android_net_context& netcontext,
+ const int reportingLevel)
+ : mClient(c),
+ mHost(host),
+ mService(service),
+ mHints(hints),
+ mNetContext(netcontext),
+ mReportingLevel(reportingLevel) {}
DnsProxyListener::GetAddrInfoHandler::~GetAddrInfoHandler() {
free(mHost);
@@ -439,7 +518,7 @@
}
// Returns true on success
-static bool sendhostent(SocketClient *c, struct hostent *hp) {
+static bool sendhostent(SocketClient* c, hostent* hp) {
bool success = true;
int i;
if (hp->h_name != nullptr) {
@@ -466,7 +545,7 @@
return success;
}
-static bool sendaddrinfo(SocketClient* c, struct addrinfo* ai) {
+static bool sendaddrinfo(SocketClient* c, addrinfo* ai) {
// struct addrinfo {
// int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */
// int ai_family; /* PF_xxx */
@@ -559,7 +638,7 @@
mNetContext.uid, mNetContext.flags);
}
- struct addrinfo* result = nullptr;
+ addrinfo* result = nullptr;
Stopwatch s;
maybeFixupNetContext(&mNetContext);
const uid_t uid = mClient->getUid();
@@ -583,7 +662,7 @@
mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, &rv, sizeof(rv));
} else {
bool success = !mClient->sendCode(ResponseCode::DnsProxyQueryResult);
- struct addrinfo* ai = result;
+ addrinfo* ai = result;
while (ai && success) {
success = sendBE32(mClient, 1) && sendaddrinfo(mClient, ai);
ai = ai->ai_next;
@@ -593,49 +672,17 @@
ALOGW("Error writing DNS result to client");
}
}
- std::vector<String16> ip_addrs;
- int total_ip_addr_count = 0;
- if (result) {
- if (mNetdEventListener != nullptr
- && mReportingLevel == INetdEventListener::REPORTING_LEVEL_FULL) {
- for (addrinfo* ai = result; ai; ai = ai->ai_next) {
- sockaddr* ai_addr = ai->ai_addr;
- if (ai_addr) {
- addIpAddrWithinLimit(&ip_addrs, ai_addr, ai->ai_addrlen);
- total_ip_addr_count++;
- }
- }
- }
- freeaddrinfo(result);
- }
+ std::vector<std::string> ip_addrs;
+ const int total_ip_addr_count = extractGetaddrinfoAnswers(result, &ip_addrs);
+ reportDnsInfoAll(mReportingLevel, INetdEventListener::EVENT_GETADDRINFO, mNetContext, latencyMs,
+ rv, mHost, ip_addrs, total_ip_addr_count);
+ freeaddrinfo(result);
mClient->decRef();
- if (mNetdEventListener != nullptr) {
- switch (mReportingLevel) {
- case INetdEventListener::REPORTING_LEVEL_NONE:
- // Skip reporting.
- break;
- case INetdEventListener::REPORTING_LEVEL_METRICS:
- // Metrics reporting is on. Send metrics.
- mNetdEventListener->onDnsEvent(mNetContext.dns_netid,
- INetdEventListener::EVENT_GETADDRINFO, rv,
- latencyMs, String16(""), {}, -1, -1);
- break;
- case INetdEventListener::REPORTING_LEVEL_FULL:
- // Full event info reporting is on. Send full info.
- mNetdEventListener->onDnsEvent(mNetContext.dns_netid,
- INetdEventListener::EVENT_GETADDRINFO, rv,
- latencyMs, String16(mHost), ip_addrs,
- total_ip_addr_count, mNetContext.uid);
- break;
- }
- } else {
- ALOGW("Netd event listener is not available; skipping.");
- }
}
namespace {
-void addIpAddrWithinLimit(std::vector<android::String16>* ip_addrs, const sockaddr* addr,
+void addIpAddrWithinLimit(std::vector<std::string>* ip_addrs, const sockaddr* addr,
socklen_t addrlen) {
// ipAddresses array is limited to first INetdEventListener::DNS_REPORTED_IP_ADDRESSES_LIMIT
// addresses for A and AAAA. Total count of addresses is provided, to be able to tell whether
@@ -643,7 +690,7 @@
if (ip_addrs->size() < INetdEventListener::DNS_REPORTED_IP_ADDRESSES_LIMIT) {
char ip_addr[INET6_ADDRSTRLEN];
if (getnameinfo(addr, addrlen, ip_addr, sizeof(ip_addr), nullptr, 0, NI_NUMERICHOST) == 0) {
- ip_addrs->push_back(String16(ip_addr));
+ ip_addrs->push_back(std::string(ip_addr));
}
}
}
@@ -682,7 +729,7 @@
service = strdup(service);
}
- struct addrinfo* hints = nullptr;
+ addrinfo* hints = nullptr;
int ai_flags = strtol(argv[3], nullptr, 10);
int ai_family = strtol(argv[4], nullptr, 10);
int ai_socktype = strtol(argv[5], nullptr, 10);
@@ -699,7 +746,7 @@
if (ai_flags != -1 || ai_family != -1 ||
ai_socktype != -1 || ai_protocol != -1) {
- hints = (struct addrinfo*) calloc(1, sizeof(struct addrinfo));
+ hints = (addrinfo*) calloc(1, sizeof(addrinfo));
hints->ai_flags = ai_flags;
hints->ai_family = ai_family;
hints->ai_socktype = ai_socktype;
@@ -717,9 +764,8 @@
const int metricsLevel = mDnsProxyListener->mEventReporter->getMetricsReportingLevel();
- DnsProxyListener::GetAddrInfoHandler* handler =
- new DnsProxyListener::GetAddrInfoHandler(cli, name, service, hints, netcontext,
- metricsLevel, mDnsProxyListener->mEventReporter->getNetdEventListener());
+ DnsProxyListener::GetAddrInfoHandler* handler = new DnsProxyListener::GetAddrInfoHandler(
+ cli, name, service, hints, netcontext, metricsLevel);
tryThreadOrError(cli, handler);
return 0;
}
@@ -754,22 +800,16 @@
}
const int metricsLevel = mDnsProxyListener->mEventReporter->getMetricsReportingLevel();
- DnsProxyListener::ResNSendHandler* handler = new DnsProxyListener::ResNSendHandler(
- cli, argv[1], netcontext, metricsLevel,
- mDnsProxyListener->mEventReporter->getNetdEventListener());
+ DnsProxyListener::ResNSendHandler* handler =
+ new DnsProxyListener::ResNSendHandler(cli, argv[1], netcontext, metricsLevel);
tryThreadOrError(cli, handler);
return 0;
}
-DnsProxyListener::ResNSendHandler::ResNSendHandler(
- SocketClient* c, std::string msg, const android_net_context& netcontext,
- const int reportingLevel,
- const android::sp<android::net::metrics::INetdEventListener>& netdEventListener)
- : mClient(c),
- mMsg(std::move(msg)),
- mNetContext(netcontext),
- mReportingLevel(reportingLevel),
- mNetdEventListener(netdEventListener) {}
+DnsProxyListener::ResNSendHandler::ResNSendHandler(SocketClient* c, std::string msg,
+ const android_net_context& netcontext,
+ const int reportingLevel)
+ : mClient(c), mMsg(std::move(msg)), mNetContext(netcontext), mReportingLevel(reportingLevel) {}
DnsProxyListener::ResNSendHandler::~ResNSendHandler() {
mClient->decRef();
@@ -826,6 +866,10 @@
// Fail, send -errno
if (nsendAns < 0) {
sendBE32(mClient, nsendAns);
+ if (rr_type == ns_t_a || rr_type == ns_t_aaaa) {
+ reportDnsInfoAll(mReportingLevel, INetdEventListener::EVENT_RES_NSEND, mNetContext,
+ latencyMs, resNSendToAiError(nsendAns, arcode), rr_name);
+ }
return;
}
@@ -841,32 +885,13 @@
return;
}
- // Parse result for statistics
- if (mNetdEventListener != nullptr) {
- // TODO: Enable this when we have a INetdEventListener::EVENT_RES_NSEND constant
- if (0) {
- switch (mReportingLevel) {
- case INetdEventListener::REPORTING_LEVEL_NONE:
- // Reporting is off.
- break;
- case INetdEventListener::REPORTING_LEVEL_METRICS:
- // Metrics reporting is on. Send metrics.
- mNetdEventListener->onDnsEvent(
- mNetContext.dns_netid, INetdEventListener::EVENT_GETHOSTBYNAME,
- nsendAns > 0 ? 0 : nsendAns, latencyMs, String16(""), {}, -1, -1);
- break;
- case INetdEventListener::REPORTING_LEVEL_FULL:
- // Full event info reporting is on. Send full info.
- std::vector<String16> ip_addrs;
- int total_ip_addr_count =
- extractIpAddressAnswers(ansBuf.data(), nsendAns, rr_type, &ip_addrs);
- mNetdEventListener->onDnsEvent(
- mNetContext.dns_netid, INetdEventListener::EVENT_GETHOSTBYNAME,
- nsendAns > 0 ? 0 : nsendAns, latencyMs, String16(rr_name.c_str()),
- ip_addrs, total_ip_addr_count, uid);
- break;
- }
- }
+ if (rr_type == ns_t_a || rr_type == ns_t_aaaa) {
+ std::vector<std::string> ip_addrs;
+ const int total_ip_addr_count =
+ extractResNsendAnswers((uint8_t*) ansBuf.data(), nsendAns, rr_type, &ip_addrs);
+ reportDnsInfoAll(mReportingLevel, INetdEventListener::EVENT_RES_NSEND, mNetContext,
+ latencyMs, resNSendToAiError(nsendAns, arcode), rr_name, ip_addrs,
+ total_ip_addr_count);
}
}
@@ -912,22 +937,15 @@
const int metricsLevel = mDnsProxyListener->mEventReporter->getMetricsReportingLevel();
DnsProxyListener::GetHostByNameHandler* handler =
- new DnsProxyListener::GetHostByNameHandler(cli, name, af, netcontext, metricsLevel,
- mDnsProxyListener->mEventReporter->getNetdEventListener());
+ new DnsProxyListener::GetHostByNameHandler(cli, name, af, netcontext, metricsLevel);
tryThreadOrError(cli, handler);
return 0;
}
DnsProxyListener::GetHostByNameHandler::GetHostByNameHandler(SocketClient* c, char* name, int af,
- const android_net_context& netcontext, const int metricsLevel,
- const android::sp<android::net::metrics::INetdEventListener>& netdEventListener)
- : mClient(c),
- mName(name),
- mAf(af),
- mNetContext(netcontext),
- mReportingLevel(metricsLevel),
- mNetdEventListener(netdEventListener) {
-}
+ const android_net_context& netcontext,
+ const int metricsLevel)
+ : mClient(c), mName(name), mAf(af), mNetContext(netcontext), mReportingLevel(metricsLevel) {}
DnsProxyListener::GetHostByNameHandler::~GetHostByNameHandler() {
free(mName);
@@ -976,7 +994,7 @@
Stopwatch s;
maybeFixupNetContext(&mNetContext);
const uid_t uid = mClient->getUid();
- struct hostent* hp = nullptr;
+ hostent* hp = nullptr;
int32_t rv = 0;
if (queryLimiter.start(uid)) {
rv = RESOLV_STUB.android_gethostbynamefornetcontext(mName, mAf, &mNetContext, &hp);
@@ -1009,46 +1027,10 @@
ALOGW("GetHostByNameHandler: Error writing DNS result to client");
}
- if (mNetdEventListener != nullptr) {
- std::vector<String16> ip_addrs;
- int total_ip_addr_count = 0;
- if (mReportingLevel == INetdEventListener::REPORTING_LEVEL_FULL) {
- if (hp != nullptr && hp->h_addrtype == AF_INET) {
- in_addr** list = (in_addr**) hp->h_addr_list;
- for (int i = 0; list[i] != nullptr; i++) {
- sockaddr_in sin = { .sin_family = AF_INET, .sin_addr = *list[i] };
- addIpAddrWithinLimit(&ip_addrs, (sockaddr*) &sin, sizeof(sin));
- total_ip_addr_count++;
- }
- } else if (hp != nullptr && hp->h_addrtype == AF_INET6) {
- in6_addr** list = (in6_addr**) hp->h_addr_list;
- for (int i = 0; list[i] != nullptr; i++) {
- sockaddr_in6 sin6 = { .sin6_family = AF_INET6, .sin6_addr = *list[i] };
- addIpAddrWithinLimit(&ip_addrs, (sockaddr*) &sin6, sizeof(sin6));
- total_ip_addr_count++;
- }
- }
- }
- switch (mReportingLevel) {
- case INetdEventListener::REPORTING_LEVEL_NONE:
- // Reporting is off.
- break;
- case INetdEventListener::REPORTING_LEVEL_METRICS:
- // Metrics reporting is on. Send metrics.
- mNetdEventListener->onDnsEvent(mNetContext.dns_netid,
- INetdEventListener::EVENT_GETHOSTBYNAME,
- rv, latencyMs, String16(""), {}, -1, -1);
- break;
- case INetdEventListener::REPORTING_LEVEL_FULL:
- // Full event info reporting is on. Send full info.
- mNetdEventListener->onDnsEvent(mNetContext.dns_netid,
- INetdEventListener::EVENT_GETHOSTBYNAME,
- rv, latencyMs, String16(mName), ip_addrs,
- total_ip_addr_count, uid);
- break;
- }
- }
-
+ std::vector<std::string> ip_addrs;
+ const int total_ip_addr_count = extractGethostbynameAnswers(hp, &ip_addrs);
+ reportDnsInfoAll(mReportingLevel, INetdEventListener::EVENT_GETHOSTBYNAME, mNetContext,
+ latencyMs, rv, mName, ip_addrs, total_ip_addr_count);
mClient->decRef();
}
@@ -1081,7 +1063,7 @@
unsigned netId = strtoul(argv[4], nullptr, 10);
const bool useLocalNameservers = checkAndClearUseLocalNameserversFlag(&netId);
- void* addr = malloc(sizeof(struct in6_addr));
+ void* addr = malloc(sizeof(in6_addr));
errno = 0;
int result = inet_pton(addrFamily, addrStr, addr);
if (result <= 0) {
@@ -1151,8 +1133,8 @@
if (queryLimiter.start(uid)) {
// Remove NAT64 prefix and do reverse DNS query
struct in_addr v4addr = {.s_addr = v6addr.s6_addr32[3]};
- *hpp = RESOLV_STUB.android_gethostbyaddrfornetcontext(&v4addr, sizeof(v4addr), AF_INET,
- &mNetContext);
+ RESOLV_STUB.android_gethostbyaddrfornetcontext(&v4addr, sizeof(v4addr), AF_INET,
+ &mNetContext, hpp);
queryLimiter.finish(uid);
if (*hpp) {
// Replace IPv4 address with original queried IPv6 address in place. The space has
@@ -1175,22 +1157,23 @@
maybeFixupNetContext(&mNetContext);
const uid_t uid = mClient->getUid();
- struct hostent* hp = nullptr;
+ hostent* hp = nullptr;
+ int32_t rv = 0;
if (queryLimiter.start(uid)) {
- hp = RESOLV_STUB.android_gethostbyaddrfornetcontext(mAddress, mAddressLen, mAddressFamily,
- &mNetContext);
+ rv = RESOLV_STUB.android_gethostbyaddrfornetcontext(mAddress, mAddressLen, mAddressFamily,
+ &mNetContext, &hp);
queryLimiter.finish(uid);
} else {
+ rv = EAI_MEMORY;
ALOGE("gethostbyaddr: from UID %d, max concurrent queries reached", uid);
}
doDns64ReverseLookup(&hp);
if (DBG) {
- ALOGD("GetHostByAddrHandler::run gethostbyaddr errno: %s hp->h_name = %s, name_len = %zu",
- hp ? "success" : strerror(errno),
- (hp && hp->h_name) ? hp->h_name : "null",
- (hp && hp->h_name) ? strlen(hp->h_name) + 1 : 0);
+ ALOGD("GetHostByAddrHandler::run gethostbyaddr result: %s hp->h_name = %s, name_len = %zu",
+ hp ? "success" : gai_strerror(rv), (hp && hp->h_name) ? hp->h_name : "null",
+ (hp && hp->h_name) ? strlen(hp->h_name) + 1 : 0);
}
bool success = true;
diff --git a/server/DnsProxyListener.h b/server/DnsProxyListener.h
index e3fcd88..985ed62 100644
--- a/server/DnsProxyListener.h
+++ b/server/DnsProxyListener.h
@@ -22,8 +22,7 @@
#include "EventReporter.h"
#include "NetdCommand.h"
-#include "android/net/metrics/INetdEventListener.h"
-#include "netd_resolv/resolv.h" // struct android_net_context
+#include "netd_resolv/resolv.h" // android_net_context
namespace android {
namespace net {
@@ -51,30 +50,25 @@
DnsProxyListener* mDnsProxyListener;
};
+ /* ------ getaddrinfo ------*/
class GetAddrInfoHandler {
public:
// Note: All of host, service, and hints may be NULL
- GetAddrInfoHandler(SocketClient *c,
- char* host,
- char* service,
- struct addrinfo* hints,
- const struct android_net_context& netcontext,
- const int reportingLevel,
- const android::sp<android::net::metrics::INetdEventListener>& listener);
+ GetAddrInfoHandler(SocketClient* c, char* host, char* service, addrinfo* hints,
+ const android_net_context& netcontext, int reportingLevel);
~GetAddrInfoHandler();
void run();
private:
- void doDns64Synthesis(int32_t* rv, struct addrinfo** res);
+ void doDns64Synthesis(int32_t* rv, addrinfo** res);
SocketClient* mClient; // ref counted
char* mHost; // owned. TODO: convert to std::string.
char* mService; // owned. TODO: convert to std::string.
- struct addrinfo* mHints; // owned
- struct android_net_context mNetContext;
+ addrinfo* mHints; // owned
+ android_net_context mNetContext;
const int mReportingLevel;
- android::sp<android::net::metrics::INetdEventListener> mNetdEventListener;
};
/* ------ gethostbyname ------*/
@@ -90,25 +84,20 @@
class GetHostByNameHandler {
public:
- GetHostByNameHandler(SocketClient *c,
- char *name,
- int af,
- const android_net_context& netcontext,
- int reportingLevel,
- const android::sp<android::net::metrics::INetdEventListener>& listener);
+ GetHostByNameHandler(SocketClient* c, char* name, int af,
+ const android_net_context& netcontext, int reportingLevel);
~GetHostByNameHandler();
void run();
private:
- void doDns64Synthesis(int32_t* rv, struct hostent** hpp);
+ void doDns64Synthesis(int32_t* rv, hostent** hpp);
SocketClient* mClient; //ref counted
char* mName; // owned. TODO: convert to std::string.
int mAf;
android_net_context mNetContext;
const int mReportingLevel;
- android::sp<android::net::metrics::INetdEventListener> mNetdEventListener;
};
/* ------ gethostbyaddr ------*/
@@ -134,7 +123,7 @@
void run();
private:
- void doDns64ReverseLookup(struct hostent** hpp);
+ void doDns64ReverseLookup(hostent** hpp);
SocketClient* mClient; // ref counted
void* mAddress; // address to lookup; owned
@@ -157,8 +146,7 @@
class ResNSendHandler {
public:
ResNSendHandler(SocketClient* c, std::string msg, const android_net_context& netcontext,
- const int reportingLevel,
- const android::sp<android::net::metrics::INetdEventListener>& listener);
+ int reportingLevel);
~ResNSendHandler();
void run();
@@ -166,9 +154,8 @@
private:
SocketClient* mClient; // ref counted
std::string mMsg;
- struct android_net_context mNetContext;
+ android_net_context mNetContext;
const int mReportingLevel;
- android::sp<android::net::metrics::INetdEventListener> mNetdEventListener;
};
};
diff --git a/server/ResolverController.cpp b/server/ResolverController.cpp
index a0dc3de..39a0b83 100644
--- a/server/ResolverController.cpp
+++ b/server/ResolverController.cpp
@@ -321,7 +321,7 @@
ExternalPrivateDnsStatus privateDnsStatus = {PrivateDnsMode::OFF, 0, {}};
RESOLV_STUB.resolv_get_private_dns_status_for_net(netId, &privateDnsStatus);
- for (unsigned i = 0; i < privateDnsStatus.numServers; i++) {
+ for (int i = 0; i < privateDnsStatus.numServers; i++) {
std::string tlsServer_str = addrToString(&(privateDnsStatus.serverStatus[i].ss));
tlsServers->push_back(std::move(tlsServer_str));
}
@@ -418,7 +418,7 @@
} else {
dw.println("Private DNS configuration (%u entries)", privateDnsStatus.numServers);
dw.incIndent();
- for (unsigned i = 0; i < privateDnsStatus.numServers; i++) {
+ for (int i = 0; i < privateDnsStatus.numServers; i++) {
dw.println("%s name{%s} status{%s}",
addrToString(&(privateDnsStatus.serverStatus[i].ss)).c_str(),
privateDnsStatus.serverStatus[i].hostname,
diff --git a/server/TetherController.cpp b/server/TetherController.cpp
index 62dcbbf..7d7be58 100644
--- a/server/TetherController.cpp
+++ b/server/TetherController.cpp
@@ -325,11 +325,10 @@
// dnsmasq can't parse commands larger than this due to the fixed-size buffer
// in check_android_listeners(). The receiving buffer is 1024 bytes long, but
// dnsmasq reads up to 1023 bytes.
-#define MAX_CMD_SIZE 1023
+const size_t MAX_CMD_SIZE = 1023;
+// TODO: convert callers to the overload taking a vector<string>
int TetherController::setDnsForwarders(unsigned netId, char **servers, int numServers) {
- int i;
-
Fwmark fwmark;
fwmark.netId = netId;
fwmark.explicitlySelected = true;
@@ -339,7 +338,7 @@
std::string daemonCmd = StringPrintf("update_dns%s0x%x", SEPARATOR, fwmark.intValue);
mDnsForwarders.clear();
- for (i = 0; i < numServers; i++) {
+ for (int i = 0; i < numServers; i++) {
ALOGD("setDnsForwarders(0x%x %d = '%s')", fwmark.intValue, i, servers[i]);
addrinfo *res, hints = { .ai_flags = AI_NUMERICHOST };
diff --git a/server/TrafficController.cpp b/server/TrafficController.cpp
index b6d1320..b921c9a 100644
--- a/server/TrafficController.cpp
+++ b/server/TrafficController.cpp
@@ -200,6 +200,34 @@
return netdutils::status::ok;
}
+static Status attachProgramToCgroup(const char* programPath, const int cgroupFd,
+ bpf_attach_type type) {
+ unique_fd cgroupProg(bpfFdGet(programPath, 0));
+ if (cgroupProg == -1) {
+ int ret = errno;
+ ALOGE("Failed to get program from %s: %s", programPath, strerror(ret));
+ return statusFromErrno(ret, "cgroup program get failed");
+ }
+ if (android::bpf::attachProgram(type, cgroupProg, cgroupFd)) {
+ int ret = errno;
+ ALOGE("Program from %s attach failed: %s", programPath, strerror(ret));
+ return statusFromErrno(ret, "program attach failed");
+ }
+ return netdutils::status::ok;
+}
+
+static Status initPrograms() {
+ unique_fd cg_fd(open(CGROUP_ROOT_PATH, O_DIRECTORY | O_RDONLY | O_CLOEXEC));
+ if (cg_fd == -1) {
+ int ret = errno;
+ ALOGE("Failed to open the cgroup directory: %s", strerror(ret));
+ return statusFromErrno(ret, "Open the cgroup directory failed");
+ }
+ RETURN_IF_NOT_OK(attachProgramToCgroup(BPF_EGRESS_PROG_PATH, cg_fd, BPF_CGROUP_INET_EGRESS));
+ RETURN_IF_NOT_OK(attachProgramToCgroup(BPF_INGRESS_PROG_PATH, cg_fd, BPF_CGROUP_INET_INGRESS));
+ return netdutils::status::ok;
+}
+
Status TrafficController::start() {
if (!ebpfSupported) {
@@ -216,6 +244,8 @@
RETURN_IF_NOT_OK(initMaps());
+ RETURN_IF_NOT_OK(initPrograms());
+
// Fetch the list of currently-existing interfaces. At this point NetlinkHandler is
// already running, so it will call addInterface() when any new interface appears.
std::map<std::string, uint32_t> ifacePairs;
@@ -257,19 +287,6 @@
};
expectOk(mSkDestroyListener->subscribe(kSockDiagDoneMsgType, rxDoneHandler));
- int* status = nullptr;
-
- std::vector<const char*> prog_args{
- "/system/bin/bpfloader",
- };
-
- prog_args.push_back(nullptr);
- int ret = android_fork_execvp(prog_args.size(), (char**) prog_args.data(), status, false, true);
- if (ret) {
- ret = errno;
- ALOGE("failed to execute %s: %s", prog_args[0], strerror(errno));
- return statusFromErrno(ret, "run bpf loader failed");
- }
return netdutils::status::ok;
}
diff --git a/server/binder/android/net/metrics/INetdEventListener.aidl b/server/binder/android/net/metrics/INetdEventListener.aidl
index 95b07ea..ef1b2cb 100644
--- a/server/binder/android/net/metrics/INetdEventListener.aidl
+++ b/server/binder/android/net/metrics/INetdEventListener.aidl
@@ -24,6 +24,8 @@
oneway interface INetdEventListener {
const int EVENT_GETADDRINFO = 1;
const int EVENT_GETHOSTBYNAME = 2;
+ const int EVENT_GETHOSTBYADDR = 3;
+ const int EVENT_RES_NSEND = 4;
const int REPORTING_LEVEL_NONE = 0;
const int REPORTING_LEVEL_METRICS = 1;
@@ -46,8 +48,9 @@
* of ipAddresses if there were too many addresses to log.
* @param uid the UID of the application that performed the query.
*/
- void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs, String hostname,
- in String[] ipAddresses, int ipAddressesCount, int uid);
+ void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs,
+ @utf8InCpp String hostname, in @utf8InCpp String[] ipAddresses,
+ int ipAddressesCount, int uid);
/**
* Represents a private DNS validation success or failure.
diff --git a/server/main.cpp b/server/main.cpp
index b9ff33f..4b06ada 100644
--- a/server/main.cpp
+++ b/server/main.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <chrono>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
@@ -31,6 +32,7 @@
#include "log/log.h"
+#include <android-base/properties.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
@@ -90,6 +92,12 @@
// Before we start any threads, populate the resolver stub pointers.
resolv_stub_init();
+ // Make sure BPF programs are loaded before doing anything
+ while (!android::base::WaitForProperty("bpf.progs_loaded", "1",
+ std::chrono::seconds(5))) {
+ ALOGD("netd waited 5s for bpf.progs_loaded, still waiting...");
+ }
+
NetlinkManager *nm = NetlinkManager::Instance();
if (nm == nullptr) {
ALOGE("Unable to create NetlinkManager");
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp
index c4029f0..d7c449e 100644
--- a/tests/binder_test.cpp
+++ b/tests/binder_test.cpp
@@ -940,7 +940,6 @@
for (size_t i = 0; i < std::size(kTestData); i++) {
const auto& td = kTestData[i];
-
const binder::Status status =
mNetd->setProcSysNet(td.ipversion, td.which, td.ifname, td.parameter, td.value);