DnsManager.java revision 1742fe1309b9b1d73a15b40829a9ce2e651d21fd
1/* 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; 20import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; 21import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; 22import static android.provider.Settings.Global.DNS_RESOLVER_MIN_SAMPLES; 23import static android.provider.Settings.Global.DNS_RESOLVER_MAX_SAMPLES; 24import static android.provider.Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS; 25import static android.provider.Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT; 26import static android.provider.Settings.Global.PRIVATE_DNS_MODE; 27import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER; 28 29import android.content.ContentResolver; 30import android.content.Context; 31import android.content.Intent; 32import android.net.NetworkUtils; 33import android.os.Binder; 34import android.os.INetworkManagementService; 35import android.os.Handler; 36import android.os.UserHandle; 37import android.provider.Settings; 38import android.text.TextUtils; 39import android.util.Slog; 40 41import com.android.server.connectivity.MockableSystemProperties; 42 43import java.net.InetAddress; 44import java.util.Collection; 45 46 47/** 48 * Encapsulate the management of DNS settings for networks. 49 * 50 * This class it NOT designed for concurrent access. Furthermore, all non-static 51 * methods MUST be called from ConnectivityService's thread. 52 * 53 * @hide 54 */ 55public class DnsManager { 56 private static final String TAG = DnsManager.class.getSimpleName(); 57 58 /* Defaults for resolver parameters. */ 59 private static final int DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800; 60 private static final int DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT = 25; 61 private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8; 62 private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64; 63 64 private final Context mContext; 65 private final ContentResolver mContentResolver; 66 private final INetworkManagementService mNMS; 67 private final MockableSystemProperties mSystemProperties; 68 69 private int mNumDnsEntries; 70 private int mSampleValidity; 71 private int mSuccessThreshold; 72 private int mMinSamples; 73 private int mMaxSamples; 74 private String mPrivateDnsMode; 75 private String mPrivateDnsSpecifier; 76 77 public DnsManager(Context ctx, INetworkManagementService nms, MockableSystemProperties sp) { 78 mContext = ctx; 79 mContentResolver = mContext.getContentResolver(); 80 mNMS = nms; 81 mSystemProperties = sp; 82 83 // TODO: Create and register ContentObservers to track every setting 84 // used herein, posting messages to respond to changes. 85 } 86 87 public boolean isPrivateDnsInStrictMode() { 88 return !TextUtils.isEmpty(mPrivateDnsMode) && 89 mPrivateDnsMode.startsWith(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME) && 90 !TextUtils.isEmpty(mPrivateDnsSpecifier); 91 } 92 93 public void setDnsConfigurationForNetwork( 94 int netId, Collection<InetAddress> servers, String domains, boolean isDefaultNetwork) { 95 updateParametersSettings(); 96 updatePrivateDnsSettings(); 97 98 final String[] serverStrs = NetworkUtils.makeStrings(servers); 99 final String[] domainStrs = (domains == null) ? new String[0] : domains.split(" "); 100 final int[] params = { mSampleValidity, mSuccessThreshold, mMinSamples, mMaxSamples }; 101 final boolean useTls = shouldUseTls(mPrivateDnsMode); 102 // TODO: Populate tlsHostname once it's decided how the hostname's IP 103 // addresses will be resolved: 104 // 105 // [1] network-provided DNS servers are included here with the 106 // hostname and netd will use the network-provided servers to 107 // resolve the hostname and fix up its internal structures, or 108 // 109 // [2] network-provided DNS servers are included here without the 110 // hostname, the ConnectivityService layer resolves the given 111 // hostname, and then reconfigures netd with this information. 112 // 113 // In practice, there will always be a need for ConnectivityService or 114 // the captive portal app to use the network-provided services to make 115 // some queries. This argues in favor of [1], in concert with another 116 // mechanism, perhaps setting a high bit in the netid, to indicate 117 // via existing DNS APIs which set of servers (network-provided or 118 // non-network-provided private DNS) should be queried. 119 final String tlsHostname = ""; 120 try { 121 mNMS.setDnsConfigurationForNetwork( 122 netId, serverStrs, domainStrs, params, useTls, tlsHostname); 123 } catch (Exception e) { 124 Slog.e(TAG, "Error setting DNS configuration: " + e); 125 return; 126 } 127 128 // TODO: netd should listen on [::1]:53 and proxy queries to the current 129 // default network, and we should just set net.dns1 to ::1, not least 130 // because applications attempting to use net.dns resolvers will bypass 131 // the privacy protections of things like DNS-over-TLS. 132 if (isDefaultNetwork) setDefaultDnsSystemProperties(servers); 133 flushVmDnsCache(); 134 } 135 136 public void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) { 137 int last = 0; 138 for (InetAddress dns : dnses) { 139 ++last; 140 setNetDnsProperty(last, dns.getHostAddress()); 141 } 142 for (int i = last + 1; i <= mNumDnsEntries; ++i) { 143 setNetDnsProperty(i, ""); 144 } 145 mNumDnsEntries = last; 146 } 147 148 private void flushVmDnsCache() { 149 /* 150 * Tell the VMs to toss their DNS caches 151 */ 152 final Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE); 153 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 154 /* 155 * Connectivity events can happen before boot has completed ... 156 */ 157 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 158 final long ident = Binder.clearCallingIdentity(); 159 try { 160 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 161 } finally { 162 Binder.restoreCallingIdentity(ident); 163 } 164 } 165 166 private void updatePrivateDnsSettings() { 167 mPrivateDnsMode = getStringSetting(PRIVATE_DNS_MODE); 168 mPrivateDnsSpecifier = getStringSetting(PRIVATE_DNS_SPECIFIER); 169 } 170 171 private void updateParametersSettings() { 172 mSampleValidity = getIntSetting( 173 DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, 174 DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS); 175 if (mSampleValidity < 0 || mSampleValidity > 65535) { 176 Slog.w(TAG, "Invalid sampleValidity=" + mSampleValidity + ", using default=" + 177 DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS); 178 mSampleValidity = DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS; 179 } 180 181 mSuccessThreshold = getIntSetting( 182 DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, 183 DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT); 184 if (mSuccessThreshold < 0 || mSuccessThreshold > 100) { 185 Slog.w(TAG, "Invalid successThreshold=" + mSuccessThreshold + ", using default=" + 186 DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT); 187 mSuccessThreshold = DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT; 188 } 189 190 mMinSamples = getIntSetting(DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES); 191 mMaxSamples = getIntSetting(DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES); 192 if (mMinSamples < 0 || mMinSamples > mMaxSamples || mMaxSamples > 64) { 193 Slog.w(TAG, "Invalid sample count (min, max)=(" + mMinSamples + ", " + mMaxSamples + 194 "), using default=(" + DNS_RESOLVER_DEFAULT_MIN_SAMPLES + ", " + 195 DNS_RESOLVER_DEFAULT_MAX_SAMPLES + ")"); 196 mMinSamples = DNS_RESOLVER_DEFAULT_MIN_SAMPLES; 197 mMaxSamples = DNS_RESOLVER_DEFAULT_MAX_SAMPLES; 198 } 199 } 200 201 private String getStringSetting(String which) { 202 return Settings.Global.getString(mContentResolver, which); 203 } 204 205 private int getIntSetting(String which, int dflt) { 206 return Settings.Global.getInt(mContentResolver, which, dflt); 207 } 208 209 private void setNetDnsProperty(int which, String value) { 210 final String key = "net.dns" + which; 211 // Log and forget errors setting unsupported properties. 212 try { 213 mSystemProperties.set(key, value); 214 } catch (Exception e) { 215 Slog.e(TAG, "Error setting unsupported net.dns property: ", e); 216 } 217 } 218 219 private static boolean shouldUseTls(String mode) { 220 if (TextUtils.isEmpty(mode)) { 221 mode = PRIVATE_DNS_DEFAULT_MODE; 222 } 223 return mode.equals(PRIVATE_DNS_MODE_OPPORTUNISTIC) || 224 mode.startsWith(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME); 225 } 226} 227