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_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 + base::Milliseconds(1));
56
57 uint16_t port = 3889;
58 uint16_t id = 3456;
59
60 // Because the query record has expired, the ID should be treated as
61 // unrecognized.
62 for (size_t i = 0; i < DnsUdpTracker::kUnrecognizedIdMismatchThreshold; ++i) {
63 EXPECT_FALSE(tracker_.low_entropy());
64 tracker_.RecordQuery(++port, ++id);
65 tracker_.RecordResponseId(id /* query_id */, kOldId /* response_id */);
66 }
67
68 EXPECT_TRUE(tracker_.low_entropy());
69 }
70
71 // Test for ID mismatches using an ID still kept in recorded queries, but not
72 // recent enough to be considered reognized.
TEST_F(DnsUdpTrackerTest,ReusedMismatches_Old)73 TEST_F(DnsUdpTrackerTest, ReusedMismatches_Old) {
74 static const uint16_t kOldId = 786;
75 tracker_.RecordQuery(123 /* port */, kOldId);
76
77 test_tick_clock_.Advance(DnsUdpTracker::kMaxRecognizedIdAge +
78 base::Milliseconds(1));
79
80 uint16_t port = 3889;
81 uint16_t id = 3456;
82
83 // Expect the ID to be treated as unrecognized.
84 for (size_t i = 0; i < DnsUdpTracker::kUnrecognizedIdMismatchThreshold; ++i) {
85 EXPECT_FALSE(tracker_.low_entropy());
86 tracker_.RecordQuery(++port, ++id);
87 tracker_.RecordResponseId(id /* query_id */, kOldId /* response_id */);
88 }
89
90 EXPECT_TRUE(tracker_.low_entropy());
91 }
92
TEST_F(DnsUdpTrackerTest,ReusedMismatches_Full)93 TEST_F(DnsUdpTrackerTest, ReusedMismatches_Full) {
94 static const uint16_t kOldId = 786;
95 tracker_.RecordQuery(123 /* port */, kOldId);
96
97 uint16_t port = 124;
98 uint16_t id = 3457;
99 for (size_t i = 0; i < DnsUdpTracker::kMaxRecordedQueries; ++i) {
100 tracker_.RecordQuery(++port, ++id);
101 }
102
103 // Expect the ID to be treated as unrecognized.
104 for (size_t i = 0; i < DnsUdpTracker::kUnrecognizedIdMismatchThreshold; ++i) {
105 EXPECT_FALSE(tracker_.low_entropy());
106 tracker_.RecordResponseId(id /* query_id */, kOldId /* response_id */);
107 }
108
109 EXPECT_TRUE(tracker_.low_entropy());
110 }
111
TEST_F(DnsUdpTrackerTest,UnknownMismatches)112 TEST_F(DnsUdpTrackerTest, UnknownMismatches) {
113 uint16_t port = 10014;
114 uint16_t id = 4332;
115 for (size_t i = 0; i < DnsUdpTracker::kUnrecognizedIdMismatchThreshold; ++i) {
116 EXPECT_FALSE(tracker_.low_entropy());
117 tracker_.RecordQuery(++port, ++id);
118 tracker_.RecordResponseId(id /* query_id */, 743 /* response_id */);
119 }
120
121 EXPECT_TRUE(tracker_.low_entropy());
122 }
123
TEST_F(DnsUdpTrackerTest,ReusedPort)124 TEST_F(DnsUdpTrackerTest, ReusedPort) {
125 static const uint16_t kPort = 2135;
126 tracker_.RecordQuery(kPort, 579 /* query_id */);
127
128 uint16_t id = 580;
129 for (int i = 0; i < DnsUdpTracker::kPortReuseThreshold; ++i) {
130 EXPECT_FALSE(tracker_.low_entropy());
131 tracker_.RecordQuery(kPort, ++id);
132 tracker_.RecordResponseId(id /* query_id */, id /* response_id */);
133 }
134
135 EXPECT_TRUE(tracker_.low_entropy());
136 }
137
TEST_F(DnsUdpTrackerTest,ReusedPort_Expired)138 TEST_F(DnsUdpTrackerTest, ReusedPort_Expired) {
139 static const uint16_t kPort = 2135;
140 tracker_.RecordQuery(kPort, 579 /* query_id */);
141
142 test_tick_clock_.Advance(DnsUdpTracker::kMaxAge + base::Milliseconds(1));
143
144 EXPECT_FALSE(tracker_.low_entropy());
145
146 uint16_t id = 580;
147 for (int i = 0; i < DnsUdpTracker::kPortReuseThreshold; ++i) {
148 tracker_.RecordQuery(kPort, ++id);
149 tracker_.RecordResponseId(id /* query_id */, id /* response_id */);
150 EXPECT_FALSE(tracker_.low_entropy());
151 }
152 }
153
TEST_F(DnsUdpTrackerTest,ReusedPort_Full)154 TEST_F(DnsUdpTrackerTest, ReusedPort_Full) {
155 static const uint16_t kPort = 2135;
156 tracker_.RecordQuery(kPort, 579 /* query_id */);
157
158 uint16_t port = 124;
159 uint16_t id = 3457;
160 for (size_t i = 0; i < DnsUdpTracker::kMaxRecordedQueries; ++i) {
161 tracker_.RecordQuery(++port, ++id);
162 }
163
164 EXPECT_FALSE(tracker_.low_entropy());
165
166 for (int i = 0; i < DnsUdpTracker::kPortReuseThreshold; ++i) {
167 tracker_.RecordQuery(kPort, ++id);
168 tracker_.RecordResponseId(id /* query_id */, id /* response_id */);
169 EXPECT_FALSE(tracker_.low_entropy());
170 }
171 }
172
TEST_F(DnsUdpTrackerTest,ConnectionError)173 TEST_F(DnsUdpTrackerTest, ConnectionError) {
174 tracker_.RecordConnectionError(ERR_FAILED);
175
176 EXPECT_FALSE(tracker_.low_entropy());
177 }
178
TEST_F(DnsUdpTrackerTest,ConnectionError_InsufficientResources)179 TEST_F(DnsUdpTrackerTest, ConnectionError_InsufficientResources) {
180 tracker_.RecordConnectionError(ERR_INSUFFICIENT_RESOURCES);
181
182 EXPECT_TRUE(tracker_.low_entropy());
183 }
184
185 } // namespace
186
187 } // namespace net
188