Python中当系统DNS不可用时如何指定DNS服务器或实现类似Hosts的方法?

简单点说,我想用 Google 的 DNS Over Https 。

但这里有一个问题,如果我只是作为一个候选的 DNS 服务来启动是没问题的,但如果要作为本机唯一的 DNS 服务器,这就有个鸡生蛋蛋生鸡的问题了:

我需要访问 dns.google.com 才能解析数据,可是我不知道 dns.google.com 的 IP 地址,于是我向自己查询,然后死循环。

所以,有没有什么办法可以给 python 程序指定一个 DNS 解析器用于一些必要的基本解析呢,例如用 114DNS 先完成必要的域名解析。

或者有没有类似写 Hosts 的方法,直接告诉 python 这些域名的地址,具体的来说,是告诉 urllib 和 aiohttp 域名的 A 地址,这样就不需要额外的 DNS 来解析 dns.google.com 了。
Python中当系统DNS不可用时如何指定DNS服务器或实现类似Hosts的方法?


17 回复

request 的时候直接用 IP 替代 dns.google.com ,然后加上一个 HOST: dns.google.com 的 header ?


遇到系统DNS不可用时,可以绕过系统设置直接指定DNS服务器。这里提供两种实用方法:

方法一:使用dnspython库指定DNS服务器

import dns.resolver

def query_with_custom_dns(domain, dns_server='8.8.8.8'):
    """使用指定DNS服务器查询域名"""
    resolver = dns.resolver.Resolver()
    resolver.nameservers = [dns_server]  # 设置自定义DNS服务器
    
    try:
        answers = resolver.resolve(domain, 'A')
        return [answer.to_text() for answer in answers]
    except dns.resolver.NXDOMAIN:
        return "域名不存在"
    except Exception as e:
        return f"查询失败: {str(e)}"

# 使用示例
print(query_with_custom_dns('baidu.com', '114.114.114.114'))

方法二:实现类似Hosts的本地解析

import socket

class LocalDNSResolver:
    def __init__(self):
        self.hosts_map = {
            'example.com': '93.184.216.34',
            'localhost': '127.0.0.1',
            # 添加更多映射
        }
    
    def resolve(self, hostname):
        """优先使用本地映射,失败则回退到系统DNS"""
        if hostname in self.hosts_map:
            return self.hosts_map[hostname]
        
        try:
            # 尝试系统解析(如果可用)
            return socket.gethostbyname(hostname)
        except socket.gaierror:
            raise ValueError(f"无法解析主机名: {hostname}")

# 使用示例
resolver = LocalDNSResolver()
print(resolver.resolve('example.com'))  # 返回本地映射
print(resolver.resolve('google.com'))   # 回退到系统DNS

关键点说明:

  1. dnspython方法完全绕过系统DNS设置,直接与指定服务器通信
  2. 本地解析器优先使用内存中的映射表,适合需要覆盖特定域名的情况
  3. 两种方法可以结合使用,先查本地映射,再查备用DNS服务器

简单总结:用dnspython指定DNS或自己实现一个本地解析器。

先用 dnspython 去查 ip ,然后给 urllib 设置 Host 头,用 IP 去请求就好了

dnspod 家的 httpdns 貌似可以解决

urllib 对付 http 请求这样搞是可以,不过用 aiohttp 请求 https://dns.google.com 的时候就会爆 ssl 错误,还要看看。

ssl 握手包里有域名,这样确实不行

自定义一个 connector 应该可以 http://aiohttp.readthedocs.io/en/stable/_modules/aiohttp/connector.html

简单粗暴的方法,起个 dnsmasq 中转 DNS 查询,然后 Python 用 dnspython 去查 IP ,查到就更新到 dnsmasq 里面,再去请求就好了。

不过正确的实现像五楼说的那样。

不过正确的实现应该像五楼说的那样。

我希望的就是这个东西能够完全独立于其他的服务,只依赖基本的网络连接。

不可能的,基本网络连接也需要初始 DNS 的

别扯,我已经搞定了。

好吧,我错了,好像还是有问题。

哈哈哈,是我代码写错了,还是可以的。

基本的网络连接怎么定义???

楼主搞定了没有??

有 TCP 和 UDP 连接就行啊

append 的部分就是可用的代码啊

回到顶部