1 // Copyright 2011 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_util.h"
6
7 #include <errno.h>
8 #include <limits.h>
9 #include <stdint.h>
10
11 #include <cstring>
12 #include <string>
13 #include <string_view>
14 #include <unordered_map>
15 #include <vector>
16
17 #include "base/check_op.h"
18 #include "base/containers/contains.h"
19 #include "base/feature_list.h"
20 #include "base/metrics/field_trial.h"
21 #include "base/metrics/histogram_macros.h"
22 #include "base/numerics/byte_conversions.h"
23 #include "base/ranges/algorithm.h"
24 #include "base/strings/string_number_conversions.h"
25 #include "base/strings/string_split.h"
26 #include "build/build_config.h"
27 #include "net/dns/public/dns_protocol.h"
28 #include "net/dns/public/doh_provider_entry.h"
29 #include "net/dns/public/util.h"
30 #include "net/third_party/uri_template/uri_template.h"
31
32 #if BUILDFLAG(IS_POSIX)
33 #include <net/if.h>
34 #include <netinet/in.h>
35 #if !BUILDFLAG(IS_ANDROID)
36 #include <ifaddrs.h>
37 #endif // !BUILDFLAG(IS_ANDROID)
38 #endif // BUILDFLAG(IS_POSIX)
39
40 #if BUILDFLAG(IS_ANDROID)
41 #include "net/android/network_library.h"
42 #endif
43
44 namespace net {
45 namespace {
46
GetDohProviderEntriesFromNameservers(const std::vector<IPEndPoint> & dns_servers)47 DohProviderEntry::List GetDohProviderEntriesFromNameservers(
48 const std::vector<IPEndPoint>& dns_servers) {
49 const DohProviderEntry::List& providers = DohProviderEntry::GetList();
50 DohProviderEntry::List entries;
51
52 for (const auto& server : dns_servers) {
53 for (const net::DohProviderEntry* entry : providers) {
54 // DoH servers should only be added once.
55 // Note: Check whether the provider is enabled *after* we've determined
56 // that the IP addresses match so that if we are doing experimentation via
57 // Finch, the experiment only includes possible users of the
58 // corresponding DoH provider (since the client will be included in the
59 // experiment if the provider feature flag is checked).
60 if (base::Contains(entry->ip_addresses, server.address()) &&
61 base::FeatureList::IsEnabled(entry->feature) &&
62 !base::Contains(entries, entry)) {
63 entries.push_back(entry);
64 }
65 }
66 }
67 return entries;
68 }
69
70 } // namespace
71
GetURLFromTemplateWithoutParameters(const string & server_template)72 std::string GetURLFromTemplateWithoutParameters(const string& server_template) {
73 std::string url_string;
74 std::unordered_map<string, string> parameters;
75 uri_template::Expand(server_template, parameters, &url_string);
76 return url_string;
77 }
78
79 namespace {
80
GetTimeDeltaForConnectionTypeFromFieldTrial(const char * field_trial,NetworkChangeNotifier::ConnectionType type,base::TimeDelta * out)81 bool GetTimeDeltaForConnectionTypeFromFieldTrial(
82 const char* field_trial,
83 NetworkChangeNotifier::ConnectionType type,
84 base::TimeDelta* out) {
85 std::string group = base::FieldTrialList::FindFullName(field_trial);
86 if (group.empty())
87 return false;
88 std::vector<std::string_view> group_parts = base::SplitStringPiece(
89 group, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
90 if (type < 0)
91 return false;
92 size_t type_size = static_cast<size_t>(type);
93 if (type_size >= group_parts.size())
94 return false;
95 int64_t ms;
96 if (!base::StringToInt64(group_parts[type_size], &ms))
97 return false;
98 *out = base::Milliseconds(ms);
99 return true;
100 }
101
102 } // namespace
103
GetTimeDeltaForConnectionTypeFromFieldTrialOrDefault(const char * field_trial,base::TimeDelta default_delta,NetworkChangeNotifier::ConnectionType type)104 base::TimeDelta GetTimeDeltaForConnectionTypeFromFieldTrialOrDefault(
105 const char* field_trial,
106 base::TimeDelta default_delta,
107 NetworkChangeNotifier::ConnectionType type) {
108 base::TimeDelta out;
109 if (!GetTimeDeltaForConnectionTypeFromFieldTrial(field_trial, type, &out))
110 out = default_delta;
111 return out;
112 }
113
CreateNamePointer(uint16_t offset)114 std::string CreateNamePointer(uint16_t offset) {
115 DCHECK_EQ(offset & ~dns_protocol::kOffsetMask, 0);
116 std::array<uint8_t, 2> buf = base::U16ToBigEndian(offset);
117 buf[0u] |= dns_protocol::kLabelPointer;
118 return std::string(buf.begin(), buf.end());
119 }
120
DnsQueryTypeToQtype(DnsQueryType dns_query_type)121 uint16_t DnsQueryTypeToQtype(DnsQueryType dns_query_type) {
122 switch (dns_query_type) {
123 case DnsQueryType::UNSPECIFIED:
124 NOTREACHED();
125 return 0;
126 case DnsQueryType::A:
127 return dns_protocol::kTypeA;
128 case DnsQueryType::AAAA:
129 return dns_protocol::kTypeAAAA;
130 case DnsQueryType::TXT:
131 return dns_protocol::kTypeTXT;
132 case DnsQueryType::PTR:
133 return dns_protocol::kTypePTR;
134 case DnsQueryType::SRV:
135 return dns_protocol::kTypeSRV;
136 case DnsQueryType::HTTPS:
137 return dns_protocol::kTypeHttps;
138 }
139 }
140
AddressFamilyToDnsQueryType(AddressFamily address_family)141 DnsQueryType AddressFamilyToDnsQueryType(AddressFamily address_family) {
142 switch (address_family) {
143 case ADDRESS_FAMILY_UNSPECIFIED:
144 return DnsQueryType::UNSPECIFIED;
145 case ADDRESS_FAMILY_IPV4:
146 return DnsQueryType::A;
147 case ADDRESS_FAMILY_IPV6:
148 return DnsQueryType::AAAA;
149 default:
150 NOTREACHED();
151 return DnsQueryType::UNSPECIFIED;
152 }
153 }
154
GetDohUpgradeServersFromDotHostname(const std::string & dot_server)155 std::vector<DnsOverHttpsServerConfig> GetDohUpgradeServersFromDotHostname(
156 const std::string& dot_server) {
157 std::vector<DnsOverHttpsServerConfig> doh_servers;
158
159 if (dot_server.empty())
160 return doh_servers;
161
162 for (const net::DohProviderEntry* entry : DohProviderEntry::GetList()) {
163 // Note: Check whether the provider is enabled *after* we've determined that
164 // the hostnames match so that if we are doing experimentation via Finch,
165 // the experiment only includes possible users of the corresponding DoH
166 // provider (since the client will be included in the experiment if the
167 // provider feature flag is checked).
168 if (base::Contains(entry->dns_over_tls_hostnames, dot_server) &&
169 base::FeatureList::IsEnabled(entry->feature)) {
170 doh_servers.push_back(entry->doh_server_config);
171 }
172 }
173 return doh_servers;
174 }
175
GetDohUpgradeServersFromNameservers(const std::vector<IPEndPoint> & dns_servers)176 std::vector<DnsOverHttpsServerConfig> GetDohUpgradeServersFromNameservers(
177 const std::vector<IPEndPoint>& dns_servers) {
178 const auto entries = GetDohProviderEntriesFromNameservers(dns_servers);
179 std::vector<DnsOverHttpsServerConfig> doh_servers;
180 doh_servers.reserve(entries.size());
181 base::ranges::transform(entries, std::back_inserter(doh_servers),
182 &DohProviderEntry::doh_server_config);
183 return doh_servers;
184 }
185
GetDohProviderIdForHistogramFromServerConfig(const DnsOverHttpsServerConfig & doh_server)186 std::string GetDohProviderIdForHistogramFromServerConfig(
187 const DnsOverHttpsServerConfig& doh_server) {
188 const auto& entries = DohProviderEntry::GetList();
189 const auto it = base::ranges::find(entries, doh_server,
190 &DohProviderEntry::doh_server_config);
191 return it != entries.end() ? (*it)->provider : "Other";
192 }
193
GetDohProviderIdForHistogramFromNameserver(const IPEndPoint & nameserver)194 std::string GetDohProviderIdForHistogramFromNameserver(
195 const IPEndPoint& nameserver) {
196 const auto entries = GetDohProviderEntriesFromNameservers({nameserver});
197 return entries.empty() ? "Other" : entries[0]->provider;
198 }
199
SecureDnsModeToString(const SecureDnsMode secure_dns_mode)200 std::string SecureDnsModeToString(const SecureDnsMode secure_dns_mode) {
201 switch (secure_dns_mode) {
202 case SecureDnsMode::kOff:
203 return "Off";
204 case SecureDnsMode::kAutomatic:
205 return "Automatic";
206 case SecureDnsMode::kSecure:
207 return "Secure";
208 }
209 }
210
211 } // namespace net
212