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