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