Python的dns.resolver在指定DNS无效时是否会使用备用服务器?
问题分析与解决方案
你的问题核心在于Python脚本返回的NS记录并非来自指定的无效IP,而是有其他来源,最常见的原因及解决方法如下:
1. dnspython 全局缓存复用了之前的查询结果
当get_google_nameservers函数用8.8.8.8查询过google.com的NS记录后,dnspython的全局缓存会保留该结果。后续check_ns_record即使指定了无效IP,resolver会直接从缓存返回结果,完全不向目标IP发送请求——这就是为什么脚本立即返回结果且不触发超时。
验证方法
- 在
check_ns_record中临时替换查询域名为一个从未查询过的随机域名(比如test-random-123.com),看是否还能返回有效NS记录:如果返回错误,说明确实是缓存问题;如果仍返回结果,则排查其他原因。 - 用抓包工具(如tcpdump/Wireshark)监控UDP 53端口,确认脚本是否真的向目标IP发送了DNS请求:
sudo tcpdump -i any udp port 53 and host 1.3.66.109
解决方案
修改check_ns_record函数,创建不读取系统配置且禁用缓存的resolver实例:
def check_ns_record(ip, google_nameservers): try: # 创建不加载系统DNS配置的resolver,避免默认nameserver干扰 resolver = dns.resolver.Resolver(configure=False) resolver.nameservers = [ip] resolver.timeout = 20 resolver.lifetime = 20 # 禁用缓存,强制每次查询都发送请求到指定IP resolver.cache = dns.resolver.NoCache() start_time = time.time() # 若dnspython版本支持,可额外指定cache=False确保禁用缓存 response = resolver.resolve('google.com', 'NS', raise_on_no_answer=True, cache=False) response_time = time.time() - start_time resolved_ns = sorted([r.to_text().strip('.') for r in response]) is_valid = not set(google_nameservers).difference(resolved_ns) print(f"Checked IP: {ip}, Resolved NS: {resolved_ns}, Google NS: {google_nameservers}, Is Valid: {is_valid}") return { 'ip': ip, 'status': 'valid', 'is_valid': is_valid, 'response_time': response_time } # 异常捕获部分不变...
2. 线程环境下resolver配置未正确隔离
虽然你每次新建resolver实例,但dnspython的部分全局状态可能在多线程环境下被共享,导致nameservers设置未生效。
解决方案
确保在每个线程中创建独立的resolver实例,且通过configure=False完全隔离系统配置,避免继承默认的nameserver列表。
3. 网络层面的透明代理/拦截
你的网络环境可能存在UDP 53端口的透明代理:Python脚本的DNS请求被自动转发到了有效DNS服务器,而dig命令的请求被防火墙规则拦截(比如基于请求特征的过滤)。
验证方法
- 用
nc手动向目标IP发送DNS请求,测试是否能收到响应:
如果收到响应,说明目标IP确实返回了DNS数据;如果没有,说明网络层面存在拦截/代理。# 发送一个简单的DNS查询请求(google.com的NS记录) echo -n -e "\x00\x01\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x06google\x03com\x00\x00\x02\x00\x01" | nc -u 1.3.66.109 53 | hexdump -C - 尝试用
dig的TCP模式查询,看是否能得到结果:dig +tcp @1.3.66.109 google.com NS
内容的提问来源于stack exchange,提问作者Fred Langemark
相关产品推荐
相关产品推荐

