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/public/doh_provider_entry.h"
6
7 #include <string_view>
8 #include <utility>
9
10 #include "base/check_op.h"
11 #include "base/containers/to_vector.h"
12 #include "base/feature_list.h"
13 #include "base/no_destructor.h"
14 #include "base/ranges/algorithm.h"
15 #include "net/dns/public/dns_over_https_server_config.h"
16 #include "net/dns/public/util.h"
17
18 namespace net {
19
20 namespace {
21
ParseIPs(const std::initializer_list<std::string_view> & ip_strs)22 std::set<IPAddress> ParseIPs(
23 const std::initializer_list<std::string_view>& ip_strs) {
24 std::set<IPAddress> ip_addresses;
25 for (std::string_view ip_str : ip_strs) {
26 IPAddress ip_address;
27 bool success = ip_address.AssignFromIPLiteral(ip_str);
28 DCHECK(success);
29 ip_addresses.insert(std::move(ip_address));
30 }
31 return ip_addresses;
32 }
33
ParseValidDohTemplate(std::string server_template,const std::initializer_list<std::string_view> & endpoint_ip_strs)34 DnsOverHttpsServerConfig ParseValidDohTemplate(
35 std::string server_template,
36 const std::initializer_list<std::string_view>& endpoint_ip_strs) {
37 std::set<IPAddress> endpoint_ips = ParseIPs(endpoint_ip_strs);
38
39 std::vector<std::vector<IPAddress>> endpoints;
40
41 // Note: `DnsOverHttpsServerConfig` supports separate groups of endpoint IPs,
42 // but for now we'll just support all endpoint IPs combined into one grouping
43 // since the only use of the endpoint IPs in the server config combines them
44 // anyway.
45 if (!endpoint_ips.empty()) {
46 endpoints.emplace_back(endpoint_ips.begin(), endpoint_ips.end());
47 }
48
49 auto parsed_template = DnsOverHttpsServerConfig::FromString(
50 std::move(server_template), std::move(endpoints));
51 DCHECK(parsed_template.has_value()); // Template must be valid.
52 return std::move(*parsed_template);
53 }
54
55 } // namespace
56
57 #define MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(feature_name, feature_state) \
58 ([]() { \
59 static BASE_FEATURE(k##feature_name, #feature_name, feature_state); \
60 return &k##feature_name; \
61 })()
62
63 // static
GetList()64 const DohProviderEntry::List& DohProviderEntry::GetList() {
65 // See /net/docs/adding_doh_providers.md for instructions on modifying this
66 // DoH provider list.
67 //
68 // The provider names in these entries should be kept in sync with the
69 // DohProviderId histogram suffix list in
70 // tools/metrics/histograms/metadata/histogram_suffixes_list.xml.
71 static const auto entries(base::NoDestructor(std::to_array<DohProviderEntry>(
72 {{"AlekBergNl",
73 MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(DohProviderAlekBergNl,
74 base::FEATURE_ENABLED_BY_DEFAULT),
75 /*dns_over_53_server_ip_strs=*/{}, /*dns_over_tls_hostnames=*/{},
76 "https://dnsnl.alekberg.net/dns-query{?dns}",
77 /*ui_name=*/"alekberg.net (NL)",
78 /*privacy_policy=*/"https://alekberg.net/privacy",
79 /*display_globally=*/false,
80 /*display_countries=*/{"NL"}, LoggingLevel::kNormal},
81 {"CleanBrowsingAdult",
82 MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(DohProviderCleanBrowsingAdult,
83 base::FEATURE_ENABLED_BY_DEFAULT),
84 {"185.228.168.10", "185.228.169.11", "2a0d:2a00:1::1",
85 "2a0d:2a00:2::1"},
86 /*dns_over_tls_hostnames=*/{"adult-filter-dns.cleanbrowsing.org"},
87 "https://doh.cleanbrowsing.org/doh/adult-filter{?dns}",
88 /*ui_name=*/"",
89 /*privacy_policy=*/"",
90 /*display_globally=*/false,
91 /*display_countries=*/{},
92 LoggingLevel::kNormal},
93 {"CleanBrowsingFamily",
94 MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(DohProviderCleanBrowsingFamily,
95 base::FEATURE_ENABLED_BY_DEFAULT),
96 {"185.228.168.168", "185.228.169.168",
97 "2a0d:2a00:1::", "2a0d:2a00:2::"},
98 /*dns_over_tls_hostnames=*/{"family-filter-dns.cleanbrowsing.org"},
99 "https://doh.cleanbrowsing.org/doh/family-filter{?dns}",
100 /*ui_name=*/"CleanBrowsing (Family Filter)",
101 /*privacy_policy=*/"https://cleanbrowsing.org/privacy",
102 /*display_globally=*/true,
103 /*display_countries=*/{},
104 LoggingLevel::kNormal},
105 {"CleanBrowsingSecure",
106 MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(DohProviderCleanBrowsingSecure,
107 base::FEATURE_ENABLED_BY_DEFAULT),
108 {"185.228.168.9", "185.228.169.9", "2a0d:2a00:1::2", "2a0d:2a00:2::2"},
109 /*dns_over_tls_hostnames=*/{"security-filter-dns.cleanbrowsing.org"},
110 "https://doh.cleanbrowsing.org/doh/security-filter{?dns}",
111 /*ui_name=*/"",
112 /*privacy_policy=*/"",
113 /*display_globally=*/false,
114 /*display_countries=*/{},
115 LoggingLevel::kNormal},
116 {"Cloudflare",
117 MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(DohProviderCloudflare,
118 base::FEATURE_ENABLED_BY_DEFAULT),
119 {"1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001"},
120 /*dns_over_tls_hostnames=*/
121 {"one.one.one.one", "1dot1dot1dot1.cloudflare-dns.com"},
122 "https://chrome.cloudflare-dns.com/dns-query",
123 /*ui_name=*/"Cloudflare (1.1.1.1)",
124 "https://developers.cloudflare.com/1.1.1.1/privacy/"
125 /*privacy_policy=*/"public-dns-resolver/",
126 /*display_globally=*/true,
127 /*display_countries=*/{},
128 LoggingLevel::kExtra},
129 {"Comcast",
130 MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(DohProviderComcast,
131 base::FEATURE_ENABLED_BY_DEFAULT),
132 {"75.75.75.75", "75.75.76.76", "2001:558:feed::1", "2001:558:feed::2"},
133 /*dns_over_tls_hostnames=*/{"dot.xfinity.com"},
134 "https://doh.xfinity.com/dns-query{?dns}",
135 /*ui_name=*/"",
136 /*privacy_policy*/ "",
137 /*display_globally=*/false,
138 /*display_countries=*/{},
139 LoggingLevel::kExtra},
140 {"Cox",
141 MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(DohProviderCox,
142 base::FEATURE_ENABLED_BY_DEFAULT),
143 {"68.105.28.11", "68.105.28.12", "2001:578:3f::30"},
144 /*dns_over_tls_hostnames=*/{"dot.cox.net"},
145 "https://doh.cox.net/dns-query",
146 /*ui_name=*/"",
147 /*privacy_policy=*/"",
148 /*display_globally=*/false,
149 /*display_countries=*/{},
150 LoggingLevel::kNormal},
151 {"Cznic",
152 MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(DohProviderCznic,
153 base::FEATURE_ENABLED_BY_DEFAULT),
154 {"185.43.135.1", "193.17.47.1", "2001:148f:fffe::1",
155 "2001:148f:ffff::1"},
156 /*dns_over_tls_hostnames=*/{"odvr.nic.cz"},
157 "https://odvr.nic.cz/doh",
158 /*ui_name=*/"CZ.NIC ODVR",
159 /*privacy_policy=*/"https://www.nic.cz/odvr/",
160 /*display_globally=*/false,
161 /*display_countries=*/{"CZ"},
162 LoggingLevel::kNormal},
163 {"Dnssb",
164 MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(DohProviderDnssb,
165 base::FEATURE_ENABLED_BY_DEFAULT),
166 {"185.222.222.222", "45.11.45.11", "2a09::", "2a11::"},
167 /*dns_over_tls_hostnames=*/{"dns.sb"},
168 "https://doh.dns.sb/dns-query{?dns}",
169 /*ui_name=*/"DNS.SB",
170 /*privacy_policy=*/"https://dns.sb/privacy/",
171 /*display_globally=*/false,
172 /*display_countries=*/{"EE", "DE"},
173 LoggingLevel::kNormal},
174 {"Google",
175 MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(DohProviderGoogle,
176 base::FEATURE_ENABLED_BY_DEFAULT),
177 {"8.8.8.8", "8.8.4.4", "2001:4860:4860::8888", "2001:4860:4860::8844"},
178 /*dns_over_tls_hostnames=*/
179 {"dns.google", "dns.google.com", "8888.google"},
180 "https://dns.google/dns-query{?dns}",
181 /*ui_name=*/"Google (Public DNS)",
182 "https://developers.google.com/speed/public-dns/"
183 /*privacy_policy=*/"privacy",
184 /*display_globally=*/true,
185 /*display_countries=*/{},
186 LoggingLevel::kExtra},
187 {"GoogleDns64",
188 MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(DohProviderGoogleDns64,
189 base::FEATURE_ENABLED_BY_DEFAULT),
190 {"2001:4860:4860::64", "2001:4860:4860::6464"},
191 /*dns_over_tls_hostnames=*/{"dns64.dns.google"},
192 "https://dns64.dns.google/dns-query{?dns}",
193 /*ui_name=*/"",
194 /*privacy_policy=*/"",
195 /*display_globally=*/false,
196 /*display_countries=*/{},
197 LoggingLevel::kNormal},
198 {"Iij",
199 MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(DohProviderIij,
200 base::FEATURE_ENABLED_BY_DEFAULT),
201 /*dns_over_53_server_ip_strs=*/{},
202 /*dns_over_tls_hostnames=*/{}, "https://public.dns.iij.jp/dns-query",
203 /*ui_name=*/"IIJ (Public DNS)",
204 /*privacy_policy=*/"https://policy.public.dns.iij.jp/",
205 /*display_globally=*/false, /*display_countries=*/{"JP"},
206 LoggingLevel::kNormal},
207 {"Levonet",
208 MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(DohProviderLevonet,
209 base::FEATURE_ENABLED_BY_DEFAULT),
210 {"109.236.119.2", "109.236.120.2", "2a02:6ca3:0:1::2",
211 "2a02:6ca3:0:2::2"},
212 /*dns_over_tls_hostnames=*/{},
213 "https://dns.levonet.sk/dns-query{?dns}",
214 /*ui_name=*/"",
215 /*privacy_policy=*/"",
216 /*display_globally=*/false,
217 /*display_countries=*/{},
218 LoggingLevel::kNormal,
219 {"109.236.119.2", "109.236.120.2", "2a02:6ca3:0:1::2",
220 "2a02:6ca3:0:2::2"}},
221 {"NextDns",
222 MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(DohProviderNextDns,
223 base::FEATURE_ENABLED_BY_DEFAULT),
224 /*dns_over_53_server_ip_strs=*/{},
225 /*dns_over_tls_hostnames=*/{}, "https://chromium.dns.nextdns.io",
226 /*ui_name=*/"NextDNS",
227 /*privacy_policy=*/"https://nextdns.io/privacy",
228 /*display_globally=*/false, /*display_countries=*/{"US"},
229 LoggingLevel::kNormal},
230 {"OpenDNS",
231 MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(DohProviderOpenDNS,
232 base::FEATURE_ENABLED_BY_DEFAULT),
233 {"208.67.222.222", "208.67.220.220", "2620:119:35::35",
234 "2620:119:53::53"},
235 /*dns_over_tls_hostnames=*/{},
236 "https://doh.opendns.com/dns-query{?dns}",
237 /*ui_name=*/"OpenDNS",
238 "https://www.cisco.com/c/en/us/about/legal/"
239 /*privacy_policy=*/"privacy-full.html",
240 /*display_globally=*/true,
241 /*display_countries=*/{},
242 LoggingLevel::kNormal},
243 {"OpenDNSFamily",
244 MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(DohProviderOpenDNSFamily,
245 base::FEATURE_ENABLED_BY_DEFAULT),
246 {"208.67.222.123", "208.67.220.123", "2620:119:35::123",
247 "2620:119:53::123"},
248 /*dns_over_tls_hostnames=*/{},
249 "https://doh.familyshield.opendns.com/dns-query{?dns}",
250 /*ui_name=*/"",
251 /*privacy_policy=*/"",
252 /*display_globally=*/false,
253 /*display_countries=*/{},
254 LoggingLevel::kNormal},
255 {"Quad9Cdn",
256 MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(DohProviderQuad9Cdn,
257 base::FEATURE_ENABLED_BY_DEFAULT),
258 {"9.9.9.11", "149.112.112.11", "2620:fe::11", "2620:fe::fe:11"},
259 /*dns_over_tls_hostnames=*/{"dns11.quad9.net"},
260 "https://dns11.quad9.net/dns-query",
261 /*ui_name=*/"",
262 /*privacy_policy=*/"",
263 /*display_globally=*/false,
264 /*display_countries=*/{},
265 LoggingLevel::kNormal},
266 {"Quad9Insecure",
267 MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(DohProviderQuad9Insecure,
268 base::FEATURE_ENABLED_BY_DEFAULT),
269 {"9.9.9.10", "149.112.112.10", "2620:fe::10", "2620:fe::fe:10"},
270 /*dns_over_tls_hostnames=*/{"dns10.quad9.net"},
271 "https://dns10.quad9.net/dns-query",
272 /*ui_name=*/"",
273 /*privacy_policy=*/"",
274 /*display_globally=*/false,
275 /*display_countries=*/{},
276 LoggingLevel::kNormal},
277 {"Quad9Secure",
278 MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(
279 DohProviderQuad9Secure, base::FEATURE_DISABLED_BY_DEFAULT),
280 {"9.9.9.9", "149.112.112.112", "2620:fe::fe", "2620:fe::9"},
281 /*dns_over_tls_hostnames=*/{"dns.quad9.net", "dns9.quad9.net"},
282 "https://dns.quad9.net/dns-query",
283 /*ui_name=*/"Quad9 (9.9.9.9)",
284 /*privacy_policy=*/"https://www.quad9.net/home/privacy/",
285 /*display_globally=*/true,
286 /*display_countries=*/{},
287 LoggingLevel::kExtra},
288 {"Quickline",
289 MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(DohProviderQuickline,
290 base::FEATURE_ENABLED_BY_DEFAULT),
291 {"212.60.61.246", "212.60.63.246", "2001:1a88:10:ffff::1",
292 "2001:1a88:10:ffff::2"},
293 /*dns_over_tls_hostnames=*/{"dot.quickline.ch"},
294 "https://doh.quickline.ch/dns-query{?dns}",
295 /*ui_name=*/"",
296 /*privacy_policy=*/"",
297 /*display_globally=*/false,
298 /*display_countries=*/{},
299 LoggingLevel::kNormal},
300 {"Spectrum1",
301 MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(DohProviderSpectrum1,
302 base::FEATURE_ENABLED_BY_DEFAULT),
303 {"209.18.47.61", "209.18.47.62", "2001:1998:0f00:0001::1",
304 "2001:1998:0f00:0002::1"},
305 /*dns_over_tls_hostnames=*/{},
306 "https://doh-01.spectrum.com/dns-query{?dns}",
307 /*ui_name=*/"",
308 /*privacy_policy=*/"",
309 /*display_globally=*/false,
310 /*display_countries=*/{},
311 LoggingLevel::kNormal},
312 {"Spectrum2",
313 MAKE_BASE_FEATURE_WITH_STATIC_STORAGE(DohProviderSpectrum2,
314 base::FEATURE_ENABLED_BY_DEFAULT),
315 {"209.18.47.61", "209.18.47.62", "2001:1998:0f00:0001::1",
316 "2001:1998:0f00:0002::1"},
317 /*dns_over_tls_hostnames=*/{},
318 "https://doh-02.spectrum.com/dns-query{?dns}",
319 /*ui_name=*/"",
320 /*privacy_policy=*/"",
321 /*display_globally=*/false,
322 /*display_countries=*/{},
323 LoggingLevel::kNormal}})));
324
325 static const base::NoDestructor<DohProviderEntry::List> providers(
326 base::ToVector(*entries, [](const DohProviderEntry& entry) {
327 return raw_ptr<const DohProviderEntry, VectorExperimental>(&entry);
328 }));
329 return *providers;
330 }
331
332 #undef MAKE_BASE_FEATURE_WITH_STATIC_STORAGE
333
334 // static
ConstructForTesting(std::string_view provider,const base::Feature * feature,std::initializer_list<std::string_view> dns_over_53_server_ip_strs,base::flat_set<std::string_view> dns_over_tls_hostnames,std::string dns_over_https_template,std::string_view ui_name,std::string_view privacy_policy,bool display_globally,base::flat_set<std::string> display_countries,LoggingLevel logging_level)335 DohProviderEntry DohProviderEntry::ConstructForTesting(
336 std::string_view provider,
337 const base::Feature* feature,
338 std::initializer_list<std::string_view> dns_over_53_server_ip_strs,
339 base::flat_set<std::string_view> dns_over_tls_hostnames,
340 std::string dns_over_https_template,
341 std::string_view ui_name,
342 std::string_view privacy_policy,
343 bool display_globally,
344 base::flat_set<std::string> display_countries,
345 LoggingLevel logging_level) {
346 return DohProviderEntry(provider, feature, dns_over_53_server_ip_strs,
347 std::move(dns_over_tls_hostnames),
348 std::move(dns_over_https_template), ui_name,
349 privacy_policy, display_globally,
350 std::move(display_countries), logging_level);
351 }
352
353 DohProviderEntry::~DohProviderEntry() = default;
354
DohProviderEntry(std::string_view provider,const base::Feature * feature,std::initializer_list<std::string_view> dns_over_53_server_ip_strs,base::flat_set<std::string_view> dns_over_tls_hostnames,std::string dns_over_https_template,std::string_view ui_name,std::string_view privacy_policy,bool display_globally,base::flat_set<std::string> display_countries,LoggingLevel logging_level,std::initializer_list<std::string_view> dns_over_https_server_ip_strs)355 DohProviderEntry::DohProviderEntry(
356 std::string_view provider,
357 const base::Feature* feature,
358 std::initializer_list<std::string_view> dns_over_53_server_ip_strs,
359 base::flat_set<std::string_view> dns_over_tls_hostnames,
360 std::string dns_over_https_template,
361 std::string_view ui_name,
362 std::string_view privacy_policy,
363 bool display_globally,
364 base::flat_set<std::string> display_countries,
365 LoggingLevel logging_level,
366 std::initializer_list<std::string_view> dns_over_https_server_ip_strs)
367 : provider(provider),
368 feature(*feature),
369 ip_addresses(ParseIPs(dns_over_53_server_ip_strs)),
370 dns_over_tls_hostnames(std::move(dns_over_tls_hostnames)),
371 doh_server_config(
372 ParseValidDohTemplate(std::move(dns_over_https_template),
373 dns_over_https_server_ip_strs)),
374 ui_name(ui_name),
375 privacy_policy(privacy_policy),
376 display_globally(display_globally),
377 display_countries(std::move(display_countries)),
378 logging_level(logging_level) {
379 DCHECK(!display_globally || this->display_countries.empty());
380 if (display_globally || !this->display_countries.empty()) {
381 DCHECK(!this->ui_name.empty());
382 DCHECK(!this->privacy_policy.empty());
383 }
384 for (const auto& display_country : this->display_countries) {
385 DCHECK_EQ(2u, display_country.size());
386 }
387 }
388
389 DohProviderEntry::DohProviderEntry(DohProviderEntry&& other) = default;
390 } // namespace net
391