1 // Copyright 2020 The Chromium Authors. All rights reserved.
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_udp_tracker.h"
6 
7 #include "base/test/simple_test_tick_clock.h"
8 #include "net/base/net_errors.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 
11 namespace net {
12 
13 namespace {
14 
15 class DnsUdpTrackerTest : public testing::Test {
16  public:
DnsUdpTrackerTest()17   DnsUdpTrackerTest() {
18     tracker_.set_tick_clock_for_testing(&test_tick_clock_);
19   }
20 
21  protected:
22   DnsUdpTracker tracker_;
23   base::SimpleTestTickClock test_tick_clock_;
24 };
25 
TEST_F(DnsUdpTrackerTest,MatchingId)26 TEST_F(DnsUdpTrackerTest, MatchingId) {
27   uint16_t port = 416;
28   uint16_t id = 56;
29   for (size_t i = 0; i < DnsUdpTracker::kRecognizedIdMismatchThreshold; ++i) {
30     tracker_.RecordQuery(++port, ++id);
31     tracker_.RecordResponseId(id /* query_id */, id /* response_id */);
32     EXPECT_FALSE(tracker_.low_entropy());
33   }
34 }
35 
TEST_F(DnsUdpTrackerTest,ReusedMismatches)36 TEST_F(DnsUdpTrackerTest, ReusedMismatches) {
37   static const uint16_t kOldId = 786;
38   tracker_.RecordQuery(123 /* port */, kOldId);
39 
40   uint16_t port = 3889;
41   uint16_t id = 3456;
42   for (size_t i = 0; i < DnsUdpTracker::kRecognizedIdMismatchThreshold; ++i) {
43     EXPECT_FALSE(tracker_.low_entropy());
44     tracker_.RecordQuery(++port, ++id);
45     tracker_.RecordResponseId(id /* query_id */, kOldId /* response_id */);
46   }
47 
48   EXPECT_TRUE(tracker_.low_entropy());
49 }
50 
TEST_F(DnsUdpTrackerTest,ReusedMismatches_Expired)51 TEST_F(DnsUdpTrackerTest, ReusedMismatches_Expired) {
52   static const uint16_t kOldId = 786;
53   tracker_.RecordQuery(123 /* port */, kOldId);
54 
55   test_tick_clock_.Advance(DnsUdpTracker::kMaxAge +
56                            base::TimeDelta::FromMilliseconds(1));
57 
58   uint16_t port = 3889;
59   uint16_t id = 3456;
60 
61   // Because the query record has expired, the ID should be treated as
62   // unrecognized.
63   for (size_t i = 0; i < DnsUdpTracker::kUnrecognizedIdMismatchThreshold; ++i) {
64     EXPECT_FALSE(tracker_.low_entropy());
65     tracker_.RecordQuery(++port, ++id);
66     tracker_.RecordResponseId(id /* query_id */, kOldId /* response_id */);
67   }
68 
69   EXPECT_TRUE(tracker_.low_entropy());
70 }
71 
72 // Test for ID mismatches using an ID still kept in recorded queries, but not
73 // recent enough to be considered reognized.
TEST_F(DnsUdpTrackerTest,ReusedMismatches_Old)74 TEST_F(DnsUdpTrackerTest, ReusedMismatches_Old) {
75   static const uint16_t kOldId = 786;
76   tracker_.RecordQuery(123 /* port */, kOldId);
77 
78   test_tick_clock_.Advance(DnsUdpTracker::kMaxRecognizedIdAge +
79                            base::TimeDelta::FromMilliseconds(1));
80 
81   uint16_t port = 3889;
82   uint16_t id = 3456;
83 
84   // Expect the ID to be treated as unrecognized.
85   for (size_t i = 0; i < DnsUdpTracker::kUnrecognizedIdMismatchThreshold; ++i) {
86     EXPECT_FALSE(tracker_.low_entropy());
87     tracker_.RecordQuery(++port, ++id);
88     tracker_.RecordResponseId(id /* query_id */, kOldId /* response_id */);
89   }
90 
91   EXPECT_TRUE(tracker_.low_entropy());
92 }
93 
TEST_F(DnsUdpTrackerTest,ReusedMismatches_Full)94 TEST_F(DnsUdpTrackerTest, ReusedMismatches_Full) {
95   static const uint16_t kOldId = 786;
96   tracker_.RecordQuery(123 /* port */, kOldId);
97 
98   uint16_t port = 124;
99   uint16_t id = 3457;
100   for (size_t i = 0; i < DnsUdpTracker::kMaxRecordedQueries; ++i) {
101     tracker_.RecordQuery(++port, ++id);
102   }
103 
104   // Expect the ID to be treated as unrecognized.
105   for (size_t i = 0; i < DnsUdpTracker::kUnrecognizedIdMismatchThreshold; ++i) {
106     EXPECT_FALSE(tracker_.low_entropy());
107     tracker_.RecordResponseId(id /* query_id */, kOldId /* response_id */);
108   }
109 
110   EXPECT_TRUE(tracker_.low_entropy());
111 }
112 
TEST_F(DnsUdpTrackerTest,UnknownMismatches)113 TEST_F(DnsUdpTrackerTest, UnknownMismatches) {
114   uint16_t port = 10014;
115   uint16_t id = 4332;
116   for (size_t i = 0; i < DnsUdpTracker::kUnrecognizedIdMismatchThreshold; ++i) {
117     EXPECT_FALSE(tracker_.low_entropy());
118     tracker_.RecordQuery(++port, ++id);
119     tracker_.RecordResponseId(id /* query_id */, 743 /* response_id */);
120   }
121 
122   EXPECT_TRUE(tracker_.low_entropy());
123 }
124 
TEST_F(DnsUdpTrackerTest,ReusedPort)125 TEST_F(DnsUdpTrackerTest, ReusedPort) {
126   static const uint16_t kPort = 2135;
127   tracker_.RecordQuery(kPort, 579 /* query_id */);
128 
129   uint16_t id = 580;
130   for (int i = 0; i < DnsUdpTracker::kPortReuseThreshold; ++i) {
131     EXPECT_FALSE(tracker_.low_entropy());
132     tracker_.RecordQuery(kPort, ++id);
133     tracker_.RecordResponseId(id /* query_id */, id /* response_id */);
134   }
135 
136   EXPECT_TRUE(tracker_.low_entropy());
137 }
138 
TEST_F(DnsUdpTrackerTest,ReusedPort_Expired)139 TEST_F(DnsUdpTrackerTest, ReusedPort_Expired) {
140   static const uint16_t kPort = 2135;
141   tracker_.RecordQuery(kPort, 579 /* query_id */);
142 
143   test_tick_clock_.Advance(DnsUdpTracker::kMaxAge +
144                            base::TimeDelta::FromMilliseconds(1));
145 
146   EXPECT_FALSE(tracker_.low_entropy());
147 
148   uint16_t id = 580;
149   for (int i = 0; i < DnsUdpTracker::kPortReuseThreshold; ++i) {
150     tracker_.RecordQuery(kPort, ++id);
151     tracker_.RecordResponseId(id /* query_id */, id /* response_id */);
152     EXPECT_FALSE(tracker_.low_entropy());
153   }
154 }
155 
TEST_F(DnsUdpTrackerTest,ReusedPort_Full)156 TEST_F(DnsUdpTrackerTest, ReusedPort_Full) {
157   static const uint16_t kPort = 2135;
158   tracker_.RecordQuery(kPort, 579 /* query_id */);
159 
160   uint16_t port = 124;
161   uint16_t id = 3457;
162   for (size_t i = 0; i < DnsUdpTracker::kMaxRecordedQueries; ++i) {
163     tracker_.RecordQuery(++port, ++id);
164   }
165 
166   EXPECT_FALSE(tracker_.low_entropy());
167 
168   for (int i = 0; i < DnsUdpTracker::kPortReuseThreshold; ++i) {
169     tracker_.RecordQuery(kPort, ++id);
170     tracker_.RecordResponseId(id /* query_id */, id /* response_id */);
171     EXPECT_FALSE(tracker_.low_entropy());
172   }
173 }
174 
TEST_F(DnsUdpTrackerTest,ConnectionError)175 TEST_F(DnsUdpTrackerTest, ConnectionError) {
176   tracker_.RecordConnectionError(ERR_FAILED);
177 
178   EXPECT_FALSE(tracker_.low_entropy());
179 }
180 
TEST_F(DnsUdpTrackerTest,ConnectionError_InsufficientResources)181 TEST_F(DnsUdpTrackerTest, ConnectionError_InsufficientResources) {
182   tracker_.RecordConnectionError(ERR_INSUFFICIENT_RESOURCES);
183 
184   EXPECT_TRUE(tracker_.low_entropy());
185 }
186 
187 }  // namespace
188 
189 }  // namespace net
190