Loading include/netd_resolv/resolv.h +3 −3 Original line number Diff line number Diff line Loading @@ -104,6 +104,6 @@ LIBNETD_RESOLV_PUBLIC bool resolv_init(const ResolverNetdCallbacks* callbacks); // Function that performs RDNS in local cache. The |domain_name_size| is the size of domain_name // buffer, which is recommended to NS_MAXDNAME. Function return false if hostname not found or // domain_name_size > NS_MAXDNAME. LIBNETD_RESOLV_PUBLIC bool resolv_gethostbyaddr_from_local_cache(unsigned netId, char domain_name[], unsigned domain_name_size, char* ip_address); LIBNETD_RESOLV_PUBLIC bool resolv_gethostbyaddr_from_cache(unsigned netId, char domain_name[], size_t domain_name_size, const char* ip_address, int af); include/netd_resolv/resolv_stub.h +3 −2 Original line number Diff line number Diff line Loading @@ -38,8 +38,9 @@ extern struct ResolvStub { bool (*resolv_init)(const ResolverNetdCallbacks& callbacks); bool (*resolv_gethostbyaddr_from_local_cache)(unsigned netId, char domain_name[], unsigned domain_name_size, char* ip_address); bool (*resolv_gethostbyaddr_from_cache)(unsigned netId, char domain_name[], size_t domain_name_size, const char* ip_address, int af); } RESOLV_STUB; int resolv_stub_init(); Loading libnetd_resolv.map.txt +1 −1 Original line number Diff line number Diff line Loading @@ -22,7 +22,7 @@ LIBNETD_RESOLV { global: resolv_has_nameservers; resolv_init; resolv_gethostbyaddr_from_local_cache; resolv_gethostbyaddr_from_cache; local: *; }; res_cache.cpp +31 −28 Original line number Diff line number Diff line Loading @@ -1293,10 +1293,16 @@ int resolv_cache_add(unsigned netid, const void* query, int querylen, const void return 0; } bool resolv_gethostbyaddr_from_local_cache(unsigned netid, char domain_name[], unsigned domain_name_size, char* ip_address) { bool resolv_gethostbyaddr_from_cache(unsigned netid, char domain_name[], size_t domain_name_size, const char* ip_address, int af) { if (domain_name_size > NS_MAXDNAME) { LOG(ERROR) << __func__ << ": invalid domain_name_size " << domain_name_size; LOG(WARNING) << __func__ << ": invalid domain_name_size " << domain_name_size; return false; } else if (ip_address == nullptr || ip_address[0] == '\0') { LOG(WARNING) << __func__ << ": invalid ip_address"; return false; } else if (af != AF_INET && af != AF_INET6) { LOG(WARNING) << __func__ << ": unsupported AF"; return false; } Loading @@ -1305,14 +1311,11 @@ bool resolv_gethostbyaddr_from_local_cache(unsigned netid, char domain_name[], ns_rr rr; ns_msg handle; int query_count; ns_rr rr_query; // For ntop. char* resolved_ip = nullptr; char buf4[INET_ADDRSTRLEN]; char buf6[INET6_ADDRSTRLEN]; struct sockaddr_in sa; struct sockaddr_in6 sa6; char* addr_buf = nullptr; std::lock_guard guard(cache_mutex); Loading Loading @@ -1340,20 +1343,21 @@ bool resolv_gethostbyaddr_from_local_cache(unsigned netid, char domain_name[], continue; } resolved_ip = nullptr; if (ns_rr_type(rr) == ns_t_a) { inet_ntop(AF_INET, ns_rr_rdata(rr), buf4, sizeof(buf4)); resolved_ip = buf4; } else if (ns_rr_type(rr) == ns_t_aaaa) { inet_ntop(AF_INET6, ns_rr_rdata(rr), buf6, sizeof(buf6)); resolved_ip = buf6; if (ns_rr_type(rr) == ns_t_a && af == AF_INET) { addr_buf = (char*)&(sa.sin_addr); } else if (ns_rr_type(rr) == ns_t_aaaa && af == AF_INET6) { addr_buf = (char*)&(sa6.sin6_addr); } else { continue; } if ((resolved_ip != nullptr) && (resolved_ip[0] != '\0')) { if (strcmp(resolved_ip, ip_address) == 0) { query_count = ns_msg_count(handle, ns_s_qd); if (inet_pton(af, ip_address, addr_buf) != 1) { LOG(WARNING) << __func__ << ": inet_pton() fail"; return false; } if (memcmp(ns_rr_rdata(rr), addr_buf, ns_rr_rdlen(rr)) == 0) { int query_count = ns_msg_count(handle, ns_s_qd); for (int i = 0; i < query_count; i++) { memset(&rr_query, 0, sizeof(rr_query)); if (ns_parserr(&handle, ns_s_qd, i, &rr_query)) { Loading @@ -1367,7 +1371,6 @@ bool resolv_gethostbyaddr_from_local_cache(unsigned netid, char domain_name[], } } } } return false; } Loading resolv_cache_unit_test.cpp +80 −1 Original line number Diff line number Diff line Loading @@ -84,7 +84,7 @@ std::vector<char> makeAnswer(const std::vector<char>& query, const char* rdata_s .rclass = question.qclass, .ttl = ttl, }; test::DNSResponder::fillAnswerRdata(rdata_str, record); test::DNSResponder::fillRdata(rdata_str, record); header.answers.push_back(std::move(record)); } Loading Loading @@ -708,6 +708,85 @@ TEST_F(ResolvCacheTest, GetStats) { expectCacheStats("GetStats", TEST_NETID, cacheStats); } TEST_F(ResolvCacheTest, GetHostByAddrFromCache_InvalidArgs) { char domain_name[NS_MAXDNAME] = {}; const char query_v4[] = "1.2.3.5"; // invalid buffer size EXPECT_FALSE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME + 1, nullptr, AF_INET)); EXPECT_STREQ("", domain_name); // invalid query EXPECT_FALSE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, nullptr, AF_INET)); EXPECT_STREQ("", domain_name); // unsupported AF EXPECT_FALSE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v4, AF_UNSPEC)); EXPECT_STREQ("", domain_name); } TEST_F(ResolvCacheTest, GetHostByAddrFromCache) { char domain_name[NS_MAXDNAME] = {}; const char query_v4[] = "1.2.3.5"; const char query_v6[] = "2001:db8::102:304"; const char query_v6_unabbreviated[] = "2001:0db8:0000:0000:0000:0000:0102:0304"; const char query_v6_mixed[] = "2001:db8::1.2.3.4"; const char answer[] = "existent.in.cache"; // cache does not exist EXPECT_FALSE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v4, AF_INET)); EXPECT_STREQ("", domain_name); // cache is empty EXPECT_EQ(0, cacheCreate(TEST_NETID)); EXPECT_FALSE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v4, AF_INET)); EXPECT_STREQ("", domain_name); // no v4 match in cache CacheEntry ce = makeCacheEntry(QUERY, "any.data", ns_c_in, ns_t_a, "1.2.3.4"); EXPECT_EQ(0, cacheAdd(TEST_NETID, ce)); EXPECT_FALSE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v4, AF_INET)); EXPECT_STREQ("", domain_name); // v4 match ce = makeCacheEntry(QUERY, answer, ns_c_in, ns_t_a, query_v4); EXPECT_EQ(0, cacheAdd(TEST_NETID, ce)); EXPECT_TRUE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v4, AF_INET)); EXPECT_STREQ(answer, domain_name); // no v6 match in cache memset(domain_name, 0, NS_MAXDNAME); EXPECT_FALSE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v6, AF_INET6)); EXPECT_STREQ("", domain_name); // v6 match ce = makeCacheEntry(QUERY, answer, ns_c_in, ns_t_aaaa, query_v6); EXPECT_EQ(0, cacheAdd(TEST_NETID, ce)); EXPECT_TRUE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v6, AF_INET6)); EXPECT_STREQ(answer, domain_name); // v6 match with unabbreviated address format memset(domain_name, 0, NS_MAXDNAME); EXPECT_TRUE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v6_unabbreviated, AF_INET6)); EXPECT_STREQ(answer, domain_name); // v6 with mixed address format memset(domain_name, 0, NS_MAXDNAME); EXPECT_TRUE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v6_mixed, AF_INET6)); EXPECT_STREQ(answer, domain_name); } namespace { constexpr int EAI_OK = 0; Loading Loading
include/netd_resolv/resolv.h +3 −3 Original line number Diff line number Diff line Loading @@ -104,6 +104,6 @@ LIBNETD_RESOLV_PUBLIC bool resolv_init(const ResolverNetdCallbacks* callbacks); // Function that performs RDNS in local cache. The |domain_name_size| is the size of domain_name // buffer, which is recommended to NS_MAXDNAME. Function return false if hostname not found or // domain_name_size > NS_MAXDNAME. LIBNETD_RESOLV_PUBLIC bool resolv_gethostbyaddr_from_local_cache(unsigned netId, char domain_name[], unsigned domain_name_size, char* ip_address); LIBNETD_RESOLV_PUBLIC bool resolv_gethostbyaddr_from_cache(unsigned netId, char domain_name[], size_t domain_name_size, const char* ip_address, int af);
include/netd_resolv/resolv_stub.h +3 −2 Original line number Diff line number Diff line Loading @@ -38,8 +38,9 @@ extern struct ResolvStub { bool (*resolv_init)(const ResolverNetdCallbacks& callbacks); bool (*resolv_gethostbyaddr_from_local_cache)(unsigned netId, char domain_name[], unsigned domain_name_size, char* ip_address); bool (*resolv_gethostbyaddr_from_cache)(unsigned netId, char domain_name[], size_t domain_name_size, const char* ip_address, int af); } RESOLV_STUB; int resolv_stub_init(); Loading
libnetd_resolv.map.txt +1 −1 Original line number Diff line number Diff line Loading @@ -22,7 +22,7 @@ LIBNETD_RESOLV { global: resolv_has_nameservers; resolv_init; resolv_gethostbyaddr_from_local_cache; resolv_gethostbyaddr_from_cache; local: *; };
res_cache.cpp +31 −28 Original line number Diff line number Diff line Loading @@ -1293,10 +1293,16 @@ int resolv_cache_add(unsigned netid, const void* query, int querylen, const void return 0; } bool resolv_gethostbyaddr_from_local_cache(unsigned netid, char domain_name[], unsigned domain_name_size, char* ip_address) { bool resolv_gethostbyaddr_from_cache(unsigned netid, char domain_name[], size_t domain_name_size, const char* ip_address, int af) { if (domain_name_size > NS_MAXDNAME) { LOG(ERROR) << __func__ << ": invalid domain_name_size " << domain_name_size; LOG(WARNING) << __func__ << ": invalid domain_name_size " << domain_name_size; return false; } else if (ip_address == nullptr || ip_address[0] == '\0') { LOG(WARNING) << __func__ << ": invalid ip_address"; return false; } else if (af != AF_INET && af != AF_INET6) { LOG(WARNING) << __func__ << ": unsupported AF"; return false; } Loading @@ -1305,14 +1311,11 @@ bool resolv_gethostbyaddr_from_local_cache(unsigned netid, char domain_name[], ns_rr rr; ns_msg handle; int query_count; ns_rr rr_query; // For ntop. char* resolved_ip = nullptr; char buf4[INET_ADDRSTRLEN]; char buf6[INET6_ADDRSTRLEN]; struct sockaddr_in sa; struct sockaddr_in6 sa6; char* addr_buf = nullptr; std::lock_guard guard(cache_mutex); Loading Loading @@ -1340,20 +1343,21 @@ bool resolv_gethostbyaddr_from_local_cache(unsigned netid, char domain_name[], continue; } resolved_ip = nullptr; if (ns_rr_type(rr) == ns_t_a) { inet_ntop(AF_INET, ns_rr_rdata(rr), buf4, sizeof(buf4)); resolved_ip = buf4; } else if (ns_rr_type(rr) == ns_t_aaaa) { inet_ntop(AF_INET6, ns_rr_rdata(rr), buf6, sizeof(buf6)); resolved_ip = buf6; if (ns_rr_type(rr) == ns_t_a && af == AF_INET) { addr_buf = (char*)&(sa.sin_addr); } else if (ns_rr_type(rr) == ns_t_aaaa && af == AF_INET6) { addr_buf = (char*)&(sa6.sin6_addr); } else { continue; } if ((resolved_ip != nullptr) && (resolved_ip[0] != '\0')) { if (strcmp(resolved_ip, ip_address) == 0) { query_count = ns_msg_count(handle, ns_s_qd); if (inet_pton(af, ip_address, addr_buf) != 1) { LOG(WARNING) << __func__ << ": inet_pton() fail"; return false; } if (memcmp(ns_rr_rdata(rr), addr_buf, ns_rr_rdlen(rr)) == 0) { int query_count = ns_msg_count(handle, ns_s_qd); for (int i = 0; i < query_count; i++) { memset(&rr_query, 0, sizeof(rr_query)); if (ns_parserr(&handle, ns_s_qd, i, &rr_query)) { Loading @@ -1367,7 +1371,6 @@ bool resolv_gethostbyaddr_from_local_cache(unsigned netid, char domain_name[], } } } } return false; } Loading
resolv_cache_unit_test.cpp +80 −1 Original line number Diff line number Diff line Loading @@ -84,7 +84,7 @@ std::vector<char> makeAnswer(const std::vector<char>& query, const char* rdata_s .rclass = question.qclass, .ttl = ttl, }; test::DNSResponder::fillAnswerRdata(rdata_str, record); test::DNSResponder::fillRdata(rdata_str, record); header.answers.push_back(std::move(record)); } Loading Loading @@ -708,6 +708,85 @@ TEST_F(ResolvCacheTest, GetStats) { expectCacheStats("GetStats", TEST_NETID, cacheStats); } TEST_F(ResolvCacheTest, GetHostByAddrFromCache_InvalidArgs) { char domain_name[NS_MAXDNAME] = {}; const char query_v4[] = "1.2.3.5"; // invalid buffer size EXPECT_FALSE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME + 1, nullptr, AF_INET)); EXPECT_STREQ("", domain_name); // invalid query EXPECT_FALSE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, nullptr, AF_INET)); EXPECT_STREQ("", domain_name); // unsupported AF EXPECT_FALSE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v4, AF_UNSPEC)); EXPECT_STREQ("", domain_name); } TEST_F(ResolvCacheTest, GetHostByAddrFromCache) { char domain_name[NS_MAXDNAME] = {}; const char query_v4[] = "1.2.3.5"; const char query_v6[] = "2001:db8::102:304"; const char query_v6_unabbreviated[] = "2001:0db8:0000:0000:0000:0000:0102:0304"; const char query_v6_mixed[] = "2001:db8::1.2.3.4"; const char answer[] = "existent.in.cache"; // cache does not exist EXPECT_FALSE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v4, AF_INET)); EXPECT_STREQ("", domain_name); // cache is empty EXPECT_EQ(0, cacheCreate(TEST_NETID)); EXPECT_FALSE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v4, AF_INET)); EXPECT_STREQ("", domain_name); // no v4 match in cache CacheEntry ce = makeCacheEntry(QUERY, "any.data", ns_c_in, ns_t_a, "1.2.3.4"); EXPECT_EQ(0, cacheAdd(TEST_NETID, ce)); EXPECT_FALSE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v4, AF_INET)); EXPECT_STREQ("", domain_name); // v4 match ce = makeCacheEntry(QUERY, answer, ns_c_in, ns_t_a, query_v4); EXPECT_EQ(0, cacheAdd(TEST_NETID, ce)); EXPECT_TRUE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v4, AF_INET)); EXPECT_STREQ(answer, domain_name); // no v6 match in cache memset(domain_name, 0, NS_MAXDNAME); EXPECT_FALSE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v6, AF_INET6)); EXPECT_STREQ("", domain_name); // v6 match ce = makeCacheEntry(QUERY, answer, ns_c_in, ns_t_aaaa, query_v6); EXPECT_EQ(0, cacheAdd(TEST_NETID, ce)); EXPECT_TRUE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v6, AF_INET6)); EXPECT_STREQ(answer, domain_name); // v6 match with unabbreviated address format memset(domain_name, 0, NS_MAXDNAME); EXPECT_TRUE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v6_unabbreviated, AF_INET6)); EXPECT_STREQ(answer, domain_name); // v6 with mixed address format memset(domain_name, 0, NS_MAXDNAME); EXPECT_TRUE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v6_mixed, AF_INET6)); EXPECT_STREQ(answer, domain_name); } namespace { constexpr int EAI_OK = 0; Loading