blob: d8bb635f2ce8a7e00edf2feacce42a7c9130baab [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_PROVIDER_HOSTNAME;
Erik Kline1742fe12017-12-13 19:40:49 +090022import static android.provider.Settings.Global.DNS_RESOLVER_MAX_SAMPLES;
Remi NGUYEN VANe67b0c32018-12-27 16:43:56 +090023import static android.provider.Settings.Global.DNS_RESOLVER_MIN_SAMPLES;
Erik Kline1742fe12017-12-13 19:40:49 +090024import static android.provider.Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS;
25import static android.provider.Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT;
Erik Kline19841792018-05-16 16:41:57 +090026import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE;
Erik Kline1742fe12017-12-13 19:40:49 +090027import 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;
Remi NGUYEN VANe67b0c32018-12-27 16:43:56 +090037import android.net.shared.PrivateDnsConfig;
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
Erik Kline1742fe12017-12-13 19:40:49 +090046import java.net.InetAddress;
Erik Klinea24d4592018-01-11 21:07:29 +090047import java.util.Arrays;
Erik Kline1742fe12017-12-13 19:40:49 +090048import java.util.Collection;
Chalard Jeanf0f364f2018-04-11 18:58:52 +090049import java.util.Collections;
Erik Klinea24d4592018-01-11 21:07:29 +090050import java.util.HashMap;
dalyk1fcb7392018-03-05 12:42:22 -050051import java.util.HashSet;
52import java.util.Iterator;
Erik Klinea24d4592018-01-11 21:07:29 +090053import java.util.Map;
dalyk1fcb7392018-03-05 12:42:22 -050054import java.util.Set;
Remi NGUYEN VANe67b0c32018-12-27 16:43:56 +090055import java.util.stream.Collectors;
Erik Kline1742fe12017-12-13 19:40:49 +090056
57
58/**
59 * Encapsulate the management of DNS settings for networks.
60 *
61 * This class it NOT designed for concurrent access. Furthermore, all non-static
62 * methods MUST be called from ConnectivityService's thread.
63 *
Erik Kline79c6d052018-03-21 07:18:33 -070064 * [ Private DNS ]
65 * The code handling Private DNS is spread across several components, but this
66 * seems like the least bad place to collect all the observations.
67 *
68 * Private DNS handling and updating occurs in response to several different
69 * events. Each is described here with its corresponding intended handling.
70 *
71 * [A] Event: A new network comes up.
72 * Mechanics:
73 * [1] ConnectivityService gets notifications from NetworkAgents.
74 * [2] in updateNetworkInfo(), the first time the NetworkAgent goes into
75 * into CONNECTED state, the Private DNS configuration is retrieved,
76 * programmed, and strict mode hostname resolution (if applicable) is
77 * enqueued in NetworkAgent's NetworkMonitor, via a call to
78 * handlePerNetworkPrivateDnsConfig().
79 * [3] Re-resolution of strict mode hostnames that fail to return any
80 * IP addresses happens inside NetworkMonitor; it sends itself a
81 * delayed CMD_EVALUATE_PRIVATE_DNS message in a simple backoff
82 * schedule.
83 * [4] Successfully resolved hostnames are sent to ConnectivityService
84 * inside an EVENT_PRIVATE_DNS_CONFIG_RESOLVED message. The resolved
85 * IP addresses are programmed into netd via:
86 *
87 * updatePrivateDns() -> updateDnses()
88 *
89 * both of which make calls into DnsManager.
90 * [5] Upon a successful hostname resolution NetworkMonitor initiates a
91 * validation attempt in the form of a lookup for a one-time hostname
92 * that uses Private DNS.
93 *
94 * [B] Event: Private DNS settings are changed.
95 * Mechanics:
96 * [1] ConnectivityService gets notifications from its SettingsObserver.
97 * [2] handlePrivateDnsSettingsChanged() is called, which calls
98 * handlePerNetworkPrivateDnsConfig() and the process proceeds
99 * as if from A.3 above.
100 *
101 * [C] Event: An application calls ConnectivityManager#reportBadNetwork().
102 * Mechanics:
103 * [1] NetworkMonitor is notified and initiates a reevaluation, which
104 * always bypasses Private DNS.
105 * [2] Once completed, NetworkMonitor checks if strict mode is in operation
106 * and if so enqueues another evaluation of Private DNS, as if from
107 * step A.5 above.
108 *
Erik Kline1742fe12017-12-13 19:40:49 +0900109 * @hide
110 */
111public class DnsManager {
112 private static final String TAG = DnsManager.class.getSimpleName();
dalyk1fcb7392018-03-05 12:42:22 -0500113 private static final PrivateDnsConfig PRIVATE_DNS_OFF = new PrivateDnsConfig();
Erik Kline1742fe12017-12-13 19:40:49 +0900114
115 /* Defaults for resolver parameters. */
116 private static final int DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800;
117 private static final int DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT = 25;
118 private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
119 private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
120
Erik Klinea24d4592018-01-11 21:07:29 +0900121 public static PrivateDnsConfig getPrivateDnsConfig(ContentResolver cr) {
122 final String mode = getPrivateDnsMode(cr);
123
124 final boolean useTls = !TextUtils.isEmpty(mode) && !PRIVATE_DNS_MODE_OFF.equals(mode);
125
126 if (PRIVATE_DNS_MODE_PROVIDER_HOSTNAME.equals(mode)) {
127 final String specifier = getStringSetting(cr, PRIVATE_DNS_SPECIFIER);
128 return new PrivateDnsConfig(specifier, null);
129 }
130
131 return new PrivateDnsConfig(useTls);
132 }
133
Erik Klinea24d4592018-01-11 21:07:29 +0900134 public static Uri[] getPrivateDnsSettingsUris() {
Erik Klinec43d2f52018-03-21 07:18:33 -0700135 return new Uri[]{
Erik Kline19841792018-05-16 16:41:57 +0900136 Settings.Global.getUriFor(PRIVATE_DNS_DEFAULT_MODE),
Erik Klinec43d2f52018-03-21 07:18:33 -0700137 Settings.Global.getUriFor(PRIVATE_DNS_MODE),
138 Settings.Global.getUriFor(PRIVATE_DNS_SPECIFIER),
139 };
Erik Klinea24d4592018-01-11 21:07:29 +0900140 }
141
dalyk1fcb7392018-03-05 12:42:22 -0500142 public static class PrivateDnsValidationUpdate {
143 final public int netId;
144 final public InetAddress ipAddress;
145 final public String hostname;
146 final public boolean validated;
147
148 public PrivateDnsValidationUpdate(int netId, InetAddress ipAddress,
149 String hostname, boolean validated) {
150 this.netId = netId;
151 this.ipAddress = ipAddress;
152 this.hostname = hostname;
153 this.validated = validated;
154 }
155 }
156
157 private static class PrivateDnsValidationStatuses {
158 enum ValidationStatus {
159 IN_PROGRESS,
160 FAILED,
161 SUCCEEDED
162 }
163
164 // Validation statuses of <hostname, ipAddress> pairs for a single netId
Chalard Jeanf0f364f2018-04-11 18:58:52 +0900165 // Caution : not thread-safe. As mentioned in the top file comment, all
166 // methods of this class must only be called on ConnectivityService's thread.
dalyk1fcb7392018-03-05 12:42:22 -0500167 private Map<Pair<String, InetAddress>, ValidationStatus> mValidationMap;
168
169 private PrivateDnsValidationStatuses() {
170 mValidationMap = new HashMap<>();
171 }
172
173 private boolean hasValidatedServer() {
174 for (ValidationStatus status : mValidationMap.values()) {
175 if (status == ValidationStatus.SUCCEEDED) {
176 return true;
177 }
178 }
179 return false;
180 }
181
182 private void updateTrackedDnses(String[] ipAddresses, String hostname) {
183 Set<Pair<String, InetAddress>> latestDnses = new HashSet<>();
184 for (String ipAddress : ipAddresses) {
185 try {
186 latestDnses.add(new Pair(hostname,
187 InetAddress.parseNumericAddress(ipAddress)));
188 } catch (IllegalArgumentException e) {}
189 }
190 // Remove <hostname, ipAddress> pairs that should not be tracked.
191 for (Iterator<Map.Entry<Pair<String, InetAddress>, ValidationStatus>> it =
192 mValidationMap.entrySet().iterator(); it.hasNext(); ) {
193 Map.Entry<Pair<String, InetAddress>, ValidationStatus> entry = it.next();
194 if (!latestDnses.contains(entry.getKey())) {
195 it.remove();
196 }
197 }
198 // Add new <hostname, ipAddress> pairs that should be tracked.
199 for (Pair<String, InetAddress> p : latestDnses) {
200 if (!mValidationMap.containsKey(p)) {
201 mValidationMap.put(p, ValidationStatus.IN_PROGRESS);
202 }
203 }
204 }
205
206 private void updateStatus(PrivateDnsValidationUpdate update) {
207 Pair<String, InetAddress> p = new Pair(update.hostname,
208 update.ipAddress);
209 if (!mValidationMap.containsKey(p)) {
210 return;
211 }
212 if (update.validated) {
213 mValidationMap.put(p, ValidationStatus.SUCCEEDED);
214 } else {
215 mValidationMap.put(p, ValidationStatus.FAILED);
216 }
217 }
Chalard Jeanf0f364f2018-04-11 18:58:52 +0900218
219 private LinkProperties fillInValidatedPrivateDns(LinkProperties lp) {
220 lp.setValidatedPrivateDnsServers(Collections.EMPTY_LIST);
221 mValidationMap.forEach((key, value) -> {
222 if (value == ValidationStatus.SUCCEEDED) {
223 lp.addValidatedPrivateDnsServer(key.second);
224 }
225 });
226 return lp;
227 }
dalyk1fcb7392018-03-05 12:42:22 -0500228 }
229
Erik Kline1742fe12017-12-13 19:40:49 +0900230 private final Context mContext;
231 private final ContentResolver mContentResolver;
232 private final INetworkManagementService mNMS;
233 private final MockableSystemProperties mSystemProperties;
dalyk1fcb7392018-03-05 12:42:22 -0500234 // TODO: Replace these Maps with SparseArrays.
Erik Klinea24d4592018-01-11 21:07:29 +0900235 private final Map<Integer, PrivateDnsConfig> mPrivateDnsMap;
dalyk1fcb7392018-03-05 12:42:22 -0500236 private final Map<Integer, PrivateDnsValidationStatuses> mPrivateDnsValidationMap;
Erik Kline1742fe12017-12-13 19:40:49 +0900237
238 private int mNumDnsEntries;
239 private int mSampleValidity;
240 private int mSuccessThreshold;
241 private int mMinSamples;
242 private int mMaxSamples;
243 private String mPrivateDnsMode;
244 private String mPrivateDnsSpecifier;
245
246 public DnsManager(Context ctx, INetworkManagementService nms, MockableSystemProperties sp) {
247 mContext = ctx;
248 mContentResolver = mContext.getContentResolver();
249 mNMS = nms;
250 mSystemProperties = sp;
Erik Klinea24d4592018-01-11 21:07:29 +0900251 mPrivateDnsMap = new HashMap<>();
dalyk1fcb7392018-03-05 12:42:22 -0500252 mPrivateDnsValidationMap = new HashMap<>();
Erik Kline1742fe12017-12-13 19:40:49 +0900253
254 // TODO: Create and register ContentObservers to track every setting
255 // used herein, posting messages to respond to changes.
256 }
257
Erik Klinea24d4592018-01-11 21:07:29 +0900258 public PrivateDnsConfig getPrivateDnsConfig() {
259 return getPrivateDnsConfig(mContentResolver);
260 }
261
262 public void removeNetwork(Network network) {
263 mPrivateDnsMap.remove(network.netId);
dalyk1fcb7392018-03-05 12:42:22 -0500264 mPrivateDnsValidationMap.remove(network.netId);
Erik Klinea24d4592018-01-11 21:07:29 +0900265 }
266
267 public PrivateDnsConfig updatePrivateDns(Network network, PrivateDnsConfig cfg) {
268 Slog.w(TAG, "updatePrivateDns(" + network + ", " + cfg + ")");
269 return (cfg != null)
270 ? mPrivateDnsMap.put(network.netId, cfg)
Andreas Gampeba061332018-03-05 17:23:07 -0800271 : mPrivateDnsMap.remove(network.netId);
Erik Kline1742fe12017-12-13 19:40:49 +0900272 }
273
dalyk1fcb7392018-03-05 12:42:22 -0500274 public void updatePrivateDnsStatus(int netId, LinkProperties lp) {
275 // Use the PrivateDnsConfig data pushed to this class instance
276 // from ConnectivityService.
277 final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.getOrDefault(netId,
278 PRIVATE_DNS_OFF);
279
280 final boolean useTls = privateDnsCfg.useTls;
Chalard Jeanf0f364f2018-04-11 18:58:52 +0900281 final PrivateDnsValidationStatuses statuses =
282 useTls ? mPrivateDnsValidationMap.get(netId) : null;
283 final boolean validated = (null != statuses) && statuses.hasValidatedServer();
dalyk1fcb7392018-03-05 12:42:22 -0500284 final boolean strictMode = privateDnsCfg.inStrictMode();
Chalard Jeanf0f364f2018-04-11 18:58:52 +0900285 final String tlsHostname = strictMode ? privateDnsCfg.hostname : null;
286 final boolean usingPrivateDns = strictMode || validated;
dalyk1fcb7392018-03-05 12:42:22 -0500287
Chalard Jeanf0f364f2018-04-11 18:58:52 +0900288 lp.setUsePrivateDns(usingPrivateDns);
289 lp.setPrivateDnsServerName(tlsHostname);
290 if (usingPrivateDns && null != statuses) {
291 statuses.fillInValidatedPrivateDns(lp);
dalyk1fcb7392018-03-05 12:42:22 -0500292 } else {
Chalard Jeanf0f364f2018-04-11 18:58:52 +0900293 lp.setValidatedPrivateDnsServers(Collections.EMPTY_LIST);
dalyk1fcb7392018-03-05 12:42:22 -0500294 }
295 }
296
297 public void updatePrivateDnsValidation(PrivateDnsValidationUpdate update) {
298 final PrivateDnsValidationStatuses statuses =
299 mPrivateDnsValidationMap.get(update.netId);
300 if (statuses == null) return;
301 statuses.updateStatus(update);
302 }
303
Erik Kline1742fe12017-12-13 19:40:49 +0900304 public void setDnsConfigurationForNetwork(
Erik Klinea24d4592018-01-11 21:07:29 +0900305 int netId, LinkProperties lp, boolean isDefaultNetwork) {
Erik Kline117e7f32018-03-04 21:01:01 +0900306 final String[] assignedServers = NetworkUtils.makeStrings(lp.getDnsServers());
307 final String[] domainStrs = getDomainStrings(lp.getDomains());
308
309 updateParametersSettings();
310 final int[] params = { mSampleValidity, mSuccessThreshold, mMinSamples, mMaxSamples };
311
Erik Klinea24d4592018-01-11 21:07:29 +0900312 // We only use the PrivateDnsConfig data pushed to this class instance
313 // from ConnectivityService because it works in coordination with
314 // NetworkMonitor to decide which networks need validation and runs the
315 // blocking calls to resolve Private DNS strict mode hostnames.
316 //
Erik Klinec43d2f52018-03-21 07:18:33 -0700317 // At this time we do not attempt to enable Private DNS on non-Internet
Erik Klinea24d4592018-01-11 21:07:29 +0900318 // networks like IMS.
dalyk1fcb7392018-03-05 12:42:22 -0500319 final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.getOrDefault(netId,
320 PRIVATE_DNS_OFF);
Erik Kline1742fe12017-12-13 19:40:49 +0900321
dalyk1fcb7392018-03-05 12:42:22 -0500322 final boolean useTls = privateDnsCfg.useTls;
323 final boolean strictMode = privateDnsCfg.inStrictMode();
Erik Klinea24d4592018-01-11 21:07:29 +0900324 final String tlsHostname = strictMode ? privateDnsCfg.hostname : "";
Erik Kline117e7f32018-03-04 21:01:01 +0900325 final String[] tlsServers =
326 strictMode ? NetworkUtils.makeStrings(
327 Arrays.stream(privateDnsCfg.ips)
328 .filter((ip) -> lp.isReachable(ip))
329 .collect(Collectors.toList()))
330 : useTls ? assignedServers // Opportunistic
331 : new String[0]; // Off
Erik Klinea24d4592018-01-11 21:07:29 +0900332
dalyk1fcb7392018-03-05 12:42:22 -0500333 // Prepare to track the validation status of the DNS servers in the
334 // resolver config when private DNS is in opportunistic or strict mode.
335 if (useTls) {
336 if (!mPrivateDnsValidationMap.containsKey(netId)) {
337 mPrivateDnsValidationMap.put(netId, new PrivateDnsValidationStatuses());
338 }
339 mPrivateDnsValidationMap.get(netId).updateTrackedDnses(tlsServers, tlsHostname);
340 } else {
341 mPrivateDnsValidationMap.remove(netId);
342 }
343
Erik Klinea24d4592018-01-11 21:07:29 +0900344 Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %s, %s, %s)",
Erik Kline117e7f32018-03-04 21:01:01 +0900345 netId, Arrays.toString(assignedServers), Arrays.toString(domainStrs),
346 Arrays.toString(params), tlsHostname, Arrays.toString(tlsServers)));
Erik Kline1742fe12017-12-13 19:40:49 +0900347 try {
348 mNMS.setDnsConfigurationForNetwork(
Erik Kline117e7f32018-03-04 21:01:01 +0900349 netId, assignedServers, domainStrs, params, tlsHostname, tlsServers);
Erik Kline1742fe12017-12-13 19:40:49 +0900350 } catch (Exception e) {
351 Slog.e(TAG, "Error setting DNS configuration: " + e);
352 return;
353 }
354
355 // TODO: netd should listen on [::1]:53 and proxy queries to the current
356 // default network, and we should just set net.dns1 to ::1, not least
357 // because applications attempting to use net.dns resolvers will bypass
358 // the privacy protections of things like DNS-over-TLS.
Erik Klinea24d4592018-01-11 21:07:29 +0900359 if (isDefaultNetwork) setDefaultDnsSystemProperties(lp.getDnsServers());
Erik Kline1742fe12017-12-13 19:40:49 +0900360 flushVmDnsCache();
361 }
362
363 public void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) {
364 int last = 0;
365 for (InetAddress dns : dnses) {
366 ++last;
367 setNetDnsProperty(last, dns.getHostAddress());
368 }
369 for (int i = last + 1; i <= mNumDnsEntries; ++i) {
370 setNetDnsProperty(i, "");
371 }
372 mNumDnsEntries = last;
373 }
374
375 private void flushVmDnsCache() {
376 /*
377 * Tell the VMs to toss their DNS caches
378 */
379 final Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE);
380 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
381 /*
382 * Connectivity events can happen before boot has completed ...
383 */
384 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
385 final long ident = Binder.clearCallingIdentity();
386 try {
387 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
388 } finally {
389 Binder.restoreCallingIdentity(ident);
390 }
391 }
392
Erik Kline1742fe12017-12-13 19:40:49 +0900393 private void updateParametersSettings() {
394 mSampleValidity = getIntSetting(
395 DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
396 DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
397 if (mSampleValidity < 0 || mSampleValidity > 65535) {
398 Slog.w(TAG, "Invalid sampleValidity=" + mSampleValidity + ", using default=" +
399 DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
400 mSampleValidity = DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS;
401 }
402
403 mSuccessThreshold = getIntSetting(
404 DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
405 DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
406 if (mSuccessThreshold < 0 || mSuccessThreshold > 100) {
407 Slog.w(TAG, "Invalid successThreshold=" + mSuccessThreshold + ", using default=" +
408 DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
409 mSuccessThreshold = DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT;
410 }
411
412 mMinSamples = getIntSetting(DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
413 mMaxSamples = getIntSetting(DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
414 if (mMinSamples < 0 || mMinSamples > mMaxSamples || mMaxSamples > 64) {
415 Slog.w(TAG, "Invalid sample count (min, max)=(" + mMinSamples + ", " + mMaxSamples +
416 "), using default=(" + DNS_RESOLVER_DEFAULT_MIN_SAMPLES + ", " +
417 DNS_RESOLVER_DEFAULT_MAX_SAMPLES + ")");
418 mMinSamples = DNS_RESOLVER_DEFAULT_MIN_SAMPLES;
419 mMaxSamples = DNS_RESOLVER_DEFAULT_MAX_SAMPLES;
420 }
421 }
422
Erik Kline1742fe12017-12-13 19:40:49 +0900423 private int getIntSetting(String which, int dflt) {
424 return Settings.Global.getInt(mContentResolver, which, dflt);
425 }
426
427 private void setNetDnsProperty(int which, String value) {
428 final String key = "net.dns" + which;
429 // Log and forget errors setting unsupported properties.
430 try {
431 mSystemProperties.set(key, value);
432 } catch (Exception e) {
433 Slog.e(TAG, "Error setting unsupported net.dns property: ", e);
434 }
435 }
436
Erik Klinea24d4592018-01-11 21:07:29 +0900437 private static String getPrivateDnsMode(ContentResolver cr) {
Erik Kline19841792018-05-16 16:41:57 +0900438 String mode = getStringSetting(cr, PRIVATE_DNS_MODE);
439 if (TextUtils.isEmpty(mode)) mode = getStringSetting(cr, PRIVATE_DNS_DEFAULT_MODE);
440 if (TextUtils.isEmpty(mode)) mode = PRIVATE_DNS_DEFAULT_MODE_FALLBACK;
441 return mode;
Erik Klinea24d4592018-01-11 21:07:29 +0900442 }
443
444 private static String getStringSetting(ContentResolver cr, String which) {
445 return Settings.Global.getString(cr, which);
446 }
447
448 private static String[] getDomainStrings(String domains) {
449 return (TextUtils.isEmpty(domains)) ? new String[0] : domains.split(" ");
Erik Kline1742fe12017-12-13 19:40:49 +0900450 }
451}