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