blob: 26774de42272b14df75192f91db76db8887bf9f4 [file] [log] [blame]
Hungming Chenf9cd4eb2019-08-06 20:55:28 +09001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18#define LOG_TAG "resolv_gold_test"
19
Hungming Chenc6556622019-10-02 16:01:07 +080020#include <Fwmark.h>
21#include <android-base/chrono_utils.h>
Hungming Chen21c0f832019-09-20 18:38:47 +080022#include <android-base/file.h>
Hungming Chen7b6c23b2019-10-03 17:46:11 +080023#include <android-base/stringprintf.h>
Hungming Chenf9cd4eb2019-08-06 20:55:28 +090024#include <gmock/gmock-matchers.h>
Hungming Chen21c0f832019-09-20 18:38:47 +080025#include <google/protobuf/text_format.h>
Hungming Chenf9cd4eb2019-08-06 20:55:28 +090026#include <gtest/gtest.h>
27
Hungming Chenc6556622019-10-02 16:01:07 +080028#include "PrivateDnsConfiguration.h"
Hungming Chenf9cd4eb2019-08-06 20:55:28 +090029#include "dns_responder/dns_responder.h"
Hungming Chenc6556622019-10-02 16:01:07 +080030#include "dns_responder_client.h"
Hungming Chenf9cd4eb2019-08-06 20:55:28 +090031#include "getaddrinfo.h"
Hungming Chen21c0f832019-09-20 18:38:47 +080032#include "golddata.pb.h"
Hungming Chenf9cd4eb2019-08-06 20:55:28 +090033#include "resolv_cache.h"
34#include "resolv_test_utils.h"
Hungming Chenc6556622019-10-02 16:01:07 +080035#include "tests/dns_responder/dns_tls_certificate.h"
36#include "tests/dns_responder/dns_tls_frontend.h"
Hungming Chenf9cd4eb2019-08-06 20:55:28 +090037
Hungming Chen7b6c23b2019-10-03 17:46:11 +080038namespace android::net {
39
40using android::base::StringPrintf;
Hungming Chenf9cd4eb2019-08-06 20:55:28 +090041using android::netdutils::ScopedAddrinfo;
Hungming Chenc6556622019-10-02 16:01:07 +080042using std::chrono::milliseconds;
43
Hungming Chen7b6c23b2019-10-03 17:46:11 +080044enum class DnsProtocol { CLEARTEXT, TLS };
45
Hungming Chenc6556622019-10-02 16:01:07 +080046const std::string kTestDataPath = android::base::GetExecutableDirectory() + "/testdata/";
Hungming Chen2a56a622019-09-24 17:01:01 +080047const std::vector<std::string> kGoldFilesGetAddrInfo = {
48 "getaddrinfo.topsite.google.pbtxt", "getaddrinfo.topsite.youtube.pbtxt",
49 "getaddrinfo.topsite.amazon.pbtxt", "getaddrinfo.topsite.yahoo.pbtxt",
50 "getaddrinfo.topsite.facebook.pbtxt", "getaddrinfo.topsite.reddit.pbtxt",
51 "getaddrinfo.topsite.wikipedia.pbtxt", "getaddrinfo.topsite.ebay.pbtxt",
52 "getaddrinfo.topsite.netflix.pbtxt", "getaddrinfo.topsite.bing.pbtxt"};
Hungming Chen7b6c23b2019-10-03 17:46:11 +080053const std::vector<std::string> kGoldFilesGetAddrInfoTls = {"getaddrinfo.tls.topsite.google.pbtxt"};
Hungming Chenf9cd4eb2019-08-06 20:55:28 +090054
Hungming Chen21c0f832019-09-20 18:38:47 +080055// Fixture test class definition.
Hungming Chenf9cd4eb2019-08-06 20:55:28 +090056class TestBase : public ::testing::Test {
57 protected:
58 void SetUp() override {
59 // Create cache for test
60 resolv_create_cache_for_net(TEST_NETID);
61 }
62
63 void TearDown() override {
Hungming Chenc6556622019-10-02 16:01:07 +080064 // Clear TLS configuration for test
65 gPrivateDnsConfiguration.clear(TEST_NETID);
Hungming Chenf9cd4eb2019-08-06 20:55:28 +090066 // Delete cache for test
67 resolv_delete_cache_for_net(TEST_NETID);
68 }
69
Hungming Chenc6556622019-10-02 16:01:07 +080070 void SetResolverConfiguration(const std::vector<std::string>& servers = {},
71 const std::vector<std::string>& domains = {},
72 const std::vector<std::string>& tlsServers = {},
73 const std::string& tlsHostname = "",
74 const std::string& caCert = "") {
75 // Determine the DNS configuration steps from setResolverConfiguration() in
76 // packages/modules/DnsResolver/ResolverController.cpp. The gold test just needs to setup
77 // simply DNS and DNS-over-TLS server configuration. Some implementation in
78 // setResolverConfiguration() are not required. For example, limiting TLS server amount is
79 // not necessary for gold test because gold test has only one TLS server for testing
80 // so far.
81 Fwmark fwmark;
82 fwmark.netId = TEST_NETID;
83 fwmark.explicitlySelected = true;
84 fwmark.protectedFromVpn = true;
85 fwmark.permission = PERMISSION_SYSTEM;
86 ASSERT_EQ(gPrivateDnsConfiguration.set(TEST_NETID, fwmark.intValue, tlsServers, tlsHostname,
87 caCert),
88 0);
89 ASSERT_EQ(resolv_set_nameservers(TEST_NETID, servers, domains, kParams), 0);
Hungming Chenf9cd4eb2019-08-06 20:55:28 +090090 }
91
Hungming Chenc6556622019-10-02 16:01:07 +080092 void SetResolvers() { SetResolverConfiguration(kDefaultServers, kDefaultSearchDomains); }
93
94 void SetResolversWithTls() {
95 // Pass servers as both network-assigned and TLS servers. Tests can
96 // determine on which server and by which protocol queries arrived.
97 // See also DnsClient::SetResolversWithTls() in
98 // packages/modules/DnsResolver/tests/dns_responder/dns_responder_client.h.
99 SetResolverConfiguration(kDefaultServers, kDefaultSearchDomains, kDefaultServers,
100 kDefaultPrivateDnsHostName, kCaCert);
101 }
102
103 bool WaitForPrivateDnsValidation(const std::string& serverAddr) {
104 constexpr milliseconds retryIntervalMs{20};
105 constexpr milliseconds timeoutMs{3000};
106 android::base::Timer t;
107 while (t.duration() < timeoutMs) {
108 const auto& validatedServers =
109 gPrivateDnsConfiguration.getStatus(TEST_NETID).validatedServers();
110 for (const auto& server : validatedServers) {
111 if (serverAddr == ToString(&server.ss)) return true;
112 }
113 std::this_thread::sleep_for(retryIntervalMs);
114 }
115 return false;
116 }
117
Hungming Chen7b6c23b2019-10-03 17:46:11 +0800118 GoldTest ToProto(const std::string& file) {
119 // Convert the testing configuration from .pbtxt file to proto.
120 std::string file_content;
121 EXPECT_TRUE(android::base::ReadFileToString(kTestDataPath + file, &file_content))
122 << strerror(errno);
123 android::net::GoldTest goldtest;
124 EXPECT_TRUE(google::protobuf::TextFormat::ParseFromString(file_content, &goldtest));
125 return goldtest;
126 }
127
128 void SetupMappings(const android::net::GoldTest& goldtest, test::DNSResponder& dns) {
129 for (const auto& m : goldtest.packet_mapping()) {
130 // Convert string to bytes because .proto type "bytes" is "string" type in C++.
131 // See also the section "Scalar Value Types" in "Language Guide (proto3)".
132 // TODO: Use C++20 std::span in addMappingBinaryPacket. It helps to take both
133 // std::string and std::vector without conversions.
134 dns.addMappingBinaryPacket(
135 std::vector<uint8_t>(m.query().begin(), m.query().end()),
136 std::vector<uint8_t>(m.response().begin(), m.response().end()));
137 }
138 }
139
140 android_net_context GetNetContext(const DnsProtocol protocol) {
141 return protocol == DnsProtocol::TLS ? kNetcontextTls : kNetcontext;
142 }
143
144 template <class AddressType>
145 void VerifyAddress(const android::net::GoldTest& goldtest, const AddressType& result) {
146 if (goldtest.result().return_code() != GT_EAI_NO_ERROR) {
147 EXPECT_EQ(result, nullptr);
148 } else {
149 ASSERT_NE(result, nullptr);
150 const auto& addresses = goldtest.result().addresses();
151 EXPECT_THAT(ToStrings(result), ::testing::UnorderedElementsAreArray(addresses));
152 }
153 }
154
155 void VerifyGetAddrInfo(const android::net::GoldTest& goldtest, const DnsProtocol protocol) {
156 ASSERT_TRUE(goldtest.config().has_addrinfo());
157 const auto& args = goldtest.config().addrinfo();
158 const addrinfo hints = {
159 // Clear the flag AI_ADDRCONFIG to avoid flaky test because AI_ADDRCONFIG looks at
160 // whether connectivity is available. It makes that the resolver may send only A
161 // or AAAA DNS query per connectivity even AF_UNSPEC has been assigned. See also
162 // have_ipv6() and have_ipv4() in packages/modules/DnsResolver/getaddrinfo.cpp.
163 // TODO: Consider keeping the configuration flag AI_ADDRCONFIG once the unit
164 // test can treat the IPv4 and IPv6 connectivity.
165 .ai_flags = args.ai_flags() & ~AI_ADDRCONFIG,
166 .ai_family = args.family(),
167 .ai_socktype = args.socktype(),
168 .ai_protocol = args.protocol(),
169 };
170 addrinfo* res = nullptr;
171 const android_net_context netcontext = GetNetContext(protocol);
172 NetworkDnsEventReported event;
173 const int rv =
174 resolv_getaddrinfo(args.host().c_str(), nullptr, &hints, &netcontext, &res, &event);
175 ScopedAddrinfo result(res);
176 ASSERT_EQ(rv, goldtest.result().return_code());
177 VerifyAddress(goldtest, result);
178 }
179
180 void VerifyResolver(const android::net::GoldTest& goldtest, const test::DNSResponder& dns,
181 const test::DnsTlsFrontend& tls, const DnsProtocol protocol) {
182 size_t queries;
183 std::string name;
184
185 // Verify DNS query calls and results by proto. Then, determine expected query times and
186 // queried name for checking server query status later.
187 switch (const auto calltype = goldtest.config().call()) {
188 case android::net::CallType::CALL_GETADDRINFO:
189 ASSERT_TRUE(goldtest.config().has_addrinfo());
190 ASSERT_NO_FATAL_FAILURE(VerifyGetAddrInfo(goldtest, protocol));
191 queries = goldtest.config().addrinfo().family() == AF_UNSPEC ? 2U : 1U;
192 name = goldtest.config().addrinfo().host();
193 break;
194 default:
195 FAIL() << "Unsupported call type: " << calltype;
196 }
197
198 // Verify DNS server query status.
199 EXPECT_EQ(GetNumQueries(dns, name.c_str()), queries);
200 if (protocol == DnsProtocol::TLS) EXPECT_EQ(tls.queries(), static_cast<int>(queries));
201 }
202
Hungming Chenf9cd4eb2019-08-06 20:55:28 +0900203 static constexpr res_params kParams = {
204 .sample_validity = 300,
205 .success_threshold = 25,
206 .min_samples = 8,
207 .max_samples = 8,
208 .base_timeout_msec = 1000,
209 .retry_count = 2,
210 };
Hungming Chenf9cd4eb2019-08-06 20:55:28 +0900211 static constexpr android_net_context kNetcontext = {
212 .app_netid = TEST_NETID,
213 .app_mark = MARK_UNSET,
214 .dns_netid = TEST_NETID,
215 .dns_mark = MARK_UNSET,
216 .uid = NET_CONTEXT_INVALID_UID,
217 };
Hungming Chenc6556622019-10-02 16:01:07 +0800218 static constexpr android_net_context kNetcontextTls = {
219 .app_netid = TEST_NETID,
220 .app_mark = MARK_UNSET,
221 .dns_netid = TEST_NETID,
222 .dns_mark = MARK_UNSET,
223 .uid = NET_CONTEXT_INVALID_UID,
224 // Set TLS flags. See also maybeFixupNetContext() in
225 // packages/modules/DnsResolver/DnsProxyListener.cpp.
226 .flags = NET_CONTEXT_FLAG_USE_DNS_OVER_TLS | NET_CONTEXT_FLAG_USE_EDNS,
227 };
Hungming Chenf9cd4eb2019-08-06 20:55:28 +0900228};
Hungming Chenf9cd4eb2019-08-06 20:55:28 +0900229class ResolvGetAddrInfo : public TestBase {};
230
Hungming Chen21c0f832019-09-20 18:38:47 +0800231// Fixture tests.
Hungming Chenf9cd4eb2019-08-06 20:55:28 +0900232TEST_F(ResolvGetAddrInfo, RemovePacketMapping) {
233 test::DNSResponder dns(test::DNSResponder::MappingType::BINARY_PACKET);
234 ASSERT_TRUE(dns.startServer());
Hungming Chenc6556622019-10-02 16:01:07 +0800235 ASSERT_NO_FATAL_FAILURE(SetResolvers());
Hungming Chenf9cd4eb2019-08-06 20:55:28 +0900236
237 dns.addMappingBinaryPacket(kHelloExampleComQueryV4, kHelloExampleComResponseV4);
238
239 addrinfo* res = nullptr;
240 const addrinfo hints = {.ai_family = AF_INET};
241 NetworkDnsEventReported event;
242 int rv = resolv_getaddrinfo(kHelloExampleCom, nullptr, &hints, &kNetcontext, &res, &event);
243 ScopedAddrinfo result(res);
Hungming Chenc6556622019-10-02 16:01:07 +0800244 ASSERT_NE(result, nullptr);
245 ASSERT_EQ(rv, 0);
Hungming Chen7b6c23b2019-10-03 17:46:11 +0800246 EXPECT_EQ(ToString(result), kHelloExampleComAddrV4);
Hungming Chenf9cd4eb2019-08-06 20:55:28 +0900247
248 // Remove existing DNS record.
249 dns.removeMappingBinaryPacket(kHelloExampleComQueryV4);
250
251 // Expect to have no answer in DNS query result.
252 rv = resolv_getaddrinfo(kHelloExampleCom, nullptr, &hints, &kNetcontext, &res, &event);
253 result.reset(res);
Hungming Chenc6556622019-10-02 16:01:07 +0800254 ASSERT_EQ(result, nullptr);
255 ASSERT_EQ(rv, EAI_NODATA);
Hungming Chenf9cd4eb2019-08-06 20:55:28 +0900256}
257
258TEST_F(ResolvGetAddrInfo, ReplacePacketMapping) {
259 test::DNSResponder dns(test::DNSResponder::MappingType::BINARY_PACKET);
260 ASSERT_TRUE(dns.startServer());
Hungming Chenc6556622019-10-02 16:01:07 +0800261 ASSERT_NO_FATAL_FAILURE(SetResolvers());
Hungming Chenf9cd4eb2019-08-06 20:55:28 +0900262
263 // Register the record which uses IPv4 address 1.2.3.4.
264 dns.addMappingBinaryPacket(kHelloExampleComQueryV4, kHelloExampleComResponseV4);
265
266 // Expect that the DNS query returns IPv4 address 1.2.3.4.
267 addrinfo* res = nullptr;
268 const addrinfo hints = {.ai_family = AF_INET};
269 NetworkDnsEventReported event;
270 int rv = resolv_getaddrinfo(kHelloExampleCom, nullptr, &hints, &kNetcontext, &res, &event);
271 ScopedAddrinfo result(res);
Hungming Chenc6556622019-10-02 16:01:07 +0800272 ASSERT_NE(result, nullptr);
273 ASSERT_EQ(rv, 0);
274 EXPECT_EQ(ToString(result), "1.2.3.4");
Hungming Chenf9cd4eb2019-08-06 20:55:28 +0900275
276 // Replace the registered record with a record which uses new IPv4 address 5.6.7.8.
277 std::vector<uint8_t> newHelloExampleComResponseV4 = {
278 /* Header */
279 0x00, 0x00, /* Transaction ID: 0x0000 */
280 0x81, 0x80, /* Flags: qr rd ra */
281 0x00, 0x01, /* Questions: 1 */
282 0x00, 0x01, /* Answer RRs: 1 */
283 0x00, 0x00, /* Authority RRs: 0 */
284 0x00, 0x00, /* Additional RRs: 0 */
285 /* Queries */
286 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65,
287 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name: hello.example.com */
288 0x00, 0x01, /* Type: A */
289 0x00, 0x01, /* Class: IN */
290 /* Answers */
291 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65,
292 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name: hello.example.com */
293 0x00, 0x01, /* Type: A */
294 0x00, 0x01, /* Class: IN */
295 0x00, 0x00, 0x00, 0x00, /* Time to live: 0 */
296 0x00, 0x04, /* Data length: 4 */
297 0x05, 0x06, 0x07, 0x08 /* Address: 5.6.7.8 */
298 };
299 dns.addMappingBinaryPacket(kHelloExampleComQueryV4, newHelloExampleComResponseV4);
300
301 // Expect that DNS query returns new IPv4 address 5.6.7.8.
302 rv = resolv_getaddrinfo(kHelloExampleCom, nullptr, &hints, &kNetcontext, &res, &event);
303 result.reset(res);
Hungming Chenc6556622019-10-02 16:01:07 +0800304 ASSERT_NE(result, nullptr);
305 ASSERT_EQ(rv, 0);
306 EXPECT_EQ(ToString(result), "5.6.7.8");
307}
308
309TEST_F(ResolvGetAddrInfo, BasicTlsQuery) {
310 test::DNSResponder dns;
Hungming Chen7b6c23b2019-10-03 17:46:11 +0800311 dns.addMapping(kHelloExampleCom, ns_type::ns_t_a, kHelloExampleComAddrV4);
312 dns.addMapping(kHelloExampleCom, ns_type::ns_t_aaaa, kHelloExampleComAddrV6);
Hungming Chenc6556622019-10-02 16:01:07 +0800313 ASSERT_TRUE(dns.startServer());
314
315 test::DnsTlsFrontend tls;
316 ASSERT_TRUE(tls.startServer());
317 ASSERT_NO_FATAL_FAILURE(SetResolversWithTls());
318 EXPECT_TRUE(WaitForPrivateDnsValidation(tls.listen_address()));
319
320 dns.clearQueries();
321 addrinfo* res = nullptr;
322 // If the socket type is not specified, every address will appear twice, once for
323 // SOCK_STREAM and one for SOCK_DGRAM. Just pick one because the addresses for
324 // the second query of different socket type are responded by the cache.
325 const addrinfo hints = {.ai_family = AF_UNSPEC, .ai_socktype = SOCK_STREAM};
326 NetworkDnsEventReported event;
327 const int rv =
328 resolv_getaddrinfo(kHelloExampleCom, nullptr, &hints, &kNetcontextTls, &res, &event);
329 ScopedAddrinfo result(res);
330 ASSERT_EQ(rv, 0);
331 EXPECT_EQ(GetNumQueries(dns, kHelloExampleCom), 2U);
332 const std::vector<std::string> result_strs = ToStrings(result);
Hungming Chen7b6c23b2019-10-03 17:46:11 +0800333 EXPECT_THAT(result_strs, testing::UnorderedElementsAreArray(
334 {kHelloExampleComAddrV4, kHelloExampleComAddrV6}));
Hungming Chenc6556622019-10-02 16:01:07 +0800335 EXPECT_EQ(tls.queries(), 3);
Hungming Chenf9cd4eb2019-08-06 20:55:28 +0900336}
337
Hungming Chen7b6c23b2019-10-03 17:46:11 +0800338// Parameterized test class definition.
339using GoldTestParamType = std::tuple<DnsProtocol, std::string /* filename */>;
340class ResolvGoldTest : public TestBase, public ::testing::WithParamInterface<GoldTestParamType> {
341 public:
342 // Generate readable string for test name from test parameters.
343 static std::string Name(::testing::TestParamInfo<GoldTestParamType> info) {
344 const auto& [protocol, file] = info.param;
345 std::string name = StringPrintf(
346 "%s_%s", protocol == DnsProtocol::CLEARTEXT ? "CLEARTEXT" : "TLS", file.c_str());
347 std::replace_if(
348 std::begin(name), std::end(name), [](char ch) { return !std::isalnum(ch); }, '_');
349 return name;
350 }
351};
352
353// GetAddrInfo tests.
354INSTANTIATE_TEST_SUITE_P(GetAddrInfo, ResolvGoldTest,
355 ::testing::Combine(::testing::Values(DnsProtocol::CLEARTEXT),
356 ::testing::ValuesIn(kGoldFilesGetAddrInfo)),
357 ResolvGoldTest::Name);
358INSTANTIATE_TEST_SUITE_P(GetAddrInfoTls, ResolvGoldTest,
359 ::testing::Combine(::testing::Values(DnsProtocol::TLS),
360 ::testing::ValuesIn(kGoldFilesGetAddrInfoTls)),
361 ResolvGoldTest::Name);
362
Hungming Chen21c0f832019-09-20 18:38:47 +0800363TEST_P(ResolvGoldTest, GoldData) {
Hungming Chen7b6c23b2019-10-03 17:46:11 +0800364 const auto& [protocol, file] = GetParam();
Hungming Chen21c0f832019-09-20 18:38:47 +0800365
Hungming Chen7b6c23b2019-10-03 17:46:11 +0800366 // Setup DNS server configuration.
Hungming Chen21c0f832019-09-20 18:38:47 +0800367 test::DNSResponder dns(test::DNSResponder::MappingType::BINARY_PACKET);
368 ASSERT_TRUE(dns.startServer());
Hungming Chen7b6c23b2019-10-03 17:46:11 +0800369 test::DnsTlsFrontend tls;
Hungming Chen21c0f832019-09-20 18:38:47 +0800370
Hungming Chen7b6c23b2019-10-03 17:46:11 +0800371 if (protocol == DnsProtocol::CLEARTEXT) {
372 ASSERT_NO_FATAL_FAILURE(SetResolvers());
373 } else if (protocol == DnsProtocol::TLS) {
374 ASSERT_TRUE(tls.startServer());
375 ASSERT_NO_FATAL_FAILURE(SetResolversWithTls());
376 EXPECT_TRUE(WaitForPrivateDnsValidation(tls.listen_address()));
377 tls.clearQueries();
Hungming Chen21c0f832019-09-20 18:38:47 +0800378 }
379
Hungming Chen7b6c23b2019-10-03 17:46:11 +0800380 // Read test configuration from proto text file to proto.
381 const auto goldtest = ToProto(file);
Hungming Chen21c0f832019-09-20 18:38:47 +0800382
Hungming Chen7b6c23b2019-10-03 17:46:11 +0800383 // Register packet mappings (query, response) from proto.
384 SetupMappings(goldtest, dns);
385
386 // Verify the resolver by proto.
387 VerifyResolver(goldtest, dns, tls, protocol);
Hungming Chen21c0f832019-09-20 18:38:47 +0800388}
389
Hungming Chen7b6c23b2019-10-03 17:46:11 +0800390} // namespace android::net