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 
18 #include "resolv_stats_test_utils.h"
19 
20 #include <iostream>
21 #include <regex>
22 
23 #include <android-base/logging.h>
24 #include <android-base/parseint.h>
25 #include <android-base/strings.h>
26 #include <gmock/gmock.h>
27 #include <stats.pb.h>
28 
29 namespace android::net {
30 
31 using android::net::NetworkDnsEventReported;
32 
33 // The fromNetworkDnsEventReportedStr is a function to generate a protocol buffer message
34 // NetworkDnsEventReported from a string. How to define the sting for NetworkDnsEventReported,
35 // please refer to test case AlphabeticalHostname.
36 // There are 3 proto messages(1. NetworkDnsEventReported 2. dns_query_events 3. dns_query_event)
37 // The names of these 3 messages will not be verified, please do not change.
38 // Each field will be parsed into corresponding message by those char pairs "{" & "}".
39 // Example: (Don't need to fill Level 1 fields in NetworkDnsEventReported. Currently,
40 // no verification is performed.)
41 // NetworkDnsEventReported { <= construct the NetworkDnsEventReported message (Level 1)
42 //  dns_query_events:(Level 2)
43 //  { <= construct the dns_query_events message
44 //   dns_query_event:(Level 3)
45 //    {  <= construct the 1st dns_query_event message
46 //     [field]: value,
47 //     [field]: value,
48 //    } <= finish the 1st dns_query_event message
49 //   dns_query_event:(Level 3)
50 //    {  <= construct 2nd dns_query_event message
51 //     [field]: value,
52 //     [field]: value,
53 //    } <= finish the 1nd dns_query_event message
54 //  } <= finish the dns_query_events message
55 // } <= finish the NetworkDnsEventReported message
56 
fromNetworkDnsEventReportedStr(const std::string & str)57 NetworkDnsEventReported fromNetworkDnsEventReportedStr(const std::string& str) {
58     using android::base::ParseInt;
59     using android::base::Split;
60     // Remove unnecessary space
61     std::regex re(": ");
62     std::string s = std::regex_replace(str, re, ":");
63     // Using space to separate each parse line
64     static const std::regex words_regex("[^\\s]+");
65     auto words_begin = std::sregex_iterator(s.begin(), s.end(), words_regex);
66     auto words_end = std::sregex_iterator();
67     // Using strproto to identify the position of NetworkDnsEventReported proto
68     int strproto = 0;
69     NetworkDnsEventReported event;
70     DnsQueryEvent* dnsQueryEvent = nullptr;
71     for (std::sregex_iterator i = words_begin; i != words_end; ++i) {
72         std::string match_str = (*i).str();
73         // Using "{" and "}" to identify the Start/End of each proto
74         if (match_str == "{") {
75             // strproto 1.NetworkDnsEventReported 2.dns_query_events 3.dns_query_event
76             if (++strproto == 3) {
77                 dnsQueryEvent = event.mutable_dns_query_events()->add_dns_query_event();
78             }
79             continue;
80         }
81         if (match_str == "}" | match_str == "},") {
82             strproto--;
83             continue;
84         }
85         // Parsing each field of the proto and fill it into NetworkDnsEventReported event
86         static const std::regex pieces_regex("([a-zA-Z0-9_]+)\\:([0-9]+),");
87         std::smatch protoField;
88         std::regex_match(match_str, protoField, pieces_regex);
89         int value = 0;
90         LOG(DEBUG) << "Str:" << match_str << " Name:" << protoField[1]
91                    << " Value:" << protoField[2];
92         // Parsing each field of the proto NetworkDnsEventReported
93         if (strproto == 1) {
94             if (protoField[1] == "event_type" && ParseInt(protoField[2], &value)) {
95                 event.set_event_type(static_cast<EventType>(value));
96             } else if (protoField[1] == "return_code" && ParseInt(protoField[2], &value)) {
97                 event.set_return_code(static_cast<ReturnCode>(value));
98             } else if (protoField[1] == "latency_micros" && ParseInt(protoField[2], &value)) {
99                 event.set_latency_micros(value);
100             } else if (protoField[1] == "hints_ai_flags" && ParseInt(protoField[2], &value)) {
101                 event.set_hints_ai_flags(value);
102             } else if (protoField[1] == "res_nsend_flags" && ParseInt(protoField[2], &value)) {
103                 event.set_res_nsend_flags(value);
104             } else if (protoField[1] == "network_type" && ParseInt(protoField[2], &value)) {
105                 event.set_network_type(static_cast<NetworkType>(value));
106             } else if (protoField[1] == "private_dns_modes" && ParseInt(protoField[2], &value)) {
107                 event.set_private_dns_modes(static_cast<PrivateDnsModes>(value));
108             } else if (protoField[1] == "sampling_rate_denom" && ParseInt(protoField[2], &value)) {
109                 event.set_sampling_rate_denom(value);
110             }
111         }
112         // Parsing each field of the proto DnsQueryEvent
113         if (strproto == 3) {
114             if (dnsQueryEvent == nullptr) continue;
115             if (protoField[1] == "rcode" && ParseInt(protoField[2], &value)) {
116                 dnsQueryEvent->set_rcode(static_cast<NsRcode>(value));
117             } else if (protoField[1] == "type" && ParseInt(protoField[2], &value)) {
118                 dnsQueryEvent->set_type(static_cast<NsType>(value));
119             } else if (protoField[1] == "cache_hit" && ParseInt(protoField[2], &value)) {
120                 dnsQueryEvent->set_cache_hit(static_cast<CacheStatus>(value));
121             } else if (protoField[1] == "ip_version" && ParseInt(protoField[2], &value)) {
122                 dnsQueryEvent->set_ip_version(static_cast<IpVersion>(value));
123             } else if (protoField[1] == "protocol" && ParseInt(protoField[2], &value)) {
124                 dnsQueryEvent->set_protocol(static_cast<Protocol>(value));
125             } else if (protoField[1] == "retry_times" && ParseInt(protoField[2], &value)) {
126                 dnsQueryEvent->set_retry_times(value);
127             } else if (protoField[1] == "dns_server_index" && ParseInt(protoField[2], &value)) {
128                 dnsQueryEvent->set_dns_server_index(value);
129             } else if (protoField[1] == "connected" && ParseInt(protoField[2], &value)) {
130                 dnsQueryEvent->set_connected(static_cast<bool>(value));
131             } else if (protoField[1] == "latency_micros" && ParseInt(protoField[2], &value)) {
132                 dnsQueryEvent->set_latency_micros(value);
133             } else if (protoField[1] == "linux_errno" && ParseInt(protoField[2], &value)) {
134                 dnsQueryEvent->set_linux_errno(static_cast<LinuxErrno>(value));
135             }
136         }
137     }
138     return event;
139 }
140 
PrintTo(const DnsQueryEvents & event,std::ostream * os)141 void PrintTo(const DnsQueryEvents& event, std::ostream* os) {
142     *os << "query events: {\n";
143     *os << "  dns_query_event_size: " << event.dns_query_event_size() << "\n";
144     *os << "}";
145 }
146 
PrintTo(const DnsQueryEvent & event,std::ostream * os)147 void PrintTo(const DnsQueryEvent& event, std::ostream* os) {
148     *os << "dns query event: {\n";
149     *os << "  rcode: " << event.rcode() << "\n";
150     *os << "  ns_type: " << event.type() << "\n";
151     *os << "  cache_hit: " << event.cache_hit() << "\n";
152     *os << "  ip_version: " << event.ip_version() << "\n";
153     *os << "  protocol: " << event.protocol() << "\n";
154     *os << "  retry_times: " << event.retry_times() << "\n";
155     *os << "  dns_server_index: " << event.dns_server_index() << "\n";
156     *os << "  connected: " << event.connected() << "\n";
157     *os << "  latency_micros: " << event.latency_micros() << "\n";
158     *os << "  linux_errno: " << event.linux_errno() << "\n";
159     *os << "}";
160 }
161 
PrintTo(const NetworkDnsEventReported & event,std::ostream * os)162 void PrintTo(const NetworkDnsEventReported& event, std::ostream* os) {
163     *os << "network dns event: {\n";
164     *os << "  event_type: " << event.event_type() << "\n";
165     *os << "  return_code: " << event.return_code() << "\n";
166     *os << "  latency_micros: " << event.latency_micros() << "\n";
167     *os << "  hints_ai_flags: " << event.hints_ai_flags() << "\n";
168     *os << "  res_nsend_flags: " << event.res_nsend_flags() << "\n";
169     *os << "  network_type: " << event.network_type() << "\n";
170     *os << "  private_dns_modes: " << event.private_dns_modes() << "\n";
171     *os << "  dns_query_event_size: " << event.dns_query_events().dns_query_event_size() << "\n";
172     *os << "}";
173 }
174 
175 }  // namespace android::net
176