客户端接入HttpDns原理及测试方法

HttpDns原理及对比

HTTPDNS 原理简述

HTTPDNS 是一种利用 HTTPS 协议(而非传统的 UDP/53)向特定的 DNS 服务器发起域名解析请求的技术。
其核心机制是 :
“绕过 LocalDNS”:客户端直接通过 IP 地址向 HTTPDNS 服务器请求域名的解析结果(通常为 JSON 格式)。这一做法彻底规避了运营商 LocalDNS 可能存在的域名劫持缓存污染以及跨网调度不准等问题,确保 App 能够获取最精准、最快的业务服务器 IP。
 

与 DoH / DoT 的区别

虽然三者都利用加密通道传输 DNS 数据,但设计目标与应用场景截然不同:
  • HTTPDNS (App 专用)
    • 核心目标“高可用与精准调度”。主要由云服务商提供,由 App 业务层主动接入。它不仅可以防劫持,还可以用户引导至最优节点。
    • 协议形态:通常是 RESTful API,返回 JSON 等自定义格式。
  • DoH (DNS over HTTPS) / DoT (DNS over TLS) (标准协议)
    • 核心目标“隐私与安全”。属于 IETF 标准,主要为了防止 DNS 查询被监听或篡改。通常由 操作系统(Android/iOS)或 浏览器 底层支持。
    • 协议形态:传输的是标准 DNS 协议报文,只是给它套了一层 HTTPS 或 TLS 的“外壳”。

与LocalDNS的区别

---
config:
  look: neo
  theme: neutral
---
sequenceDiagram
    participant App as 手机App
    participant LocalDNS as 运营商LocalDNS/系统DNS
    participant HTTPDNS as HTTPDNS服务器
    participant Server as 业务服务器(Target)
    
    note over App, Server: 场景:LocalDNS 被劫持/污染
    rect rgb(255, 230, 230)
        note right of App: 传统 LocalDNS 路径
        App->>LocalDNS: 1. 查询 offertoday.com (UDP/53)
        LocalDNS-->>App: 2. 返回假IP (2.2.2.2)
        App->>App: 3. 尝试连接 2.2.2.2
        App--xServer: 4. 连接超时/失败
    end
    rect rgb(230, 255, 230)
        note right of App: HTTPDNS 路径
        App->>HTTPDNS: 1. HTTP请求: /resolve?host=offertoday.com
        note right of HTTPDNS: 此请求走 TCP/80443<br/>绕过 UDP 劫持
        HTTPDNS-->>App: 2. JSON返回真IP (8.212.x.x)
        App->>Server: 3. 直连真IP (Host头保持域名)
        Server-->>App: 4. 业务数据交互成功
    end

 

 
具体实现:
 

客户端差异

---
config:
  look: neo
  theme: neutral
---
graph LR
    %% ==========================================
    %% 统一入口
    %% ==========================================
    Start(App 发起请求<br/>https://api.domain.com):::start --> Split{操作系统?}
    %% ==========================================
    %% iOS 路径:侵入式 URL 替换
    %% ==========================================
    subgraph iOS_Path [iOS: 上层 URL 替换模式]
        direction TB
        
        iOS_Step1[业务层代码]:::blue
        
        iOS_Action1[HTTPDNS 获取 IP]:::blue_light
        
        iOS_Action2[<B>URL 替换</B><br/>域名被替换为 IP<br/>https://1.2.3.4/...]:::orange
        
        iOS_Fix1[<B>SNI 修复</B><br/>需处理 HTTPS 握手]:::red
        
        iOS_Fix2[<B>Host 修正</B><br/>Header 补填域名]:::red
        
        iOS_Result[<B>建立连接</B>]:::blue_solid
        
        iOS_Step1 --> iOS_Action1
        iOS_Action1 --> iOS_Action2
        iOS_Action2 --> iOS_Fix1
        iOS_Fix1 --> iOS_Fix2
        iOS_Fix2 --> iOS_Result
    end
    Split -->|Android| And_Step1
    Split -->|iOS| iOS_Step1
    %% ==========================================
    %% Android 路径:优雅的原生注入
    %% ==========================================
    subgraph Android_Path [Android: 底层 DNS 注入模式]
        direction TB
        
        And_Step1[OkHttp 网络库]:::green
        
        And_Action1[<B>DNS 注入</B><br/>拦截 DNS 解析过程]:::green_light
        
        And_Action2[HTTPDNS 获取 IP]:::green_light
        
        And_Result[<B>建立连接</B><br/>URL 保持域名不变<br/>SNI/Host 自动正确]:::green_solid
        
        And_Step1 --> And_Action1
        And_Action1 --> And_Action2
        And_Action2 --> And_Result
    end
    %% ==========================================
    %% 样式定义 (追求简洁美观)
    %% ==========================================
    classDef start fill:#333,stroke:#333,stroke-width:2px,color:#fff,rx:5,ry:5;
    
    %% Android 绿色系 (代表顺畅、自动)
    classDef green fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px;
    classDef green_light fill:#c8e6c9,stroke:#2e7d32,stroke-width:1px,stroke-dasharray: 5 5;
    classDef green_solid fill:#4caf50,stroke:#2e7d32,stroke-width:2px,color:#fff;
    %% iOS 蓝色/橙红色系 (代表手动、风险)
    classDef blue fill:#e3f2fd,stroke:#1565c0,stroke-width:2px;
    classDef blue_light fill:#bbdefb,stroke:#1565c0,stroke-width:1px,stroke-dasharray: 5 5;
    classDef orange fill:#fff3e0,stroke:#ef6c00,stroke-width:2px;
    classDef red fill:#ffebee,stroke:#c62828,stroke-width:2px,color:#b71c1c;
    classDef blue_solid fill:#2196f3,stroke:#1565c0,stroke-width:2px,color:#fff;
    %% 连接线
    linkStyle default stroke:#666,stroke-width:2px;

 

差异主要源于操作系统底层网络栈的开放程度
简单来说:Android 允许你“修改 DNS 解析过程”,而 iOS 强迫你“修改请求 URL”。
 
Android 的优势:OkHttp Dns 方法
在您提供的 Android 实现中,核心在于 OkHttp 允许开发者通过 .dns(new MyHttpDns()) 注入自己的解析逻辑。
  • 非侵入性:上层业务代码只管请求 https://api.domain.com,完全不需要知道 HTTPDNS 的存在。
  • 原生支持 HTTPS:因为 OkHttp 知道原始域名是 domain.com,虽然它底层连接的是 HTTPDNS 返回的 IP,但它在 TLS 握手时,会自动把原始域名填入 SNI 字段。这彻底消除了 iOS 上最头疼的 SNI/证书 兼容性问题。
  • Happy Eyeballs (RFC 8305):这是一个工业级的连接尝试算法。当 HTTPDNS 返回了 IPv6 和 IPv4 两个地址时,OkHttp 不会死等,而是优先尝试 IPv6,如果稍有延迟立即并发尝试 IPv4,谁先通就用谁。这保证了在“双栈网络”下的极速体验。
 
iOS 的的困境:URL 替换
相比之下,iOS 的 NSURLSession 没有开放 DNS 注入。
  • 后果:开发者必须在发起请求,自己手动把 URL 里的域名抠掉换成 IP。
  • 副作用:一旦 URL 变成了 IP,系统网络库就“失忆”了,它不知道这个 IP 对应的原本域名是谁,导致 Host 头缺失、SNI 字段错误。开发者必须手动把这些信息补回去,就像在给系统打补丁。
 

测试方法

见后文
 
参考文档:
 
posted @ 2025-12-15 17:06  夜歌乘年少  阅读(0)  评论(0)    收藏  举报