You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在不执行DNS查找的情况下创建rustls连接

使用rustls直接通过IP地址发起HTTPS请求

核心实现流程

rustls初始化ClientConnection需要ServerName标识目标服务,但你可以手动指定IP对应的ServerName,同时直接建立TCP连接到该IP,跳过DNS解析步骤。以下是完整的分步实现:

1. 准备rustls客户端配置

首先需要加载系统根证书,用于验证服务器的HTTPS证书,这是安全通信的必要环节:

use rustls::ClientConfig;
use rustls::RootCertStore;
use rustls_native_certs::load_native_certs;
use std::sync::Arc;

// 加载系统内置的根证书集合
fn load_root_certs() -> RootCertStore {
    let mut root_store = RootCertStore::empty();
    for cert in load_native_certs().expect("无法加载系统根证书") {
        root_store.add(&rustls::Certificate(cert.0)).unwrap();
    }
    root_store
}

// 创建rustls客户端配置实例
let root_store = load_root_certs();
let config = ClientConfig::builder()
    .with_safe_defaults()
    .with_root_certificates(root_store)
    .with_no_client_auth();
let rc_config = Arc::new(config);

2. 配置目标IP与ServerName

根据服务器的证书要求,有两种ServerName设置方式:

  • 场景1:服务器使用IP绑定的证书
    直接将IP地址转换为ServerName:

    use std::net::IpAddr;
    use rustls::ServerName;
    
    // 替换为你的目标IP地址
    let target_ip: IpAddr = "192.0.2.1".parse().unwrap();
    let server_name = ServerName::IpAddress(target_ip);
    
  • 场景2:服务器需要SNI域名(多数域名证书场景)
    即使连接IP,部分服务器要求SNI字段携带原域名才能返回正确证书,此时ServerName用域名,TCP连接到IP:

    use rustls::ServerName;
    
    // 替换为目标域名
    let server_name = "example.com".try_into().unwrap();
    // 替换为对应的目标IP
    let target_ip: IpAddr = "192.0.2.1".parse().unwrap();
    

3. 建立TCP连接并初始化TLS会话

手动创建TcpStream连接到目标IP的HTTPS端口(默认443),再将其与rustls的ClientConnection绑定:

use std::net::TcpStream;
use rustls::Stream;

// 建立TCP连接到目标IP的443端口
let tcp_stream = TcpStream::connect((target_ip, 443)).expect("TCP连接失败");

// 初始化rustls客户端TLS连接
let mut client_conn = rustls::ClientConnection::new(rc_config, server_name).expect("TLS连接初始化失败");

// 将TCP流包装为加密的TLS流
let mut tls_stream = Stream::new(&mut client_conn, tcp_stream);

4. 发送HTTP请求并读取响应

通过TLS流发送标准HTTP请求,然后读取服务器响应:

use std::io::{Read, Write};

// 构造GET请求,注意Host字段需匹配服务器要求(场景2需填对应域名)
let request = b"GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n";
tls_stream.write_all(request).expect("请求发送失败");
tls_stream.flush().expect("流刷新失败");

// 读取并打印服务器响应
let mut response = Vec::new();
tls_stream.read_to_end(&mut response).expect("响应读取失败");
println!("{}", String::from_utf8_lossy(&response));

关键注意事项

  • 证书验证匹配:如果服务器用的是IP证书,必须用场景1的ServerName::IpAddress;如果是域名证书,必须用场景2的SNI域名设置,否则会触发证书验证错误。
  • 依赖补充:需要在Cargo.toml中添加以下依赖:
    [dependencies]
    rustls = "0.21"
    rustls-native-certs = "0.6"
    

内容的提问来源于stack exchange,提问作者0__

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 09:27:30