blob: d51a196b76ab90c57fc80fe24fb453df3228ac87 [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
19import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE;
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;
27import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
28import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
29
30import android.content.ContentResolver;
31import android.content.Context;
32import android.content.Intent;
Erik Klinea24d4592018-01-11 21:07:29 +090033import android.net.LinkProperties;
34import android.net.Network;
Erik Kline1742fe12017-12-13 19:40:49 +090035import android.net.NetworkUtils;
Erik Klinea24d4592018-01-11 21:07:29 +090036import android.net.Uri;
Erik Klinec43d2f52018-03-21 07:18:33 -070037import android.net.dns.ResolvUtil;
Erik Kline1742fe12017-12-13 19:40:49 +090038import android.os.Binder;
39import android.os.INetworkManagementService;
Erik Kline1742fe12017-12-13 19:40:49 +090040import android.os.UserHandle;
41import android.provider.Settings;
42import android.text.TextUtils;
dalyk1fcb7392018-03-05 12:42:22 -050043import android.util.Pair;
Erik Kline1742fe12017-12-13 19:40:49 +090044import android.util.Slog;
45
46import com.android.server.connectivity.MockableSystemProperties;
47
48import java.net.InetAddress;
Erik Klinec43d2f52018-03-21 07:18:33 -070049import java.net.UnknownHostException;
Erik Klinea24d4592018-01-11 21:07:29 +090050import java.util.Arrays;
Erik Kline1742fe12017-12-13 19:40:49 +090051import java.util.Collection;
Chalard Jeanf0f364f2018-04-11 18:58:52 +090052import java.util.Collections;
Erik Klinea24d4592018-01-11 21:07:29 +090053import java.util.HashMap;
dalyk1fcb7392018-03-05 12:42:22 -050054import java.util.HashSet;
55import java.util.Iterator;
Erik Klinea24d4592018-01-11 21:07:29 +090056import java.util.Map;
dalyk1fcb7392018-03-05 12:42:22 -050057import java.util.Objects;
Erik Klinea24d4592018-01-11 21:07:29 +090058import java.util.stream.Collectors;
dalyk1fcb7392018-03-05 12:42:22 -050059import java.util.Set;
Erik Klinea24d4592018-01-11 21:07:29 +090060import java.util.StringJoiner;
Erik Kline1742fe12017-12-13 19:40:49 +090061
62
63/**
64 * Encapsulate the management of DNS settings for networks.
65 *
66 * This class it NOT designed for concurrent access. Furthermore, all non-static
67 * methods MUST be called from ConnectivityService's thread.
68 *
Erik Kline79c6d052018-03-21 07:18:33 -070069 * [ Private DNS ]
70 * The code handling Private DNS is spread across several components, but this
71 * seems like the least bad place to collect all the observations.
72 *
73 * Private DNS handling and updating occurs in response to several different
74 * events. Each is described here with its corresponding intended handling.
75 *
76 * [A] Event: A new network comes up.
77 * Mechanics:
78 * [1] ConnectivityService gets notifications from NetworkAgents.
79 * [2] in updateNetworkInfo(), the first time the NetworkAgent goes into
80 * into CONNECTED state, the Private DNS configuration is retrieved,
81 * programmed, and strict mode hostname resolution (if applicable) is
82 * enqueued in NetworkAgent's NetworkMonitor, via a call to
83 * handlePerNetworkPrivateDnsConfig().
84 * [3] Re-resolution of strict mode hostnames that fail to return any
85 * IP addresses happens inside NetworkMonitor; it sends itself a
86 * delayed CMD_EVALUATE_PRIVATE_DNS message in a simple backoff
87 * schedule.
88 * [4] Successfully resolved hostnames are sent to ConnectivityService
89 * inside an EVENT_PRIVATE_DNS_CONFIG_RESOLVED message. The resolved
90 * IP addresses are programmed into netd via:
91 *
92 * updatePrivateDns() -> updateDnses()
93 *
94 * both of which make calls into DnsManager.
95 * [5] Upon a successful hostname resolution NetworkMonitor initiates a
96 * validation attempt in the form of a lookup for a one-time hostname
97 * that uses Private DNS.
98 *
99 * [B] Event: Private DNS settings are changed.
100 * Mechanics:
101 * [1] ConnectivityService gets notifications from its SettingsObserver.
102 * [2] handlePrivateDnsSettingsChanged() is called, which calls
103 * handlePerNetworkPrivateDnsConfig() and the process proceeds
104 * as if from A.3 above.
105 *
106 * [C] Event: An application calls ConnectivityManager#reportBadNetwork().
107 * Mechanics:
108 * [1] NetworkMonitor is notified and initiates a reevaluation, which
109 * always bypasses Private DNS.
110 * [2] Once completed, NetworkMonitor checks if strict mode is in operation
111 * and if so enqueues another evaluation of Private DNS, as if from
112 * step A.5 above.
113 *
Erik Kline1742fe12017-12-13 19:40:49 +0900114 * @hide
115 */
116public class DnsManager {
117 private static final String TAG = DnsManager.class.getSimpleName();
dalyk1fcb7392018-03-05 12:42:22 -0500118 private static final PrivateDnsConfig PRIVATE_DNS_OFF = new PrivateDnsConfig();
Erik Kline1742fe12017-12-13 19:40:49 +0900119
120 /* Defaults for resolver parameters. */
121 private static final int DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800;
122 private static final int DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT = 25;
123 private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
124 private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
125
Erik Klinea24d4592018-01-11 21:07:29 +0900126 public static class PrivateDnsConfig {
127 public final boolean useTls;
128 public final String hostname;
129 public final InetAddress[] ips;
130
131 public PrivateDnsConfig() {
132 this(false);
133 }
134
135 public PrivateDnsConfig(boolean useTls) {
136 this.useTls = useTls;
137 this.hostname = "";
138 this.ips = new InetAddress[0];
139 }
140
141 public PrivateDnsConfig(String hostname, InetAddress[] ips) {
142 this.useTls = !TextUtils.isEmpty(hostname);
143 this.hostname = useTls ? hostname : "";
144 this.ips = (ips != null) ? ips : new InetAddress[0];
145 }
146
147 public PrivateDnsConfig(PrivateDnsConfig cfg) {
148 useTls = cfg.useTls;
149 hostname = cfg.hostname;
150 ips = cfg.ips;
151 }
152
153 public boolean inStrictMode() {
154 return useTls && !TextUtils.isEmpty(hostname);
155 }
156
157 public String toString() {
158 return PrivateDnsConfig.class.getSimpleName() +
159 "{" + useTls + ":" + hostname + "/" + Arrays.toString(ips) + "}";
160 }
161 }
162
163 public static PrivateDnsConfig getPrivateDnsConfig(ContentResolver cr) {
164 final String mode = getPrivateDnsMode(cr);
165
166 final boolean useTls = !TextUtils.isEmpty(mode) && !PRIVATE_DNS_MODE_OFF.equals(mode);
167
168 if (PRIVATE_DNS_MODE_PROVIDER_HOSTNAME.equals(mode)) {
169 final String specifier = getStringSetting(cr, PRIVATE_DNS_SPECIFIER);
170 return new PrivateDnsConfig(specifier, null);
171 }
172
173 return new PrivateDnsConfig(useTls);
174 }
175
176 public static PrivateDnsConfig tryBlockingResolveOf(Network network, String name) {
Erik Klinea24d4592018-01-11 21:07:29 +0900177 try {
Erik Klinec43d2f52018-03-21 07:18:33 -0700178 final InetAddress[] ips = ResolvUtil.blockingResolveAllLocally(network, name);
179 return new PrivateDnsConfig(name, ips);
180 } catch (UnknownHostException uhe) {
181 return new PrivateDnsConfig(name, null);
182 }
Erik Klinea24d4592018-01-11 21:07:29 +0900183 }
184
185 public static Uri[] getPrivateDnsSettingsUris() {
Erik Klinec43d2f52018-03-21 07:18:33 -0700186 return new Uri[]{
187 Settings.Global.getUriFor(PRIVATE_DNS_MODE),
188 Settings.Global.getUriFor(PRIVATE_DNS_SPECIFIER),
189 };
Erik Klinea24d4592018-01-11 21:07:29 +0900190 }
191
dalyk1fcb7392018-03-05 12:42:22 -0500192 public static class PrivateDnsValidationUpdate {
193 final public int netId;
194 final public InetAddress ipAddress;
195 final public String hostname;
196 final public boolean validated;
197
198 public PrivateDnsValidationUpdate(int netId, InetAddress ipAddress,
199 String hostname, boolean validated) {
200 this.netId = netId;
201 this.ipAddress = ipAddress;
202 this.hostname = hostname;
203 this.validated = validated;
204 }
205 }
206
207 private static class PrivateDnsValidationStatuses {
208 enum ValidationStatus {
209 IN_PROGRESS,
210 FAILED,
211 SUCCEEDED
212 }
213
214 // Validation statuses of <hostname, ipAddress> pairs for a single netId
Chalard Jeanf0f364f2018-04-11 18:58:52 +0900215 // Caution : not thread-safe. As mentioned in the top file comment, all
216 // methods of this class must only be called on ConnectivityService's thread.
dalyk1fcb7392018-03-05 12:42:22 -0500217 private Map<Pair<String, InetAddress>, ValidationStatus> mValidationMap;
218
219 private PrivateDnsValidationStatuses() {
220 mValidationMap = new HashMap<>();
221 }
222
223 private boolean hasValidatedServer() {
224 for (ValidationStatus status : mValidationMap.values()) {
225 if (status == ValidationStatus.SUCCEEDED) {
226 return true;
227 }
228 }
229 return false;
230 }
231
232 private void updateTrackedDnses(String[] ipAddresses, String hostname) {
233 Set<Pair<String, InetAddress>> latestDnses = new HashSet<>();
234 for (String ipAddress : ipAddresses) {
235 try {
236 latestDnses.add(new Pair(hostname,
237 InetAddress.parseNumericAddress(ipAddress)));
238 } catch (IllegalArgumentException e) {}
239 }
240 // Remove <hostname, ipAddress> pairs that should not be tracked.
241 for (Iterator<Map.Entry<Pair<String, InetAddress>, ValidationStatus>> it =
242 mValidationMap.entrySet().iterator(); it.hasNext(); ) {
243 Map.Entry<Pair<String, InetAddress>, ValidationStatus> entry = it.next();
244 if (!latestDnses.contains(entry.getKey())) {
245 it.remove();
246 }
247 }
248 // Add new <hostname, ipAddress> pairs that should be tracked.
249 for (Pair<String, InetAddress> p : latestDnses) {
250 if (!mValidationMap.containsKey(p)) {
251 mValidationMap.put(p, ValidationStatus.IN_PROGRESS);
252 }
253 }
254 }
255
256 private void updateStatus(PrivateDnsValidationUpdate update) {
257 Pair<String, InetAddress> p = new Pair(update.hostname,
258 update.ipAddress);
259 if (!mValidationMap.containsKey(p)) {
260 return;
261 }
262 if (update.validated) {
263 mValidationMap.put(p, ValidationStatus.SUCCEEDED);
264 } else {
265 mValidationMap.put(p, ValidationStatus.FAILED);
266 }
267 }
Chalard Jeanf0f364f2018-04-11 18:58:52 +0900268
269 private LinkProperties fillInValidatedPrivateDns(LinkProperties lp) {
270 lp.setValidatedPrivateDnsServers(Collections.EMPTY_LIST);
271 mValidationMap.forEach((key, value) -> {
272 if (value == ValidationStatus.SUCCEEDED) {
273 lp.addValidatedPrivateDnsServer(key.second);
274 }
275 });
276 return lp;
277 }
dalyk1fcb7392018-03-05 12:42:22 -0500278 }
279
Erik Kline1742fe12017-12-13 19:40:49 +0900280 private final Context mContext;
281 private final ContentResolver mContentResolver;
282 private final INetworkManagementService mNMS;
283 private final MockableSystemProperties mSystemProperties;
dalyk1fcb7392018-03-05 12:42:22 -0500284 // TODO: Replace these Maps with SparseArrays.
Erik Klinea24d4592018-01-11 21:07:29 +0900285 private final Map<Integer, PrivateDnsConfig> mPrivateDnsMap;
dalyk1fcb7392018-03-05 12:42:22 -0500286 private final Map<Integer, PrivateDnsValidationStatuses> mPrivateDnsValidationMap;
Erik Kline1742fe12017-12-13 19:40:49 +0900287
288 private int mNumDnsEntries;
289 private int mSampleValidity;
290 private int mSuccessThreshold;
291 private int mMinSamples;
292 private int mMaxSamples;
293 private String mPrivateDnsMode;
294 private String mPrivateDnsSpecifier;
295
296 public DnsManager(Context ctx, INetworkManagementService nms, MockableSystemProperties sp) {
297 mContext = ctx;
298 mContentResolver = mContext.getContentResolver();
299 mNMS = nms;
300 mSystemProperties = sp;
Erik Klinea24d4592018-01-11 21:07:29 +0900301 mPrivateDnsMap = new HashMap<>();
dalyk1fcb7392018-03-05 12:42:22 -0500302 mPrivateDnsValidationMap = new HashMap<>();
Erik Kline1742fe12017-12-13 19:40:49 +0900303
304 // TODO: Create and register ContentObservers to track every setting
305 // used herein, posting messages to respond to changes.
306 }
307
Erik Klinea24d4592018-01-11 21:07:29 +0900308 public PrivateDnsConfig getPrivateDnsConfig() {
309 return getPrivateDnsConfig(mContentResolver);
310 }
311
312 public void removeNetwork(Network network) {
313 mPrivateDnsMap.remove(network.netId);
dalyk1fcb7392018-03-05 12:42:22 -0500314 mPrivateDnsValidationMap.remove(network.netId);
Erik Klinea24d4592018-01-11 21:07:29 +0900315 }
316
317 public PrivateDnsConfig updatePrivateDns(Network network, PrivateDnsConfig cfg) {
318 Slog.w(TAG, "updatePrivateDns(" + network + ", " + cfg + ")");
319 return (cfg != null)
320 ? mPrivateDnsMap.put(network.netId, cfg)
Andreas Gampeba061332018-03-05 17:23:07 -0800321 : mPrivateDnsMap.remove(network.netId);
Erik Kline1742fe12017-12-13 19:40:49 +0900322 }
323
dalyk1fcb7392018-03-05 12:42:22 -0500324 public void updatePrivateDnsStatus(int netId, LinkProperties lp) {
325 // Use the PrivateDnsConfig data pushed to this class instance
326 // from ConnectivityService.
327 final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.getOrDefault(netId,
328 PRIVATE_DNS_OFF);
329
330 final boolean useTls = privateDnsCfg.useTls;
Chalard Jeanf0f364f2018-04-11 18:58:52 +0900331 final PrivateDnsValidationStatuses statuses =
332 useTls ? mPrivateDnsValidationMap.get(netId) : null;
333 final boolean validated = (null != statuses) && statuses.hasValidatedServer();
dalyk1fcb7392018-03-05 12:42:22 -0500334 final boolean strictMode = privateDnsCfg.inStrictMode();
Chalard Jeanf0f364f2018-04-11 18:58:52 +0900335 final String tlsHostname = strictMode ? privateDnsCfg.hostname : null;
336 final boolean usingPrivateDns = strictMode || validated;
dalyk1fcb7392018-03-05 12:42:22 -0500337
Chalard Jeanf0f364f2018-04-11 18:58:52 +0900338 lp.setUsePrivateDns(usingPrivateDns);
339 lp.setPrivateDnsServerName(tlsHostname);
340 if (usingPrivateDns && null != statuses) {
341 statuses.fillInValidatedPrivateDns(lp);
dalyk1fcb7392018-03-05 12:42:22 -0500342 } else {
Chalard Jeanf0f364f2018-04-11 18:58:52 +0900343 lp.setValidatedPrivateDnsServers(Collections.EMPTY_LIST);
dalyk1fcb7392018-03-05 12:42:22 -0500344 }
345 }
346
347 public void updatePrivateDnsValidation(PrivateDnsValidationUpdate update) {
348 final PrivateDnsValidationStatuses statuses =
349 mPrivateDnsValidationMap.get(update.netId);
350 if (statuses == null) return;
351 statuses.updateStatus(update);
352 }
353
Erik Kline1742fe12017-12-13 19:40:49 +0900354 public void setDnsConfigurationForNetwork(
Erik Klinea24d4592018-01-11 21:07:29 +0900355 int netId, LinkProperties lp, boolean isDefaultNetwork) {
Erik Kline117e7f32018-03-04 21:01:01 +0900356 final String[] assignedServers = NetworkUtils.makeStrings(lp.getDnsServers());
357 final String[] domainStrs = getDomainStrings(lp.getDomains());
358
359 updateParametersSettings();
360 final int[] params = { mSampleValidity, mSuccessThreshold, mMinSamples, mMaxSamples };
361
Erik Klinea24d4592018-01-11 21:07:29 +0900362 // We only use the PrivateDnsConfig data pushed to this class instance
363 // from ConnectivityService because it works in coordination with
364 // NetworkMonitor to decide which networks need validation and runs the
365 // blocking calls to resolve Private DNS strict mode hostnames.
366 //
Erik Klinec43d2f52018-03-21 07:18:33 -0700367 // At this time we do not attempt to enable Private DNS on non-Internet
Erik Klinea24d4592018-01-11 21:07:29 +0900368 // networks like IMS.
dalyk1fcb7392018-03-05 12:42:22 -0500369 final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.getOrDefault(netId,
370 PRIVATE_DNS_OFF);
Erik Kline1742fe12017-12-13 19:40:49 +0900371
dalyk1fcb7392018-03-05 12:42:22 -0500372 final boolean useTls = privateDnsCfg.useTls;
373 final boolean strictMode = privateDnsCfg.inStrictMode();
Erik Klinea24d4592018-01-11 21:07:29 +0900374 final String tlsHostname = strictMode ? privateDnsCfg.hostname : "";
Erik Kline117e7f32018-03-04 21:01:01 +0900375 final String[] tlsServers =
376 strictMode ? NetworkUtils.makeStrings(
377 Arrays.stream(privateDnsCfg.ips)
378 .filter((ip) -> lp.isReachable(ip))
379 .collect(Collectors.toList()))
380 : useTls ? assignedServers // Opportunistic
381 : new String[0]; // Off
Erik Klinea24d4592018-01-11 21:07:29 +0900382
dalyk1fcb7392018-03-05 12:42:22 -0500383 // Prepare to track the validation status of the DNS servers in the
384 // resolver config when private DNS is in opportunistic or strict mode.
385 if (useTls) {
386 if (!mPrivateDnsValidationMap.containsKey(netId)) {
387 mPrivateDnsValidationMap.put(netId, new PrivateDnsValidationStatuses());
388 }
389 mPrivateDnsValidationMap.get(netId).updateTrackedDnses(tlsServers, tlsHostname);
390 } else {
391 mPrivateDnsValidationMap.remove(netId);
392 }
393
Erik Klinea24d4592018-01-11 21:07:29 +0900394 Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %s, %s, %s)",
Erik Kline117e7f32018-03-04 21:01:01 +0900395 netId, Arrays.toString(assignedServers), Arrays.toString(domainStrs),
396 Arrays.toString(params), tlsHostname, Arrays.toString(tlsServers)));
Erik Kline1742fe12017-12-13 19:40:49 +0900397 try {
398 mNMS.setDnsConfigurationForNetwork(
Erik Kline117e7f32018-03-04 21:01:01 +0900399 netId, assignedServers, domainStrs, params, tlsHostname, tlsServers);
Erik Kline1742fe12017-12-13 19:40:49 +0900400 } catch (Exception e) {
401 Slog.e(TAG, "Error setting DNS configuration: " + e);
402 return;
403 }
404
405 // TODO: netd should listen on [::1]:53 and proxy queries to the current
406 // default network, and we should just set net.dns1 to ::1, not least
407 // because applications attempting to use net.dns resolvers will bypass
408 // the privacy protections of things like DNS-over-TLS.
Erik Klinea24d4592018-01-11 21:07:29 +0900409 if (isDefaultNetwork) setDefaultDnsSystemProperties(lp.getDnsServers());
Erik Kline1742fe12017-12-13 19:40:49 +0900410 flushVmDnsCache();
411 }
412
413 public void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) {
414 int last = 0;
415 for (InetAddress dns : dnses) {
416 ++last;
417 setNetDnsProperty(last, dns.getHostAddress());
418 }
419 for (int i = last + 1; i <= mNumDnsEntries; ++i) {
420 setNetDnsProperty(i, "");
421 }
422 mNumDnsEntries = last;
423 }
424
425 private void flushVmDnsCache() {
426 /*
427 * Tell the VMs to toss their DNS caches
428 */
429 final Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE);
430 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
431 /*
432 * Connectivity events can happen before boot has completed ...
433 */
434 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
435 final long ident = Binder.clearCallingIdentity();
436 try {
437 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
438 } finally {
439 Binder.restoreCallingIdentity(ident);
440 }
441 }
442
Erik Kline1742fe12017-12-13 19:40:49 +0900443 private void updateParametersSettings() {
444 mSampleValidity = getIntSetting(
445 DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
446 DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
447 if (mSampleValidity < 0 || mSampleValidity > 65535) {
448 Slog.w(TAG, "Invalid sampleValidity=" + mSampleValidity + ", using default=" +
449 DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
450 mSampleValidity = DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS;
451 }
452
453 mSuccessThreshold = getIntSetting(
454 DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
455 DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
456 if (mSuccessThreshold < 0 || mSuccessThreshold > 100) {
457 Slog.w(TAG, "Invalid successThreshold=" + mSuccessThreshold + ", using default=" +
458 DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
459 mSuccessThreshold = DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT;
460 }
461
462 mMinSamples = getIntSetting(DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
463 mMaxSamples = getIntSetting(DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
464 if (mMinSamples < 0 || mMinSamples > mMaxSamples || mMaxSamples > 64) {
465 Slog.w(TAG, "Invalid sample count (min, max)=(" + mMinSamples + ", " + mMaxSamples +
466 "), using default=(" + DNS_RESOLVER_DEFAULT_MIN_SAMPLES + ", " +
467 DNS_RESOLVER_DEFAULT_MAX_SAMPLES + ")");
468 mMinSamples = DNS_RESOLVER_DEFAULT_MIN_SAMPLES;
469 mMaxSamples = DNS_RESOLVER_DEFAULT_MAX_SAMPLES;
470 }
471 }
472
Erik Kline1742fe12017-12-13 19:40:49 +0900473 private int getIntSetting(String which, int dflt) {
474 return Settings.Global.getInt(mContentResolver, which, dflt);
475 }
476
477 private void setNetDnsProperty(int which, String value) {
478 final String key = "net.dns" + which;
479 // Log and forget errors setting unsupported properties.
480 try {
481 mSystemProperties.set(key, value);
482 } catch (Exception e) {
483 Slog.e(TAG, "Error setting unsupported net.dns property: ", e);
484 }
485 }
486
Erik Klinea24d4592018-01-11 21:07:29 +0900487 private static String getPrivateDnsMode(ContentResolver cr) {
488 final String mode = getStringSetting(cr, PRIVATE_DNS_MODE);
489 return !TextUtils.isEmpty(mode) ? mode : PRIVATE_DNS_DEFAULT_MODE;
490 }
491
492 private static String getStringSetting(ContentResolver cr, String which) {
493 return Settings.Global.getString(cr, which);
494 }
495
496 private static String[] getDomainStrings(String domains) {
497 return (TextUtils.isEmpty(domains)) ? new String[0] : domains.split(" ");
Erik Kline1742fe12017-12-13 19:40:49 +0900498 }
499}