blob: 7aaac06024e761602aeda0400061517bd3031dd5 [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;
Erik Klinea24d4592018-01-11 21:07:29 +090052import java.util.HashMap;
dalyk1fcb7392018-03-05 12:42:22 -050053import java.util.HashSet;
54import java.util.Iterator;
Erik Klinea24d4592018-01-11 21:07:29 +090055import java.util.Map;
dalyk1fcb7392018-03-05 12:42:22 -050056import java.util.Objects;
Erik Klinea24d4592018-01-11 21:07:29 +090057import java.util.stream.Collectors;
dalyk1fcb7392018-03-05 12:42:22 -050058import java.util.Set;
Erik Klinea24d4592018-01-11 21:07:29 +090059import java.util.StringJoiner;
Erik Kline1742fe12017-12-13 19:40:49 +090060
61
62/**
63 * Encapsulate the management of DNS settings for networks.
64 *
65 * This class it NOT designed for concurrent access. Furthermore, all non-static
66 * methods MUST be called from ConnectivityService's thread.
67 *
Erik Kline79c6d052018-03-21 07:18:33 -070068 * [ Private DNS ]
69 * The code handling Private DNS is spread across several components, but this
70 * seems like the least bad place to collect all the observations.
71 *
72 * Private DNS handling and updating occurs in response to several different
73 * events. Each is described here with its corresponding intended handling.
74 *
75 * [A] Event: A new network comes up.
76 * Mechanics:
77 * [1] ConnectivityService gets notifications from NetworkAgents.
78 * [2] in updateNetworkInfo(), the first time the NetworkAgent goes into
79 * into CONNECTED state, the Private DNS configuration is retrieved,
80 * programmed, and strict mode hostname resolution (if applicable) is
81 * enqueued in NetworkAgent's NetworkMonitor, via a call to
82 * handlePerNetworkPrivateDnsConfig().
83 * [3] Re-resolution of strict mode hostnames that fail to return any
84 * IP addresses happens inside NetworkMonitor; it sends itself a
85 * delayed CMD_EVALUATE_PRIVATE_DNS message in a simple backoff
86 * schedule.
87 * [4] Successfully resolved hostnames are sent to ConnectivityService
88 * inside an EVENT_PRIVATE_DNS_CONFIG_RESOLVED message. The resolved
89 * IP addresses are programmed into netd via:
90 *
91 * updatePrivateDns() -> updateDnses()
92 *
93 * both of which make calls into DnsManager.
94 * [5] Upon a successful hostname resolution NetworkMonitor initiates a
95 * validation attempt in the form of a lookup for a one-time hostname
96 * that uses Private DNS.
97 *
98 * [B] Event: Private DNS settings are changed.
99 * Mechanics:
100 * [1] ConnectivityService gets notifications from its SettingsObserver.
101 * [2] handlePrivateDnsSettingsChanged() is called, which calls
102 * handlePerNetworkPrivateDnsConfig() and the process proceeds
103 * as if from A.3 above.
104 *
105 * [C] Event: An application calls ConnectivityManager#reportBadNetwork().
106 * Mechanics:
107 * [1] NetworkMonitor is notified and initiates a reevaluation, which
108 * always bypasses Private DNS.
109 * [2] Once completed, NetworkMonitor checks if strict mode is in operation
110 * and if so enqueues another evaluation of Private DNS, as if from
111 * step A.5 above.
112 *
Erik Kline1742fe12017-12-13 19:40:49 +0900113 * @hide
114 */
115public class DnsManager {
116 private static final String TAG = DnsManager.class.getSimpleName();
dalyk1fcb7392018-03-05 12:42:22 -0500117 private static final PrivateDnsConfig PRIVATE_DNS_OFF = new PrivateDnsConfig();
Erik Kline1742fe12017-12-13 19:40:49 +0900118
119 /* Defaults for resolver parameters. */
120 private static final int DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800;
121 private static final int DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT = 25;
122 private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
123 private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
124
Erik Klinea24d4592018-01-11 21:07:29 +0900125 public static class PrivateDnsConfig {
126 public final boolean useTls;
127 public final String hostname;
128 public final InetAddress[] ips;
129
130 public PrivateDnsConfig() {
131 this(false);
132 }
133
134 public PrivateDnsConfig(boolean useTls) {
135 this.useTls = useTls;
136 this.hostname = "";
137 this.ips = new InetAddress[0];
138 }
139
140 public PrivateDnsConfig(String hostname, InetAddress[] ips) {
141 this.useTls = !TextUtils.isEmpty(hostname);
142 this.hostname = useTls ? hostname : "";
143 this.ips = (ips != null) ? ips : new InetAddress[0];
144 }
145
146 public PrivateDnsConfig(PrivateDnsConfig cfg) {
147 useTls = cfg.useTls;
148 hostname = cfg.hostname;
149 ips = cfg.ips;
150 }
151
152 public boolean inStrictMode() {
153 return useTls && !TextUtils.isEmpty(hostname);
154 }
155
156 public String toString() {
157 return PrivateDnsConfig.class.getSimpleName() +
158 "{" + useTls + ":" + hostname + "/" + Arrays.toString(ips) + "}";
159 }
160 }
161
162 public static PrivateDnsConfig getPrivateDnsConfig(ContentResolver cr) {
163 final String mode = getPrivateDnsMode(cr);
164
165 final boolean useTls = !TextUtils.isEmpty(mode) && !PRIVATE_DNS_MODE_OFF.equals(mode);
166
167 if (PRIVATE_DNS_MODE_PROVIDER_HOSTNAME.equals(mode)) {
168 final String specifier = getStringSetting(cr, PRIVATE_DNS_SPECIFIER);
169 return new PrivateDnsConfig(specifier, null);
170 }
171
172 return new PrivateDnsConfig(useTls);
173 }
174
175 public static PrivateDnsConfig tryBlockingResolveOf(Network network, String name) {
Erik Klinea24d4592018-01-11 21:07:29 +0900176 try {
Erik Klinec43d2f52018-03-21 07:18:33 -0700177 final InetAddress[] ips = ResolvUtil.blockingResolveAllLocally(network, name);
178 return new PrivateDnsConfig(name, ips);
179 } catch (UnknownHostException uhe) {
180 return new PrivateDnsConfig(name, null);
181 }
Erik Klinea24d4592018-01-11 21:07:29 +0900182 }
183
184 public static Uri[] getPrivateDnsSettingsUris() {
Erik Klinec43d2f52018-03-21 07:18:33 -0700185 return new Uri[]{
186 Settings.Global.getUriFor(PRIVATE_DNS_MODE),
187 Settings.Global.getUriFor(PRIVATE_DNS_SPECIFIER),
188 };
Erik Klinea24d4592018-01-11 21:07:29 +0900189 }
190
dalyk1fcb7392018-03-05 12:42:22 -0500191 public static class PrivateDnsValidationUpdate {
192 final public int netId;
193 final public InetAddress ipAddress;
194 final public String hostname;
195 final public boolean validated;
196
197 public PrivateDnsValidationUpdate(int netId, InetAddress ipAddress,
198 String hostname, boolean validated) {
199 this.netId = netId;
200 this.ipAddress = ipAddress;
201 this.hostname = hostname;
202 this.validated = validated;
203 }
204 }
205
206 private static class PrivateDnsValidationStatuses {
207 enum ValidationStatus {
208 IN_PROGRESS,
209 FAILED,
210 SUCCEEDED
211 }
212
213 // Validation statuses of <hostname, ipAddress> pairs for a single netId
214 private Map<Pair<String, InetAddress>, ValidationStatus> mValidationMap;
215
216 private PrivateDnsValidationStatuses() {
217 mValidationMap = new HashMap<>();
218 }
219
220 private boolean hasValidatedServer() {
221 for (ValidationStatus status : mValidationMap.values()) {
222 if (status == ValidationStatus.SUCCEEDED) {
223 return true;
224 }
225 }
226 return false;
227 }
228
229 private void updateTrackedDnses(String[] ipAddresses, String hostname) {
230 Set<Pair<String, InetAddress>> latestDnses = new HashSet<>();
231 for (String ipAddress : ipAddresses) {
232 try {
233 latestDnses.add(new Pair(hostname,
234 InetAddress.parseNumericAddress(ipAddress)));
235 } catch (IllegalArgumentException e) {}
236 }
237 // Remove <hostname, ipAddress> pairs that should not be tracked.
238 for (Iterator<Map.Entry<Pair<String, InetAddress>, ValidationStatus>> it =
239 mValidationMap.entrySet().iterator(); it.hasNext(); ) {
240 Map.Entry<Pair<String, InetAddress>, ValidationStatus> entry = it.next();
241 if (!latestDnses.contains(entry.getKey())) {
242 it.remove();
243 }
244 }
245 // Add new <hostname, ipAddress> pairs that should be tracked.
246 for (Pair<String, InetAddress> p : latestDnses) {
247 if (!mValidationMap.containsKey(p)) {
248 mValidationMap.put(p, ValidationStatus.IN_PROGRESS);
249 }
250 }
251 }
252
253 private void updateStatus(PrivateDnsValidationUpdate update) {
254 Pair<String, InetAddress> p = new Pair(update.hostname,
255 update.ipAddress);
256 if (!mValidationMap.containsKey(p)) {
257 return;
258 }
259 if (update.validated) {
260 mValidationMap.put(p, ValidationStatus.SUCCEEDED);
261 } else {
262 mValidationMap.put(p, ValidationStatus.FAILED);
263 }
264 }
265 }
266
Erik Kline1742fe12017-12-13 19:40:49 +0900267 private final Context mContext;
268 private final ContentResolver mContentResolver;
269 private final INetworkManagementService mNMS;
270 private final MockableSystemProperties mSystemProperties;
dalyk1fcb7392018-03-05 12:42:22 -0500271 // TODO: Replace these Maps with SparseArrays.
Erik Klinea24d4592018-01-11 21:07:29 +0900272 private final Map<Integer, PrivateDnsConfig> mPrivateDnsMap;
dalyk1fcb7392018-03-05 12:42:22 -0500273 private final Map<Integer, PrivateDnsValidationStatuses> mPrivateDnsValidationMap;
Erik Kline1742fe12017-12-13 19:40:49 +0900274
275 private int mNumDnsEntries;
276 private int mSampleValidity;
277 private int mSuccessThreshold;
278 private int mMinSamples;
279 private int mMaxSamples;
280 private String mPrivateDnsMode;
281 private String mPrivateDnsSpecifier;
282
283 public DnsManager(Context ctx, INetworkManagementService nms, MockableSystemProperties sp) {
284 mContext = ctx;
285 mContentResolver = mContext.getContentResolver();
286 mNMS = nms;
287 mSystemProperties = sp;
Erik Klinea24d4592018-01-11 21:07:29 +0900288 mPrivateDnsMap = new HashMap<>();
dalyk1fcb7392018-03-05 12:42:22 -0500289 mPrivateDnsValidationMap = new HashMap<>();
Erik Kline1742fe12017-12-13 19:40:49 +0900290
291 // TODO: Create and register ContentObservers to track every setting
292 // used herein, posting messages to respond to changes.
293 }
294
Erik Klinea24d4592018-01-11 21:07:29 +0900295 public PrivateDnsConfig getPrivateDnsConfig() {
296 return getPrivateDnsConfig(mContentResolver);
297 }
298
299 public void removeNetwork(Network network) {
300 mPrivateDnsMap.remove(network.netId);
dalyk1fcb7392018-03-05 12:42:22 -0500301 mPrivateDnsValidationMap.remove(network.netId);
Erik Klinea24d4592018-01-11 21:07:29 +0900302 }
303
304 public PrivateDnsConfig updatePrivateDns(Network network, PrivateDnsConfig cfg) {
305 Slog.w(TAG, "updatePrivateDns(" + network + ", " + cfg + ")");
306 return (cfg != null)
307 ? mPrivateDnsMap.put(network.netId, cfg)
Andreas Gampeba061332018-03-05 17:23:07 -0800308 : mPrivateDnsMap.remove(network.netId);
Erik Kline1742fe12017-12-13 19:40:49 +0900309 }
310
dalyk1fcb7392018-03-05 12:42:22 -0500311 public void updatePrivateDnsStatus(int netId, LinkProperties lp) {
312 // Use the PrivateDnsConfig data pushed to this class instance
313 // from ConnectivityService.
314 final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.getOrDefault(netId,
315 PRIVATE_DNS_OFF);
316
317 final boolean useTls = privateDnsCfg.useTls;
318 final boolean strictMode = privateDnsCfg.inStrictMode();
319 final String tlsHostname = strictMode ? privateDnsCfg.hostname : "";
320
321 if (strictMode) {
322 lp.setUsePrivateDns(true);
323 lp.setPrivateDnsServerName(tlsHostname);
324 } else if (useTls) {
325 // We are in opportunistic mode. Private DNS should be used if there
326 // is a known DNS-over-TLS validated server.
327 boolean validated = mPrivateDnsValidationMap.containsKey(netId) &&
328 mPrivateDnsValidationMap.get(netId).hasValidatedServer();
329 lp.setUsePrivateDns(validated);
330 lp.setPrivateDnsServerName(null);
331 } else {
332 // Private DNS is disabled.
333 lp.setUsePrivateDns(false);
334 lp.setPrivateDnsServerName(null);
335 }
336 }
337
338 public void updatePrivateDnsValidation(PrivateDnsValidationUpdate update) {
339 final PrivateDnsValidationStatuses statuses =
340 mPrivateDnsValidationMap.get(update.netId);
341 if (statuses == null) return;
342 statuses.updateStatus(update);
343 }
344
Erik Kline1742fe12017-12-13 19:40:49 +0900345 public void setDnsConfigurationForNetwork(
Erik Klinea24d4592018-01-11 21:07:29 +0900346 int netId, LinkProperties lp, boolean isDefaultNetwork) {
Erik Kline117e7f32018-03-04 21:01:01 +0900347 final String[] assignedServers = NetworkUtils.makeStrings(lp.getDnsServers());
348 final String[] domainStrs = getDomainStrings(lp.getDomains());
349
350 updateParametersSettings();
351 final int[] params = { mSampleValidity, mSuccessThreshold, mMinSamples, mMaxSamples };
352
Erik Klinea24d4592018-01-11 21:07:29 +0900353 // We only use the PrivateDnsConfig data pushed to this class instance
354 // from ConnectivityService because it works in coordination with
355 // NetworkMonitor to decide which networks need validation and runs the
356 // blocking calls to resolve Private DNS strict mode hostnames.
357 //
Erik Klinec43d2f52018-03-21 07:18:33 -0700358 // At this time we do not attempt to enable Private DNS on non-Internet
Erik Klinea24d4592018-01-11 21:07:29 +0900359 // networks like IMS.
dalyk1fcb7392018-03-05 12:42:22 -0500360 final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.getOrDefault(netId,
361 PRIVATE_DNS_OFF);
Erik Kline1742fe12017-12-13 19:40:49 +0900362
dalyk1fcb7392018-03-05 12:42:22 -0500363 final boolean useTls = privateDnsCfg.useTls;
364 final boolean strictMode = privateDnsCfg.inStrictMode();
Erik Klinea24d4592018-01-11 21:07:29 +0900365 final String tlsHostname = strictMode ? privateDnsCfg.hostname : "";
Erik Kline117e7f32018-03-04 21:01:01 +0900366 final String[] tlsServers =
367 strictMode ? NetworkUtils.makeStrings(
368 Arrays.stream(privateDnsCfg.ips)
369 .filter((ip) -> lp.isReachable(ip))
370 .collect(Collectors.toList()))
371 : useTls ? assignedServers // Opportunistic
372 : new String[0]; // Off
Erik Klinea24d4592018-01-11 21:07:29 +0900373
dalyk1fcb7392018-03-05 12:42:22 -0500374 // Prepare to track the validation status of the DNS servers in the
375 // resolver config when private DNS is in opportunistic or strict mode.
376 if (useTls) {
377 if (!mPrivateDnsValidationMap.containsKey(netId)) {
378 mPrivateDnsValidationMap.put(netId, new PrivateDnsValidationStatuses());
379 }
380 mPrivateDnsValidationMap.get(netId).updateTrackedDnses(tlsServers, tlsHostname);
381 } else {
382 mPrivateDnsValidationMap.remove(netId);
383 }
384
Erik Klinea24d4592018-01-11 21:07:29 +0900385 Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %s, %s, %s)",
Erik Kline117e7f32018-03-04 21:01:01 +0900386 netId, Arrays.toString(assignedServers), Arrays.toString(domainStrs),
387 Arrays.toString(params), tlsHostname, Arrays.toString(tlsServers)));
Erik Kline1742fe12017-12-13 19:40:49 +0900388 try {
389 mNMS.setDnsConfigurationForNetwork(
Erik Kline117e7f32018-03-04 21:01:01 +0900390 netId, assignedServers, domainStrs, params, tlsHostname, tlsServers);
Erik Kline1742fe12017-12-13 19:40:49 +0900391 } catch (Exception e) {
392 Slog.e(TAG, "Error setting DNS configuration: " + e);
393 return;
394 }
395
396 // TODO: netd should listen on [::1]:53 and proxy queries to the current
397 // default network, and we should just set net.dns1 to ::1, not least
398 // because applications attempting to use net.dns resolvers will bypass
399 // the privacy protections of things like DNS-over-TLS.
Erik Klinea24d4592018-01-11 21:07:29 +0900400 if (isDefaultNetwork) setDefaultDnsSystemProperties(lp.getDnsServers());
Erik Kline1742fe12017-12-13 19:40:49 +0900401 flushVmDnsCache();
402 }
403
404 public void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) {
405 int last = 0;
406 for (InetAddress dns : dnses) {
407 ++last;
408 setNetDnsProperty(last, dns.getHostAddress());
409 }
410 for (int i = last + 1; i <= mNumDnsEntries; ++i) {
411 setNetDnsProperty(i, "");
412 }
413 mNumDnsEntries = last;
414 }
415
416 private void flushVmDnsCache() {
417 /*
418 * Tell the VMs to toss their DNS caches
419 */
420 final Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE);
421 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
422 /*
423 * Connectivity events can happen before boot has completed ...
424 */
425 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
426 final long ident = Binder.clearCallingIdentity();
427 try {
428 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
429 } finally {
430 Binder.restoreCallingIdentity(ident);
431 }
432 }
433
Erik Kline1742fe12017-12-13 19:40:49 +0900434 private void updateParametersSettings() {
435 mSampleValidity = getIntSetting(
436 DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
437 DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
438 if (mSampleValidity < 0 || mSampleValidity > 65535) {
439 Slog.w(TAG, "Invalid sampleValidity=" + mSampleValidity + ", using default=" +
440 DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
441 mSampleValidity = DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS;
442 }
443
444 mSuccessThreshold = getIntSetting(
445 DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
446 DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
447 if (mSuccessThreshold < 0 || mSuccessThreshold > 100) {
448 Slog.w(TAG, "Invalid successThreshold=" + mSuccessThreshold + ", using default=" +
449 DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
450 mSuccessThreshold = DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT;
451 }
452
453 mMinSamples = getIntSetting(DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
454 mMaxSamples = getIntSetting(DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
455 if (mMinSamples < 0 || mMinSamples > mMaxSamples || mMaxSamples > 64) {
456 Slog.w(TAG, "Invalid sample count (min, max)=(" + mMinSamples + ", " + mMaxSamples +
457 "), using default=(" + DNS_RESOLVER_DEFAULT_MIN_SAMPLES + ", " +
458 DNS_RESOLVER_DEFAULT_MAX_SAMPLES + ")");
459 mMinSamples = DNS_RESOLVER_DEFAULT_MIN_SAMPLES;
460 mMaxSamples = DNS_RESOLVER_DEFAULT_MAX_SAMPLES;
461 }
462 }
463
Erik Kline1742fe12017-12-13 19:40:49 +0900464 private int getIntSetting(String which, int dflt) {
465 return Settings.Global.getInt(mContentResolver, which, dflt);
466 }
467
468 private void setNetDnsProperty(int which, String value) {
469 final String key = "net.dns" + which;
470 // Log and forget errors setting unsupported properties.
471 try {
472 mSystemProperties.set(key, value);
473 } catch (Exception e) {
474 Slog.e(TAG, "Error setting unsupported net.dns property: ", e);
475 }
476 }
477
Erik Klinea24d4592018-01-11 21:07:29 +0900478 private static String getPrivateDnsMode(ContentResolver cr) {
479 final String mode = getStringSetting(cr, PRIVATE_DNS_MODE);
480 return !TextUtils.isEmpty(mode) ? mode : PRIVATE_DNS_DEFAULT_MODE;
481 }
482
483 private static String getStringSetting(ContentResolver cr, String which) {
484 return Settings.Global.getString(cr, which);
485 }
486
487 private static String[] getDomainStrings(String domains) {
488 return (TextUtils.isEmpty(domains)) ? new String[0] : domains.split(" ");
Erik Kline1742fe12017-12-13 19:40:49 +0900489 }
490}