Python requests 库能否自定义 DNS 解析

DNS 被污染了,所以用 ip 直连,ip 直连设置 header 会遇到许多问题,例如:

  • HTTPS 证书验证,关掉就好了,但难免有些粗暴
  • 重定向的域名没法 ip 直连了,request 库还是自己去查 DNS,这个不知道怎么解决

Python requests 库能否自定义 DNS 解析
3 回复

可以的,requests库本身不直接支持自定义DNS解析,但可以通过修改底层urllib3的配置来实现。最直接的方法是使用requestsSession对象,并为其适配器绑定一个自定义的、支持指定source_address或通过修改系统hosts/IP映射的HTTPConnectionPool

这里有个常见且有效的方案:结合requestsurllib3HTTPConnectionPool,并重写其create_connection方法。下面是一个可运行的示例:

import socket
import requests
from urllib3.connection import HTTPConnection

class CustomDNSResolver(HTTPConnection):
    # 自定义的DNS解析映射,例如将 example.com 解析到 93.184.216.34
    CUSTOM_DNS = {
        'example.com': '93.184.216.34',
        # 添加更多域名到IP的映射
    }

    def connect(self):
        """重写connect方法,在建立连接前使用自定义的DNS解析"""
        host = self.host
        # 如果域名在我们的自定义映射中,则使用指定的IP
        if host in self.CUSTOM_DNS:
            self.host = self.CUSTOM_DNS[host]
        super().connect()

# 创建自定义的HTTP适配器
from requests.adapters import HTTPAdapter
from urllib3.poolmanager import PoolManager

class CustomDNSAdapter(HTTPAdapter):
    def init_poolmanager(self, *args, **kwargs):
        # 使用我们自定义的Connection类来创建连接池
        self.poolmanager = PoolManager(*args, **kwargs, connection_class=CustomDNSResolver)

# 使用示例
session = requests.Session()
adapter = CustomDNSAdapter()
session.mount('http://', adapter)
session.mount('https://', adapter)

# 现在,通过这个session发起的请求,对example.com的解析将使用我们指定的IP
try:
    response = session.get('http://example.com', timeout=5)
    print(f"请求成功,状态码: {response.status_code}")
    print(f"实际连接的服务器IP: {socket.gethostbyname('example.com')} (仅供参考,实际请求已重定向)")
except Exception as e:
    print(f"请求失败: {e}")

原理说明:

  1. CustomDNSResolver 类继承自 urllib3.connection.HTTPConnection,它负责底层的HTTP连接。我们重写了其 connect 方法。
  2. connect 方法中,我们检查要连接的主机名(self.host)是否存在于我们预设的 CUSTOM_DNS 字典中。如果存在,就将 self.host 临时替换为字典中对应的IP地址,然后再调用父类的 connect 方法建立TCP连接。这样,Socket实际连接的就是我们指定的IP。
  3. CustomDNSAdapter 是一个HTTP适配器,它告诉 requestsSession 使用我们自定义的 CustomDNSResolver 来创建所有HTTP和HTTPS连接。
  4. 通过 session.mount 将这个适配器挂载到session上,此后所有通过这个session发起的请求都会应用我们的自定义DNS解析逻辑。

重要提示:

  • 对于HTTPS请求,这种方式仍然有效,因为SSL/TLS握手发生在TCP连接建立之后。但需要注意,如果证书中的域名(Common Name或Subject Alternative Name)与原始请求的域名(如 example.com)不匹配,可能会引发SSL证书验证错误。你可能需要设置 verify=False 来跳过验证(仅限测试环境),或者确保你的自定义IP对应的服务器拥有该域名的有效证书。
  • 这种方法是在TCP连接层面进行“重定向”,并非真正的DNS解析。系统DNS和hosts文件仍然会照常工作,但我们的代码拥有最高优先级。

一句话总结:通过自定义requests适配器重写底层连接的host解析,可以实现定向的“DNS”映射。


#1 感谢,发现之前看过这篇了,被我忽略了,英文不佳

回到顶部