blob: c0beb37577fc1849c693752d2171b65d11a7a76f [file] [log] [blame]
Erik Kline1742fe12017-12-13 19:40:49 +09001/*
2 * Copyright (C) 2018 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
17package com.android.server.connectivity;
18
Erik Kline19841792018-05-16 16:41:57 +090019import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE_FALLBACK;
Erik Klinea24d4592018-01-11 21:07:29 +090020import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
Erik Kline1742fe12017-12-13 19:40:49 +090021import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
22import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
23import static android.provider.Settings.Global.DNS_RESOLVER_MIN_SAMPLES;
24import static android.provider.Settings.Global.DNS_RESOLVER_MAX_SAMPLES;
25import static android.provider.Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS;
26import static android.provider.Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT;
Erik Kline19841792018-05-16 16:41:57 +090027import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE;
Erik Kline1742fe12017-12-13 19:40:49 +090028import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
29import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
30
31import android.content.ContentResolver;
32import android.content.Context;
33import android.content.Intent;
Erik Klinea24d4592018-01-11 21:07:29 +090034import android.net.LinkProperties;
35import android.net.Network;
Erik Kline1742fe12017-12-13 19:40:49 +090036import android.net.NetworkUtils;
Erik Klinea24d4592018-01-11 21:07:29 +090037import android.net.Uri;
Erik Klinec43d2f52018-03-21 07:18:33 -070038import android.net.dns.ResolvUtil;
Erik Kline1742fe12017-12-13 19:40:49 +090039import android.os.Binder;
40import android.os.INetworkManagementService;
Erik Kline1742fe12017-12-13 19:40:49 +090041import android.os.UserHandle;
42import android.provider.Settings;
43import android.text.TextUtils;
dalyk1fcb7392018-03-05 12:42:22 -050044import android.util.Pair;
Erik Kline1742fe12017-12-13 19:40:49 +090045import android.util.Slog;
46
47import com.android.server.connectivity.MockableSystemProperties;
48
49import java.net.InetAddress;
Erik Klinec43d2f52018-03-21 07:18:33 -070050import java.net.UnknownHostException;
Erik Klinea24d4592018-01-11 21:07:29 +090051import java.util.Arrays;
Erik Kline1742fe12017-12-13 19:40:49 +090052import java.util.Collection;
Chalard Jeanf0f364f2018-04-11 18:58:52 +090053import java.util.Collections;
Erik Klinea24d4592018-01-11 21:07:29 +090054import java.util.HashMap;
dalyk1fcb7392018-03-05 12:42:22 -050055import java.util.HashSet;
56import java.util.Iterator;
Erik Klinea24d4592018-01-11 21:07:29 +090057import java.util.Map;
dalyk1fcb7392018-03-05 12:42:22 -050058import java.util.Objects;
Erik Klinea24d4592018-01-11 21:07:29 +090059import java.util.stream.Collectors;
dalyk1fcb7392018-03-05 12:42:22 -050060import java.util.Set;
Erik Klinea24d4592018-01-11 21:07:29 +090061import java.util.StringJoiner;
Erik Kline1742fe12017-12-13 19:40:49 +090062
63
64/**
65 * Encapsulate the management of DNS settings for networks.
66 *
67 * This class it NOT designed for concurrent access. Furthermore, all non-static
68 * methods MUST be called from ConnectivityService's thread.
69 *
Erik Kline79c6d052018-03-21 07:18:33 -070070 * [ Private DNS ]
71 * The code handling Private DNS is spread across several components, but this
72 * seems like the least bad place to collect all the observations.
73 *
74 * Private DNS handling and updating occurs in response to several different
75 * events. Each is described here with its corresponding intended handling.
76 *
77 * [A] Event: A new network comes up.
78 * Mechanics:
79 * [1] ConnectivityService gets notifications from NetworkAgents.
80 * [2] in updateNetworkInfo(), the first time the NetworkAgent goes into
81 * into CONNECTED state, the Private DNS configuration is retrieved,
82 * programmed, and strict mode hostname resolution (if applicable) is
83 * enqueued in NetworkAgent's NetworkMonitor, via a call to
84 * handlePerNetworkPrivateDnsConfig().
85 * [3] Re-resolution of strict mode hostnames that fail to return any
86 * IP addresses happens inside NetworkMonitor; it sends itself a
87 * delayed CMD_EVALUATE_PRIVATE_DNS message in a simple backoff
88 * schedule.
89 * [4] Successfully resolved hostnames are sent to ConnectivityService
90 * inside an EVENT_PRIVATE_DNS_CONFIG_RESOLVED message. The resolved
91 * IP addresses are programmed into netd via:
92 *
93 * updatePrivateDns() -> updateDnses()
94 *
95 * both of which make calls into DnsManager.
96 * [5] Upon a successful hostname resolution NetworkMonitor initiates a
97 * validation attempt in the form of a lookup for a one-time hostname
98 * that uses Private DNS.
99 *
100 * [B] Event: Private DNS settings are changed.
101 * Mechanics:
102 * [1] ConnectivityService gets notifications from its SettingsObserver.
103 * [2] handlePrivateDnsSettingsChanged() is called, which calls
104 * handlePerNetworkPrivateDnsConfig() and the process proceeds
105 * as if from A.3 above.
106 *
107 * [C] Event: An application calls ConnectivityManager#reportBadNetwork().
108 * Mechanics:
109 * [1] NetworkMonitor is notified and initiates a reevaluation, which
110 * always bypasses Private DNS.
111 * [2] Once completed, NetworkMonitor checks if strict mode is in operation
112 * and if so enqueues another evaluation of Private DNS, as if from
113 * step A.5 above.
114 *
Erik Kline1742fe12017-12-13 19:40:49 +0900115 * @hide
116 */
117public class DnsManager {
118 private static final String TAG = DnsManager.class.getSimpleName();
dalyk1fcb7392018-03-05 12:42:22 -0500119 private static final PrivateDnsConfig PRIVATE_DNS_OFF = new PrivateDnsConfig();
Erik Kline1742fe12017-12-13 19:40:49 +0900120
121 /* Defaults for resolver parameters. */
122 private static final int DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800;
123 private static final int DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT = 25;
124 private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
125 private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
126
Erik Klinea24d4592018-01-11 21:07:29 +0900127 public static class PrivateDnsConfig {
128 public final boolean useTls;
129 public final String hostname;
130 public final InetAddress[] ips;
131
132 public PrivateDnsConfig() {
133 this(false);
134 }
135
136 public PrivateDnsConfig(boolean useTls) {
137 this.useTls = useTls;
138 this.hostname = "";
139 this.ips = new InetAddress[0];
140 }
141
142 public PrivateDnsConfig(String hostname, InetAddress[] ips) {
143 this.useTls = !TextUtils.isEmpty(hostname);
144 this.hostname = useTls ? hostname : "";
145 this.ips = (ips != null) ? ips : new InetAddress[0];
146 }
147
148 public PrivateDnsConfig(PrivateDnsConfig cfg) {
149 useTls = cfg.useTls;
150 hostname = cfg.hostname;
151 ips = cfg.ips;
152 }
153
154 public boolean inStrictMode() {
155 return useTls && !TextUtils.isEmpty(hostname);
156 }
157
158 public String toString() {
159 return PrivateDnsConfig.class.getSimpleName() +
160 "{" + useTls + ":" + hostname + "/" + Arrays.toString(ips) + "}";
161 }
162 }
163
164 public static PrivateDnsConfig getPrivateDnsConfig(ContentResolver cr) {
165 final String mode = getPrivateDnsMode(cr);
166
167 final boolean useTls = !TextUtils.isEmpty(mode) && !PRIVATE_DNS_MODE_OFF.equals(mode);
168
169 if (PRIVATE_DNS_MODE_PROVIDER_HOSTNAME.equals(mode)) {
170 final String specifier = getStringSetting(cr, PRIVATE_DNS_SPECIFIER);
171 return new PrivateDnsConfig(specifier, null);
172 }
173
174 return new PrivateDnsConfig(useTls);
175 }
176
177 public static PrivateDnsConfig tryBlockingResolveOf(Network network, String name) {
Erik Klinea24d4592018-01-11 21:07:29 +0900178 try {
Erik Klinec43d2f52018-03-21 07:18:33 -0700179 final InetAddress[] ips = ResolvUtil.blockingResolveAllLocally(network, name);
180 return new PrivateDnsConfig(name, ips);
181 } catch (UnknownHostException uhe) {
182 return new PrivateDnsConfig(name, null);
183 }
Erik Klinea24d4592018-01-11 21:07:29 +0900184 }
185
186 public static Uri[] getPrivateDnsSettingsUris() {
Erik Klinec43d2f52018-03-21 07:18:33 -0700187 return new Uri[]{
Erik Kline19841792018-05-16 16:41:57 +0900188 Settings.Global.getUriFor(PRIVATE_DNS_DEFAULT_MODE),
Erik Klinec43d2f52018-03-21 07:18:33 -0700189 Settings.Global.getUriFor(PRIVATE_DNS_MODE),
190 Settings.Global.getUriFor(PRIVATE_DNS_SPECIFIER),
191 };
Erik Klinea24d4592018-01-11 21:07:29 +0900192 }
193
dalyk1fcb7392018-03-05 12:42:22 -0500194 public static class PrivateDnsValidationUpdate {
195 final public int netId;
196 final public InetAddress ipAddress;
197 final public String hostname;
198 final public boolean validated;
199
200 public PrivateDnsValidationUpdate(int netId, InetAddress ipAddress,
201 String hostname, boolean validated) {
202 this.netId = netId;
203 this.ipAddress = ipAddress;
204 this.hostname = hostname;
205 this.validated = validated;
206 }
207 }
208
209 private static class PrivateDnsValidationStatuses {
210 enum ValidationStatus {
211 IN_PROGRESS,
212 FAILED,
213 SUCCEEDED
214 }
215
216 // Validation statuses of <hostname, ipAddress> pairs for a single netId
Chalard Jeanf0f364f2018-04-11 18:58:52 +0900217 // Caution : not thread-safe. As mentioned in the top file comment, all
218 // methods of this class must only be called on ConnectivityService's thread.
dalyk1fcb7392018-03-05 12:42:22 -0500219 private Map<Pair<String, InetAddress>, ValidationStatus> mValidationMap;
220
221 private PrivateDnsValidationStatuses() {
222 mValidationMap = new HashMap<>();
223 }
224
225 private boolean hasValidatedServer() {
226 for (ValidationStatus status : mValidationMap.values()) {
227 if (status == ValidationStatus.SUCCEEDED) {
228 return true;
229 }
230 }
231 return false;
232 }
233
234 private void updateTrackedDnses(String[] ipAddresses, String hostname) {
235 Set<Pair<String, InetAddress>> latestDnses = new HashSet<>();
236 for (String ipAddress : ipAddresses) {
237 try {
238 latestDnses.add(new Pair(hostname,
239 InetAddress.parseNumericAddress(ipAddress)));
240 } catch (IllegalArgumentException e) {}
241 }
242 // Remove <hostname, ipAddress> pairs that should not be tracked.
243 for (Iterator<Map.Entry<Pair<String, InetAddress>, ValidationStatus>> it =
244 mValidationMap.entrySet().iterator(); it.hasNext(); ) {
245 Map.Entry<Pair<String, InetAddress>, ValidationStatus> entry = it.next();
246 if (!latestDnses.contains(entry.getKey())) {
247 it.remove();
248 }
249 }
250 // Add new <hostname, ipAddress> pairs that should be tracked.
251 for (Pair<String, InetAddress> p : latestDnses) {
252 if (!mValidationMap.containsKey(p)) {
253 mValidationMap.put(p, ValidationStatus.IN_PROGRESS);
254 }
255 }
256 }
257
258 private void updateStatus(PrivateDnsValidationUpdate update) {
259 Pair<String, InetAddress> p = new Pair(update.hostname,
260 update.ipAddress);
261 if (!mValidationMap.containsKey(p)) {
262 return;
263 }
264 if (update.validated) {
265 mValidationMap.put(p, ValidationStatus.SUCCEEDED);
266 } else {
267 mValidationMap.put(p, ValidationStatus.FAILED);
268 }
269 }
Chalard Jeanf0f364f2018-04-11 18:58:52 +0900270
271 private LinkProperties fillInValidatedPrivateDns(LinkProperties lp) {
272 lp.setValidatedPrivateDnsServers(Collections.EMPTY_LIST);
273 mValidationMap.forEach((key, value) -> {
274 if (value == ValidationStatus.SUCCEEDED) {
275 lp.addValidatedPrivateDnsServer(key.second);
276 }
277 });
278 return lp;
279 }
dalyk1fcb7392018-03-05 12:42:22 -0500280 }
281
Erik Kline1742fe12017-12-13 19:40:49 +0900282 private final Context mContext;
283 private final ContentResolver mContentResolver;
284 private final INetworkManagementService mNMS;
285 private final MockableSystemProperties mSystemProperties;
dalyk1fcb7392018-03-05 12:42:22 -0500286 // TODO: Replace these Maps with SparseArrays.
Erik Klinea24d4592018-01-11 21:07:29 +0900287 private final Map<Integer, PrivateDnsConfig> mPrivateDnsMap;
dalyk1fcb7392018-03-05 12:42:22 -0500288 private final Map<Integer, PrivateDnsValidationStatuses> mPrivateDnsValidationMap;
Erik Kline1742fe12017-12-13 19:40:49 +0900289
290 private int mNumDnsEntries;
291 private int mSampleValidity;
292 private int mSuccessThreshold;
293 private int mMinSamples;
294 private int mMaxSamples;
295 private String mPrivateDnsMode;
296 private String mPrivateDnsSpecifier;
297
298 public DnsManager(Context ctx, INetworkManagementService nms, MockableSystemProperties sp) {
299 mContext = ctx;
300 mContentResolver = mContext.getContentResolver();
301 mNMS = nms;
302 mSystemProperties = sp;
Erik Klinea24d4592018-01-11 21:07:29 +0900303 mPrivateDnsMap = new HashMap<>();
dalyk1fcb7392018-03-05 12:42:22 -0500304 mPrivateDnsValidationMap = new HashMap<>();
Erik Kline1742fe12017-12-13 19:40:49 +0900305
306 // TODO: Create and register ContentObservers to track every setting
307 // used herein, posting messages to respond to changes.
308 }
309
Erik Klinea24d4592018-01-11 21:07:29 +0900310 public PrivateDnsConfig getPrivateDnsConfig() {
311 return getPrivateDnsConfig(mContentResolver);
312 }
313
314 public void removeNetwork(Network network) {
315 mPrivateDnsMap.remove(network.netId);
dalyk1fcb7392018-03-05 12:42:22 -0500316 mPrivateDnsValidationMap.remove(network.netId);
Erik Klinea24d4592018-01-11 21:07:29 +0900317 }
318
319 public PrivateDnsConfig updatePrivateDns(Network network, PrivateDnsConfig cfg) {
320 Slog.w(TAG, "updatePrivateDns(" + network + ", " + cfg + ")");
321 return (cfg != null)
322 ? mPrivateDnsMap.put(network.netId, cfg)
Andreas Gampeba061332018-03-05 17:23:07 -0800323 : mPrivateDnsMap.remove(network.netId);
Erik Kline1742fe12017-12-13 19:40:49 +0900324 }
325
dalyk1fcb7392018-03-05 12:42:22 -0500326 public void updatePrivateDnsStatus(int netId, LinkProperties lp) {
327 // Use the PrivateDnsConfig data pushed to this class instance
328 // from ConnectivityService.
329 final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.getOrDefault(netId,
330 PRIVATE_DNS_OFF);
331
332 final boolean useTls = privateDnsCfg.useTls;
Chalard Jeanf0f364f2018-04-11 18:58:52 +0900333 final PrivateDnsValidationStatuses statuses =
334 useTls ? mPrivateDnsValidationMap.get(netId) : null;
335 final boolean validated = (null != statuses) && statuses.hasValidatedServer();
dalyk1fcb7392018-03-05 12:42:22 -0500336 final boolean strictMode = privateDnsCfg.inStrictMode();
Chalard Jeanf0f364f2018-04-11 18:58:52 +0900337 final String tlsHostname = strictMode ? privateDnsCfg.hostname : null;
338 final boolean usingPrivateDns = strictMode || validated;
dalyk1fcb7392018-03-05 12:42:22 -0500339
Chalard Jeanf0f364f2018-04-11 18:58:52 +0900340 lp.setUsePrivateDns(usingPrivateDns);
341 lp.setPrivateDnsServerName(tlsHostname);
342 if (usingPrivateDns && null != statuses) {
343 statuses.fillInValidatedPrivateDns(lp);
dalyk1fcb7392018-03-05 12:42:22 -0500344 } else {
Chalard Jeanf0f364f2018-04-11 18:58:52 +0900345 lp.setValidatedPrivateDnsServers(Collections.EMPTY_LIST);
dalyk1fcb7392018-03-05 12:42:22 -0500346 }
347 }
348
349 public void updatePrivateDnsValidation(PrivateDnsValidationUpdate update) {
350 final PrivateDnsValidationStatuses statuses =
351 mPrivateDnsValidationMap.get(update.netId);
352 if (statuses == null) return;
353 statuses.updateStatus(update);
354 }
355
Erik Kline1742fe12017-12-13 19:40:49 +0900356 public void setDnsConfigurationForNetwork(
Erik Klinea24d4592018-01-11 21:07:29 +0900357 int netId, LinkProperties lp, boolean isDefaultNetwork) {
Erik Kline117e7f32018-03-04 21:01:01 +0900358 final String[] assignedServers = NetworkUtils.makeStrings(lp.getDnsServers());
359 final String[] domainStrs = getDomainStrings(lp.getDomains());
360
361 updateParametersSettings();
362 final int[] params = { mSampleValidity, mSuccessThreshold, mMinSamples, mMaxSamples };
363
Erik Klinea24d4592018-01-11 21:07:29 +0900364 // We only use the PrivateDnsConfig data pushed to this class instance
365 // from ConnectivityService because it works in coordination with
366 // NetworkMonitor to decide which networks need validation and runs the
367 // blocking calls to resolve Private DNS strict mode hostnames.
368 //
Erik Klinec43d2f52018-03-21 07:18:33 -0700369 // At this time we do not attempt to enable Private DNS on non-Internet
Erik Klinea24d4592018-01-11 21:07:29 +0900370 // networks like IMS.
dalyk1fcb7392018-03-05 12:42:22 -0500371 final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.getOrDefault(netId,
372 PRIVATE_DNS_OFF);
Erik Kline1742fe12017-12-13 19:40:49 +0900373
dalyk1fcb7392018-03-05 12:42:22 -0500374 final boolean useTls = privateDnsCfg.useTls;
375 final boolean strictMode = privateDnsCfg.inStrictMode();
Erik Klinea24d4592018-01-11 21:07:29 +0900376 final String tlsHostname = strictMode ? privateDnsCfg.hostname : "";
Erik Kline117e7f32018-03-04 21:01:01 +0900377 final String[] tlsServers =
378 strictMode ? NetworkUtils.makeStrings(
379 Arrays.stream(privateDnsCfg.ips)
380 .filter((ip) -> lp.isReachable(ip))
381 .collect(Collectors.toList()))
382 : useTls ? assignedServers // Opportunistic
383 : new String[0]; // Off
Erik Klinea24d4592018-01-11 21:07:29 +0900384
dalyk1fcb7392018-03-05 12:42:22 -0500385 // Prepare to track the validation status of the DNS servers in the
386 // resolver config when private DNS is in opportunistic or strict mode.
387 if (useTls) {
388 if (!mPrivateDnsValidationMap.containsKey(netId)) {
389 mPrivateDnsValidationMap.put(netId, new PrivateDnsValidationStatuses());
390 }
391 mPrivateDnsValidationMap.get(netId).updateTrackedDnses(tlsServers, tlsHostname);
392 } else {
393 mPrivateDnsValidationMap.remove(netId);
394 }
395
Erik Klinea24d4592018-01-11 21:07:29 +0900396 Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %s, %s, %s)",
Erik Kline117e7f32018-03-04 21:01:01 +0900397 netId, Arrays.toString(assignedServers), Arrays.toString(domainStrs),
398 Arrays.toString(params), tlsHostname, Arrays.toString(tlsServers)));
Erik Kline1742fe12017-12-13 19:40:49 +0900399 try {
400 mNMS.setDnsConfigurationForNetwork(
Erik Kline117e7f32018-03-04 21:01:01 +0900401 netId, assignedServers, domainStrs, params, tlsHostname, tlsServers);
Erik Kline1742fe12017-12-13 19:40:49 +0900402 } catch (Exception e) {
403 Slog.e(TAG, "Error setting DNS configuration: " + e);
404 return;
405 }
406
407 // TODO: netd should listen on [::1]:53 and proxy queries to the current
408 // default network, and we should just set net.dns1 to ::1, not least
409 // because applications attempting to use net.dns resolvers will bypass
410 // the privacy protections of things like DNS-over-TLS.
Erik Klinea24d4592018-01-11 21:07:29 +0900411 if (isDefaultNetwork) setDefaultDnsSystemProperties(lp.getDnsServers());
Erik Kline1742fe12017-12-13 19:40:49 +0900412 flushVmDnsCache();
413 }
414
415 public void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) {
416 int last = 0;
417 for (InetAddress dns : dnses) {
418 ++last;
419 setNetDnsProperty(last, dns.getHostAddress());
420 }
421 for (int i = last + 1; i <= mNumDnsEntries; ++i) {
422 setNetDnsProperty(i, "");
423 }
424 mNumDnsEntries = last;
425 }
426
427 private void flushVmDnsCache() {
428 /*
429 * Tell the VMs to toss their DNS caches
430 */
431 final Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE);
432 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
433 /*
434 * Connectivity events can happen before boot has completed ...
435 */
436 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
437 final long ident = Binder.clearCallingIdentity();
438 try {
439 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
440 } finally {
441 Binder.restoreCallingIdentity(ident);
442 }
443 }
444
Erik Kline1742fe12017-12-13 19:40:49 +0900445 private void updateParametersSettings() {
446 mSampleValidity = getIntSetting(
447 DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
448 DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
449 if (mSampleValidity < 0 || mSampleValidity > 65535) {
450 Slog.w(TAG, "Invalid sampleValidity=" + mSampleValidity + ", using default=" +
451 DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
452 mSampleValidity = DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS;
453 }
454
455 mSuccessThreshold = getIntSetting(
456 DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
457 DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
458 if (mSuccessThreshold < 0 || mSuccessThreshold > 100) {
459 Slog.w(TAG, "Invalid successThreshold=" + mSuccessThreshold + ", using default=" +
460 DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
461 mSuccessThreshold = DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT;
462 }
463
464 mMinSamples = getIntSetting(DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
465 mMaxSamples = getIntSetting(DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
466 if (mMinSamples < 0 || mMinSamples > mMaxSamples || mMaxSamples > 64) {
467 Slog.w(TAG, "Invalid sample count (min, max)=(" + mMinSamples + ", " + mMaxSamples +
468 "), using default=(" + DNS_RESOLVER_DEFAULT_MIN_SAMPLES + ", " +
469 DNS_RESOLVER_DEFAULT_MAX_SAMPLES + ")");
470 mMinSamples = DNS_RESOLVER_DEFAULT_MIN_SAMPLES;
471 mMaxSamples = DNS_RESOLVER_DEFAULT_MAX_SAMPLES;
472 }
473 }
474
Erik Kline1742fe12017-12-13 19:40:49 +0900475 private int getIntSetting(String which, int dflt) {
476 return Settings.Global.getInt(mContentResolver, which, dflt);
477 }
478
479 private void setNetDnsProperty(int which, String value) {
480 final String key = "net.dns" + which;
481 // Log and forget errors setting unsupported properties.
482 try {
483 mSystemProperties.set(key, value);
484 } catch (Exception e) {
485 Slog.e(TAG, "Error setting unsupported net.dns property: ", e);
486 }
487 }
488
Erik Klinea24d4592018-01-11 21:07:29 +0900489 private static String getPrivateDnsMode(ContentResolver cr) {
Erik Kline19841792018-05-16 16:41:57 +0900490 String mode = getStringSetting(cr, PRIVATE_DNS_MODE);
491 if (TextUtils.isEmpty(mode)) mode = getStringSetting(cr, PRIVATE_DNS_DEFAULT_MODE);
492 if (TextUtils.isEmpty(mode)) mode = PRIVATE_DNS_DEFAULT_MODE_FALLBACK;
493 return mode;
Erik Klinea24d4592018-01-11 21:07:29 +0900494 }
495
496 private static String getStringSetting(ContentResolver cr, String which) {
497 return Settings.Global.getString(cr, which);
498 }
499
500 private static String[] getDomainStrings(String domains) {
501 return (TextUtils.isEmpty(domains)) ? new String[0] : domains.split(" ");
Erik Kline1742fe12017-12-13 19:40:49 +0900502 }
503}