1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/dns/dns_response_result_extractor.h"
6
7 #include <string>
8 #include <utility>
9 #include <vector>
10
11 #include "base/ranges/algorithm.h"
12 #include "base/strings/string_piece.h"
13 #include "base/test/simple_test_clock.h"
14 #include "base/test/simple_test_tick_clock.h"
15 #include "base/time/time.h"
16 #include "net/base/connection_endpoint_metadata_test_util.h"
17 #include "net/base/host_port_pair.h"
18 #include "net/base/ip_address.h"
19 #include "net/base/ip_endpoint.h"
20 #include "net/base/net_errors.h"
21 #include "net/dns/dns_query.h"
22 #include "net/dns/dns_response.h"
23 #include "net/dns/dns_test_util.h"
24 #include "net/dns/host_cache.h"
25 #include "net/dns/host_resolver_internal_result.h"
26 #include "net/dns/host_resolver_internal_result_test_util.h"
27 #include "net/dns/host_resolver_results_test_util.h"
28 #include "net/dns/public/dns_protocol.h"
29 #include "net/dns/public/dns_query_type.h"
30 #include "net/test/gtest_util.h"
31 #include "testing/gmock/include/gmock/gmock.h"
32 #include "testing/gtest/include/gtest/gtest.h"
33 #include "third_party/abseil-cpp/absl/types/optional.h"
34
35 namespace net {
36 namespace {
37
38 using ::testing::AllOf;
39 using ::testing::ElementsAre;
40 using ::testing::ElementsAreArray;
41 using ::testing::Eq;
42 using ::testing::IsEmpty;
43 using ::testing::Ne;
44 using ::testing::Pair;
45 using ::testing::Pointee;
46 using ::testing::ResultOf;
47 using ::testing::SizeIs;
48 using ::testing::UnorderedElementsAre;
49
50 using ExtractionError = DnsResponseResultExtractor::ExtractionError;
51 using ResultsOrError = DnsResponseResultExtractor::ResultsOrError;
52
53 constexpr HostResolverInternalResult::Source kDnsSource =
54 HostResolverInternalResult::Source::kDns;
55
56 class DnsResponseResultExtractorTest : public ::testing::Test {
57 protected:
58 base::SimpleTestClock clock_;
59 base::SimpleTestTickClock tick_clock_;
60 };
61
TEST_F(DnsResponseResultExtractorTest,ExtractsSingleARecord)62 TEST_F(DnsResponseResultExtractorTest, ExtractsSingleARecord) {
63 constexpr char kName[] = "address.test";
64 const IPAddress kExpected(192, 168, 0, 1);
65
66 DnsResponse response = BuildTestDnsAddressResponse(kName, kExpected);
67 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
68
69 ResultsOrError results =
70 extractor.ExtractDnsResults(DnsQueryType::A,
71 /*original_domain_name=*/kName,
72 /*request_port=*/0);
73
74 ASSERT_TRUE(results.has_value());
75 EXPECT_THAT(results.value(),
76 ElementsAre(Pointee(ExpectHostResolverInternalDataResult(
77 kName, DnsQueryType::A, kDnsSource,
78 /*expiration_matcher=*/Ne(absl::nullopt),
79 /*timed_expiration_matcher=*/Ne(absl::nullopt),
80 ElementsAre(IPEndPoint(kExpected, /*port=*/0))))));
81 }
82
TEST_F(DnsResponseResultExtractorTest,ExtractsSingleAAAARecord)83 TEST_F(DnsResponseResultExtractorTest, ExtractsSingleAAAARecord) {
84 constexpr char kName[] = "address.test";
85
86 IPAddress expected;
87 CHECK(expected.AssignFromIPLiteral("2001:4860:4860::8888"));
88
89 DnsResponse response = BuildTestDnsAddressResponse(kName, expected);
90 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
91
92 ResultsOrError results =
93 extractor.ExtractDnsResults(DnsQueryType::AAAA,
94 /*original_domain_name=*/kName,
95 /*request_port=*/0);
96
97 ASSERT_TRUE(results.has_value());
98 EXPECT_THAT(results.value(),
99 ElementsAre(Pointee(ExpectHostResolverInternalDataResult(
100 kName, DnsQueryType::AAAA, kDnsSource,
101 /*expiration_matcher=*/Ne(absl::nullopt),
102 /*timed_expiration_matcher=*/Ne(absl::nullopt),
103 ElementsAre(IPEndPoint(expected, /*port=*/0))))));
104 }
105
TEST_F(DnsResponseResultExtractorTest,ExtractsSingleARecordWithCname)106 TEST_F(DnsResponseResultExtractorTest, ExtractsSingleARecordWithCname) {
107 const IPAddress kExpected(192, 168, 0, 1);
108 constexpr char kName[] = "address.test";
109 constexpr char kCanonicalName[] = "alias.test";
110
111 DnsResponse response =
112 BuildTestDnsAddressResponseWithCname(kName, kExpected, kCanonicalName);
113 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
114
115 ResultsOrError results =
116 extractor.ExtractDnsResults(DnsQueryType::A,
117 /*original_domain_name=*/kName,
118 /*request_port=*/0);
119
120 ASSERT_TRUE(results.has_value());
121 EXPECT_THAT(
122 results.value(),
123 UnorderedElementsAre(Pointee(ExpectHostResolverInternalDataResult(
124 kCanonicalName, DnsQueryType::A, kDnsSource,
125 /*expiration_matcher=*/Ne(absl::nullopt),
126 /*timed_expiration_matcher=*/Ne(absl::nullopt),
127 ElementsAre(IPEndPoint(kExpected, /*port=*/0)))),
128 Pointee(ExpectHostResolverInternalAliasResult(
129 kName, DnsQueryType::A, kDnsSource,
130 /*expiration_matcher=*/Ne(absl::nullopt),
131 /*timed_expiration_matcher=*/Ne(absl::nullopt),
132 kCanonicalName))));
133 }
134
TEST_F(DnsResponseResultExtractorTest,ExtractsARecordsWithCname)135 TEST_F(DnsResponseResultExtractorTest, ExtractsARecordsWithCname) {
136 constexpr char kName[] = "addresses.test";
137
138 DnsResponse response = BuildTestDnsResponse(
139 "addresses.test", dns_protocol::kTypeA,
140 {
141 BuildTestAddressRecord("alias.test", IPAddress(74, 125, 226, 179)),
142 BuildTestAddressRecord("alias.test", IPAddress(74, 125, 226, 180)),
143 BuildTestCnameRecord(kName, "alias.test"),
144 BuildTestAddressRecord("alias.test", IPAddress(74, 125, 226, 176)),
145 BuildTestAddressRecord("alias.test", IPAddress(74, 125, 226, 177)),
146 BuildTestAddressRecord("alias.test", IPAddress(74, 125, 226, 178)),
147 });
148 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
149
150 ResultsOrError results =
151 extractor.ExtractDnsResults(DnsQueryType::A,
152 /*original_domain_name=*/kName,
153 /*request_port=*/0);
154
155 ASSERT_TRUE(results.has_value());
156 EXPECT_THAT(
157 results.value(),
158 UnorderedElementsAre(
159 Pointee(ExpectHostResolverInternalDataResult(
160 "alias.test", DnsQueryType::A, kDnsSource,
161 /*expiration_matcher=*/Ne(absl::nullopt),
162 /*timed_expiration_matcher=*/Ne(absl::nullopt),
163 UnorderedElementsAre(
164 IPEndPoint(IPAddress(74, 125, 226, 179), /*port=*/0),
165 IPEndPoint(IPAddress(74, 125, 226, 180), /*port=*/0),
166 IPEndPoint(IPAddress(74, 125, 226, 176), /*port=*/0),
167 IPEndPoint(IPAddress(74, 125, 226, 177), /*port=*/0),
168 IPEndPoint(IPAddress(74, 125, 226, 178), /*port=*/0)))),
169 Pointee(ExpectHostResolverInternalAliasResult(
170 kName, DnsQueryType::A, kDnsSource,
171 /*expiration_matcher=*/Ne(absl::nullopt),
172 /*timed_expiration_matcher=*/Ne(absl::nullopt), "alias.test"))));
173 }
174
TEST_F(DnsResponseResultExtractorTest,ExtractsNxdomainAResponses)175 TEST_F(DnsResponseResultExtractorTest, ExtractsNxdomainAResponses) {
176 constexpr char kName[] = "address.test";
177 constexpr auto kTtl = base::Hours(2);
178
179 DnsResponse response = BuildTestDnsResponse(
180 kName, dns_protocol::kTypeA, /*answers=*/{},
181 /*authority=*/
182 {BuildTestDnsRecord(kName, dns_protocol::kTypeSOA, "fake rdata", kTtl)},
183 /*additional=*/{}, dns_protocol::kRcodeNXDOMAIN);
184 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
185
186 ResultsOrError results =
187 extractor.ExtractDnsResults(DnsQueryType::A,
188 /*original_domain_name=*/kName,
189 /*request_port=*/0);
190
191 ASSERT_TRUE(results.has_value());
192 EXPECT_THAT(results.value(),
193 ElementsAre(Pointee(ExpectHostResolverInternalErrorResult(
194 kName, DnsQueryType::A, kDnsSource,
195 /*expiration_matcher=*/Eq(tick_clock_.NowTicks() + kTtl),
196 /*timed_expiration_matcher=*/Eq(clock_.Now() + kTtl),
197 ERR_NAME_NOT_RESOLVED))));
198 }
199
TEST_F(DnsResponseResultExtractorTest,ExtractsNodataAResponses)200 TEST_F(DnsResponseResultExtractorTest, ExtractsNodataAResponses) {
201 constexpr char kName[] = "address.test";
202 constexpr auto kTtl = base::Minutes(15);
203
204 DnsResponse response = BuildTestDnsResponse(
205 kName, dns_protocol::kTypeA, /*answers=*/{},
206 /*authority=*/
207 {BuildTestDnsRecord(kName, dns_protocol::kTypeSOA, "fake rdata", kTtl)});
208 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
209
210 ResultsOrError results =
211 extractor.ExtractDnsResults(DnsQueryType::A,
212 /*original_domain_name=*/kName,
213 /*request_port=*/0);
214
215 ASSERT_TRUE(results.has_value());
216 EXPECT_THAT(results.value(),
217 ElementsAre(Pointee(ExpectHostResolverInternalErrorResult(
218 kName, DnsQueryType::A, kDnsSource,
219 /*expiration_matcher=*/Eq(tick_clock_.NowTicks() + kTtl),
220 /*timed_expiration_matcher=*/Eq(clock_.Now() + kTtl),
221 ERR_NAME_NOT_RESOLVED))));
222 }
223
TEST_F(DnsResponseResultExtractorTest,RejectsMalformedARecord)224 TEST_F(DnsResponseResultExtractorTest, RejectsMalformedARecord) {
225 constexpr char kName[] = "address.test";
226
227 DnsResponse response = BuildTestDnsResponse(
228 kName, dns_protocol::kTypeA,
229 {BuildTestDnsRecord(kName, dns_protocol::kTypeA,
230 "malformed rdata")} /* answers */);
231 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
232
233 EXPECT_EQ(extractor
234 .ExtractDnsResults(DnsQueryType::A,
235 /*original_domain_name=*/kName,
236 /*request_port=*/0)
237 .error_or(ExtractionError::kOk),
238 ExtractionError::kMalformedRecord);
239 }
240
TEST_F(DnsResponseResultExtractorTest,RejectsWrongNameARecord)241 TEST_F(DnsResponseResultExtractorTest, RejectsWrongNameARecord) {
242 constexpr char kName[] = "address.test";
243
244 DnsResponse response = BuildTestDnsAddressResponse(
245 kName, IPAddress(1, 2, 3, 4), "different.test");
246 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
247
248 EXPECT_EQ(extractor
249 .ExtractDnsResults(DnsQueryType::A,
250 /*original_domain_name=*/kName,
251 /*request_port=*/0)
252 .error_or(ExtractionError::kOk),
253 ExtractionError::kNameMismatch);
254 }
255
TEST_F(DnsResponseResultExtractorTest,IgnoresWrongTypeRecordsInAResponse)256 TEST_F(DnsResponseResultExtractorTest, IgnoresWrongTypeRecordsInAResponse) {
257 constexpr char kName[] = "address.test";
258
259 DnsResponse response = BuildTestDnsResponse(
260 kName, dns_protocol::kTypeA,
261 {BuildTestTextRecord("address.test", {"foo"} /* text_strings */)});
262 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
263
264 ResultsOrError results =
265 extractor.ExtractDnsResults(DnsQueryType::A,
266 /*original_domain_name=*/kName,
267 /*request_port=*/0);
268
269 // Expect empty results because NODATA is not cacheable (due to no TTL).
270 ASSERT_TRUE(results.has_value());
271 EXPECT_THAT(results.value(), IsEmpty());
272 }
273
TEST_F(DnsResponseResultExtractorTest,IgnoresWrongTypeRecordsMixedWithARecords)274 TEST_F(DnsResponseResultExtractorTest,
275 IgnoresWrongTypeRecordsMixedWithARecords) {
276 constexpr char kName[] = "address.test";
277 const IPAddress kExpected(8, 8, 8, 8);
278 constexpr auto kTtl = base::Days(3);
279
280 DnsResponse response = BuildTestDnsResponse(
281 kName, dns_protocol::kTypeA,
282 {BuildTestTextRecord(kName, /*text_strings=*/{"foo"}, base::Hours(2)),
283 BuildTestAddressRecord(kName, kExpected, kTtl)});
284 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
285
286 ResultsOrError results =
287 extractor.ExtractDnsResults(DnsQueryType::A,
288 /*original_domain_name=*/kName,
289 /*request_port=*/0);
290
291 ASSERT_TRUE(results.has_value());
292 EXPECT_THAT(results.value(),
293 ElementsAre(Pointee(ExpectHostResolverInternalDataResult(
294 kName, DnsQueryType::A, kDnsSource,
295 /*expiration_matcher=*/Eq(tick_clock_.NowTicks() + kTtl),
296 /*timed_expiration_matcher=*/Eq(clock_.Now() + kTtl),
297 ElementsAre(IPEndPoint(kExpected, /*port=*/0))))));
298 }
299
TEST_F(DnsResponseResultExtractorTest,ExtractsMinATtl)300 TEST_F(DnsResponseResultExtractorTest, ExtractsMinATtl) {
301 constexpr char kName[] = "name.test";
302 constexpr base::TimeDelta kMinTtl = base::Minutes(4);
303
304 DnsResponse response = BuildTestDnsResponse(
305 kName, dns_protocol::kTypeA,
306 {BuildTestAddressRecord(kName, IPAddress(1, 2, 3, 4), base::Hours(3)),
307 BuildTestAddressRecord(kName, IPAddress(2, 3, 4, 5), kMinTtl),
308 BuildTestAddressRecord(kName, IPAddress(3, 4, 5, 6),
309 base::Minutes(15))});
310 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
311
312 ResultsOrError results =
313 extractor.ExtractDnsResults(DnsQueryType::A,
314 /*original_domain_name=*/kName,
315 /*request_port=*/0);
316
317 ASSERT_TRUE(results.has_value());
318 EXPECT_THAT(results.value(),
319 ElementsAre(Pointee(ExpectHostResolverInternalDataResult(
320 kName, DnsQueryType::A, kDnsSource,
321 /*expiration_matcher=*/Eq(tick_clock_.NowTicks() + kMinTtl),
322 /*timed_expiration_matcher=*/Eq(clock_.Now() + kMinTtl),
323 /*endpoints_matcher=*/SizeIs(3)))));
324 }
325
326 MATCHER_P(ContainsContiguousElements, elements, "") {
327 return base::ranges::search(arg, elements) != arg.end();
328 }
329
TEST_F(DnsResponseResultExtractorTest,ExtractsTxtResponses)330 TEST_F(DnsResponseResultExtractorTest, ExtractsTxtResponses) {
331 constexpr char kName[] = "name.test";
332
333 // Simulate two separate DNS records, each with multiple strings.
334 std::vector<std::string> foo_records = {"foo1", "foo2", "foo3"};
335 std::vector<std::string> bar_records = {"bar1", "bar2"};
336 std::vector<std::vector<std::string>> text_records = {foo_records,
337 bar_records};
338
339 DnsResponse response =
340 BuildTestDnsTextResponse(kName, std::move(text_records));
341 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
342
343 ResultsOrError results =
344 extractor.ExtractDnsResults(DnsQueryType::TXT,
345 /*original_domain_name=*/kName,
346 /*request_port=*/0);
347
348 ASSERT_TRUE(results.has_value());
349 // Order between separate DNS records is undefined, but each record should
350 // stay in order as that order may be meaningful.
351 EXPECT_THAT(
352 results.value(),
353 ElementsAre(Pointee(ExpectHostResolverInternalDataResult(
354 kName, DnsQueryType::TXT, kDnsSource,
355 /*expiration_matcher=*/Ne(absl::nullopt),
356 /*timed_expiration_matcher=*/Ne(absl::nullopt),
357 /*endpoints_matcher=*/IsEmpty(),
358 /*strings_matcher=*/
359 AllOf(UnorderedElementsAre("foo1", "foo2", "foo3", "bar1", "bar2"),
360 ContainsContiguousElements(foo_records),
361 ContainsContiguousElements(bar_records))))));
362 }
363
TEST_F(DnsResponseResultExtractorTest,ExtractsNxdomainTxtResponses)364 TEST_F(DnsResponseResultExtractorTest, ExtractsNxdomainTxtResponses) {
365 constexpr char kName[] = "name.test";
366 constexpr auto kTtl = base::Days(4);
367
368 DnsResponse response = BuildTestDnsResponse(
369 kName, dns_protocol::kTypeTXT, /*answers=*/{},
370 /*authority=*/
371 {BuildTestDnsRecord(kName, dns_protocol::kTypeSOA, "fake rdata", kTtl)},
372 /*additional=*/{}, dns_protocol::kRcodeNXDOMAIN);
373 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
374
375 ResultsOrError results =
376 extractor.ExtractDnsResults(DnsQueryType::TXT,
377 /*original_domain_name=*/kName,
378 /*request_port=*/0);
379
380 ASSERT_TRUE(results.has_value());
381 EXPECT_THAT(results.value(),
382 ElementsAre(Pointee(ExpectHostResolverInternalErrorResult(
383 kName, DnsQueryType::TXT, kDnsSource,
384 /*expiration_matcher=*/Eq(tick_clock_.NowTicks() + kTtl),
385 /*timed_expiration_matcher=*/Eq(clock_.Now() + kTtl),
386 ERR_NAME_NOT_RESOLVED))));
387 }
388
TEST_F(DnsResponseResultExtractorTest,ExtractsNodataTxtResponses)389 TEST_F(DnsResponseResultExtractorTest, ExtractsNodataTxtResponses) {
390 constexpr char kName[] = "name.test";
391 constexpr auto kTtl = base::Minutes(42);
392
393 DnsResponse response = BuildTestDnsResponse(
394 kName, dns_protocol::kTypeTXT,
395 /*answers=*/{}, /*authority=*/
396 {BuildTestDnsRecord(kName, dns_protocol::kTypeSOA, "fake rdata", kTtl)});
397 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
398
399 ResultsOrError results =
400 extractor.ExtractDnsResults(DnsQueryType::TXT,
401 /*original_domain_name=*/kName,
402 /*request_port=*/0);
403
404 ASSERT_TRUE(results.has_value());
405 EXPECT_THAT(results.value(),
406 ElementsAre(Pointee(ExpectHostResolverInternalErrorResult(
407 kName, DnsQueryType::TXT, kDnsSource,
408 /*expiration_matcher=*/Eq(tick_clock_.NowTicks() + kTtl),
409 /*timed_expiration_matcher=*/Eq(clock_.Now() + kTtl),
410 ERR_NAME_NOT_RESOLVED))));
411 }
412
TEST_F(DnsResponseResultExtractorTest,RejectsMalformedTxtRecord)413 TEST_F(DnsResponseResultExtractorTest, RejectsMalformedTxtRecord) {
414 constexpr char kName[] = "name.test";
415
416 DnsResponse response = BuildTestDnsResponse(
417 kName, dns_protocol::kTypeTXT,
418 {BuildTestDnsRecord(kName, dns_protocol::kTypeTXT,
419 "malformed rdata")} /* answers */);
420 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
421
422 EXPECT_EQ(extractor
423 .ExtractDnsResults(DnsQueryType::TXT,
424 /*original_domain_name=*/kName,
425 /*request_port=*/0)
426 .error_or(ExtractionError::kOk),
427 ExtractionError::kMalformedRecord);
428 }
429
TEST_F(DnsResponseResultExtractorTest,RejectsWrongNameTxtRecord)430 TEST_F(DnsResponseResultExtractorTest, RejectsWrongNameTxtRecord) {
431 constexpr char kName[] = "name.test";
432
433 DnsResponse response =
434 BuildTestDnsTextResponse(kName, {{"foo"}}, "different.test");
435 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
436
437 EXPECT_EQ(extractor
438 .ExtractDnsResults(DnsQueryType::TXT,
439 /*original_domain_name=*/kName,
440 /*request_port=*/0)
441 .error_or(ExtractionError::kOk),
442 ExtractionError::kNameMismatch);
443 }
444
TEST_F(DnsResponseResultExtractorTest,IgnoresWrongTypeTxtResponses)445 TEST_F(DnsResponseResultExtractorTest, IgnoresWrongTypeTxtResponses) {
446 constexpr char kName[] = "name.test";
447
448 DnsResponse response = BuildTestDnsResponse(
449 kName, dns_protocol::kTypeTXT,
450 {BuildTestAddressRecord(kName, IPAddress(1, 2, 3, 4))});
451 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
452
453 ResultsOrError results =
454 extractor.ExtractDnsResults(DnsQueryType::TXT,
455 /*original_domain_name=*/kName,
456 /*request_port=*/0);
457
458 // Expect empty results because NODATA is not cacheable (due to no TTL).
459 ASSERT_TRUE(results.has_value());
460 EXPECT_THAT(results.value(), IsEmpty());
461 }
462
TEST_F(DnsResponseResultExtractorTest,ExtractsMinTxtTtl)463 TEST_F(DnsResponseResultExtractorTest, ExtractsMinTxtTtl) {
464 constexpr char kName[] = "name.test";
465 constexpr base::TimeDelta kMinTtl = base::Minutes(4);
466
467 DnsResponse response = BuildTestDnsResponse(
468 kName, dns_protocol::kTypeTXT,
469 {BuildTestTextRecord(kName, {"foo"}, base::Hours(3)),
470 BuildTestTextRecord(kName, {"bar"}, kMinTtl),
471 BuildTestTextRecord(kName, {"baz"}, base::Minutes(15))});
472 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
473
474 ResultsOrError results =
475 extractor.ExtractDnsResults(DnsQueryType::TXT,
476 /*original_domain_name=*/kName,
477 /*request_port=*/0);
478
479 ASSERT_TRUE(results.has_value());
480 EXPECT_THAT(results.value(),
481 ElementsAre(Pointee(ExpectHostResolverInternalDataResult(
482 kName, DnsQueryType::TXT, kDnsSource,
483 /*expiration_matcher=*/Eq(tick_clock_.NowTicks() + kMinTtl),
484 /*timed_expiration_matcher=*/Eq(clock_.Now() + kMinTtl),
485 /*endpoints_matcher=*/IsEmpty(),
486 /*strings_matcher=*/SizeIs(3)))));
487 }
488
TEST_F(DnsResponseResultExtractorTest,ExtractsPtrResponses)489 TEST_F(DnsResponseResultExtractorTest, ExtractsPtrResponses) {
490 constexpr char kName[] = "name.test";
491
492 DnsResponse response =
493 BuildTestDnsPointerResponse(kName, {"foo.com", "bar.com"});
494 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
495
496 ResultsOrError results =
497 extractor.ExtractDnsResults(DnsQueryType::PTR,
498 /*original_domain_name=*/kName,
499 /*request_port=*/0);
500
501 ASSERT_TRUE(results.has_value());
502 EXPECT_THAT(results.value(),
503 ElementsAre(Pointee(ExpectHostResolverInternalDataResult(
504 kName, DnsQueryType::PTR, kDnsSource,
505 /*expiration_matcher=*/Ne(absl::nullopt),
506 /*timed_expiration_matcher=*/Ne(absl::nullopt),
507 /*endpoints_matcher=*/IsEmpty(),
508 /*strings_matcher=*/IsEmpty(),
509 /*hosts_matcher=*/
510 UnorderedElementsAre(HostPortPair("foo.com", 0),
511 HostPortPair("bar.com", 0))))));
512 }
513
TEST_F(DnsResponseResultExtractorTest,ExtractsNxdomainPtrResponses)514 TEST_F(DnsResponseResultExtractorTest, ExtractsNxdomainPtrResponses) {
515 constexpr char kName[] = "name.test";
516 constexpr auto kTtl = base::Hours(5);
517
518 DnsResponse response = BuildTestDnsResponse(
519 kName, dns_protocol::kTypePTR, /*answers=*/{},
520 /*authority=*/
521 {BuildTestDnsRecord(kName, dns_protocol::kTypeSOA, "fake rdata", kTtl)},
522 /*additional=*/{}, dns_protocol::kRcodeNXDOMAIN);
523 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
524
525 ResultsOrError results =
526 extractor.ExtractDnsResults(DnsQueryType::PTR,
527 /*original_domain_name=*/kName,
528 /*request_port=*/0);
529
530 ASSERT_TRUE(results.has_value());
531 EXPECT_THAT(results.value(),
532 ElementsAre(Pointee(ExpectHostResolverInternalErrorResult(
533 kName, DnsQueryType::PTR, kDnsSource,
534 /*expiration_matcher=*/Eq(tick_clock_.NowTicks() + kTtl),
535 /*timed_expiration_matcher=*/Eq(clock_.Now() + kTtl),
536 ERR_NAME_NOT_RESOLVED))));
537 }
538
TEST_F(DnsResponseResultExtractorTest,ExtractsNodataPtrResponses)539 TEST_F(DnsResponseResultExtractorTest, ExtractsNodataPtrResponses) {
540 constexpr char kName[] = "name.test";
541 constexpr auto kTtl = base::Minutes(50);
542
543 DnsResponse response = BuildTestDnsResponse(
544 kName, dns_protocol::kTypePTR, /*answers=*/{},
545 /*authority=*/
546 {BuildTestDnsRecord(kName, dns_protocol::kTypeSOA, "fake rdata", kTtl)});
547 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
548
549 ResultsOrError results =
550 extractor.ExtractDnsResults(DnsQueryType::PTR,
551 /*original_domain_name=*/kName,
552 /*request_port=*/0);
553
554 ASSERT_TRUE(results.has_value());
555 EXPECT_THAT(results.value(),
556 ElementsAre(Pointee(ExpectHostResolverInternalErrorResult(
557 kName, DnsQueryType::PTR, kDnsSource,
558 /*expiration_matcher=*/Eq(tick_clock_.NowTicks() + kTtl),
559 /*timed_expiration_matcher=*/Eq(clock_.Now() + kTtl),
560 ERR_NAME_NOT_RESOLVED))));
561 }
562
TEST_F(DnsResponseResultExtractorTest,RejectsMalformedPtrRecord)563 TEST_F(DnsResponseResultExtractorTest, RejectsMalformedPtrRecord) {
564 constexpr char kName[] = "name.test";
565
566 DnsResponse response = BuildTestDnsResponse(
567 kName, dns_protocol::kTypePTR,
568 {BuildTestDnsRecord(kName, dns_protocol::kTypePTR,
569 "malformed rdata")} /* answers */);
570 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
571
572 EXPECT_EQ(extractor
573 .ExtractDnsResults(DnsQueryType::PTR,
574 /*original_domain_name=*/kName,
575 /*request_port=*/0)
576 .error_or(ExtractionError::kOk),
577 ExtractionError::kMalformedRecord);
578 }
579
TEST_F(DnsResponseResultExtractorTest,RejectsWrongNamePtrRecord)580 TEST_F(DnsResponseResultExtractorTest, RejectsWrongNamePtrRecord) {
581 constexpr char kName[] = "name.test";
582
583 DnsResponse response = BuildTestDnsPointerResponse(
584 kName, {"foo.com", "bar.com"}, "different.test");
585 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
586
587 EXPECT_EQ(extractor
588 .ExtractDnsResults(DnsQueryType::PTR,
589 /*original_domain_name=*/kName,
590 /*request_port=*/0)
591 .error_or(ExtractionError::kOk),
592 ExtractionError::kNameMismatch);
593 }
594
TEST_F(DnsResponseResultExtractorTest,IgnoresWrongTypePtrResponses)595 TEST_F(DnsResponseResultExtractorTest, IgnoresWrongTypePtrResponses) {
596 constexpr char kName[] = "name.test";
597
598 DnsResponse response = BuildTestDnsResponse(
599 kName, dns_protocol::kTypePTR,
600 {BuildTestAddressRecord(kName, IPAddress(1, 2, 3, 4))});
601 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
602
603 ResultsOrError results =
604 extractor.ExtractDnsResults(DnsQueryType::PTR,
605 /*original_domain_name=*/kName,
606 /*request_port=*/0);
607
608 // Expect empty results because NODATA is not cacheable (due to no TTL).
609 ASSERT_TRUE(results.has_value());
610 EXPECT_THAT(results.value(), IsEmpty());
611 }
612
TEST_F(DnsResponseResultExtractorTest,ExtractsSrvResponses)613 TEST_F(DnsResponseResultExtractorTest, ExtractsSrvResponses) {
614 constexpr char kName[] = "name.test";
615
616 const TestServiceRecord kRecord1 = {2, 3, 1223, "foo.com"};
617 const TestServiceRecord kRecord2 = {5, 10, 80, "bar.com"};
618 const TestServiceRecord kRecord3 = {5, 1, 5, "google.com"};
619 const TestServiceRecord kRecord4 = {2, 100, 12345, "chromium.org"};
620
621 DnsResponse response = BuildTestDnsServiceResponse(
622 kName, {kRecord1, kRecord2, kRecord3, kRecord4});
623 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
624
625 ResultsOrError results =
626 extractor.ExtractDnsResults(DnsQueryType::SRV,
627 /*original_domain_name=*/kName,
628 /*request_port=*/0);
629
630 ASSERT_TRUE(results.has_value());
631 EXPECT_THAT(results.value(),
632 ElementsAre(Pointee(ExpectHostResolverInternalDataResult(
633 kName, DnsQueryType::SRV, kDnsSource,
634 /*expiration_matcher=*/Ne(absl::nullopt),
635 /*timed_expiration_matcher=*/Ne(absl::nullopt),
636 /*endpoints_matcher=*/IsEmpty(),
637 /*strings_matcher=*/IsEmpty(),
638 /*hosts_matcher=*/
639 UnorderedElementsAre(HostPortPair("foo.com", 1223),
640 HostPortPair("bar.com", 80),
641 HostPortPair("google.com", 5),
642 HostPortPair("chromium.org", 12345))))));
643
644 // Expect ordered by priority, and random within a priority.
645 std::vector<HostPortPair> result_hosts =
646 (*results.value().begin())->AsData().hosts();
647 auto priority2 =
648 std::vector<HostPortPair>(result_hosts.begin(), result_hosts.begin() + 2);
649 EXPECT_THAT(priority2, testing::UnorderedElementsAre(
650 HostPortPair("foo.com", 1223),
651 HostPortPair("chromium.org", 12345)));
652 auto priority5 =
653 std::vector<HostPortPair>(result_hosts.begin() + 2, result_hosts.end());
654 EXPECT_THAT(priority5,
655 testing::UnorderedElementsAre(HostPortPair("bar.com", 80),
656 HostPortPair("google.com", 5)));
657 }
658
659 // 0-weight services are allowed. Ensure that we can handle such records,
660 // especially the case where all entries have weight 0.
TEST_F(DnsResponseResultExtractorTest,ExtractsZeroWeightSrvResponses)661 TEST_F(DnsResponseResultExtractorTest, ExtractsZeroWeightSrvResponses) {
662 constexpr char kName[] = "name.test";
663
664 const TestServiceRecord kRecord1 = {5, 0, 80, "bar.com"};
665 const TestServiceRecord kRecord2 = {5, 0, 5, "google.com"};
666
667 DnsResponse response =
668 BuildTestDnsServiceResponse(kName, {kRecord1, kRecord2});
669 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
670
671 ResultsOrError results =
672 extractor.ExtractDnsResults(DnsQueryType::SRV,
673 /*original_domain_name=*/kName,
674 /*request_port=*/0);
675
676 ASSERT_TRUE(results.has_value());
677 EXPECT_THAT(results.value(),
678 ElementsAre(Pointee(ExpectHostResolverInternalDataResult(
679 kName, DnsQueryType::SRV, kDnsSource,
680 /*expiration_matcher=*/Ne(absl::nullopt),
681 /*timed_expiration_matcher=*/Ne(absl::nullopt),
682 /*endpoints_matcher=*/IsEmpty(),
683 /*strings_matcher=*/IsEmpty(),
684 /*hosts_matcher=*/
685 UnorderedElementsAre(HostPortPair("bar.com", 80),
686 HostPortPair("google.com", 5))))));
687 }
688
TEST_F(DnsResponseResultExtractorTest,ExtractsNxdomainSrvResponses)689 TEST_F(DnsResponseResultExtractorTest, ExtractsNxdomainSrvResponses) {
690 constexpr char kName[] = "name.test";
691 constexpr auto kTtl = base::Days(7);
692
693 DnsResponse response = BuildTestDnsResponse(
694 kName, dns_protocol::kTypeSRV, /*answers=*/{},
695 /*authority=*/
696 {BuildTestDnsRecord(kName, dns_protocol::kTypeSOA, "fake rdata", kTtl)},
697 /*additional=*/{}, dns_protocol::kRcodeNXDOMAIN);
698 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
699
700 ResultsOrError results =
701 extractor.ExtractDnsResults(DnsQueryType::SRV,
702 /*original_domain_name=*/kName,
703 /*request_port=*/0);
704
705 ASSERT_TRUE(results.has_value());
706 EXPECT_THAT(results.value(),
707 ElementsAre(Pointee(ExpectHostResolverInternalErrorResult(
708 kName, DnsQueryType::SRV, kDnsSource,
709 /*expiration_matcher=*/Eq(tick_clock_.NowTicks() + kTtl),
710 /*timed_expiration_matcher=*/Eq(clock_.Now() + kTtl),
711 ERR_NAME_NOT_RESOLVED))));
712 }
713
TEST_F(DnsResponseResultExtractorTest,ExtractsNodataSrvResponses)714 TEST_F(DnsResponseResultExtractorTest, ExtractsNodataSrvResponses) {
715 constexpr char kName[] = "name.test";
716 constexpr auto kTtl = base::Hours(12);
717
718 DnsResponse response = BuildTestDnsResponse(
719 kName, dns_protocol::kTypeSRV, /*answers=*/{},
720 /*authority=*/
721 {BuildTestDnsRecord(kName, dns_protocol::kTypeSOA, "fake rdata", kTtl)});
722 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
723
724 ResultsOrError results =
725 extractor.ExtractDnsResults(DnsQueryType::SRV,
726 /*original_domain_name=*/kName,
727 /*request_port=*/0);
728
729 ASSERT_TRUE(results.has_value());
730 EXPECT_THAT(results.value(),
731 ElementsAre(Pointee(ExpectHostResolverInternalErrorResult(
732 kName, DnsQueryType::SRV, kDnsSource,
733 /*expiration_matcher=*/Eq(tick_clock_.NowTicks() + kTtl),
734 /*timed_expiration_matcher=*/Eq(clock_.Now() + kTtl),
735 ERR_NAME_NOT_RESOLVED))));
736 }
737
TEST_F(DnsResponseResultExtractorTest,RejectsMalformedSrvRecord)738 TEST_F(DnsResponseResultExtractorTest, RejectsMalformedSrvRecord) {
739 constexpr char kName[] = "name.test";
740
741 DnsResponse response = BuildTestDnsResponse(
742 kName, dns_protocol::kTypeSRV,
743 {BuildTestDnsRecord(kName, dns_protocol::kTypeSRV,
744 "malformed rdata")} /* answers */);
745 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
746
747 EXPECT_EQ(extractor
748 .ExtractDnsResults(DnsQueryType::SRV,
749 /*original_domain_name=*/kName,
750 /*request_port=*/0)
751 .error_or(ExtractionError::kOk),
752 ExtractionError::kMalformedRecord);
753 }
754
TEST_F(DnsResponseResultExtractorTest,RejectsWrongNameSrvRecord)755 TEST_F(DnsResponseResultExtractorTest, RejectsWrongNameSrvRecord) {
756 constexpr char kName[] = "name.test";
757
758 const TestServiceRecord kRecord = {2, 3, 1223, "foo.com"};
759 DnsResponse response =
760 BuildTestDnsServiceResponse(kName, {kRecord}, "different.test");
761 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
762
763 EXPECT_EQ(extractor
764 .ExtractDnsResults(DnsQueryType::SRV,
765 /*original_domain_name=*/kName,
766 /*request_port=*/0)
767 .error_or(ExtractionError::kOk),
768 ExtractionError::kNameMismatch);
769 }
770
TEST_F(DnsResponseResultExtractorTest,IgnoresWrongTypeSrvResponses)771 TEST_F(DnsResponseResultExtractorTest, IgnoresWrongTypeSrvResponses) {
772 constexpr char kName[] = "name.test";
773
774 DnsResponse response = BuildTestDnsResponse(
775 kName, dns_protocol::kTypeSRV,
776 {BuildTestAddressRecord(kName, IPAddress(1, 2, 3, 4))});
777 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
778
779 ResultsOrError results =
780 extractor.ExtractDnsResults(DnsQueryType::SRV,
781 /*original_domain_name=*/kName,
782 /*request_port=*/0);
783
784 // Expect empty results because NODATA is not cacheable (due to no TTL).
785 ASSERT_TRUE(results.has_value());
786 EXPECT_THAT(results.value(), IsEmpty());
787 }
788
TEST_F(DnsResponseResultExtractorTest,ExtractsBasicHttpsResponses)789 TEST_F(DnsResponseResultExtractorTest, ExtractsBasicHttpsResponses) {
790 constexpr char kName[] = "https.test";
791 constexpr auto kTtl = base::Hours(12);
792
793 DnsResponse response =
794 BuildTestDnsResponse(kName, dns_protocol::kTypeHttps,
795 {BuildTestHttpsServiceRecord(kName,
796 /*priority=*/4,
797 /*service_name=*/".",
798 /*params=*/{}, kTtl)});
799 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
800
801 ResultsOrError results =
802 extractor.ExtractDnsResults(DnsQueryType::HTTPS,
803 /*original_domain_name=*/kName,
804 /*request_port=*/0);
805
806 ASSERT_TRUE(results.has_value());
807 EXPECT_THAT(
808 results.value(),
809 ElementsAre(Pointee(ExpectHostResolverInternalMetadataResult(
810 kName, DnsQueryType::HTTPS, kDnsSource,
811 Eq(tick_clock_.NowTicks() + kTtl), Eq(clock_.Now() + kTtl),
812 ElementsAre(
813 Pair(4, ExpectConnectionEndpointMetadata(
814 ElementsAre(dns_protocol::kHttpsServiceDefaultAlpn),
815 /*ech_config_list_matcher=*/IsEmpty(), kName)))))));
816 }
817
TEST_F(DnsResponseResultExtractorTest,ExtractsComprehensiveHttpsResponses)818 TEST_F(DnsResponseResultExtractorTest, ExtractsComprehensiveHttpsResponses) {
819 constexpr char kName[] = "https.test";
820 constexpr char kAlpn[] = "foo";
821 constexpr uint8_t kEchConfig[] = "EEEEEEEEECH!";
822 constexpr auto kTtl = base::Hours(12);
823
824 DnsResponse response = BuildTestDnsResponse(
825 kName, dns_protocol::kTypeHttps,
826 {BuildTestHttpsServiceRecord(
827 kName, /*priority=*/4,
828 /*service_name=*/".",
829 /*params=*/
830 {BuildTestHttpsServiceAlpnParam({kAlpn}),
831 BuildTestHttpsServiceEchConfigParam(kEchConfig)},
832 kTtl),
833 BuildTestHttpsServiceRecord(
834 kName, /*priority=*/3,
835 /*service_name=*/".",
836 /*params=*/
837 {BuildTestHttpsServiceAlpnParam({kAlpn}),
838 {dns_protocol::kHttpsServiceParamKeyNoDefaultAlpn, ""}},
839 /*ttl=*/base::Days(3))});
840 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
841
842 ResultsOrError results =
843 extractor.ExtractDnsResults(DnsQueryType::HTTPS,
844 /*original_domain_name=*/kName,
845 /*request_port=*/0);
846
847 ASSERT_TRUE(results.has_value());
848 EXPECT_THAT(
849 results.value(),
850 ElementsAre(Pointee(ExpectHostResolverInternalMetadataResult(
851 kName, DnsQueryType::HTTPS, kDnsSource,
852 Eq(tick_clock_.NowTicks() + kTtl), Eq(clock_.Now() + kTtl),
853 ElementsAre(
854 Pair(3, ExpectConnectionEndpointMetadata(
855 ElementsAre(kAlpn),
856 /*ech_config_list_matcher=*/IsEmpty(), kName)),
857 Pair(4, ExpectConnectionEndpointMetadata(
858 ElementsAre(kAlpn,
859 dns_protocol::kHttpsServiceDefaultAlpn),
860 ElementsAreArray(kEchConfig), kName)))))));
861 }
862
TEST_F(DnsResponseResultExtractorTest,IgnoresHttpsResponseWithAlias)863 TEST_F(DnsResponseResultExtractorTest, IgnoresHttpsResponseWithAlias) {
864 constexpr char kName[] = "https.test";
865
866 DnsResponse response =
867 BuildTestDnsResponse(kName, dns_protocol::kTypeHttps,
868 {BuildTestHttpsServiceRecord(kName,
869 /*priority=*/4,
870 /*service_name=*/".",
871 /*params=*/{}),
872 BuildTestHttpsAliasRecord(kName, "alias.test")});
873 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
874
875 ResultsOrError results =
876 extractor.ExtractDnsResults(DnsQueryType::HTTPS,
877 /*original_domain_name=*/kName,
878 /*request_port=*/0);
879
880 // Expect empty metadata result to signify compatible HTTPS records with no
881 // data of use to Chrome.
882 ASSERT_TRUE(results.has_value());
883 EXPECT_THAT(results.value(),
884 ElementsAre(Pointee(ExpectHostResolverInternalMetadataResult(
885 kName, DnsQueryType::HTTPS, kDnsSource,
886 /*expiration_matcher=*/Ne(absl::nullopt),
887 /*timed_expiration_matcher=*/Ne(absl::nullopt),
888 /*metadatas_matcher=*/IsEmpty()))));
889 }
890
891 // Expect the entire response to be ignored if all HTTPS records have the
892 // "no-default-alpn" param.
TEST_F(DnsResponseResultExtractorTest,IgnoresHttpsResponseWithNoDefaultAlpn)893 TEST_F(DnsResponseResultExtractorTest, IgnoresHttpsResponseWithNoDefaultAlpn) {
894 constexpr char kName[] = "https.test";
895
896 DnsResponse response = BuildTestDnsResponse(
897 kName, dns_protocol::kTypeHttps,
898 {BuildTestHttpsServiceRecord(
899 kName, /*priority=*/4,
900 /*service_name=*/".",
901 /*params=*/
902 {BuildTestHttpsServiceAlpnParam({"foo1"}),
903 {dns_protocol::kHttpsServiceParamKeyNoDefaultAlpn, ""}}),
904 BuildTestHttpsServiceRecord(
905 kName, /*priority=*/5,
906 /*service_name=*/".",
907 /*params=*/
908 {BuildTestHttpsServiceAlpnParam({"foo2"}),
909 {dns_protocol::kHttpsServiceParamKeyNoDefaultAlpn, ""}})});
910 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
911
912 ResultsOrError results =
913 extractor.ExtractDnsResults(DnsQueryType::HTTPS,
914 /*original_domain_name=*/kName,
915 /*request_port=*/0);
916
917 // Expect empty metadata result to signify compatible HTTPS records with no
918 // data of use to Chrome.
919 ASSERT_TRUE(results.has_value());
920 EXPECT_THAT(results.value(),
921 ElementsAre(Pointee(ExpectHostResolverInternalMetadataResult(
922 kName, DnsQueryType::HTTPS, kDnsSource,
923 /*expiration_matcher=*/Ne(absl::nullopt),
924 /*timed_expiration_matcher=*/Ne(absl::nullopt),
925 /*metadatas_matcher=*/IsEmpty()))));
926 }
927
928 // Unsupported/unknown HTTPS params are simply ignored if not marked mandatory.
TEST_F(DnsResponseResultExtractorTest,IgnoresUnsupportedParamsInHttpsRecord)929 TEST_F(DnsResponseResultExtractorTest, IgnoresUnsupportedParamsInHttpsRecord) {
930 constexpr char kName[] = "https.test";
931 constexpr uint16_t kMadeUpParamKey = 65500; // From the private-use block.
932
933 DnsResponse response = BuildTestDnsResponse(
934 kName, dns_protocol::kTypeHttps,
935 {BuildTestHttpsServiceRecord(kName, /*priority=*/4,
936 /*service_name=*/".",
937 /*params=*/
938 {{kMadeUpParamKey, "foo"}})});
939 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
940
941 ResultsOrError results =
942 extractor.ExtractDnsResults(DnsQueryType::HTTPS,
943 /*original_domain_name=*/kName,
944 /*request_port=*/0);
945
946 ASSERT_TRUE(results.has_value());
947 EXPECT_THAT(
948 results.value(),
949 ElementsAre(Pointee(ExpectHostResolverInternalMetadataResult(
950 kName, DnsQueryType::HTTPS, kDnsSource,
951 /*expiration_matcher=*/Ne(absl::nullopt),
952 /*timed_expiration_matcher=*/Ne(absl::nullopt),
953 ElementsAre(
954 Pair(4, ExpectConnectionEndpointMetadata(
955 ElementsAre(dns_protocol::kHttpsServiceDefaultAlpn),
956 /*ech_config_list_matcher=*/IsEmpty(), kName)))))));
957 }
958
959 // Entire record is dropped if an unsupported/unknown HTTPS param is marked
960 // mandatory.
TEST_F(DnsResponseResultExtractorTest,IgnoresHttpsRecordWithUnsupportedMandatoryParam)961 TEST_F(DnsResponseResultExtractorTest,
962 IgnoresHttpsRecordWithUnsupportedMandatoryParam) {
963 constexpr char kName[] = "https.test";
964 constexpr uint16_t kMadeUpParamKey = 65500; // From the private-use block.
965
966 DnsResponse response = BuildTestDnsResponse(
967 kName, dns_protocol::kTypeHttps,
968 {BuildTestHttpsServiceRecord(
969 kName, /*priority=*/4,
970 /*service_name=*/".",
971 /*params=*/
972 {BuildTestHttpsServiceAlpnParam({"ignored_alpn"}),
973 BuildTestHttpsServiceMandatoryParam({kMadeUpParamKey}),
974 {kMadeUpParamKey, "foo"}}),
975 BuildTestHttpsServiceRecord(
976 kName, /*priority=*/5,
977 /*service_name=*/".",
978 /*params=*/{BuildTestHttpsServiceAlpnParam({"foo"})})});
979 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
980
981 ResultsOrError results =
982 extractor.ExtractDnsResults(DnsQueryType::HTTPS,
983 /*original_domain_name=*/kName,
984 /*request_port=*/0);
985
986 ASSERT_TRUE(results.has_value());
987 EXPECT_THAT(
988 results.value(),
989 ElementsAre(Pointee(ExpectHostResolverInternalMetadataResult(
990 kName, DnsQueryType::HTTPS, kDnsSource,
991 /*expiration_matcher=*/Ne(absl::nullopt),
992 /*timed_expiration_matcher=*/Ne(absl::nullopt),
993 ElementsAre(Pair(
994 5, ExpectConnectionEndpointMetadata(
995 ElementsAre("foo", dns_protocol::kHttpsServiceDefaultAlpn),
996 /*ech_config_list_matcher=*/IsEmpty(), kName)))))));
997 }
998
TEST_F(DnsResponseResultExtractorTest,ExtractsHttpsRecordWithMatchingServiceName)999 TEST_F(DnsResponseResultExtractorTest,
1000 ExtractsHttpsRecordWithMatchingServiceName) {
1001 constexpr char kName[] = "https.test";
1002
1003 DnsResponse response = BuildTestDnsResponse(
1004 kName, dns_protocol::kTypeHttps,
1005 {BuildTestHttpsServiceRecord(kName, /*priority=*/4,
1006 /*service_name=*/kName,
1007 /*params=*/
1008 {BuildTestHttpsServiceAlpnParam({"foo"})})});
1009 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1010
1011 ResultsOrError results =
1012 extractor.ExtractDnsResults(DnsQueryType::HTTPS,
1013 /*original_domain_name=*/kName,
1014 /*request_port=*/0);
1015
1016 ASSERT_TRUE(results.has_value());
1017 EXPECT_THAT(
1018 results.value(),
1019 ElementsAre(Pointee(ExpectHostResolverInternalMetadataResult(
1020 kName, DnsQueryType::HTTPS, kDnsSource,
1021 /*expiration_matcher=*/Ne(absl::nullopt),
1022 /*timed_expiration_matcher=*/Ne(absl::nullopt),
1023 ElementsAre(Pair(
1024 4, ExpectConnectionEndpointMetadata(
1025 ElementsAre("foo", dns_protocol::kHttpsServiceDefaultAlpn),
1026 /*ech_config_list_matcher=*/IsEmpty(), kName)))))));
1027 }
1028
TEST_F(DnsResponseResultExtractorTest,ExtractsHttpsRecordWithMatchingDefaultServiceName)1029 TEST_F(DnsResponseResultExtractorTest,
1030 ExtractsHttpsRecordWithMatchingDefaultServiceName) {
1031 constexpr char kName[] = "https.test";
1032
1033 DnsResponse response = BuildTestDnsResponse(
1034 kName, dns_protocol::kTypeHttps,
1035 {BuildTestHttpsServiceRecord(kName, /*priority=*/4,
1036 /*service_name=*/".",
1037 /*params=*/
1038 {BuildTestHttpsServiceAlpnParam({"foo"})})});
1039 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1040
1041 ResultsOrError results =
1042 extractor.ExtractDnsResults(DnsQueryType::HTTPS,
1043 /*original_domain_name=*/kName,
1044 /*request_port=*/0);
1045
1046 ASSERT_TRUE(results.has_value());
1047 EXPECT_THAT(
1048 results.value(),
1049 ElementsAre(Pointee(ExpectHostResolverInternalMetadataResult(
1050 kName, DnsQueryType::HTTPS, kDnsSource,
1051 /*expiration_matcher=*/Ne(absl::nullopt),
1052 /*timed_expiration_matcher=*/Ne(absl::nullopt),
1053 ElementsAre(Pair(
1054 4, ExpectConnectionEndpointMetadata(
1055 ElementsAre("foo", dns_protocol::kHttpsServiceDefaultAlpn),
1056 /*ech_config_list_matcher=*/IsEmpty(), kName)))))));
1057 }
1058
TEST_F(DnsResponseResultExtractorTest,ExtractsHttpsRecordWithPrefixedNameAndMatchingServiceName)1059 TEST_F(DnsResponseResultExtractorTest,
1060 ExtractsHttpsRecordWithPrefixedNameAndMatchingServiceName) {
1061 constexpr char kName[] = "https.test";
1062 constexpr char kPrefixedName[] = "_444._https.https.test";
1063
1064 DnsResponse response = BuildTestDnsResponse(
1065 kPrefixedName, dns_protocol::kTypeHttps,
1066 {BuildTestHttpsServiceRecord(kPrefixedName, /*priority=*/4,
1067 /*service_name=*/kName,
1068 /*params=*/
1069 {BuildTestHttpsServiceAlpnParam({"foo"})})});
1070 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1071
1072 ResultsOrError results =
1073 extractor.ExtractDnsResults(DnsQueryType::HTTPS,
1074 /*original_domain_name=*/kName,
1075 /*request_port=*/0);
1076
1077 ASSERT_TRUE(results.has_value());
1078 EXPECT_THAT(
1079 results.value(),
1080 ElementsAre(Pointee(ExpectHostResolverInternalMetadataResult(
1081 kPrefixedName, DnsQueryType::HTTPS, kDnsSource,
1082 /*expiration_matcher=*/Ne(absl::nullopt),
1083 /*timed_expiration_matcher=*/Ne(absl::nullopt),
1084 ElementsAre(Pair(
1085 4, ExpectConnectionEndpointMetadata(
1086 ElementsAre("foo", dns_protocol::kHttpsServiceDefaultAlpn),
1087 /*ech_config_list_matcher=*/IsEmpty(), kName)))))));
1088 }
1089
TEST_F(DnsResponseResultExtractorTest,ExtractsHttpsRecordWithAliasingAndMatchingServiceName)1090 TEST_F(DnsResponseResultExtractorTest,
1091 ExtractsHttpsRecordWithAliasingAndMatchingServiceName) {
1092 constexpr char kName[] = "https.test";
1093
1094 DnsResponse response = BuildTestDnsResponse(
1095 kName, dns_protocol::kTypeHttps,
1096 {BuildTestCnameRecord(kName, "alias.test"),
1097 BuildTestHttpsServiceRecord("alias.test", /*priority=*/4,
1098 /*service_name=*/kName,
1099 /*params=*/
1100 {BuildTestHttpsServiceAlpnParam({"foo"})})});
1101 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1102
1103 ResultsOrError results =
1104 extractor.ExtractDnsResults(DnsQueryType::HTTPS,
1105 /*original_domain_name=*/kName,
1106 /*request_port=*/0);
1107
1108 ASSERT_TRUE(results.has_value());
1109 EXPECT_THAT(
1110 results.value(),
1111 UnorderedElementsAre(
1112 Pointee(ExpectHostResolverInternalAliasResult(
1113 kName, DnsQueryType::HTTPS, kDnsSource,
1114 /*expiration_matcher=*/Ne(absl::nullopt),
1115 /*timed_expiration_matcher=*/Ne(absl::nullopt), "alias.test")),
1116 Pointee(ExpectHostResolverInternalMetadataResult(
1117 "alias.test", DnsQueryType::HTTPS, kDnsSource,
1118 /*expiration_matcher=*/Ne(absl::nullopt),
1119 /*timed_expiration_matcher=*/Ne(absl::nullopt),
1120 ElementsAre(Pair(
1121 4, ExpectConnectionEndpointMetadata(
1122 ElementsAre("foo",
1123 dns_protocol::kHttpsServiceDefaultAlpn),
1124 /*ech_config_list_matcher=*/IsEmpty(), kName)))))));
1125 }
1126
TEST_F(DnsResponseResultExtractorTest,IgnoreHttpsRecordWithNonMatchingServiceName)1127 TEST_F(DnsResponseResultExtractorTest,
1128 IgnoreHttpsRecordWithNonMatchingServiceName) {
1129 constexpr char kName[] = "https.test";
1130
1131 DnsResponse response = BuildTestDnsResponse(
1132 kName, dns_protocol::kTypeHttps,
1133 {BuildTestHttpsServiceRecord(
1134 kName, /*priority=*/4,
1135 /*service_name=*/"other.service.test",
1136 /*params=*/
1137 {BuildTestHttpsServiceAlpnParam({"ignored"})}),
1138 BuildTestHttpsServiceRecord("https.test", /*priority=*/5,
1139 /*service_name=*/".",
1140 /*params=*/
1141 {BuildTestHttpsServiceAlpnParam({"foo"})})});
1142 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1143
1144 ResultsOrError results =
1145 extractor.ExtractDnsResults(DnsQueryType::HTTPS,
1146 /*original_domain_name=*/kName,
1147 /*request_port=*/0);
1148
1149 ASSERT_TRUE(results.has_value());
1150 EXPECT_THAT(
1151 results.value(),
1152 ElementsAre(Pointee(ExpectHostResolverInternalMetadataResult(
1153 kName, DnsQueryType::HTTPS, kDnsSource,
1154 /*expiration_matcher=*/Ne(absl::nullopt),
1155 /*timed_expiration_matcher=*/Ne(absl::nullopt),
1156 ElementsAre(Pair(
1157 5, ExpectConnectionEndpointMetadata(
1158 ElementsAre("foo", dns_protocol::kHttpsServiceDefaultAlpn),
1159 /*ech_config_list_matcher=*/IsEmpty(), kName)))))));
1160 }
1161
TEST_F(DnsResponseResultExtractorTest,ExtractsHttpsRecordWithPrefixedNameAndDefaultServiceName)1162 TEST_F(DnsResponseResultExtractorTest,
1163 ExtractsHttpsRecordWithPrefixedNameAndDefaultServiceName) {
1164 constexpr char kPrefixedName[] = "_445._https.https.test";
1165
1166 DnsResponse response = BuildTestDnsResponse(
1167 kPrefixedName, dns_protocol::kTypeHttps,
1168 {BuildTestHttpsServiceRecord(kPrefixedName, /*priority=*/4,
1169 /*service_name=*/".",
1170 /*params=*/
1171 {BuildTestHttpsServiceAlpnParam({"foo"})})});
1172 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1173
1174 ResultsOrError results =
1175 extractor.ExtractDnsResults(DnsQueryType::HTTPS,
1176 /*original_domain_name=*/"https.test",
1177 /*request_port=*/0);
1178
1179 ASSERT_TRUE(results.has_value());
1180 EXPECT_THAT(
1181 results.value(),
1182 ElementsAre(Pointee(ExpectHostResolverInternalMetadataResult(
1183 kPrefixedName, DnsQueryType::HTTPS, kDnsSource,
1184 /*expiration_matcher=*/Ne(absl::nullopt),
1185 /*timed_expiration_matcher=*/Ne(absl::nullopt),
1186 ElementsAre(Pair(
1187 4,
1188 ExpectConnectionEndpointMetadata(
1189 ElementsAre("foo", dns_protocol::kHttpsServiceDefaultAlpn),
1190 /*ech_config_list_matcher=*/IsEmpty(), kPrefixedName)))))));
1191 }
1192
TEST_F(DnsResponseResultExtractorTest,ExtractsHttpsRecordWithAliasingAndDefaultServiceName)1193 TEST_F(DnsResponseResultExtractorTest,
1194 ExtractsHttpsRecordWithAliasingAndDefaultServiceName) {
1195 constexpr char kName[] = "https.test";
1196
1197 DnsResponse response = BuildTestDnsResponse(
1198 kName, dns_protocol::kTypeHttps,
1199 {BuildTestCnameRecord(kName, "alias.test"),
1200 BuildTestHttpsServiceRecord("alias.test", /*priority=*/4,
1201 /*service_name=*/".",
1202 /*params=*/
1203 {BuildTestHttpsServiceAlpnParam({"foo"})})});
1204 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1205
1206 ResultsOrError results =
1207 extractor.ExtractDnsResults(DnsQueryType::HTTPS,
1208 /*original_domain_name=*/kName,
1209 /*request_port=*/0);
1210
1211 ASSERT_TRUE(results.has_value());
1212 EXPECT_THAT(
1213 results.value(),
1214 UnorderedElementsAre(
1215 Pointee(ExpectHostResolverInternalAliasResult(
1216 kName, DnsQueryType::HTTPS, kDnsSource,
1217 /*expiration_matcher=*/Ne(absl::nullopt),
1218 /*timed_expiration_matcher=*/Ne(absl::nullopt), "alias.test")),
1219 Pointee(ExpectHostResolverInternalMetadataResult(
1220 "alias.test", DnsQueryType::HTTPS, kDnsSource,
1221 /*expiration_matcher=*/Ne(absl::nullopt),
1222 /*timed_expiration_matcher=*/Ne(absl::nullopt),
1223 ElementsAre(Pair(
1224 4, ExpectConnectionEndpointMetadata(
1225 ElementsAre("foo",
1226 dns_protocol::kHttpsServiceDefaultAlpn),
1227 /*ech_config_list_matcher=*/IsEmpty(),
1228 "alias.test")))))));
1229 }
1230
TEST_F(DnsResponseResultExtractorTest,ExtractsHttpsRecordWithMatchingPort)1231 TEST_F(DnsResponseResultExtractorTest, ExtractsHttpsRecordWithMatchingPort) {
1232 constexpr char kName[] = "https.test";
1233 constexpr uint16_t kPort = 4567;
1234
1235 DnsResponse response = BuildTestDnsResponse(
1236 kName, dns_protocol::kTypeHttps,
1237 {BuildTestHttpsServiceRecord(kName, /*priority=*/4,
1238 /*service_name=*/".",
1239 /*params=*/
1240 {BuildTestHttpsServiceAlpnParam({"foo"}),
1241 BuildTestHttpsServicePortParam(kPort)})});
1242 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1243
1244 ResultsOrError results =
1245 extractor.ExtractDnsResults(DnsQueryType::HTTPS,
1246 /*original_domain_name=*/kName,
1247 /*request_port=*/kPort);
1248
1249 ASSERT_TRUE(results.has_value());
1250 EXPECT_THAT(
1251 results.value(),
1252 UnorderedElementsAre(Pointee(ExpectHostResolverInternalMetadataResult(
1253 kName, DnsQueryType::HTTPS, kDnsSource,
1254 /*expiration_matcher=*/Ne(absl::nullopt),
1255 /*timed_expiration_matcher=*/Ne(absl::nullopt),
1256 ElementsAre(Pair(
1257 4, ExpectConnectionEndpointMetadata(
1258 ElementsAre("foo", dns_protocol::kHttpsServiceDefaultAlpn),
1259 /*ech_config_list_matcher=*/IsEmpty(), kName)))))));
1260 }
1261
TEST_F(DnsResponseResultExtractorTest,IgnoresHttpsRecordWithMismatchingPort)1262 TEST_F(DnsResponseResultExtractorTest, IgnoresHttpsRecordWithMismatchingPort) {
1263 constexpr char kName[] = "https.test";
1264
1265 DnsResponse response = BuildTestDnsResponse(
1266 kName, dns_protocol::kTypeHttps,
1267 {BuildTestHttpsServiceRecord(kName, /*priority=*/4,
1268 /*service_name=*/".",
1269 /*params=*/
1270 {BuildTestHttpsServiceAlpnParam({"ignored"}),
1271 BuildTestHttpsServicePortParam(1003)}),
1272 BuildTestHttpsServiceRecord(kName, /*priority=*/4,
1273 /*service_name=*/".",
1274 /*params=*/
1275 {BuildTestHttpsServiceAlpnParam({"foo"})})});
1276 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1277
1278 ResultsOrError results =
1279 extractor.ExtractDnsResults(DnsQueryType::HTTPS,
1280 /*original_domain_name=*/kName,
1281 /*request_port=*/55);
1282
1283 ASSERT_TRUE(results.has_value());
1284 EXPECT_THAT(
1285 results.value(),
1286 UnorderedElementsAre(Pointee(ExpectHostResolverInternalMetadataResult(
1287 kName, DnsQueryType::HTTPS, kDnsSource,
1288 /*expiration_matcher=*/Ne(absl::nullopt),
1289 /*timed_expiration_matcher=*/Ne(absl::nullopt),
1290 ElementsAre(Pair(
1291 4, ExpectConnectionEndpointMetadata(
1292 ElementsAre("foo", dns_protocol::kHttpsServiceDefaultAlpn),
1293 /*ech_config_list_matcher=*/IsEmpty(), kName)))))));
1294 }
1295
1296 // HTTPS records with "no-default-alpn" but also no "alpn" are not
1297 // "self-consistent" and should be ignored.
TEST_F(DnsResponseResultExtractorTest,IgnoresHttpsRecordWithNoAlpn)1298 TEST_F(DnsResponseResultExtractorTest, IgnoresHttpsRecordWithNoAlpn) {
1299 constexpr char kName[] = "https.test";
1300
1301 DnsResponse response = BuildTestDnsResponse(
1302 kName, dns_protocol::kTypeHttps,
1303 {BuildTestHttpsServiceRecord(
1304 kName, /*priority=*/4,
1305 /*service_name=*/".",
1306 /*params=*/
1307 {{dns_protocol::kHttpsServiceParamKeyNoDefaultAlpn, ""}}),
1308 BuildTestHttpsServiceRecord(kName, /*priority=*/4,
1309 /*service_name=*/".",
1310 /*params=*/
1311 {BuildTestHttpsServiceAlpnParam({"foo"})})});
1312 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1313
1314 ResultsOrError results =
1315 extractor.ExtractDnsResults(DnsQueryType::HTTPS,
1316 /*original_domain_name=*/kName,
1317 /*request_port=*/55);
1318
1319 ASSERT_TRUE(results.has_value());
1320 EXPECT_THAT(
1321 results.value(),
1322 UnorderedElementsAre(Pointee(ExpectHostResolverInternalMetadataResult(
1323 kName, DnsQueryType::HTTPS, kDnsSource,
1324 /*expiration_matcher=*/Ne(absl::nullopt),
1325 /*timed_expiration_matcher=*/Ne(absl::nullopt),
1326 ElementsAre(Pair(
1327 4, ExpectConnectionEndpointMetadata(
1328 ElementsAre("foo", dns_protocol::kHttpsServiceDefaultAlpn),
1329 /*ech_config_list_matcher=*/IsEmpty(), kName)))))));
1330 }
1331
1332 // Expect the entire response to be ignored if all HTTPS records have the
1333 // "no-default-alpn" param.
TEST_F(DnsResponseResultExtractorTest,IgnoresHttpsResponseWithNoCompatibleDefaultAlpn)1334 TEST_F(DnsResponseResultExtractorTest,
1335 IgnoresHttpsResponseWithNoCompatibleDefaultAlpn) {
1336 constexpr char kName[] = "https.test";
1337 constexpr uint16_t kMadeUpParamKey = 65500; // From the private-use block.
1338
1339 DnsResponse response = BuildTestDnsResponse(
1340 kName, dns_protocol::kTypeHttps,
1341 {BuildTestHttpsServiceRecord(
1342 kName, /*priority=*/4,
1343 /*service_name=*/".",
1344 /*params=*/
1345 {BuildTestHttpsServiceAlpnParam({"foo1"}),
1346 {dns_protocol::kHttpsServiceParamKeyNoDefaultAlpn, ""}}),
1347 BuildTestHttpsServiceRecord(
1348 kName, /*priority=*/5,
1349 /*service_name=*/".",
1350 /*params=*/
1351 {BuildTestHttpsServiceAlpnParam({"foo2"}),
1352 {dns_protocol::kHttpsServiceParamKeyNoDefaultAlpn, ""}}),
1353 // Allows default ALPN, but ignored due to non-matching service name.
1354 BuildTestHttpsServiceRecord(kName, /*priority=*/3,
1355 /*service_name=*/"other.test",
1356 /*params=*/{}),
1357 // Allows default ALPN, but ignored due to incompatible param.
1358 BuildTestHttpsServiceRecord(
1359 kName, /*priority=*/6,
1360 /*service_name=*/".",
1361 /*params=*/
1362 {BuildTestHttpsServiceMandatoryParam({kMadeUpParamKey}),
1363 {kMadeUpParamKey, "foo"}}),
1364 // Allows default ALPN, but ignored due to mismatching port.
1365 BuildTestHttpsServiceRecord(
1366 kName, /*priority=*/10,
1367 /*service_name=*/".",
1368 /*params=*/{BuildTestHttpsServicePortParam(1005)})});
1369 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1370
1371 ResultsOrError results =
1372 extractor.ExtractDnsResults(DnsQueryType::HTTPS,
1373 /*original_domain_name=*/kName,
1374 /*request_port=*/0);
1375
1376 ASSERT_TRUE(results.has_value());
1377 EXPECT_THAT(
1378 results.value(),
1379 UnorderedElementsAre(Pointee(ExpectHostResolverInternalMetadataResult(
1380 kName, DnsQueryType::HTTPS, kDnsSource,
1381 /*expiration_matcher=*/Ne(absl::nullopt),
1382 /*timed_expiration_matcher=*/Ne(absl::nullopt),
1383 /*metadatas_matcher=*/IsEmpty()))));
1384 }
1385
TEST_F(DnsResponseResultExtractorTest,ExtractsNxdomainHttpsResponses)1386 TEST_F(DnsResponseResultExtractorTest, ExtractsNxdomainHttpsResponses) {
1387 constexpr char kName[] = "https.test";
1388 constexpr auto kTtl = base::Minutes(45);
1389
1390 DnsResponse response = BuildTestDnsResponse(
1391 kName, dns_protocol::kTypeHttps, /*answers=*/{},
1392 /*authority=*/
1393 {BuildTestDnsRecord(kName, dns_protocol::kTypeSOA, "fake rdata", kTtl)},
1394 /*additional=*/{}, dns_protocol::kRcodeNXDOMAIN);
1395 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1396
1397 ResultsOrError results =
1398 extractor.ExtractDnsResults(DnsQueryType::HTTPS,
1399 /*original_domain_name=*/kName,
1400 /*request_port=*/0);
1401
1402 ASSERT_TRUE(results.has_value());
1403 EXPECT_THAT(results.value(),
1404 ElementsAre(Pointee(ExpectHostResolverInternalErrorResult(
1405 kName, DnsQueryType::HTTPS, kDnsSource,
1406 /*expiration_matcher=*/Eq(tick_clock_.NowTicks() + kTtl),
1407 /*timed_expiration_matcher=*/Eq(clock_.Now() + kTtl),
1408 ERR_NAME_NOT_RESOLVED))));
1409 }
1410
TEST_F(DnsResponseResultExtractorTest,ExtractsNodataHttpsResponses)1411 TEST_F(DnsResponseResultExtractorTest, ExtractsNodataHttpsResponses) {
1412 constexpr char kName[] = "https.test";
1413 constexpr auto kTtl = base::Hours(36);
1414
1415 DnsResponse response = BuildTestDnsResponse(
1416 kName, dns_protocol::kTypeHttps, /*answers=*/{},
1417 /*authority=*/
1418 {BuildTestDnsRecord(kName, dns_protocol::kTypeSOA, "fake rdata", kTtl)});
1419 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1420
1421 ResultsOrError results =
1422 extractor.ExtractDnsResults(DnsQueryType::HTTPS,
1423 /*original_domain_name=*/kName,
1424 /*request_port=*/0);
1425
1426 ASSERT_TRUE(results.has_value());
1427 EXPECT_THAT(results.value(),
1428 ElementsAre(Pointee(ExpectHostResolverInternalErrorResult(
1429 kName, DnsQueryType::HTTPS, kDnsSource,
1430 /*expiration_matcher=*/Eq(tick_clock_.NowTicks() + kTtl),
1431 /*timed_expiration_matcher=*/Eq(clock_.Now() + kTtl),
1432 ERR_NAME_NOT_RESOLVED))));
1433 }
1434
TEST_F(DnsResponseResultExtractorTest,RejectsMalformedHttpsRecord)1435 TEST_F(DnsResponseResultExtractorTest, RejectsMalformedHttpsRecord) {
1436 constexpr char kName[] = "https.test";
1437
1438 DnsResponse response = BuildTestDnsResponse(
1439 kName, dns_protocol::kTypeHttps,
1440 {BuildTestDnsRecord(kName, dns_protocol::kTypeHttps,
1441 "malformed rdata")} /* answers */);
1442 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1443
1444 EXPECT_EQ(extractor
1445 .ExtractDnsResults(DnsQueryType::HTTPS,
1446 /*original_domain_name=*/kName,
1447 /*request_port=*/0)
1448 .error_or(ExtractionError::kOk),
1449 ExtractionError::kMalformedRecord);
1450 }
1451
TEST_F(DnsResponseResultExtractorTest,RejectsWrongNameHttpsRecord)1452 TEST_F(DnsResponseResultExtractorTest, RejectsWrongNameHttpsRecord) {
1453 constexpr char kName[] = "https.test";
1454
1455 DnsResponse response = BuildTestDnsResponse(
1456 kName, dns_protocol::kTypeHttps,
1457 {BuildTestHttpsAliasRecord("different.test", "alias.test")});
1458 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1459
1460 EXPECT_EQ(extractor
1461 .ExtractDnsResults(DnsQueryType::HTTPS,
1462 /*original_domain_name=*/kName,
1463 /*request_port=*/0)
1464 .error_or(ExtractionError::kOk),
1465 ExtractionError::kNameMismatch);
1466 }
1467
TEST_F(DnsResponseResultExtractorTest,IgnoresWrongTypeHttpsResponses)1468 TEST_F(DnsResponseResultExtractorTest, IgnoresWrongTypeHttpsResponses) {
1469 constexpr char kName[] = "https.test";
1470
1471 DnsResponse response = BuildTestDnsResponse(
1472 kName, dns_protocol::kTypeHttps,
1473 {BuildTestAddressRecord(kName, IPAddress(1, 2, 3, 4))});
1474 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1475
1476 ResultsOrError results =
1477 extractor.ExtractDnsResults(DnsQueryType::HTTPS,
1478 /*original_domain_name=*/kName,
1479 /*request_port=*/0);
1480
1481 ASSERT_TRUE(results.has_value());
1482 EXPECT_THAT(results.value(), IsEmpty());
1483 }
1484
TEST_F(DnsResponseResultExtractorTest,IgnoresAdditionalHttpsRecords)1485 TEST_F(DnsResponseResultExtractorTest, IgnoresAdditionalHttpsRecords) {
1486 constexpr char kName[] = "https.test";
1487 constexpr auto kTtl = base::Days(5);
1488
1489 // Give all records an "alpn" value to help validate that only the correct
1490 // record is used.
1491 DnsResponse response = BuildTestDnsResponse(
1492 kName, dns_protocol::kTypeHttps,
1493 /*answers=*/
1494 {BuildTestHttpsServiceRecord(kName, /*priority=*/5u,
1495 /*service_name=*/".",
1496 /*params=*/
1497 {BuildTestHttpsServiceAlpnParam({"foo1"})},
1498 kTtl)},
1499 /*authority=*/{},
1500 /*additional=*/
1501 {BuildTestHttpsServiceRecord(kName, /*priority=*/3u,
1502 /*service_name=*/".",
1503 /*params=*/
1504 {BuildTestHttpsServiceAlpnParam({"foo2"})},
1505 base::Minutes(44)),
1506 BuildTestHttpsServiceRecord(kName, /*priority=*/2u,
1507 /*service_name=*/".",
1508 /*params=*/
1509 {BuildTestHttpsServiceAlpnParam({"foo3"})},
1510 base::Minutes(30))});
1511 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1512
1513 ResultsOrError results =
1514 extractor.ExtractDnsResults(DnsQueryType::HTTPS,
1515 /*original_domain_name=*/kName,
1516 /*request_port=*/0);
1517
1518 ASSERT_TRUE(results.has_value());
1519 EXPECT_THAT(
1520 results.value(),
1521 UnorderedElementsAre(Pointee(ExpectHostResolverInternalMetadataResult(
1522 kName, DnsQueryType::HTTPS, kDnsSource,
1523 Eq(tick_clock_.NowTicks() + kTtl), Eq(clock_.Now() + kTtl),
1524 ElementsAre(Pair(
1525 5,
1526 ExpectConnectionEndpointMetadata(
1527 ElementsAre("foo1", dns_protocol::kHttpsServiceDefaultAlpn),
1528 /*ech_config_list_matcher=*/IsEmpty(), kName)))))));
1529 }
1530
TEST_F(DnsResponseResultExtractorTest,IgnoresUnsolicitedHttpsRecords)1531 TEST_F(DnsResponseResultExtractorTest, IgnoresUnsolicitedHttpsRecords) {
1532 constexpr char kName[] = "name.test";
1533
1534 DnsResponse response = BuildTestDnsResponse(
1535 kName, dns_protocol::kTypeTXT,
1536 {BuildTestDnsRecord(kName, dns_protocol::kTypeTXT,
1537 "\003foo")} /* answers */,
1538 {} /* authority */,
1539 {BuildTestHttpsServiceRecord(
1540 "https.test", /*priority=*/3u, /*service_name=*/".",
1541 /*params=*/
1542 {BuildTestHttpsServiceAlpnParam({"foo2"})}, base::Minutes(44)),
1543 BuildTestHttpsServiceRecord("https.test", /*priority=*/2u,
1544 /*service_name=*/".",
1545 /*params=*/
1546 {BuildTestHttpsServiceAlpnParam({"foo3"})},
1547 base::Minutes(30))} /* additional */);
1548 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1549
1550 ResultsOrError results =
1551 extractor.ExtractDnsResults(DnsQueryType::TXT,
1552 /*original_domain_name=*/kName,
1553 /*request_port=*/0);
1554
1555 ASSERT_TRUE(results.has_value());
1556 EXPECT_THAT(results.value(),
1557 ElementsAre(Pointee(ExpectHostResolverInternalDataResult(
1558 kName, DnsQueryType::TXT, kDnsSource,
1559 /*expiration_matcher=*/Ne(absl::nullopt),
1560 /*timed_expiration_matcher=*/Ne(absl::nullopt),
1561 /*endpoints_matcher=*/IsEmpty(), ElementsAre("foo")))));
1562 }
1563
TEST_F(DnsResponseResultExtractorTest,HandlesInOrderCnameChain)1564 TEST_F(DnsResponseResultExtractorTest, HandlesInOrderCnameChain) {
1565 constexpr char kName[] = "first.test";
1566
1567 DnsResponse response =
1568 BuildTestDnsResponse(kName, dns_protocol::kTypeTXT,
1569 {BuildTestCnameRecord(kName, "second.test"),
1570 BuildTestCnameRecord("second.test", "third.test"),
1571 BuildTestCnameRecord("third.test", "fourth.test"),
1572 BuildTestTextRecord("fourth.test", {"foo"}),
1573 BuildTestTextRecord("fourth.test", {"bar"})});
1574 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1575
1576 ResultsOrError results =
1577 extractor.ExtractDnsResults(DnsQueryType::TXT,
1578 /*original_domain_name=*/kName,
1579 /*request_port=*/0);
1580
1581 ASSERT_TRUE(results.has_value());
1582 EXPECT_THAT(
1583 results.value(),
1584 UnorderedElementsAre(
1585 Pointee(ExpectHostResolverInternalAliasResult(
1586 kName, DnsQueryType::TXT, kDnsSource,
1587 /*expiration_matcher=*/Ne(absl::nullopt),
1588 /*timed_expiration_matcher=*/Ne(absl::nullopt), "second.test")),
1589 Pointee(ExpectHostResolverInternalAliasResult(
1590 "second.test", DnsQueryType::TXT, kDnsSource,
1591 /*expiration_matcher=*/Ne(absl::nullopt),
1592 /*timed_expiration_matcher=*/Ne(absl::nullopt), "third.test")),
1593 Pointee(ExpectHostResolverInternalAliasResult(
1594 "third.test", DnsQueryType::TXT, kDnsSource,
1595 /*expiration_matcher=*/Ne(absl::nullopt),
1596 /*timed_expiration_matcher=*/Ne(absl::nullopt), "fourth.test")),
1597 Pointee(ExpectHostResolverInternalDataResult(
1598 "fourth.test", DnsQueryType::TXT, kDnsSource,
1599 /*expiration_matcher=*/Ne(absl::nullopt),
1600 /*timed_expiration_matcher=*/Ne(absl::nullopt),
1601 /*endpoints_matcher=*/IsEmpty(),
1602 UnorderedElementsAre("foo", "bar")))));
1603 }
1604
TEST_F(DnsResponseResultExtractorTest,HandlesInOrderCnameChainTypeA)1605 TEST_F(DnsResponseResultExtractorTest, HandlesInOrderCnameChainTypeA) {
1606 constexpr char kName[] = "first.test";
1607
1608 const IPAddress kExpected(192, 168, 0, 1);
1609 IPEndPoint expected_endpoint(kExpected, 0 /* port */);
1610
1611 DnsResponse response =
1612 BuildTestDnsResponse(kName, dns_protocol::kTypeA,
1613 {BuildTestCnameRecord(kName, "second.test"),
1614 BuildTestCnameRecord("second.test", "third.test"),
1615 BuildTestCnameRecord("third.test", "fourth.test"),
1616 BuildTestAddressRecord("fourth.test", kExpected)});
1617 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1618
1619 ResultsOrError results =
1620 extractor.ExtractDnsResults(DnsQueryType::A,
1621 /*original_domain_name=*/kName,
1622 /*request_port=*/0);
1623
1624 ASSERT_TRUE(results.has_value());
1625 EXPECT_THAT(
1626 results.value(),
1627 UnorderedElementsAre(
1628 Pointee(ExpectHostResolverInternalAliasResult(
1629 kName, DnsQueryType::A, kDnsSource,
1630 /*expiration_matcher=*/Ne(absl::nullopt),
1631 /*timed_expiration_matcher=*/Ne(absl::nullopt), "second.test")),
1632 Pointee(ExpectHostResolverInternalAliasResult(
1633 "second.test", DnsQueryType::A, kDnsSource,
1634 /*expiration_matcher=*/Ne(absl::nullopt),
1635 /*timed_expiration_matcher=*/Ne(absl::nullopt), "third.test")),
1636 Pointee(ExpectHostResolverInternalAliasResult(
1637 "third.test", DnsQueryType::A, kDnsSource,
1638 /*expiration_matcher=*/Ne(absl::nullopt),
1639 /*timed_expiration_matcher=*/Ne(absl::nullopt), "fourth.test")),
1640 Pointee(ExpectHostResolverInternalDataResult(
1641 "fourth.test", DnsQueryType::A, kDnsSource,
1642 /*expiration_matcher=*/Ne(absl::nullopt),
1643 /*timed_expiration_matcher=*/Ne(absl::nullopt),
1644 ElementsAre(expected_endpoint)))));
1645 }
1646
TEST_F(DnsResponseResultExtractorTest,HandlesReverseOrderCnameChain)1647 TEST_F(DnsResponseResultExtractorTest, HandlesReverseOrderCnameChain) {
1648 constexpr char kName[] = "first.test";
1649
1650 DnsResponse response =
1651 BuildTestDnsResponse(kName, dns_protocol::kTypeTXT,
1652 {BuildTestTextRecord("fourth.test", {"foo"}),
1653 BuildTestCnameRecord("third.test", "fourth.test"),
1654 BuildTestCnameRecord("second.test", "third.test"),
1655 BuildTestCnameRecord(kName, "second.test")});
1656 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1657
1658 ResultsOrError results =
1659 extractor.ExtractDnsResults(DnsQueryType::TXT,
1660 /*original_domain_name=*/kName,
1661 /*request_port=*/0);
1662
1663 ASSERT_TRUE(results.has_value());
1664 EXPECT_THAT(
1665 results.value(),
1666 UnorderedElementsAre(
1667 Pointee(ExpectHostResolverInternalAliasResult(
1668 kName, DnsQueryType::TXT, kDnsSource,
1669 /*expiration_matcher=*/Ne(absl::nullopt),
1670 /*timed_expiration_matcher=*/Ne(absl::nullopt), "second.test")),
1671 Pointee(ExpectHostResolverInternalAliasResult(
1672 "second.test", DnsQueryType::TXT, kDnsSource,
1673 /*expiration_matcher=*/Ne(absl::nullopt),
1674 /*timed_expiration_matcher=*/Ne(absl::nullopt), "third.test")),
1675 Pointee(ExpectHostResolverInternalAliasResult(
1676 "third.test", DnsQueryType::TXT, kDnsSource,
1677 /*expiration_matcher=*/Ne(absl::nullopt),
1678 /*timed_expiration_matcher=*/Ne(absl::nullopt), "fourth.test")),
1679 Pointee(ExpectHostResolverInternalDataResult(
1680 "fourth.test", DnsQueryType::TXT, kDnsSource,
1681 /*expiration_matcher=*/Ne(absl::nullopt),
1682 /*timed_expiration_matcher=*/Ne(absl::nullopt),
1683 /*endpoints_matcher=*/IsEmpty(), ElementsAre("foo")))));
1684 }
1685
TEST_F(DnsResponseResultExtractorTest,HandlesReverseOrderCnameChainTypeA)1686 TEST_F(DnsResponseResultExtractorTest, HandlesReverseOrderCnameChainTypeA) {
1687 constexpr char kName[] = "first.test";
1688
1689 const IPAddress kExpected(192, 168, 0, 1);
1690 IPEndPoint expected_endpoint(kExpected, 0 /* port */);
1691
1692 DnsResponse response =
1693 BuildTestDnsResponse(kName, dns_protocol::kTypeA,
1694 {BuildTestAddressRecord("fourth.test", kExpected),
1695 BuildTestCnameRecord("third.test", "fourth.test"),
1696 BuildTestCnameRecord("second.test", "third.test"),
1697 BuildTestCnameRecord(kName, "second.test")});
1698 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1699
1700 ResultsOrError results =
1701 extractor.ExtractDnsResults(DnsQueryType::A,
1702 /*original_domain_name=*/kName,
1703 /*request_port=*/0);
1704
1705 ASSERT_TRUE(results.has_value());
1706 EXPECT_THAT(
1707 results.value(),
1708 UnorderedElementsAre(
1709 Pointee(ExpectHostResolverInternalAliasResult(
1710 kName, DnsQueryType::A, kDnsSource,
1711 /*expiration_matcher=*/Ne(absl::nullopt),
1712 /*timed_expiration_matcher=*/Ne(absl::nullopt), "second.test")),
1713 Pointee(ExpectHostResolverInternalAliasResult(
1714 "second.test", DnsQueryType::A, kDnsSource,
1715 /*expiration_matcher=*/Ne(absl::nullopt),
1716 /*timed_expiration_matcher=*/Ne(absl::nullopt), "third.test")),
1717 Pointee(ExpectHostResolverInternalAliasResult(
1718 "third.test", DnsQueryType::A, kDnsSource,
1719 /*expiration_matcher=*/Ne(absl::nullopt),
1720 /*timed_expiration_matcher=*/Ne(absl::nullopt), "fourth.test")),
1721 Pointee(ExpectHostResolverInternalDataResult(
1722 "fourth.test", DnsQueryType::A, kDnsSource,
1723 /*expiration_matcher=*/Ne(absl::nullopt),
1724 /*timed_expiration_matcher=*/Ne(absl::nullopt),
1725 ElementsAre(expected_endpoint)))));
1726 }
1727
TEST_F(DnsResponseResultExtractorTest,HandlesArbitraryOrderCnameChain)1728 TEST_F(DnsResponseResultExtractorTest, HandlesArbitraryOrderCnameChain) {
1729 constexpr char kName[] = "first.test";
1730
1731 DnsResponse response =
1732 BuildTestDnsResponse(kName, dns_protocol::kTypeTXT,
1733 {BuildTestCnameRecord("second.test", "third.test"),
1734 BuildTestTextRecord("fourth.test", {"foo"}),
1735 BuildTestCnameRecord("third.test", "fourth.test"),
1736 BuildTestCnameRecord(kName, "second.test")});
1737 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1738
1739 ResultsOrError results =
1740 extractor.ExtractDnsResults(DnsQueryType::TXT,
1741 /*original_domain_name=*/kName,
1742 /*request_port=*/0);
1743
1744 ASSERT_TRUE(results.has_value());
1745 EXPECT_THAT(
1746 results.value(),
1747 UnorderedElementsAre(
1748 Pointee(ExpectHostResolverInternalAliasResult(
1749 kName, DnsQueryType::TXT, kDnsSource,
1750 /*expiration_matcher=*/Ne(absl::nullopt),
1751 /*timed_expiration_matcher=*/Ne(absl::nullopt), "second.test")),
1752 Pointee(ExpectHostResolverInternalAliasResult(
1753 "second.test", DnsQueryType::TXT, kDnsSource,
1754 /*expiration_matcher=*/Ne(absl::nullopt),
1755 /*timed_expiration_matcher=*/Ne(absl::nullopt), "third.test")),
1756 Pointee(ExpectHostResolverInternalAliasResult(
1757 "third.test", DnsQueryType::TXT, kDnsSource,
1758 /*expiration_matcher=*/Ne(absl::nullopt),
1759 /*timed_expiration_matcher=*/Ne(absl::nullopt), "fourth.test")),
1760 Pointee(ExpectHostResolverInternalDataResult(
1761 "fourth.test", DnsQueryType::TXT, kDnsSource,
1762 /*expiration_matcher=*/Ne(absl::nullopt),
1763 /*timed_expiration_matcher=*/Ne(absl::nullopt),
1764 /*endpoints_matcher=*/IsEmpty(), ElementsAre("foo")))));
1765 }
1766
TEST_F(DnsResponseResultExtractorTest,HandlesArbitraryOrderCnameChainTypeA)1767 TEST_F(DnsResponseResultExtractorTest, HandlesArbitraryOrderCnameChainTypeA) {
1768 constexpr char kName[] = "first.test";
1769
1770 const IPAddress kExpected(192, 168, 0, 1);
1771 IPEndPoint expected_endpoint(kExpected, 0 /* port */);
1772
1773 // Alias names are chosen so that the chain order is not in alphabetical
1774 // order.
1775 DnsResponse response =
1776 BuildTestDnsResponse(kName, dns_protocol::kTypeA,
1777 {BuildTestCnameRecord("qsecond.test", "athird.test"),
1778 BuildTestAddressRecord("zfourth.test", kExpected),
1779 BuildTestCnameRecord("athird.test", "zfourth.test"),
1780 BuildTestCnameRecord(kName, "qsecond.test")});
1781 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1782
1783 ResultsOrError results =
1784 extractor.ExtractDnsResults(DnsQueryType::A,
1785 /*original_domain_name=*/kName,
1786 /*request_port=*/0);
1787
1788 ASSERT_TRUE(results.has_value());
1789 EXPECT_THAT(
1790 results.value(),
1791 UnorderedElementsAre(
1792 Pointee(ExpectHostResolverInternalAliasResult(
1793 kName, DnsQueryType::A, kDnsSource,
1794 /*expiration_matcher=*/Ne(absl::nullopt),
1795 /*timed_expiration_matcher=*/Ne(absl::nullopt), "qsecond.test")),
1796 Pointee(ExpectHostResolverInternalAliasResult(
1797 "qsecond.test", DnsQueryType::A, kDnsSource,
1798 /*expiration_matcher=*/Ne(absl::nullopt),
1799 /*timed_expiration_matcher=*/Ne(absl::nullopt), "athird.test")),
1800 Pointee(ExpectHostResolverInternalAliasResult(
1801 "athird.test", DnsQueryType::A, kDnsSource,
1802 /*expiration_matcher=*/Ne(absl::nullopt),
1803 /*timed_expiration_matcher=*/Ne(absl::nullopt), "zfourth.test")),
1804 Pointee(ExpectHostResolverInternalDataResult(
1805 "zfourth.test", DnsQueryType::A, kDnsSource,
1806 /*expiration_matcher=*/Ne(absl::nullopt),
1807 /*timed_expiration_matcher=*/Ne(absl::nullopt),
1808 ElementsAre(expected_endpoint)))));
1809 }
1810
TEST_F(DnsResponseResultExtractorTest,IgnoresNonResultTypesMixedWithCnameChain)1811 TEST_F(DnsResponseResultExtractorTest,
1812 IgnoresNonResultTypesMixedWithCnameChain) {
1813 constexpr char kName[] = "first.test";
1814
1815 DnsResponse response = BuildTestDnsResponse(
1816 kName, dns_protocol::kTypeTXT,
1817 {BuildTestCnameRecord("second.test", "third.test"),
1818 BuildTestTextRecord("fourth.test", {"foo"}),
1819 BuildTestCnameRecord("third.test", "fourth.test"),
1820 BuildTestAddressRecord("third.test", IPAddress(1, 2, 3, 4)),
1821 BuildTestCnameRecord(kName, "second.test"),
1822 BuildTestAddressRecord("fourth.test", IPAddress(2, 3, 4, 5))});
1823 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1824
1825 ResultsOrError results =
1826 extractor.ExtractDnsResults(DnsQueryType::TXT,
1827 /*original_domain_name=*/kName,
1828 /*request_port=*/0);
1829
1830 ASSERT_TRUE(results.has_value());
1831 EXPECT_THAT(
1832 results.value(),
1833 UnorderedElementsAre(
1834 Pointee(ExpectHostResolverInternalAliasResult(
1835 kName, DnsQueryType::TXT, kDnsSource,
1836 /*expiration_matcher=*/Ne(absl::nullopt),
1837 /*timed_expiration_matcher=*/Ne(absl::nullopt), "second.test")),
1838 Pointee(ExpectHostResolverInternalAliasResult(
1839 "second.test", DnsQueryType::TXT, kDnsSource,
1840 /*expiration_matcher=*/Ne(absl::nullopt),
1841 /*timed_expiration_matcher=*/Ne(absl::nullopt), "third.test")),
1842 Pointee(ExpectHostResolverInternalAliasResult(
1843 "third.test", DnsQueryType::TXT, kDnsSource,
1844 /*expiration_matcher=*/Ne(absl::nullopt),
1845 /*timed_expiration_matcher=*/Ne(absl::nullopt), "fourth.test")),
1846 Pointee(ExpectHostResolverInternalDataResult(
1847 "fourth.test", DnsQueryType::TXT, kDnsSource,
1848 /*expiration_matcher=*/Ne(absl::nullopt),
1849 /*timed_expiration_matcher=*/Ne(absl::nullopt),
1850 /*endpoints_matcher=*/IsEmpty(), ElementsAre("foo")))));
1851 }
1852
TEST_F(DnsResponseResultExtractorTest,IgnoresNonResultTypesMixedWithCnameChainTypeA)1853 TEST_F(DnsResponseResultExtractorTest,
1854 IgnoresNonResultTypesMixedWithCnameChainTypeA) {
1855 constexpr char kName[] = "first.test";
1856
1857 const IPAddress kExpected(192, 168, 0, 1);
1858 IPEndPoint expected_endpoint(kExpected, 0 /* port */);
1859
1860 DnsResponse response =
1861 BuildTestDnsResponse(kName, dns_protocol::kTypeA,
1862 {BuildTestCnameRecord("second.test", "third.test"),
1863 BuildTestTextRecord("fourth.test", {"foo"}),
1864 BuildTestCnameRecord("third.test", "fourth.test"),
1865 BuildTestCnameRecord(kName, "second.test"),
1866 BuildTestAddressRecord("fourth.test", kExpected)});
1867 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1868
1869 ResultsOrError results =
1870 extractor.ExtractDnsResults(DnsQueryType::A,
1871 /*original_domain_name=*/kName,
1872 /*request_port=*/0);
1873
1874 ASSERT_TRUE(results.has_value());
1875 EXPECT_THAT(
1876 results.value(),
1877 UnorderedElementsAre(
1878 Pointee(ExpectHostResolverInternalAliasResult(
1879 kName, DnsQueryType::A, kDnsSource,
1880 /*expiration_matcher=*/Ne(absl::nullopt),
1881 /*timed_expiration_matcher=*/Ne(absl::nullopt), "second.test")),
1882 Pointee(ExpectHostResolverInternalAliasResult(
1883 "second.test", DnsQueryType::A, kDnsSource,
1884 /*expiration_matcher=*/Ne(absl::nullopt),
1885 /*timed_expiration_matcher=*/Ne(absl::nullopt), "third.test")),
1886 Pointee(ExpectHostResolverInternalAliasResult(
1887 "third.test", DnsQueryType::A, kDnsSource,
1888 /*expiration_matcher=*/Ne(absl::nullopt),
1889 /*timed_expiration_matcher=*/Ne(absl::nullopt), "fourth.test")),
1890 Pointee(ExpectHostResolverInternalDataResult(
1891 "fourth.test", DnsQueryType::A, kDnsSource,
1892 /*expiration_matcher=*/Ne(absl::nullopt),
1893 /*timed_expiration_matcher=*/Ne(absl::nullopt),
1894 ElementsAre(expected_endpoint)))));
1895 }
1896
TEST_F(DnsResponseResultExtractorTest,HandlesCnameChainWithoutResult)1897 TEST_F(DnsResponseResultExtractorTest, HandlesCnameChainWithoutResult) {
1898 constexpr char kName[] = "first.test";
1899
1900 DnsResponse response =
1901 BuildTestDnsResponse(kName, dns_protocol::kTypeTXT,
1902 {BuildTestCnameRecord("second.test", "third.test"),
1903 BuildTestCnameRecord("third.test", "fourth.test"),
1904 BuildTestCnameRecord(kName, "second.test")});
1905 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1906
1907 ResultsOrError results =
1908 extractor.ExtractDnsResults(DnsQueryType::TXT,
1909 /*original_domain_name=*/kName,
1910 /*request_port=*/0);
1911
1912 ASSERT_TRUE(results.has_value());
1913 EXPECT_THAT(
1914 results.value(),
1915 UnorderedElementsAre(
1916 Pointee(ExpectHostResolverInternalAliasResult(
1917 kName, DnsQueryType::TXT, kDnsSource,
1918 /*expiration_matcher=*/Ne(absl::nullopt),
1919 /*timed_expiration_matcher=*/Ne(absl::nullopt), "second.test")),
1920 Pointee(ExpectHostResolverInternalAliasResult(
1921 "second.test", DnsQueryType::TXT, kDnsSource,
1922 /*expiration_matcher=*/Ne(absl::nullopt),
1923 /*timed_expiration_matcher=*/Ne(absl::nullopt), "third.test")),
1924 Pointee(ExpectHostResolverInternalAliasResult(
1925 "third.test", DnsQueryType::TXT, kDnsSource,
1926 /*expiration_matcher=*/Ne(absl::nullopt),
1927 /*timed_expiration_matcher=*/Ne(absl::nullopt), "fourth.test"))));
1928 }
1929
TEST_F(DnsResponseResultExtractorTest,HandlesCnameChainWithoutResultTypeA)1930 TEST_F(DnsResponseResultExtractorTest, HandlesCnameChainWithoutResultTypeA) {
1931 constexpr char kName[] = "first.test";
1932
1933 DnsResponse response =
1934 BuildTestDnsResponse(kName, dns_protocol::kTypeA,
1935 {BuildTestCnameRecord("second.test", "third.test"),
1936 BuildTestCnameRecord("third.test", "fourth.test"),
1937 BuildTestCnameRecord(kName, "second.test")});
1938 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1939
1940 ResultsOrError results =
1941 extractor.ExtractDnsResults(DnsQueryType::A,
1942 /*original_domain_name=*/kName,
1943 /*request_port=*/0);
1944
1945 ASSERT_TRUE(results.has_value());
1946 EXPECT_THAT(
1947 results.value(),
1948 UnorderedElementsAre(
1949 Pointee(ExpectHostResolverInternalAliasResult(
1950 kName, DnsQueryType::A, kDnsSource,
1951 /*expiration_matcher=*/Ne(absl::nullopt),
1952 /*timed_expiration_matcher=*/Ne(absl::nullopt), "second.test")),
1953 Pointee(ExpectHostResolverInternalAliasResult(
1954 "second.test", DnsQueryType::A, kDnsSource,
1955 /*expiration_matcher=*/Ne(absl::nullopt),
1956 /*timed_expiration_matcher=*/Ne(absl::nullopt), "third.test")),
1957 Pointee(ExpectHostResolverInternalAliasResult(
1958 "third.test", DnsQueryType::A, kDnsSource,
1959 /*expiration_matcher=*/Ne(absl::nullopt),
1960 /*timed_expiration_matcher=*/Ne(absl::nullopt), "fourth.test"))));
1961 }
1962
TEST_F(DnsResponseResultExtractorTest,RejectsCnameChainWithLoop)1963 TEST_F(DnsResponseResultExtractorTest, RejectsCnameChainWithLoop) {
1964 constexpr char kName[] = "first.test";
1965
1966 DnsResponse response =
1967 BuildTestDnsResponse(kName, dns_protocol::kTypeTXT,
1968 {BuildTestCnameRecord("second.test", "third.test"),
1969 BuildTestTextRecord("third.test", {"foo"}),
1970 BuildTestCnameRecord("third.test", "second.test"),
1971 BuildTestCnameRecord(kName, "second.test")});
1972 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1973
1974 EXPECT_EQ(extractor
1975 .ExtractDnsResults(DnsQueryType::TXT,
1976 /*original_domain_name=*/kName,
1977 /*request_port=*/0)
1978 .error_or(ExtractionError::kOk),
1979 ExtractionError::kBadAliasChain);
1980 }
1981
TEST_F(DnsResponseResultExtractorTest,RejectsCnameChainWithLoopToBeginning)1982 TEST_F(DnsResponseResultExtractorTest, RejectsCnameChainWithLoopToBeginning) {
1983 constexpr char kName[] = "first.test";
1984
1985 DnsResponse response =
1986 BuildTestDnsResponse(kName, dns_protocol::kTypeTXT,
1987 {BuildTestCnameRecord("second.test", "third.test"),
1988 BuildTestTextRecord("third.test", {"foo"}),
1989 BuildTestCnameRecord("third.test", "first.test"),
1990 BuildTestCnameRecord(kName, "second.test")});
1991 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
1992
1993 EXPECT_EQ(extractor
1994 .ExtractDnsResults(DnsQueryType::TXT,
1995 /*original_domain_name=*/kName,
1996 /*request_port=*/0)
1997 .error_or(ExtractionError::kOk),
1998 ExtractionError::kBadAliasChain);
1999 }
2000
TEST_F(DnsResponseResultExtractorTest,RejectsCnameChainWithLoopToBeginningWithoutResult)2001 TEST_F(DnsResponseResultExtractorTest,
2002 RejectsCnameChainWithLoopToBeginningWithoutResult) {
2003 constexpr char kName[] = "first.test";
2004
2005 DnsResponse response =
2006 BuildTestDnsResponse(kName, dns_protocol::kTypeTXT,
2007 {BuildTestCnameRecord("second.test", "third.test"),
2008 BuildTestCnameRecord("third.test", "first.test"),
2009 BuildTestCnameRecord(kName, "second.test")});
2010 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
2011
2012 EXPECT_EQ(extractor
2013 .ExtractDnsResults(DnsQueryType::TXT,
2014 /*original_domain_name=*/kName,
2015 /*request_port=*/0)
2016 .error_or(ExtractionError::kOk),
2017 ExtractionError::kBadAliasChain);
2018 }
2019
TEST_F(DnsResponseResultExtractorTest,RejectsCnameChainWithWrongStart)2020 TEST_F(DnsResponseResultExtractorTest, RejectsCnameChainWithWrongStart) {
2021 constexpr char kName[] = "test.test";
2022
2023 DnsResponse response =
2024 BuildTestDnsResponse(kName, dns_protocol::kTypeTXT,
2025 {BuildTestCnameRecord("second.test", "third.test"),
2026 BuildTestTextRecord("fourth.test", {"foo"}),
2027 BuildTestCnameRecord("third.test", "fourth.test"),
2028 BuildTestCnameRecord("first.test", "second.test")});
2029 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
2030
2031 EXPECT_EQ(extractor
2032 .ExtractDnsResults(DnsQueryType::TXT,
2033 /*original_domain_name=*/kName,
2034 /*request_port=*/0)
2035 .error_or(ExtractionError::kOk),
2036 ExtractionError::kBadAliasChain);
2037 }
2038
TEST_F(DnsResponseResultExtractorTest,RejectsCnameChainWithWrongResultName)2039 TEST_F(DnsResponseResultExtractorTest, RejectsCnameChainWithWrongResultName) {
2040 constexpr char kName[] = "first.test";
2041
2042 DnsResponse response =
2043 BuildTestDnsResponse(kName, dns_protocol::kTypeTXT,
2044 {BuildTestCnameRecord("second.test", "third.test"),
2045 BuildTestTextRecord("third.test", {"foo"}),
2046 BuildTestCnameRecord("third.test", "fourth.test"),
2047 BuildTestCnameRecord(kName, "second.test")});
2048 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
2049
2050 EXPECT_EQ(extractor
2051 .ExtractDnsResults(DnsQueryType::TXT,
2052 /*original_domain_name=*/kName,
2053 /*request_port=*/0)
2054 .error_or(ExtractionError::kOk),
2055 ExtractionError::kNameMismatch);
2056 }
2057
TEST_F(DnsResponseResultExtractorTest,RejectsCnameSharedWithResult)2058 TEST_F(DnsResponseResultExtractorTest, RejectsCnameSharedWithResult) {
2059 constexpr char kName[] = "first.test";
2060
2061 DnsResponse response =
2062 BuildTestDnsResponse(kName, dns_protocol::kTypeTXT,
2063 {BuildTestCnameRecord("second.test", "third.test"),
2064 BuildTestTextRecord(kName, {"foo"}),
2065 BuildTestCnameRecord("third.test", "fourth.test"),
2066 BuildTestCnameRecord(kName, "second.test")});
2067 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
2068
2069 EXPECT_EQ(extractor
2070 .ExtractDnsResults(DnsQueryType::TXT,
2071 /*original_domain_name=*/kName,
2072 /*request_port=*/0)
2073 .error_or(ExtractionError::kOk),
2074 ExtractionError::kNameMismatch);
2075 }
2076
TEST_F(DnsResponseResultExtractorTest,RejectsDisjointCnameChain)2077 TEST_F(DnsResponseResultExtractorTest, RejectsDisjointCnameChain) {
2078 constexpr char kName[] = "first.test";
2079
2080 DnsResponse response = BuildTestDnsResponse(
2081 kName, dns_protocol::kTypeTXT,
2082 {BuildTestCnameRecord("second.test", "third.test"),
2083 BuildTestTextRecord("fourth.test", {"foo"}),
2084 BuildTestCnameRecord("third.test", "fourth.test"),
2085 BuildTestCnameRecord("other1.test", "other2.test"),
2086 BuildTestCnameRecord(kName, "second.test"),
2087 BuildTestCnameRecord("other2.test", "other3.test")});
2088 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
2089
2090 EXPECT_EQ(extractor
2091 .ExtractDnsResults(DnsQueryType::TXT,
2092 /*original_domain_name=*/kName,
2093 /*request_port=*/0)
2094 .error_or(ExtractionError::kOk),
2095 ExtractionError::kBadAliasChain);
2096 }
2097
TEST_F(DnsResponseResultExtractorTest,RejectsDoubledCnames)2098 TEST_F(DnsResponseResultExtractorTest, RejectsDoubledCnames) {
2099 constexpr char kName[] = "first.test";
2100
2101 DnsResponse response =
2102 BuildTestDnsResponse(kName, dns_protocol::kTypeTXT,
2103 {BuildTestCnameRecord("second.test", "third.test"),
2104 BuildTestTextRecord("fourth.test", {"foo"}),
2105 BuildTestCnameRecord("third.test", "fourth.test"),
2106 BuildTestCnameRecord("third.test", "fifth.test"),
2107 BuildTestCnameRecord(kName, "second.test")});
2108 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
2109
2110 EXPECT_EQ(extractor
2111 .ExtractDnsResults(DnsQueryType::TXT,
2112 /*original_domain_name=*/kName,
2113 /*request_port=*/0)
2114 .error_or(ExtractionError::kOk),
2115 ExtractionError::kMultipleCnames);
2116 }
2117
TEST_F(DnsResponseResultExtractorTest,IgnoresTtlFromNonResultType)2118 TEST_F(DnsResponseResultExtractorTest, IgnoresTtlFromNonResultType) {
2119 constexpr char kName[] = "name.test";
2120 constexpr base::TimeDelta kMinTtl = base::Minutes(4);
2121
2122 DnsResponse response = BuildTestDnsResponse(
2123 kName, dns_protocol::kTypeTXT,
2124 {BuildTestTextRecord(kName, {"foo"}, base::Hours(3)),
2125 BuildTestTextRecord(kName, {"bar"}, kMinTtl),
2126 BuildTestAddressRecord(kName, IPAddress(1, 2, 3, 4), base::Seconds(2)),
2127 BuildTestTextRecord(kName, {"baz"}, base::Minutes(15))});
2128 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
2129
2130 ResultsOrError results =
2131 extractor.ExtractDnsResults(DnsQueryType::TXT,
2132 /*original_domain_name=*/kName,
2133 /*request_port=*/0);
2134
2135 ASSERT_TRUE(results.has_value());
2136 EXPECT_THAT(
2137 results.value(),
2138 ElementsAre(Pointee(ExpectHostResolverInternalDataResult(
2139 kName, DnsQueryType::TXT, kDnsSource,
2140 Eq(tick_clock_.NowTicks() + kMinTtl), Eq(clock_.Now() + kMinTtl),
2141 /*endpoints_matcher=*/IsEmpty(),
2142 UnorderedElementsAre("foo", "bar", "baz")))));
2143 }
2144
TEST_F(DnsResponseResultExtractorTest,ExtractsTtlFromCname)2145 TEST_F(DnsResponseResultExtractorTest, ExtractsTtlFromCname) {
2146 constexpr char kName[] = "name.test";
2147 constexpr char kAlias[] = "alias.test";
2148 constexpr base::TimeDelta kTtl = base::Minutes(4);
2149
2150 DnsResponse response =
2151 BuildTestDnsResponse("name.test", dns_protocol::kTypeTXT,
2152 {BuildTestCnameRecord(kName, kAlias, kTtl)});
2153 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
2154
2155 ResultsOrError results =
2156 extractor.ExtractDnsResults(DnsQueryType::TXT,
2157 /*original_domain_name=*/kName,
2158 /*request_port=*/0);
2159
2160 ASSERT_TRUE(results.has_value());
2161 EXPECT_THAT(
2162 results.value(),
2163 UnorderedElementsAre(Pointee(ExpectHostResolverInternalAliasResult(
2164 kName, DnsQueryType::TXT, kDnsSource,
2165 Eq(tick_clock_.NowTicks() + kTtl), Eq(clock_.Now() + kTtl),
2166 kAlias))));
2167 }
2168
TEST_F(DnsResponseResultExtractorTest,ValidatesAliasNames)2169 TEST_F(DnsResponseResultExtractorTest, ValidatesAliasNames) {
2170 constexpr char kName[] = "first.test";
2171
2172 const IPAddress kExpected(192, 168, 0, 1);
2173 IPEndPoint expected_endpoint(kExpected, 0 /* port */);
2174
2175 DnsResponse response =
2176 BuildTestDnsResponse(kName, dns_protocol::kTypeA,
2177 {BuildTestCnameRecord(kName, "second.test"),
2178 BuildTestCnameRecord("second.test", "localhost"),
2179 BuildTestCnameRecord("localhost", "fourth.test"),
2180 BuildTestAddressRecord("fourth.test", kExpected)});
2181 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
2182
2183 EXPECT_EQ(extractor
2184 .ExtractDnsResults(DnsQueryType::A,
2185 /*original_domain_name=*/kName,
2186 /*request_port=*/0)
2187 .error_or(ExtractionError::kOk),
2188 ExtractionError::kMalformedRecord);
2189 }
2190
TEST_F(DnsResponseResultExtractorTest,CanonicalizesAliasNames)2191 TEST_F(DnsResponseResultExtractorTest, CanonicalizesAliasNames) {
2192 const IPAddress kExpected(192, 168, 0, 1);
2193 constexpr char kName[] = "address.test";
2194 constexpr char kCname[] = "\005ALIAS\004test\000";
2195
2196 // Need to build records directly in order to manually encode alias target
2197 // name because BuildTestDnsAddressResponseWithCname() uses
2198 // DNSDomainFromDot() which does not support non-URL-canonicalized names.
2199 std::vector<DnsResourceRecord> answers = {
2200 BuildTestDnsRecord(kName, dns_protocol::kTypeCNAME,
2201 std::string(kCname, sizeof(kCname) - 1)),
2202 BuildTestAddressRecord("alias.test", kExpected)};
2203 DnsResponse response =
2204 BuildTestDnsResponse(kName, dns_protocol::kTypeA, answers);
2205
2206 DnsResponseResultExtractor extractor(response, clock_, tick_clock_);
2207
2208 ResultsOrError results =
2209 extractor.ExtractDnsResults(DnsQueryType::A,
2210 /*original_domain_name=*/kName,
2211 /*request_port=*/0);
2212
2213 ASSERT_TRUE(results.has_value());
2214 EXPECT_THAT(
2215 results.value(),
2216 UnorderedElementsAre(
2217 Pointee(ExpectHostResolverInternalAliasResult(
2218 kName, DnsQueryType::A, kDnsSource,
2219 /*expiration_matcher=*/Ne(absl::nullopt),
2220 /*timed_expiration_matcher=*/Ne(absl::nullopt), "alias.test")),
2221 Pointee(ExpectHostResolverInternalDataResult(
2222 "alias.test", DnsQueryType::A, kDnsSource,
2223 /*expiration_matcher=*/Ne(absl::nullopt),
2224 /*timed_expiration_matcher=*/Ne(absl::nullopt),
2225 ElementsAre(IPEndPoint(kExpected, /*port=*/0))))));
2226 }
2227
2228 } // namespace
2229 } // namespace net
2230