9.7 KiB
GoEdge HTTPDNS 技术需求文档v2.5
1. 文档概览
1.1 背景
目前 GoEdge 已经具备了强大的边缘缓存、WAF 和基础 DNS 功能。但在移动端应用中,传统的 UDP DNS 容易受到运营商劫持。此外,即便使用了 HTTPDNS,HTTPS 握手阶段明文传输的 SNI (Server Name Indication) 字段仍会导致真实域名被 ISP 嗅探、封锁或审计。
1.2 目标
开发独立的 edge-httpdns 模块,并配合边缘节点提供一套对 App 业务透明、可渐进演进的 「SNI 隐藏能力」,解决域名旁路感知问题,满足金融、出海等隐私敏感业务的合规与安全对抗需求。
2. 业务架构设计
{width="6.5in" height="3.513888888888889in"}
2.1 角色定义
-
管理端 (edge-admin/edge-user):
-
配置中心:管理 AppID/Secret,下发解析路由策略及 **SNI
隐藏等级策略**。
-
凭证中心:复用第三方 DNS 运营商的 API 凭证。
-
-
HTTPDNS 节点 (edge-httpdns):独立解析网关,支持
IPv4/IPv6、批量解析、ECS 透传,并下发 TLS 指纹/证书校验策略。
-
权威 DNS 节点 (edge-dns):处理传统 Port 53 的 DNS 请求。
-
边缘节点 (edge-node):流量网关,支持 **SNI 与 Host
解耦路由**,执行 WAF 动态验签及 SNI 隐匿/ECH 解密 逻辑。
3. 功能需求
3.1 管理端配置 (Admin/User)
-
SNI 隐藏平台管理:
-
能力级别选择:支持 Level 1(固定 SNI)、Level 2(隐匿
SNI)、Level 3(ECH)。
-
公共 SNI 域名池:配置用于伪装的 Public SNI 域名及证书。
-
证书校验策略:配置是否开启证书 Pinning 或 SAN 域名强制校验。
-
-
常规配置:AppID 认证管理、ECS 掩码配置、第三方 DNS 凭证复用。
3.2 节点 API 接口
-
Endpoint: https://httpdns.example.com/resolve
-
新增返回字段:
-
sni_policy: 隐藏等级(none/mask/empty/ech)。
-
public_sni: 当级别为 mask 时下发的伪装域名。
-
cert_fingerprint: 用于证书绑定的公钥指纹。
-
4. 技术实现方案 (Go)
4.1 边缘节点 SNI 路由解耦逻辑
边缘节点需修改 TLS 接入层,支持不依赖 SNI 的握手逻辑。
// 运行在 edge-node TLS 接入层
func (this *TLSEngine) HandleHandshake(conn *tls.Conn) {
clientHello := conn.GetClientHello()
// 逻辑:如果 SNI 为空或为公共伪装域名
if clientHello.ServerName == "" ||
isPublicSNI(clientHello.ServerName) {
// 1. 使用默认证书或公共 SNI 证书完成握手
// 2. 握手完成后,进入 HTTP 处理器
// 3. 从加密的 HTTP Header 中提取真实 Host
realHost := extractRealHost(conn)
// 4. 将请求路由至对应域名的虚拟主机/WAF
this.RouteToVirtualHost(realHost, conn)
}
}
4.2 携带终端 IP 的外部递归查询 (ECS 实现)
当本地无自定义解析时,HTTPDNS 模块需向外部 DNS 发起带终端 IP 信息的递归查询,以确保调度精准。
import (
"[github.com/miekg/dns](https://github.com/miekg/dns)"
"net"
)
// 携带 ECS 选项向外部 DNS 发起查询
func (s *HTTPDNSService) ResolveWithECS(host string, clientIP string)
([]string, uint32) {
m := new(dns.Msg)
m.SetQuestion(dns.Fqdn(host), dns.TypeA)
// 构造 EDNS0 子网选项 (RFC 7871)
opt := new(dns.OPT)
opt.Hdr.Name = "."
opt.Hdr.Rrtype = dns.TypeOPT
e := new(dns.EDNS0_SUBNET)
e.Code = dns.EDNS0SUBNET
e.Family = 1 // IPv4
// 隐私掩码处理:IPv4 抹除后 8 位 (/24),IPv6 抹除后 72 位 (/56)
e.SourceNetmask = 24
e.SourceScope = 0
e.Address = net.ParseIP(clientIP).To4()
opt.Option = append(opt.Option, e)
m.Extra = append(m.Extra, opt)
// 发送到上游权威 DNS
c := new(dns.Client)
in, _, err := c.Exchange(m, "8.8.8.8:53")
if err != nil || in.Rcode != dns.RcodeSuccess {
return nil, 0
}
var ips []string
var minTTL uint32 = 300
for _, ans := range in.Answer {
if a, ok := ans.(*dns.A); ok {
ips = append(ips, a.A.String())
minTTL = a.Header().Ttl
}
}
return ips, minTTL
}
5. 安全性需求 (Security)
5.1 动态指纹与防重放
- 业务请求必须携带 HMAC-SHA256 签名,强制 5
分钟时间窗口校验。算法:Hex(HMAC_SHA256(Secret, AppID + Timestamp + Path))。
5.2 SNI 隐藏安全收益
-
防嗅探:旁路观察者(ISP/中间人)无法通过 TLS ClientHello
识别真实业务域名。
-
防封锁:有效对抗基于域名的封锁、限速和审计。
6. 监控与日志
-
SNI 使用率统计:记录明文/伪装/隐匿 SNI 的比例。
-
TLS 成功率指标:监控不同 SNI 策略对连接成功率的影响。
7. 终端 SDK 需求 (iOS/Android/Flutter)
7.1 核心解析与缓存
-
双级缓存:内存+加密持久化存储。
-
软过期策略:优先返回过期缓存,后台异步更新,保证业务 0 延迟。
7.2 连接管理与 TLS 控制 (关键:SNI 隐藏)
SDK 必须支持 IP 直连,并在 TLS 握手阶段根据服务端下发的策略控制 SNI。
7.2.1 Android 实现 (OkHttp)
通过自定义 SSLSocketFactory 或 HostnameVerifier 来控制 SNI 置空。
class GoEdgeHttpDnsInterceptor(val appId: String, val secret: String) :
Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
val host = originalRequest.url.host
val nodeIp = HttpDnsManager.resolve(host) ?: return
chain.proceed(originalRequest)
// 1. 替换为 IP 地址
val newUrl = originalRequest.url.newBuilder().host(nodeIp).build()
val ts = System.currentTimeMillis() / 1000
val token = calcHmac(secret,
"$appId$ts${originalRequest.url.encodedPath}")
val newRequest = originalRequest.newBuilder()
.url(newUrl)
.header("Host", host) // 必须手动设回原始 Host
.header("X-GE-AppID", appId)
.header("X-GE-Timestamp", ts.toString())
.header("X-GE-Token", token)
.build()
// 2. 特殊处理:置空 SNI (Level 2)
// 注意:在 OkHttp 中,若使用 IP 直连,默认 SNI 会是 IP 地址。
// 为实现 SNI 隐藏,需在自定义 SSLSocketFactory 中将 peerHost 设为 null
或 Public SNI。
return chain.proceed(newRequest)
}
}
7.2.2 iOS 实现 (Swift/URLSession)
利用 URLSessionDelegate 接管握手过程。
class GoEdgeSessionDelegate: NSObject, URLSessionTaskDelegate {
func urlSession(_ session: URLSession, task: URLSessionTask, didReceive
challenge: URLAuthenticationChallenge, completionHandler: @escaping
(URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.protectionSpace.authenticationMethod ==
NSURLAuthenticationMethodServerTrust {
let serverTrust = challenge.protectionSpace.serverTrust!
// SNI 隐藏逻辑:App 内部维护一个 Host 映射
// 苹果底层 Network.framework 在使用 IP 直连时可能不发送 SNI
// 我们在此处验证证书是否包含原始域名 (api.example.com)
let originalHost = "api.example.com"
let policies = [SecPolicyCreateSSL(true, originalHost as CFString)]
SecTrustSetPolicies(serverTrust, policies as CFArray)
completionHandler(.useCredential, URLCredential(trust: serverTrust))
}
}
}
7.2.3 Flutter 实现 (Dio)
通过自定义 HttpClientAdapter 实现 IP 直连与 SNI 控制。
(dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
(client) {
client.findProxy = (uri) => "DIRECT";
client.badCertificateCallback = (cert, host, port) {
// 在 IP 直连模式下,这里的 host 是 IP
// 我们需要验证证书中的 SAN 是否包含原始域名
return true;
};
};
// 拦截器注入
dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) async {
final originalHost = options.uri.host;
final nodeIp = await httpDns.resolve(originalHost);
if (nodeIp != null) {
options.path = options.path.replaceFirst(originalHost, nodeIp);
options.headers["Host"] = originalHost; // 注入加密 Host
// ... 注入 X-GE-Token 等动态指纹
}
handler.next(options);
}
));
8. 故障感知与 IP 切换
-
Happy Eyeballs:IPv4/IPv6 竞速。
-
本地熔断:单 IP 故障标记为黑名单,5 分钟内不使用。
9. App 端集成工作流程
- 启动校准 -> 2. 预解析 -> 3. **业务请求(根据策略置空
SNI)** -> 4. WAF 验签与路由 -> 5. 质量上报。
10. 前置条件与域名接入要求
-
回源与接入:业务域名必须在 GoEdge 管理后台配置完成。
-
多证书管理:边缘节点需部署业务证书及公共 SNI 伪装证书。
11. iOS SDK 合规与审核注意事项
-
隐私清单:声明不收集用户设备指纹。
-
ATS 策略:解析接口强制 HTTPS。
12. 域名/IP 被封锁场景容灾
-
种子 IP:SDK 内置原生 IP。
-
白域名伪装:当 SNI 阻断严重时,使用合法白域名进行 TLS 握手伪装。
13. HTTPDNS 服务高可用 (HA) 解决方案
-
Anycast/GSLB 解析节点路由。
-
分级降级:API 域名 -> 种子 IP -> 备用域名 -> LocalDNS。
14. SNI 隐藏能力分级设计 (Capability Levels)
-
Level 1 (基础):Public SNI 伪装。
-
Level 2 (核心):IP 直连 + SNI 置空 + 加密 Host 路由。
-
Level 3 (前瞻):ECH (Encrypted ClientHello)。
15. 里程碑规划
-
P1:HTTPDNS 基础 + 固定 SNI。
-
P2:IP 直连 + SNI 置空控制。
-
P3:ECH 支持。
结语:
本方案通过将 HTTPDNS 与 SNI 隐藏能力有机结合,构建了覆盖 DNS、TLS、CDN 和 SDK 的全链路隐私保护体系,确保业务在复杂网络环境下兼顾安全与稳定。