• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <array>
18 
19 #include <android-base/test_utils.h>
20 #include <gmock/gmock.h>
21 #include <gtest/gtest.h>
22 
23 #include "DnsStats.h"
24 
25 namespace android::net {
26 
27 using namespace std::chrono_literals;
28 using android::netdutils::IPSockAddr;
29 using std::chrono::milliseconds;
30 using ::testing::IsEmpty;
31 using ::testing::UnorderedElementsAreArray;
32 
33 namespace {
34 
makeDnsQueryEvent(const Protocol protocol,const NsRcode rcode,const milliseconds & latency)35 DnsQueryEvent makeDnsQueryEvent(const Protocol protocol, const NsRcode rcode,
36                                 const milliseconds& latency) {
37     DnsQueryEvent event;
38     event.set_protocol(protocol);
39     event.set_rcode(rcode);
40     event.set_latency_micros(latency.count() * 1000);
41     return event;
42 }
43 
makeStatsData(const IPSockAddr & server,const int total,const milliseconds & latencyMs,const std::map<int,int> & rcodeCounts)44 StatsData makeStatsData(const IPSockAddr& server, const int total, const milliseconds& latencyMs,
45                         const std::map<int, int>& rcodeCounts) {
46     StatsData ret(server);
47     ret.total = total;
48     ret.latencyUs = latencyMs;
49     ret.rcodeCounts = rcodeCounts;
50     return ret;
51 }
52 
53 }  // namespace
54 
55 class StatsRecordsTest : public ::testing::Test {};
56 
TEST_F(StatsRecordsTest,PushRecord)57 TEST_F(StatsRecordsTest, PushRecord) {
58     const IPSockAddr server = IPSockAddr::toIPSockAddr("127.0.0.2", 53);
59     constexpr size_t size = 3;
60     const StatsRecords::Record recordNoError = {NS_R_NO_ERROR, 10ms};
61     const StatsRecords::Record recordTimeout = {NS_R_TIMEOUT, 250ms};
62 
63     StatsRecords sr(server, size);
64     EXPECT_EQ(sr.getStatsData(), makeStatsData(server, 0, 0ms, {}));
65 
66     sr.push(recordNoError);
67     EXPECT_EQ(sr.getStatsData(), makeStatsData(server, 1, 10ms, {{NS_R_NO_ERROR, 1}}));
68 
69     sr.push(recordNoError);
70     EXPECT_EQ(sr.getStatsData(), makeStatsData(server, 2, 20ms, {{NS_R_NO_ERROR, 2}}));
71 
72     sr.push(recordTimeout);
73     EXPECT_EQ(sr.getStatsData(),
74               makeStatsData(server, 3, 270ms, {{NS_R_NO_ERROR, 2}, {NS_R_TIMEOUT, 1}}));
75 
76     sr.push(recordTimeout);
77     EXPECT_EQ(sr.getStatsData(),
78               makeStatsData(server, 3, 510ms, {{NS_R_NO_ERROR, 1}, {NS_R_TIMEOUT, 2}}));
79 
80     sr.push(recordTimeout);
81     EXPECT_EQ(sr.getStatsData(),
82               makeStatsData(server, 3, 750ms, {{NS_R_NO_ERROR, 0}, {NS_R_TIMEOUT, 3}}));
83 }
84 
85 class DnsStatsTest : public ::testing::Test {
86   protected:
captureDumpOutput()87     std::string captureDumpOutput() {
88         netdutils::DumpWriter dw(STDOUT_FILENO);
89         CapturedStdout captured;
90         mDnsStats.dump(dw);
91         return captured.str();
92     }
93 
94     // Get the output string from dump() and check the content.
verifyDumpOutput(const std::vector<StatsData> & tcpData,const std::vector<StatsData> & udpData,const std::vector<StatsData> & dotData)95     void verifyDumpOutput(const std::vector<StatsData>& tcpData,
96                           const std::vector<StatsData>& udpData,
97                           const std::vector<StatsData>& dotData) {
98         // A simple pattern to capture two matches:
99         //     server address (empty allowed) and its statistics.
100         const std::regex pattern(R"(\s{4,}([0-9a-fA-F:\.]*) ([<(].*[>)]))");
101         std::string dumpString = captureDumpOutput();
102 
103         const auto check = [&](const std::vector<StatsData>& statsData, const std::string& protocol,
104                                std::string* dumpString) {
105             SCOPED_TRACE(protocol);
106             ASSERT_NE(dumpString->find(protocol), std::string::npos);
107             std::smatch sm;
108 
109             // Expect to show something even if none of servers is set.
110             if (statsData.empty()) {
111                 ASSERT_TRUE(std::regex_search(*dumpString, sm, pattern));
112                 EXPECT_TRUE(sm[1].str().empty());
113                 EXPECT_EQ(sm[2], "<no server>");
114                 *dumpString = sm.suffix();
115                 return;
116             }
117 
118             for (const auto& stats : statsData) {
119                 ASSERT_TRUE(std::regex_search(*dumpString, sm, pattern));
120                 EXPECT_EQ(sm[1], stats.serverSockAddr.ip().toString());
121                 EXPECT_FALSE(sm[2].str().empty());
122                 *dumpString = sm.suffix();
123             }
124         };
125 
126         check(udpData, "UDP", &dumpString);
127         check(dotData, "TLS", &dumpString);
128         check(tcpData, "TCP", &dumpString);
129 
130         // Ensure the whole string has been checked.
131         EXPECT_EQ(dumpString, "\n");
132     }
133 
134     DnsStats mDnsStats;
135 };
136 
TEST_F(DnsStatsTest,SetServers)137 TEST_F(DnsStatsTest, SetServers) {
138     // Check before any operation to mDnsStats.
139     verifyDumpOutput({}, {}, {});
140 
141     static const struct {
142         std::vector<std::string> servers;
143         std::vector<std::string> expectation;
144         bool isSuccess;
145     } tests[] = {
146             // Normal case.
147             {
148                     {"127.0.0.1", "127.0.0.2", "fe80::1%22", "2001:db8::2", "::1"},
149                     {"127.0.0.1", "127.0.0.2", "fe80::1%22", "2001:db8::2", "::1"},
150                     true,
151             },
152             // Duplicate servers.
153             {
154                     {"127.0.0.1", "2001:db8::2", "127.0.0.1", "2001:db8::2"},
155                     {"127.0.0.1", "2001:db8::2"},
156                     true,
157             },
158             // Invalid server addresses. The state remains in previous state.
159             {
160                     {"not_an_ip", "127.0.0.3", "127.a.b.2"},
161                     {"127.0.0.1", "2001:db8::2"},
162                     false,
163             },
164             // Clean up the old servers 127.0.0.1 and 127.0.0.2.
165             {
166                     {"127.0.0.4", "2001:db8::5"},
167                     {"127.0.0.4", "2001:db8::5"},
168                     true,
169             },
170             // Empty list.
171             {{}, {}, true},
172     };
173 
174     for (const auto& [servers, expectation, isSuccess] : tests) {
175         std::vector<IPSockAddr> ipSockAddrs;
176         ipSockAddrs.reserve(servers.size());
177         for (const auto& server : servers) {
178             ipSockAddrs.push_back(IPSockAddr::toIPSockAddr(server, 53));
179         }
180 
181         EXPECT_TRUE(mDnsStats.setServers(ipSockAddrs, PROTO_TCP) == isSuccess);
182         EXPECT_TRUE(mDnsStats.setServers(ipSockAddrs, PROTO_UDP) == isSuccess);
183         EXPECT_TRUE(mDnsStats.setServers(ipSockAddrs, PROTO_DOT) == isSuccess);
184 
185         std::vector<StatsData> expectedStats;
186         expectedStats.reserve(expectation.size());
187         for (const auto& exp : expectation) {
188             expectedStats.push_back(makeStatsData(IPSockAddr::toIPSockAddr(exp, 53), 0, 0ms, {}));
189         }
190 
191         EXPECT_THAT(mDnsStats.getStats(PROTO_TCP), UnorderedElementsAreArray(expectedStats));
192         EXPECT_THAT(mDnsStats.getStats(PROTO_UDP), UnorderedElementsAreArray(expectedStats));
193         EXPECT_THAT(mDnsStats.getStats(PROTO_DOT), UnorderedElementsAreArray(expectedStats));
194     }
195 
196     verifyDumpOutput({}, {}, {});
197 }
198 
TEST_F(DnsStatsTest,SetServersDifferentPorts)199 TEST_F(DnsStatsTest, SetServersDifferentPorts) {
200     const std::vector<IPSockAddr> servers = {
201             IPSockAddr::toIPSockAddr("127.0.0.1", 0),   IPSockAddr::toIPSockAddr("fe80::1", 0),
202             IPSockAddr::toIPSockAddr("127.0.0.1", 53),  IPSockAddr::toIPSockAddr("127.0.0.1", 5353),
203             IPSockAddr::toIPSockAddr("127.0.0.1", 853), IPSockAddr::toIPSockAddr("fe80::1", 53),
204             IPSockAddr::toIPSockAddr("fe80::1", 5353),  IPSockAddr::toIPSockAddr("fe80::1", 853),
205     };
206 
207     // Servers setup fails due to port unset.
208     EXPECT_FALSE(mDnsStats.setServers(servers, PROTO_TCP));
209     EXPECT_FALSE(mDnsStats.setServers(servers, PROTO_UDP));
210     EXPECT_FALSE(mDnsStats.setServers(servers, PROTO_DOT));
211 
212     EXPECT_THAT(mDnsStats.getStats(PROTO_TCP), IsEmpty());
213     EXPECT_THAT(mDnsStats.getStats(PROTO_UDP), IsEmpty());
214     EXPECT_THAT(mDnsStats.getStats(PROTO_DOT), IsEmpty());
215     verifyDumpOutput({}, {}, {});
216 
217     EXPECT_TRUE(mDnsStats.setServers(std::vector(servers.begin() + 2, servers.end()), PROTO_TCP));
218     EXPECT_TRUE(mDnsStats.setServers(std::vector(servers.begin() + 2, servers.end()), PROTO_UDP));
219     EXPECT_TRUE(mDnsStats.setServers(std::vector(servers.begin() + 2, servers.end()), PROTO_DOT));
220 
221     const std::vector<StatsData> expectedStats = {
222             makeStatsData(servers[2], 0, 0ms, {}), makeStatsData(servers[3], 0, 0ms, {}),
223             makeStatsData(servers[4], 0, 0ms, {}), makeStatsData(servers[5], 0, 0ms, {}),
224             makeStatsData(servers[6], 0, 0ms, {}), makeStatsData(servers[7], 0, 0ms, {}),
225     };
226 
227     EXPECT_THAT(mDnsStats.getStats(PROTO_TCP), UnorderedElementsAreArray(expectedStats));
228     EXPECT_THAT(mDnsStats.getStats(PROTO_UDP), UnorderedElementsAreArray(expectedStats));
229     EXPECT_THAT(mDnsStats.getStats(PROTO_DOT), UnorderedElementsAreArray(expectedStats));
230     verifyDumpOutput(expectedStats, expectedStats, expectedStats);
231 }
232 
TEST_F(DnsStatsTest,AddStatsAndClear)233 TEST_F(DnsStatsTest, AddStatsAndClear) {
234     const std::vector<IPSockAddr> servers = {
235             IPSockAddr::toIPSockAddr("127.0.0.1", 53),
236             IPSockAddr::toIPSockAddr("127.0.0.2", 53),
237     };
238     const DnsQueryEvent record = makeDnsQueryEvent(PROTO_UDP, NS_R_NO_ERROR, 10ms);
239 
240     EXPECT_TRUE(mDnsStats.setServers(servers, PROTO_TCP));
241     EXPECT_TRUE(mDnsStats.setServers(servers, PROTO_UDP));
242 
243     // Fail to add stats because of incorrect arguments.
244     EXPECT_FALSE(mDnsStats.addStats(IPSockAddr::toIPSockAddr("127.0.0.4", 53), record));
245     EXPECT_FALSE(mDnsStats.addStats(IPSockAddr::toIPSockAddr("127.a.b.4", 53), record));
246 
247     EXPECT_TRUE(mDnsStats.addStats(servers[0], record));
248     EXPECT_TRUE(mDnsStats.addStats(servers[0], record));
249     EXPECT_TRUE(mDnsStats.addStats(servers[1], record));
250 
251     const std::vector<StatsData> expectedStatsForTcp = {
252             makeStatsData(servers[0], 0, 0ms, {}),
253             makeStatsData(servers[1], 0, 0ms, {}),
254     };
255     const std::vector<StatsData> expectedStatsForUdp = {
256             makeStatsData(servers[0], 2, 20ms, {{NS_R_NO_ERROR, 2}}),
257             makeStatsData(servers[1], 1, 10ms, {{NS_R_NO_ERROR, 1}}),
258     };
259 
260     EXPECT_THAT(mDnsStats.getStats(PROTO_TCP), UnorderedElementsAreArray(expectedStatsForTcp));
261     EXPECT_THAT(mDnsStats.getStats(PROTO_UDP), UnorderedElementsAreArray(expectedStatsForUdp));
262     EXPECT_THAT(mDnsStats.getStats(PROTO_DOT), IsEmpty());
263     verifyDumpOutput(expectedStatsForTcp, expectedStatsForUdp, {});
264 
265     // Clear stats.
266     EXPECT_TRUE(mDnsStats.setServers({}, PROTO_TCP));
267     EXPECT_TRUE(mDnsStats.setServers({}, PROTO_UDP));
268     EXPECT_TRUE(mDnsStats.setServers({}, PROTO_DOT));
269     EXPECT_THAT(mDnsStats.getStats(PROTO_TCP), IsEmpty());
270     EXPECT_THAT(mDnsStats.getStats(PROTO_UDP), IsEmpty());
271     EXPECT_THAT(mDnsStats.getStats(PROTO_DOT), IsEmpty());
272     verifyDumpOutput({}, {}, {});
273 }
274 
TEST_F(DnsStatsTest,StatsRemainsInExistentServer)275 TEST_F(DnsStatsTest, StatsRemainsInExistentServer) {
276     std::vector<IPSockAddr> servers = {
277             IPSockAddr::toIPSockAddr("127.0.0.1", 53),
278             IPSockAddr::toIPSockAddr("127.0.0.2", 53),
279     };
280     const DnsQueryEvent recordNoError = makeDnsQueryEvent(PROTO_UDP, NS_R_NO_ERROR, 10ms);
281     const DnsQueryEvent recordTimeout = makeDnsQueryEvent(PROTO_UDP, NS_R_TIMEOUT, 250ms);
282 
283     EXPECT_TRUE(mDnsStats.setServers(servers, PROTO_UDP));
284 
285     // Add a record to 127.0.0.1.
286     EXPECT_TRUE(mDnsStats.addStats(servers[0], recordNoError));
287 
288     // Add four records to 127.0.0.2.
289     EXPECT_TRUE(mDnsStats.addStats(servers[1], recordNoError));
290     EXPECT_TRUE(mDnsStats.addStats(servers[1], recordNoError));
291     EXPECT_TRUE(mDnsStats.addStats(servers[1], recordTimeout));
292     EXPECT_TRUE(mDnsStats.addStats(servers[1], recordTimeout));
293 
294     std::vector<StatsData> expectedStats = {
295             makeStatsData(servers[0], 1, 10ms, {{NS_R_NO_ERROR, 1}}),
296             makeStatsData(servers[1], 4, 520ms, {{NS_R_NO_ERROR, 2}, {NS_R_TIMEOUT, 2}}),
297     };
298     EXPECT_THAT(mDnsStats.getStats(PROTO_UDP), UnorderedElementsAreArray(expectedStats));
299     verifyDumpOutput({}, expectedStats, {});
300 
301     // Update the server list, the stats of 127.0.0.2 will remain.
302     servers = {
303             IPSockAddr::toIPSockAddr("127.0.0.2", 53),
304             IPSockAddr::toIPSockAddr("127.0.0.3", 53),
305             IPSockAddr::toIPSockAddr("127.0.0.4", 53),
306     };
307     EXPECT_TRUE(mDnsStats.setServers(servers, PROTO_UDP));
308     expectedStats = {
309             makeStatsData(servers[0], 4, 520ms, {{NS_R_NO_ERROR, 2}, {NS_R_TIMEOUT, 2}}),
310             makeStatsData(servers[1], 0, 0ms, {}),
311             makeStatsData(servers[2], 0, 0ms, {}),
312     };
313     EXPECT_THAT(mDnsStats.getStats(PROTO_UDP), UnorderedElementsAreArray(expectedStats));
314     verifyDumpOutput({}, expectedStats, {});
315 
316     // Let's add a record to 127.0.0.2 again.
317     EXPECT_TRUE(mDnsStats.addStats(servers[0], recordNoError));
318     expectedStats = {
319             makeStatsData(servers[0], 5, 530ms, {{NS_R_NO_ERROR, 3}, {NS_R_TIMEOUT, 2}}),
320             makeStatsData(servers[1], 0, 0ms, {}),
321             makeStatsData(servers[2], 0, 0ms, {}),
322     };
323     EXPECT_THAT(mDnsStats.getStats(PROTO_UDP), UnorderedElementsAreArray(expectedStats));
324     verifyDumpOutput({}, expectedStats, {});
325 }
326 
TEST_F(DnsStatsTest,AddStatsRecords_100000)327 TEST_F(DnsStatsTest, AddStatsRecords_100000) {
328     constexpr size_t operations = 100000;
329     constexpr size_t logSize = DnsStats::kLogSize;
330     constexpr size_t rcodeNum = 4;  // A value by which kLogSize is divisible.
331     ASSERT_EQ(logSize % rcodeNum, 0U);
332 
333     const std::vector<IPSockAddr> servers = {
334             IPSockAddr::toIPSockAddr("127.0.0.1", 53),
335             IPSockAddr::toIPSockAddr("127.0.0.2", 53),
336             IPSockAddr::toIPSockAddr("127.0.0.3", 53),
337             IPSockAddr::toIPSockAddr("127.0.0.4", 53),
338     };
339 
340     // To test unknown rcode in rcodeToName(), store the elements as type int.
341     const std::array<int, rcodeNum> rcodes = {
342             NS_R_NO_ERROR,        // NOERROR
343             NS_R_NXDOMAIN,        // NXDOMAIN
344             99,                   // UNKNOWN(99)
345             NS_R_INTERNAL_ERROR,  // INTERNAL_ERROR
346     };
347 
348     EXPECT_TRUE(mDnsStats.setServers(servers, PROTO_TCP));
349     EXPECT_TRUE(mDnsStats.setServers(servers, PROTO_UDP));
350     EXPECT_TRUE(mDnsStats.setServers(servers, PROTO_DOT));
351 
352     for (size_t i = 0; i < operations; i++) {
353         const NsRcode rcode = static_cast<NsRcode>(rcodes[i % rcodeNum]);
354         const auto eventTcp = makeDnsQueryEvent(PROTO_TCP, rcode, 10ms);
355         const auto eventUdp = makeDnsQueryEvent(PROTO_UDP, rcode, 10ms);
356         const auto eventDot = makeDnsQueryEvent(PROTO_DOT, rcode, 10ms);
357         for (const auto& server : servers) {
358             SCOPED_TRACE(server.toString() + "-" + std::to_string(i));
359             ASSERT_TRUE(mDnsStats.addStats(server, eventTcp));
360             ASSERT_TRUE(mDnsStats.addStats(server, eventUdp));
361             ASSERT_TRUE(mDnsStats.addStats(server, eventDot));
362         }
363     }
364 
365     std::map<int, int> expectedRcodeCounts;
366     for (const auto& rcode : rcodes) {
367         expectedRcodeCounts.try_emplace(rcode, 32);
368     }
369     const std::vector<StatsData> expectedStats = {
370             makeStatsData(servers[0], logSize, logSize * 10ms, expectedRcodeCounts),
371             makeStatsData(servers[1], logSize, logSize * 10ms, expectedRcodeCounts),
372             makeStatsData(servers[2], logSize, logSize * 10ms, expectedRcodeCounts),
373             makeStatsData(servers[3], logSize, logSize * 10ms, expectedRcodeCounts),
374     };
375 
376     EXPECT_THAT(mDnsStats.getStats(PROTO_TCP), UnorderedElementsAreArray(expectedStats));
377     EXPECT_THAT(mDnsStats.getStats(PROTO_UDP), UnorderedElementsAreArray(expectedStats));
378     EXPECT_THAT(mDnsStats.getStats(PROTO_DOT), UnorderedElementsAreArray(expectedStats));
379     verifyDumpOutput(expectedStats, expectedStats, expectedStats);
380 }
381 
382 }  // namespace android::net
383