blob: a1c54bd4885b094c00decebdec6debd6ad4531d5 [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 Kline1742fe12017-12-13 19:40:49 +090037import android.os.Binder;
38import android.os.INetworkManagementService;
39import android.os.Handler;
40import android.os.UserHandle;
41import android.provider.Settings;
Erik Klinea24d4592018-01-11 21:07:29 +090042import android.system.GaiException;
43import android.system.OsConstants;
44import android.system.StructAddrinfo;
Erik Kline1742fe12017-12-13 19:40:49 +090045import android.text.TextUtils;
46import android.util.Slog;
47
48import com.android.server.connectivity.MockableSystemProperties;
49
Erik Klinea24d4592018-01-11 21:07:29 +090050import libcore.io.Libcore;
51
Erik Kline1742fe12017-12-13 19:40:49 +090052import java.net.InetAddress;
Erik Klinea24d4592018-01-11 21:07:29 +090053import java.util.Arrays;
Erik Kline1742fe12017-12-13 19:40:49 +090054import java.util.Collection;
Erik Klinea24d4592018-01-11 21:07:29 +090055import java.util.HashMap;
56import java.util.Map;
57import java.util.stream.Collectors;
58import java.util.StringJoiner;
Erik Kline1742fe12017-12-13 19:40:49 +090059
60
61/**
62 * Encapsulate the management of DNS settings for networks.
63 *
64 * This class it NOT designed for concurrent access. Furthermore, all non-static
65 * methods MUST be called from ConnectivityService's thread.
66 *
67 * @hide
68 */
69public class DnsManager {
70 private static final String TAG = DnsManager.class.getSimpleName();
71
72 /* Defaults for resolver parameters. */
73 private static final int DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800;
74 private static final int DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT = 25;
75 private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
76 private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
77
Erik Klinea24d4592018-01-11 21:07:29 +090078 public static class PrivateDnsConfig {
79 public final boolean useTls;
80 public final String hostname;
81 public final InetAddress[] ips;
82
83 public PrivateDnsConfig() {
84 this(false);
85 }
86
87 public PrivateDnsConfig(boolean useTls) {
88 this.useTls = useTls;
89 this.hostname = "";
90 this.ips = new InetAddress[0];
91 }
92
93 public PrivateDnsConfig(String hostname, InetAddress[] ips) {
94 this.useTls = !TextUtils.isEmpty(hostname);
95 this.hostname = useTls ? hostname : "";
96 this.ips = (ips != null) ? ips : new InetAddress[0];
97 }
98
99 public PrivateDnsConfig(PrivateDnsConfig cfg) {
100 useTls = cfg.useTls;
101 hostname = cfg.hostname;
102 ips = cfg.ips;
103 }
104
105 public boolean inStrictMode() {
106 return useTls && !TextUtils.isEmpty(hostname);
107 }
108
109 public String toString() {
110 return PrivateDnsConfig.class.getSimpleName() +
111 "{" + useTls + ":" + hostname + "/" + Arrays.toString(ips) + "}";
112 }
113 }
114
115 public static PrivateDnsConfig getPrivateDnsConfig(ContentResolver cr) {
116 final String mode = getPrivateDnsMode(cr);
117
118 final boolean useTls = !TextUtils.isEmpty(mode) && !PRIVATE_DNS_MODE_OFF.equals(mode);
119
120 if (PRIVATE_DNS_MODE_PROVIDER_HOSTNAME.equals(mode)) {
121 final String specifier = getStringSetting(cr, PRIVATE_DNS_SPECIFIER);
122 return new PrivateDnsConfig(specifier, null);
123 }
124
125 return new PrivateDnsConfig(useTls);
126 }
127
128 public static PrivateDnsConfig tryBlockingResolveOf(Network network, String name) {
129 final StructAddrinfo hints = new StructAddrinfo();
130 // Unnecessary, but expressly no AI_ADDRCONFIG.
131 hints.ai_flags = 0;
132 // Fetch all IP addresses at once to minimize re-resolution.
133 hints.ai_family = OsConstants.AF_UNSPEC;
134 hints.ai_socktype = OsConstants.SOCK_DGRAM;
135
136 try {
137 final InetAddress[] ips = Libcore.os.android_getaddrinfo(name, hints, network.netId);
138 if (ips != null && ips.length > 0) {
139 return new PrivateDnsConfig(name, ips);
140 }
141 } catch (GaiException ignored) {}
142
143 return null;
144 }
145
146 public static Uri[] getPrivateDnsSettingsUris() {
147 final Uri[] uris = new Uri[2];
148 uris[0] = Settings.Global.getUriFor(PRIVATE_DNS_MODE);
149 uris[1] = Settings.Global.getUriFor(PRIVATE_DNS_SPECIFIER);
150 return uris;
151 }
152
Erik Kline1742fe12017-12-13 19:40:49 +0900153 private final Context mContext;
154 private final ContentResolver mContentResolver;
155 private final INetworkManagementService mNMS;
156 private final MockableSystemProperties mSystemProperties;
Erik Klinea24d4592018-01-11 21:07:29 +0900157 private final Map<Integer, PrivateDnsConfig> mPrivateDnsMap;
Erik Kline1742fe12017-12-13 19:40:49 +0900158
159 private int mNumDnsEntries;
160 private int mSampleValidity;
161 private int mSuccessThreshold;
162 private int mMinSamples;
163 private int mMaxSamples;
164 private String mPrivateDnsMode;
165 private String mPrivateDnsSpecifier;
166
167 public DnsManager(Context ctx, INetworkManagementService nms, MockableSystemProperties sp) {
168 mContext = ctx;
169 mContentResolver = mContext.getContentResolver();
170 mNMS = nms;
171 mSystemProperties = sp;
Erik Klinea24d4592018-01-11 21:07:29 +0900172 mPrivateDnsMap = new HashMap<>();
Erik Kline1742fe12017-12-13 19:40:49 +0900173
174 // TODO: Create and register ContentObservers to track every setting
175 // used herein, posting messages to respond to changes.
176 }
177
Erik Klinea24d4592018-01-11 21:07:29 +0900178 public PrivateDnsConfig getPrivateDnsConfig() {
179 return getPrivateDnsConfig(mContentResolver);
180 }
181
182 public void removeNetwork(Network network) {
183 mPrivateDnsMap.remove(network.netId);
184 }
185
186 public PrivateDnsConfig updatePrivateDns(Network network, PrivateDnsConfig cfg) {
187 Slog.w(TAG, "updatePrivateDns(" + network + ", " + cfg + ")");
188 return (cfg != null)
189 ? mPrivateDnsMap.put(network.netId, cfg)
190 : mPrivateDnsMap.remove(network);
Erik Kline1742fe12017-12-13 19:40:49 +0900191 }
192
193 public void setDnsConfigurationForNetwork(
Erik Klinea24d4592018-01-11 21:07:29 +0900194 int netId, LinkProperties lp, boolean isDefaultNetwork) {
195 // We only use the PrivateDnsConfig data pushed to this class instance
196 // from ConnectivityService because it works in coordination with
197 // NetworkMonitor to decide which networks need validation and runs the
198 // blocking calls to resolve Private DNS strict mode hostnames.
199 //
200 // At this time we do attempt to enable Private DNS on non-Internet
201 // networks like IMS.
202 final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.get(netId);
Erik Kline1742fe12017-12-13 19:40:49 +0900203
Erik Klinea24d4592018-01-11 21:07:29 +0900204 final boolean useTls = (privateDnsCfg != null) && privateDnsCfg.useTls;
205 final boolean strictMode = (privateDnsCfg != null) && privateDnsCfg.inStrictMode();
206 final String tlsHostname = strictMode ? privateDnsCfg.hostname : "";
207
208 final String[] serverStrs = NetworkUtils.makeStrings(
209 strictMode ? Arrays.stream(privateDnsCfg.ips)
210 .filter((ip) -> lp.isReachable(ip))
211 .collect(Collectors.toList())
212 : lp.getDnsServers());
213 final String[] domainStrs = getDomainStrings(lp.getDomains());
214
215 updateParametersSettings();
Erik Kline1742fe12017-12-13 19:40:49 +0900216 final int[] params = { mSampleValidity, mSuccessThreshold, mMinSamples, mMaxSamples };
Erik Klinea24d4592018-01-11 21:07:29 +0900217
218 Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %s, %s, %s)",
219 netId, Arrays.toString(serverStrs), Arrays.toString(domainStrs),
220 Arrays.toString(params), useTls, tlsHostname));
Erik Kline1742fe12017-12-13 19:40:49 +0900221 try {
222 mNMS.setDnsConfigurationForNetwork(
223 netId, serverStrs, domainStrs, params, useTls, tlsHostname);
224 } catch (Exception e) {
225 Slog.e(TAG, "Error setting DNS configuration: " + e);
226 return;
227 }
228
229 // TODO: netd should listen on [::1]:53 and proxy queries to the current
230 // default network, and we should just set net.dns1 to ::1, not least
231 // because applications attempting to use net.dns resolvers will bypass
232 // the privacy protections of things like DNS-over-TLS.
Erik Klinea24d4592018-01-11 21:07:29 +0900233 if (isDefaultNetwork) setDefaultDnsSystemProperties(lp.getDnsServers());
Erik Kline1742fe12017-12-13 19:40:49 +0900234 flushVmDnsCache();
235 }
236
237 public void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) {
238 int last = 0;
239 for (InetAddress dns : dnses) {
240 ++last;
241 setNetDnsProperty(last, dns.getHostAddress());
242 }
243 for (int i = last + 1; i <= mNumDnsEntries; ++i) {
244 setNetDnsProperty(i, "");
245 }
246 mNumDnsEntries = last;
247 }
248
249 private void flushVmDnsCache() {
250 /*
251 * Tell the VMs to toss their DNS caches
252 */
253 final Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE);
254 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
255 /*
256 * Connectivity events can happen before boot has completed ...
257 */
258 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
259 final long ident = Binder.clearCallingIdentity();
260 try {
261 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
262 } finally {
263 Binder.restoreCallingIdentity(ident);
264 }
265 }
266
Erik Kline1742fe12017-12-13 19:40:49 +0900267 private void updateParametersSettings() {
268 mSampleValidity = getIntSetting(
269 DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
270 DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
271 if (mSampleValidity < 0 || mSampleValidity > 65535) {
272 Slog.w(TAG, "Invalid sampleValidity=" + mSampleValidity + ", using default=" +
273 DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
274 mSampleValidity = DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS;
275 }
276
277 mSuccessThreshold = getIntSetting(
278 DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
279 DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
280 if (mSuccessThreshold < 0 || mSuccessThreshold > 100) {
281 Slog.w(TAG, "Invalid successThreshold=" + mSuccessThreshold + ", using default=" +
282 DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
283 mSuccessThreshold = DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT;
284 }
285
286 mMinSamples = getIntSetting(DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
287 mMaxSamples = getIntSetting(DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
288 if (mMinSamples < 0 || mMinSamples > mMaxSamples || mMaxSamples > 64) {
289 Slog.w(TAG, "Invalid sample count (min, max)=(" + mMinSamples + ", " + mMaxSamples +
290 "), using default=(" + DNS_RESOLVER_DEFAULT_MIN_SAMPLES + ", " +
291 DNS_RESOLVER_DEFAULT_MAX_SAMPLES + ")");
292 mMinSamples = DNS_RESOLVER_DEFAULT_MIN_SAMPLES;
293 mMaxSamples = DNS_RESOLVER_DEFAULT_MAX_SAMPLES;
294 }
295 }
296
Erik Kline1742fe12017-12-13 19:40:49 +0900297 private int getIntSetting(String which, int dflt) {
298 return Settings.Global.getInt(mContentResolver, which, dflt);
299 }
300
301 private void setNetDnsProperty(int which, String value) {
302 final String key = "net.dns" + which;
303 // Log and forget errors setting unsupported properties.
304 try {
305 mSystemProperties.set(key, value);
306 } catch (Exception e) {
307 Slog.e(TAG, "Error setting unsupported net.dns property: ", e);
308 }
309 }
310
Erik Klinea24d4592018-01-11 21:07:29 +0900311 private static String getPrivateDnsMode(ContentResolver cr) {
312 final String mode = getStringSetting(cr, PRIVATE_DNS_MODE);
313 return !TextUtils.isEmpty(mode) ? mode : PRIVATE_DNS_DEFAULT_MODE;
314 }
315
316 private static String getStringSetting(ContentResolver cr, String which) {
317 return Settings.Global.getString(cr, which);
318 }
319
320 private static String[] getDomainStrings(String domains) {
321 return (TextUtils.isEmpty(domains)) ? new String[0] : domains.split(" ");
Erik Kline1742fe12017-12-13 19:40:49 +0900322 }
323}