本文中含有需要您注意的重要提示信息,忽略该信息可能对您的业务造成影响,请务必仔细阅读。
本文档介绍了阿里云公共DNS 在 iOS 14原生加密DNS方案中的接入和开发方式。
概述
DNS解析是网络资源访问的第一跳,iOS 14 开始系统原生支持两种标准规范的 Encrypted DNS, 分别是 DNS over TLS 与 DNS over HTTPS,可以解决以下两个问题:
一、传统Local DNS的查询与回复均基于非加密UDP,发生我们常见的DNS劫持问题。
二、Local DNS Server本身不可信,或者本地Local DNS 服务不可用问题。
针对DNS解析过程中以上两个问题,阿里云公共DNS已经有了解决方案,即使用阿里云公共DNS SDK,但使用SDK会面临一些技术坑,比如302场景的IP直连处理、以及iOS上的SNI问题等,而iOS 14 上的 Encrypted DNS 功能很好的解决了集成SDK的方案存在的问题,您可以参考以下示例了解如何设置阿里云公共DNS为加密DNS默认解析器。
iOS14原生加密DNS方案仅支持真机运行且仅支持iOS14及其以上系统版本。
建议开发者使用DoH/DoT加密地址。
为确保app正常运行,请开发者自实现降级Local DNS 兜底机制,避免因DoH/DoT服务异常导致域名解析失败。
该方案无法保障SLA(因为我们SDK中有多级兜底),但用户可以通过自己实现兜底逻辑来规避平台侧异常的风险。
iOS 14原生加密DNS方案如何接入阿里云公共DNS
iOS 14 提供了两种设置加密DNS的方法。
第一种方式是针对单个App的所有连接启用加密DNS。
如果您只想为您的App使用加密DNS,而非整个终端系统全部接入使用加密DNS。您可以适配NetworkExtension的nw_privacy_context_t,只对您的整个App开启加密DNS,App内发起的每个DNS解析都会使用这个配置。我们为您提供了针对单个App的所有连接启用DoH的demo示例供您参考。
在App范围内使用加密DNS,使用DoH协议示例代码:
#import <NetworkExtension/NetworkExtension.h>
if (@available(iOS 14.0, *)){
nw_privacy_context_t defaultPrivacyContext = NW_DEFAULT_PRIVACY_CONTEXT;
nw_endpoint_t dohResolverEndpoint = nw_endpoint_create_url("https://*****-************.alidns.com/dns-query");//DoH加密地址
nw_endpoint_t v4ResolverEndpoint1 = nw_endpoint_create_host("223.5.5.5", "443");
nw_endpoint_t v4ResolverEndpoint2 = nw_endpoint_create_host("223.6.6.6", "443");
nw_endpoint_t v6ResolverEndpoint1 = nw_endpoint_create_host("2400:3200::1", "443");
nw_endpoint_t v6ResolverEndpoint2 = nw_endpoint_create_host("2400:3200:baba::1", "443");
nw_resolver_config_t fallbackResolvers = nw_resolver_config_create_https(dohResolverEndpoint);
nw_resolver_config_add_server_address(fallbackResolvers, v4ResolverEndpoint1);
nw_resolver_config_add_server_address(fallbackResolvers, v4ResolverEndpoint2);
nw_resolver_config_add_server_address(fallbackResolvers, v6ResolverEndpoint1);
nw_resolver_config_add_server_address(fallbackResolvers, v6ResolverEndpoint2);
nw_privacy_context_require_encrypted_name_resolution(defaultPrivacyContext, true, fallbackResolvers);
}
在App范围内使用加密DNS,使用DoT协议示例代码:
#import <NetworkExtension/NetworkExtension.h>
if (@available(iOS 14.0, *)){
nw_privacy_context_t defaultPrivacyContext = NW_DEFAULT_PRIVACY_CONTEXT;
nw_endpoint_t dotResolverEndpoint = nw_endpoint_create_host("******-************.alidns.com", "853");//DoT加密地址
nw_endpoint_t v4ResolverEndpoint1 = nw_endpoint_create_host("223.5.5.5", "853");
nw_endpoint_t v4ResolverEndpoint2 = nw_endpoint_create_host("223.6.6.6", "853");
nw_endpoint_t v6ResolverEndpoint1 = nw_endpoint_create_host("2400:3200::1", "853");
nw_endpoint_t v6ResolverEndpoint2 = nw_endpoint_create_host("2400:3200:baba::1", "853");
nw_resolver_config_t fallbackResolvers = nw_resolver_config_create_tls(dotResolverEndpoint);
nw_resolver_config_add_server_address(fallbackResolvers, v4ResolverEndpoint1);
nw_resolver_config_add_server_address(fallbackResolvers, v4ResolverEndpoint2);
nw_resolver_config_add_server_address(fallbackResolvers, v6ResolverEndpoint1);
nw_resolver_config_add_server_address(fallbackResolvers, v6ResolverEndpoint2);
nw_privacy_context_require_encrypted_name_resolution(defaultPrivacyContext, true, fallbackResolvers);
}
⽤户可以通过以下代码实现降级Local DNS 兜底机制,通过 URLSessionDelegate 获取 NSURLSessionTaskTransactionMetrics ,在请求失败后关闭 DoH/DoT。
#pragma mark URLSession Delegate
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics {
if ([metrics.transactionMetrics count] <= 0) return;
[metrics.transactionMetrics enumerateObjectsUsingBlock:^(NSURLSessionTaskTransactionMetrics *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
if (obj.resourceFetchType == NSURLSessionTaskMetricsResourceFetchTypeNetworkLoad) {
if (@available(iOS 14.0, *)) {
NSURLSessionTaskMetricsDomainResolutionProtocol dnsProtocol = obj.domainResolutionProtocol;
NSLog(@"%@",[NSString stringWithFormat:@"DNS类型为 %ld", (long)dnsProtocol]);
NSLog(@"%@",[NSString stringWithFormat:@"0:未知,1:UDP,2:TCP,3:TLS,4:HTTPS"]);
if (dnsProtocol == NSURLSessionTaskMetricsDomainResolutionProtocolUnknown) {
NSLog(@"%@",[NSString stringWithFormat:@"dns来源未知,关闭Doh"]);
nw_privacy_context_require_encrypted_name_resolution(NW_DEFAULT_PRIVACY_CONTEXT, false, nil);
}
}
}
}];
}
第二种方式是针对整个终端内所有应用的连接启用加密DNS。
如果您想为整个系统域使用加密DNS,您可以使用NEDNSSettingsManager API编写一个NetworkExtension App完成系统全局加密DNS设置。
通过NetworkExtension设置系统域全局DNS服务器,使用DoH协议示例代码:
import NetworkExtension
NEDNSSettingsManager.shared().loadFromPreferences { loadError in
if let loadError = loadError {
// ...handle error...
return
}
let dohSettings = NEDNSOverHTTPSSettings(servers: ["223.5.5.5","223.6.6.6","2400:3200:baba::1","2400:3200::1"])
dohSettings.serverURL = URL(string: "https://*****-************.alidns.com/dns-query")//DoH加密地址
NEDNSSettingsManager.shared().dnsSettings = dohSettings
NEDNSSettingsManager.shared().saveToPreferences { saveError in
if let saveError = saveError {
// ...handle error...
return
}
}
}
通过NetworkExtension设置系统域全局DNS服务器,使用DoT协议示例代码:
import NetworkExtension
NEDNSSettingsManager.shared().loadFromPreferences { loadError in
if let loadError = loadError {
// ...handle error...
return
}
let dotSettings = NEDNSOverTLSSettings(servers: ["223.5.5.5","223.6.6.6","2400:3200:baba::1","2400:3200::1"])
dotSettings.serverName = "******-************.alidns.com"//DoT加密地址
NEDNSSettingsManager.shared().dnsSettings = dotSettings
NEDNSSettingsManager.shared().saveToPreferences { saveError in
if let saveError = saveError {
// ...handle error...
return
}
}
}
一条DNS配置包括阿里公共DNS服务器地址、DoT/DoH协议、一组网络规则。网络规则确保DNS设置兼容不同的网络。
网络规则设置示例代码:
let workWiFi = NEOnDemandRuleEvaluateConnection()
workWiFi.interfaceTypeMatch = .wiFi
workWiFi.ssidMatch = ["MyWorkWiFi"]
workWiFi.connectionRules = [NEEvaluateConnectionRule(matchDomains: ["enterprise.example"], andAction: .neverConnect)]
let disableOnCell = NEOnDemandRuleDisconnect()
disableOnCell.interfaceTypeMatch = .cellular
let enableByDefault = NEOnDemandRuleConnect()
NEDNSSettingsManager.shared().onDemandRules = [
workWiFi,
disableOnCell,
enableByDefault
]
上述代码设置了三个网络规则,第一个规则表示DNS配置应该在SSID=“MyWorkWiFi”的WiFi网络生效,但对私有企业域名enterprise.example.net不开启;第二个规则表示规则在蜂窝网下应该被禁止使用;第三个NEOnDemandRuleConnect表示DNS配置应该默认开启;因为配置DNS是系统支持的,所以在编写NetworkExtension App时不需要实现Extension程序,只需要在Network Extensions中勾选DNS Settings选项。
运行NetworkExtension App,DNS配置将会被安装到系统,为了让DNS配置生效,需要前往设置->通用->VPN & Network->DNS手动启用。