目录
1.Settings相关类
布局network_and_internet.xml
<com.android.settings.network.PrivateDnsModeDialogPreference
android:key="private_dns_settings"
android:title="@string/select_private_dns_configuration_title"
android:order="15"
android:dialogTitle="@string/select_private_dns_configuration_dialog_title"
android:dialogLayout="@layout/private_dns_mode_dialog"
android:positiveButtonText="@string/save"
android:negativeButtonText="@android:string/cancel" />
PrivateDnsModeDialogPreference这是个Android自定义的控件,点击会弹出对话框,对话框是以android:dialogLayout指定的
PrivateDnsPreferenceController是xml中对应控制Preference的summary和显示状态的
private_dns_mode_dialog是对应的对话框
2.代码搜索
私人dns 设置中的菜单其实很简单,关键代码如下
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
final Context context = getContext();
if (mMode.equals(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
// Only clickable if hostname is valid, so we could save it safely
Settings.Global.putString(context.getContentResolver(), HOSTNAME_KEY,
mEditText.getText().toString());
}
FeatureFactory.getFactory(context).getMetricsFeatureProvider().action(context,
SettingsEnums.ACTION_PRIVATE_DNS_MODE, mMode);
Settings.Global.putString(context.getContentResolver(), MODE_KEY, mMode);
}
}
私人dns有三个选择项,分别是关闭、自动和私人dns提供商主机名,即手动输入设置
./strings.xml:245: <string name="private_dns_mode_provider" msgid="8354935160639360804">"私人 DNS 提供商主机名"</string>
./strings.xml:246: <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"输入 DNS 提供商的主机名"</string>
./strings.xml:247: <string name="private_dns_mode_provider_failure" msgid="231837290365031223">"无法连接"</string>
模式设置其实就是设置到MODE_KEY的SettingsProvider数据库里,而手动输入的dns提供商主机名会放到HOSTNAME_KEY的SettingsProvider数据库里
对应的数据库键值
@VisibleForTesting
static final String MODE_KEY = Settings.Global.PRIVATE_DNS_MODE;
@VisibleForTesting
static final String HOSTNAME_KEY = Settings.Global.PRIVATE_DNS_SPECIFIER;
看一下哪里获取的
在framework里搜了下主要出现在如下的文件中
./base/services/core/java/com/android/server/connectivity/DnsManager.java
./base/services/core/java/com/android/server/ConnectivityService.java
./base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
./base/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
./base/core/java/android/app/admin/DevicePolicyManager.java
./base/core/java/android/net/ConnectivityManager.java
2.1 ConnectivityManager
/**
* Private DNS Mode values.
*
* The "private_dns_mode" global setting stores a String value which is
* expected to be one of the following.
*/
/**
* @hide
*/
public static final String PRIVATE_DNS_MODE_OFF = "off";
/**
* @hide
*/
public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic";
/**
* @hide
*/
public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname";
/**
* The default Private DNS mode.
*
* This may change from release to release or may become dependent upon
* the capabilities of the underlying platform.
*
* @hide
*/
public static final String PRIVATE_DNS_DEFAULT_MODE_FALLBACK = PRIVATE_DNS_MODE_OPPORTUNISTIC;
ConnectivityManager中声明了三种模式,分别为关闭、自动和手动,默认为自动
2.2 DevicePolicyManager
/**
* Specifies that the Private DNS setting is in an unknown state.
*/
public static final int PRIVATE_DNS_MODE_UNKNOWN = 0;
/**
* Specifies that Private DNS was turned off completely.
*/
public static final int PRIVATE_DNS_MODE_OFF = 1;
/**
* Specifies that the device owner requested opportunistic DNS over TLS
*/
public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2;
/**
* Specifies that the device owner configured a specific host to use for Private DNS.
*/
public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3;
DevicePolicyManager中定义了类似的
/**
* The selected mode has been set successfully. If the mode is
* {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME} then it implies the supplied host is valid
* and reachable.
*/
public static final int PRIVATE_DNS_SET_NO_ERROR = 0;
/**
* If the {@code privateDnsHost} provided was of a valid hostname but that host was found
* to not support DNS-over-TLS.
*/
public static final int PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING = 1;
/**
* General failure to set the Private DNS mode, not due to one of the reasons listed above.
*/
public static final int PRIVATE_DNS_SET_ERROR_FAILURE_SETTING = 2;
还有几种状态
2.3 ConnectivityService
// restore private DNS settings to default mode (opportunistic)
if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_PRIVATE_DNS)) {
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OPPORTUNISTIC);
}
CS是恢复网络设置的时候会将dns的模式重新设置为自动
2.4 DnsManager
public static PrivateDnsConfig getPrivateDnsConfig(ContentResolver cr) {
final String mode = getPrivateDnsMode(cr);
final boolean useTls = !TextUtils.isEmpty(mode) && !PRIVATE_DNS_MODE_OFF.equals(mode);
if (PRIVATE_DNS_MODE_PROVIDER_HOSTNAME.equals(mode)) {
final String specifier = getStringSetting(cr, PRIVATE_DNS_SPECIFIER);
return new PrivateDnsConfig(specifier, null);
}
return new PrivateDnsConfig(useTls);
}
private static String getPrivateDnsMode(ContentResolver cr) {
String mode = getStringSetting(cr, PRIVATE_DNS_MODE);
if (TextUtils.isEmpty(mode)) mode = getStringSetting(cr, PRIVATE_DNS_DEFAULT_MODE);
if (TextUtils.isEmpty(mode)) mode = PRIVATE_DNS_DEFAULT_MODE_FALLBACK;
return mode;
}
private static String getStringSetting(ContentResolver cr, String which) {
return Settings.Global.getString(cr, which);
}
看起来是主动获取settings设置的dns模式,将其封装到一个叫做PrivateDnsConfig的类里面去
public class PrivateDnsConfig {
public final boolean useTls;
public final String hostname;
public final InetAddress[] ips;
public PrivateDnsConfig() {
this(false);
}
public PrivateDnsConfig(boolean useTls) {
this.useTls = useTls;
this.hostname = "";
this.ips = new InetAddress[0];
}
public PrivateDnsConfig(String hostname, InetAddress[] ips) {
this.useTls = !TextUtils.isEmpty(hostname);
this.hostname = useTls ? hostname : "";
this.ips = (ips != null) ? ips : new InetAddress[0];
}
public PrivateDnsConfig(PrivateDnsConfig cfg) {
useTls = cfg.useTls;
hostname = cfg.hostname;
ips = cfg.ips;
}
/**
* Indicates whether this is a strict mode private DNS configuration.
*/
public boolean inStrictMode() {
return useTls && !TextUtils.isEmpty(hostname);
}
@Override
public String toString() {
return PrivateDnsConfig.class.getSimpleName()
+ "{" + useTls + ":" + hostname + "/" + Arrays.toString(ips) + "}";
}
/**
* Create a stable AIDL-compatible parcel from the current instance.
*/
public PrivateDnsConfigParcel toParcel() {
final PrivateDnsConfigParcel parcel = new PrivateDnsConfigParcel();
parcel.hostname = hostname;
parcel.ips = toParcelableArray(
Arrays.asList(ips), IpConfigurationParcelableUtil::parcelAddress, String.class);
return parcel;
}
/**
* Build a configuration from a stable AIDL-compatible parcel.
*/
public static PrivateDnsConfig fromParcel(PrivateDnsConfigParcel parcel) {
InetAddress[] ips = new InetAddress[parcel.ips.length];
ips = fromParcelableArray(parcel.ips, IpConfigurationParcelableUtil::unparcelAddress)
.toArray(ips);
return new PrivateDnsConfig(parcel.hostname, ips);
}
}
注释里将私人dns的流程说了很清楚
/**
* Encapsulate the management of DNS settings for networks.
*
* This class it NOT designed for concurrent access. Furthermore, all non-static
* methods MUST be called from ConnectivityService's thread.
*
* [ Private DNS ]
* The code handling Private DNS is spread across several components, but this
* seems like the least bad place to collect all the observations.
*
* Private DNS handling and updating occurs in response to several different
* events. Each is described here with its corresponding intended handling.
*
* [A] Event: A new network comes up.
* Mechanics:
* [1] ConnectivityService gets notifications from NetworkAgents.
* [2] in updateNetworkInfo(), the first time the NetworkAgent goes into
* into CONNECTED state, the Private DNS configuration is retrieved,
* programmed, and strict mode hostname resolution (if applicable) is
* enqueued in NetworkAgent's NetworkMonitor, via a call to
* handlePerNetworkPrivateDnsConfig().
* [3] Re-resolution of strict mode hostnames that fail to return any
* IP addresses happens inside NetworkMonitor; it sends itself a
* delayed CMD_EVALUATE_PRIVATE_DNS message in a simple backoff
* schedule.
* [4] Successfully resolved hostnames are sent to ConnectivityService
* inside an EVENT_PRIVATE_DNS_CONFIG_RESOLVED message. The resolved
* IP addresses are programmed into netd via:
*
* updatePrivateDns() -> updateDnses()
*
* both of which make calls into DnsManager.
* [5] Upon a successful hostname resolution NetworkMonitor initiates a
* validation attempt in the form of a lookup for a one-time hostname
* that uses Private DNS.
*
* [B] Event: Private DNS settings are changed.
* Mechanics:
* [1] ConnectivityService gets notifications from its SettingsObserver.
* [2] handlePrivateDnsSettingsChanged() is called, which calls
* handlePerNetworkPrivateDnsConfig() and the process proceeds
* as if from A.3 above.
*
* [C] Event: An application calls ConnectivityManager#reportBadNetwork().
* Mechanics:
* [1] NetworkMonitor is notified and initiates a reevaluation, which
* always bypasses Private DNS.
* [2] Once completed, NetworkMonitor checks if strict mode is in operation
* and if so enqueues another evaluation of Private DNS, as if from
* step A.5 above.
*
* @hide
*/
3.流程梳理
跟着上面注释理一下流程
3.1 ConnectivityService
* [2] in updateNetworkInfo(), the first time the NetworkAgent goes into
* into CONNECTED state, the Private DNS configuration is retrieved,
* programmed, and strict mode hostname resolution (if applicable) is
* enqueued in NetworkAgent's NetworkMonitor, via a call to
* handlePerNetworkPrivateDnsConfig().
private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {
final NetworkInfo.State state = newInfo.getState();
NetworkInfo oldInfo = null;
final int oldScore = networkAgent.getCurrentScore();
synchronized (networkAgent) {
oldInfo = networkAgent.networkInfo;
networkAgent.networkInfo = newInfo;
}
notifyLockdownVpn(networkAgent);
if (DBG) {
log(networkAgent.name() + " EVENT_NETWORK_INFO_CHANGED, going from " +
(oldInfo == null ? "null" : oldInfo.getState()) +
" to " + state);
}
if (!networkAgent.created
&& (state == NetworkInfo.State.CONNECTED
|| (state == NetworkInfo.State.CONNECTING && networkAgent.isVPN()))) {
// A network that has just connected has zero requests and is thus a foreground network.
networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND);
if (!createNativeNetwork(networkAgent)) return;
networkAgent.created = true;
}
if (!networkAgent.everConnected && state == NetworkInfo.State.CONNECTED) {
networkAgent.everConnected = true;
if (networkAgent.linkProperties == null) {
Slog.wtf(TAG, networkAgent.name() + " connected with null LinkProperties");
}
// NetworkCapabilities need to be set before sending the private DNS config to
// NetworkMonitor, otherwise NetworkMonitor cannot determine if validation is required.
synchronized (networkAgent) {
networkAgent.setNetworkCapabilities(networkAgent.networkCapabilities);
}
handlePerNetworkPrivateDnsConfig(networkAgent, mDnsManager.getPrivateDnsConfig());
然后调用handlePerNetworkPrivateDnsConfig
private void handlePerNetworkPrivateDnsConfig(NetworkAgentInfo nai, PrivateDnsConfig cfg) {
// Private DNS only ever applies to networks that might provide
// Internet access and therefore also require validation.
if (!networkRequiresPrivateDnsValidation(nai)) return;
// Notify the NetworkAgentInfo/NetworkMonitor in case NetworkMonitor needs to cancel or
// schedule DNS resolutions. If a DNS resolution is required the
// result will be sent back to us.
nai.networkMonitor().notifyPrivateDnsChanged(cfg.toParcel());
// With Private DNS bypass support, we can proceed to update the
// Private DNS config immediately, even if we're in strict mode
// and have not yet resolved the provider name into a set of IPs.
updatePrivateDns(nai, cfg);
}
3.2 NetworkMonitor
NetworkMonitorManager
public boolean notifyPrivateDnsChanged(PrivateDnsConfigParcel config) {
final long token = Binder.clearCallingIdentity();
try {
mNetworkMonitor.notifyPrivateDnsChanged(config);
return true;
} catch (RemoteException e) {
log("Error in notifyPrivateDnsChanged", e);
return false;
} finally {
Binder.restoreCallingIdentity(token);
}
}
NetworkStackService
@Override
public void notifyPrivateDnsChanged(PrivateDnsConfigParcel config) {
checkNetworkStackCallingPermission();
mNm.notifyPrivateDnsSettingsChanged(PrivateDnsConfig.fromParcel(config));
}
NetworkMonitor
/**
* Send a notification to NetworkMonitor indicating that private DNS settings have changed.
* @param newCfg The new private DNS configuration.
*/
public void notifyPrivateDnsSettingsChanged(PrivateDnsConfig newCfg) {
// Cancel any outstanding resolutions.
removeMessages(CMD_PRIVATE_DNS_SETTINGS_CHANGED);
// Send the update to the proper thread.
sendMessage(CMD_PRIVATE_DNS_SETTINGS_CHANGED, newCfg);
}
发送一个私人DNS配置改变的message
/**
* ConnectivityService notifies NetworkMonitor of settings changes to
* Private DNS. If a DNS resolution is required, e.g. for DNS-over-TLS in
* strict mode, then an event is sent back to ConnectivityService with the
* result of the resolution attempt.
*
* A separate message is used to trigger (re)evaluation of the Private DNS
* configuration, so that the message can be handled as needed in different
* states, including being ignored until after an ongoing captive portal
* validation phase is completed.
*/
private static final int CMD_PRIVATE_DNS_SETTINGS_CHANGED = 13;
然后看下哪个状态会来处理
case CMD_PRIVATE_DNS_SETTINGS_CHANGED: {
final PrivateDnsConfig cfg = (PrivateDnsConfig) message.obj;
if (!isPrivateDnsValidationRequired() || cfg == null || !cfg.inStrictMode()) {
// No DNS resolution required.
//
// We don't force any validation in opportunistic mode
// here. Opportunistic mode nameservers are validated
// separately within netd.
//
// Reset Private DNS settings state.
mPrivateDnsProviderHostname = "";
break;
}
mPrivateDnsProviderHostname = cfg.hostname;
// DNS resolutions via Private DNS strict mode block for a
// few seconds (~4.2) checking for any IP addresses to
// arrive and validate. Initiating a (re)evaluation now
// should not significantly alter the validation outcome.
//
// No matter what: enqueue a validation request; one of
// three things can happen with this request:
// [1] ignored (EvaluatingState or CaptivePortalState)
// [2] transition to EvaluatingPrivateDnsState
// (DefaultState and ValidatedState)
// [3] handled (EvaluatingPrivateDnsState)
//
// The Private DNS configuration to be evaluated will:
// [1] be skipped (not in strict mode), or
// [2] validate (huzzah), or
// [3] encounter some problem (invalid hostname,
// no resolved IP addresses, IPs unreachable,
// port 853 unreachable, port 853 is not running a
// DNS-over-TLS server, et cetera).
sendMessage(CMD_EVALUATE_PRIVATE_DNS);
break;
}
如果处于严格模式会发送评估私人DNS的消息,即手动设置了dns
/**
* Indicates whether this is a strict mode private DNS configuration.
*/
public boolean inStrictMode() {
return useTls && !TextUtils.isEmpty(hostname);
}
当发送CMD_EVALUATE_PRIVATE_DNS的时候会导致重新校验
// Being in the ValidatedState State indicates a Network is:
// - Successfully validated, or
// - Wanted "as is" by the user, or
// - Does not satisfy the default NetworkRequest and so validation has been skipped.
private class ValidatedState extends State {
...
@Override
public boolean processMessage(Message message) {
switch (message.what) {
...
case CMD_EVALUATE_PRIVATE_DNS:
transitionTo(mEvaluatingPrivateDnsState);
看下EvaluatingPrivateDnsState的处理
* [3] Re-resolution of strict mode hostnames that fail to return any
* IP addresses happens inside NetworkMonitor; it sends itself a
* delayed CMD_EVALUATE_PRIVATE_DNS message in a simple backoff
* schedule.
private class EvaluatingPrivateDnsState extends State {
private int mPrivateDnsReevalDelayMs;
private PrivateDnsConfig mPrivateDnsConfig;
@Override
public void enter() {
mPrivateDnsReevalDelayMs = INITIAL_REEVALUATE_DELAY_MS;
mPrivateDnsConfig = null;
sendMessage(CMD_EVALUATE_PRIVATE_DNS);
}
@Override
public boolean processMessage(Message msg) {
switch (msg.what) {
case CMD_EVALUATE_PRIVATE_DNS:
if (inStrictMode()) {
if (!isStrictModeHostnameResolved()) {
resolveStrictModeHostname();
if (isStrictModeHostnameResolved()) {
notifyPrivateDnsConfigResolved();
} else {
handlePrivateDnsEvaluationFailure();
break;
}
}
// Look up a one-time hostname, to bypass caching.
//
// Note that this will race with ConnectivityService
// code programming the DNS-over-TLS server IP addresses
// into netd (if invoked, above). If netd doesn't know
// the IP addresses yet, or if the connections to the IP
// addresses haven't yet been validated, netd will block
// for up to a few seconds before failing the lookup.
if (!sendPrivateDnsProbe()) {
handlePrivateDnsEvaluationFailure();
break;
}
}
// All good!
transitionTo(mValidatedState);
break;
然后sendPrivateDnsProbe
private boolean sendPrivateDnsProbe() {
// q.v. system/netd/server/dns/DnsTlsTransport.cpp
final String oneTimeHostnameSuffix = "-dnsotls-ds.metric.gstatic.com";
final String host = UUID.randomUUID().toString().substring(0, 8)
+ oneTimeHostnameSuffix;
final Stopwatch watch = new Stopwatch().start();
boolean success = false;
long time;
try {
final InetAddress[] ips = mNetwork.getAllByName(host);
time = watch.stop();
final String strIps = Arrays.toString(ips);
success = (ips != null && ips.length > 0);
validationLog(PROBE_PRIVDNS, host, String.format("%dms: %s", time, strIps));
} catch (UnknownHostException uhe) {
time = watch.stop();
validationLog(PROBE_PRIVDNS, host,
String.format("%dms - Error: %s", time, uhe.getMessage()));
}
logValidationProbe(time, PROBE_PRIVDNS, success ? DNS_SUCCESS : DNS_FAILURE);
mEvaluationState.noteProbeResult(NETWORK_VALIDATION_PROBE_PRIVDNS, success);
return success;
}
3.3 ConnectivityService
NetworkMonitor通过callback再调用到CS的接口
private void notifyPrivateDnsConfigResolved() {
try {
mCallback.notifyPrivateDnsConfigResolved(mPrivateDnsConfig.toParcel());
} catch (RemoteException e) {
Log.e(TAG, "Error sending private DNS config resolved notification", e);
}
}
* [4] Successfully resolved hostnames are sent to ConnectivityService
* inside an EVENT_PRIVATE_DNS_CONFIG_RESOLVED message. The resolved
* IP addresses are programmed into netd via:
*
* updatePrivateDns() -> updateDnses()
*
* both of which make calls into DnsManager.
看下notifyPrivateDnsConfigResolved
@Override
public void notifyPrivateDnsConfigResolved(PrivateDnsConfigParcel config) {
mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
EVENT_PRIVATE_DNS_CONFIG_RESOLVED,
0, mNetId, PrivateDnsConfig.fromParcel(config)));
}
继续看下消息处理
/**
* Event for NetworkMonitor/NetworkAgentInfo to inform ConnectivityService that the private DNS
* config was resolved.
* obj = PrivateDnsConfig
* arg2 = netid
*/
public static final int EVENT_PRIVATE_DNS_CONFIG_RESOLVED = 42;
case EVENT_PRIVATE_DNS_CONFIG_RESOLVED: {
final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
if (nai == null) break;
updatePrivateDns(nai, (PrivateDnsConfig) msg.obj);
break;
}
private void updatePrivateDns(NetworkAgentInfo nai, PrivateDnsConfig newCfg) {
mDnsManager.updatePrivateDns(nai.network, newCfg);
updateDnses(nai.linkProperties, null, nai.network.netId);
}
private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId) {
if (oldLp != null && newLp.isIdenticalDnses(oldLp)) {
return; // no updating necessary
}
final NetworkAgentInfo defaultNai = getDefaultNetwork();
final boolean isDefaultNetwork = (defaultNai != null && defaultNai.network.netId == netId);
if (DBG) {
final Collection<InetAddress> dnses = newLp.getDnsServers();
log("Setting DNS servers for network " + netId + " to " + dnses);
}
try {
mDnsManager.setDnsConfigurationForNetwork(netId, newLp, isDefaultNetwork);
} catch (Exception e) {
loge("Exception in setDnsConfigurationForNetwork: " + e);
}
}
DnsManager
public PrivateDnsConfig updatePrivateDns(Network network, PrivateDnsConfig cfg) {
Slog.w(TAG, "updatePrivateDns(" + network + ", " + cfg + ")");
return (cfg != null)
? mPrivateDnsMap.put(network.netId, cfg)
: mPrivateDnsMap.remove(network.netId);
}
public void setDnsConfigurationForNetwork(
int netId, LinkProperties lp, boolean isDefaultNetwork) {
updateParametersSettings();
final ResolverParamsParcel paramsParcel = new ResolverParamsParcel();
// We only use the PrivateDnsConfig data pushed to this class instance
// from ConnectivityService because it works in coordination with
// NetworkMonitor to decide which networks need validation and runs the
// blocking calls to resolve Private DNS strict mode hostnames.
//
// At this time we do not attempt to enable Private DNS on non-Internet
// networks like IMS.
final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.getOrDefault(netId,
PRIVATE_DNS_OFF);
final boolean useTls = privateDnsCfg.useTls;
final boolean strictMode = privateDnsCfg.inStrictMode();
paramsParcel.netId = netId;
paramsParcel.sampleValiditySeconds = mSampleValidity;
paramsParcel.successThreshold = mSuccessThreshold;
paramsParcel.minSamples = mMinSamples;
paramsParcel.maxSamples = mMaxSamples;
paramsParcel.servers = NetworkUtils.makeStrings(lp.getDnsServers());
paramsParcel.domains = getDomainStrings(lp.getDomains());
paramsParcel.tlsName = strictMode ? privateDnsCfg.hostname : "";
paramsParcel.tlsServers =
strictMode ? NetworkUtils.makeStrings(
Arrays.stream(privateDnsCfg.ips)
.filter((ip) -> lp.isReachable(ip))
.collect(Collectors.toList()))
: useTls ? paramsParcel.servers // Opportunistic
: new String[0]; // Off
paramsParcel.tlsFingerprints = new String[0];
// Prepare to track the validation status of the DNS servers in the
// resolver config when private DNS is in opportunistic or strict mode.
if (useTls) {
if (!mPrivateDnsValidationMap.containsKey(netId)) {
mPrivateDnsValidationMap.put(netId, new PrivateDnsValidationStatuses());
}
mPrivateDnsValidationMap.get(netId).updateTrackedDnses(paramsParcel.tlsServers,
paramsParcel.tlsName);
} else {
mPrivateDnsValidationMap.remove(netId);
}
Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %d, %d, %d, %d, "
+ "%d, %d, %s, %s)", paramsParcel.netId, Arrays.toString(paramsParcel.servers),
Arrays.toString(paramsParcel.domains), paramsParcel.sampleValiditySeconds,
paramsParcel.successThreshold, paramsParcel.minSamples,
paramsParcel.maxSamples, paramsParcel.baseTimeoutMsec,
paramsParcel.retryCount, paramsParcel.tlsName,
Arrays.toString(paramsParcel.tlsServers)));
try {
mDnsResolver.setResolverConfiguration(paramsParcel);
} catch (RemoteException | ServiceSpecificException e) {
Slog.e(TAG, "Error setting DNS configuration: " + e);
return;
}
// TODO: netd should listen on [::1]:53 and proxy queries to the current
// default network, and we should just set net.dns1 to ::1, not least
// because applications attempting to use net.dns resolvers will bypass
// the privacy protections of things like DNS-over-TLS.
if (isDefaultNetwork) setDefaultDnsSystemProperties(lp.getDnsServers());
flushVmDnsCache();
}
3.4 netd
./resolv/DnsResolverService.h:44: ::ndk::ScopedAStatus setResolverConfiguration(
./resolv/ResolverController.cpp:198:int ResolverController::setResolverConfiguration(
198 int ResolverController::setResolverConfiguration(
199 const ResolverParamsParcel& resolverParams,
200 const std::set<std::vector<uint8_t>>& tlsFingerprints) {
201 using aidl::android::net::IDnsResolver;
202
203 // At private DNS validation time, we only know the netId, so we have to guess/compute the
204 // corresponding socket mark.
205 Fwmark fwmark;
206 fwmark.netId = resolverParams.netId;
207 fwmark.explicitlySelected = true;
208 fwmark.protectedFromVpn = true;
209 fwmark.permission = PERMISSION_SYSTEM;
210
211 // Allow at most MAXNS private DNS servers in a network to prevent too many broken servers.
212 std::vector<std::string> tlsServers = resolverParams.tlsServers;
213 if (tlsServers.size() > MAXNS) {
214 tlsServers.resize(MAXNS);
215 }
216 const int err = gPrivateDnsConfiguration.set(resolverParams.netId, fwmark.intValue, tlsServers,
217 resolverParams.tlsName, tlsFingerprints);
218 if (err != 0) {
219 return err;
220 }
221
222 // Convert network-assigned server list to bionic's format.
223 const size_t serverCount = std::min<size_t>(MAXNS, resolverParams.servers.size());
224 std::vector<const char*> server_ptrs;
225 for (size_t i = 0; i < serverCount; ++i) {
226 server_ptrs.push_back(resolverParams.servers[i].c_str());
227 }
228
229 std::string domains_str = android::base::Join(resolverParams.domains, " ");
230
231 // TODO: Change resolv_set_nameservers_for_net() to use ResolverParamsParcel directly.
232 res_params res_params = {};
233 res_params.sample_validity = resolverParams.sampleValiditySeconds;
234 res_params.success_threshold = resolverParams.successThreshold;
235 res_params.min_samples = resolverParams.minSamples;
236 res_params.max_samples = resolverParams.maxSamples;
237 res_params.base_timeout_msec = resolverParams.baseTimeoutMsec;
238 res_params.retry_count = resolverParams.retryCount;
239
240 LOG(VERBOSE) << "setDnsServers netId = " << resolverParams.netId
241 << ", numservers = " << resolverParams.domains.size();
242
243 return -resolv_set_nameservers_for_net(resolverParams.netId, server_ptrs.data(),
244 server_ptrs.size(), domains_str.c_str(), &res_params);
245 }
后面就不看了,应该不大看得懂了
4.总结
对应于DnsManager里的注释
/**
* Encapsulate the management of DNS settings for networks.
*
* This class it NOT designed for concurrent access. Furthermore, all non-static
* methods MUST be called from ConnectivityService's thread.
*
* [ Private DNS ]
* The code handling Private DNS is spread across several components, but this
* seems like the least bad place to collect all the observations.
*
* Private DNS handling and updating occurs in response to several different
* events. Each is described here with its corresponding intended handling.
*
* [A] Event: A new network comes up.
* Mechanics:
* [1] ConnectivityService gets notifications from NetworkAgents.
* [2] in updateNetworkInfo(), the first time the NetworkAgent goes into
* into CONNECTED state, the Private DNS configuration is retrieved,
* programmed, and strict mode hostname resolution (if applicable) is
* enqueued in NetworkAgent's NetworkMonitor, via a call to
* handlePerNetworkPrivateDnsConfig().
* [3] Re-resolution of strict mode hostnames that fail to return any
* IP addresses happens inside NetworkMonitor; it sends itself a
* delayed CMD_EVALUATE_PRIVATE_DNS message in a simple backoff
* schedule.
* [4] Successfully resolved hostnames are sent to ConnectivityService
* inside an EVENT_PRIVATE_DNS_CONFIG_RESOLVED message. The resolved
* IP addresses are programmed into netd via:
*
* updatePrivateDns() -> updateDnses()
*
* both of which make calls into DnsManager.
* [5] Upon a successful hostname resolution NetworkMonitor initiates a
* validation attempt in the form of a lookup for a one-time hostname
* that uses Private DNS.
*
* [B] Event: Private DNS settings are changed.
* Mechanics:
* [1] ConnectivityService gets notifications from its SettingsObserver.
* [2] handlePrivateDnsSettingsChanged() is called, which calls
* handlePerNetworkPrivateDnsConfig() and the process proceeds
* as if from A.3 above.
*
* [C] Event: An application calls ConnectivityManager#reportBadNetwork().
* Mechanics:
* [1] NetworkMonitor is notified and initiates a reevaluation, which
* always bypasses Private DNS.
* [2] Once completed, NetworkMonitor checks if strict mode is in operation
* and if so enqueues another evaluation of Private DNS, as if from
* step A.5 above.
*
* @hide
*/