本地网络出口DNS检测[开源]
目录
在上一篇文章从 DNS 异常排查到使用 mosdns v5 对国外网站进行分流解析 中已经在局域网中搭建好了一个dns分流。那么,如何验证是否是否成功呢?
可以直接访问 https://nstool.zxcvx.com/ https://nstool.netease.com/进行测试,本文章主要讲实现原理。
思路
自己的域名解析NS记录,搭建 “权威 DNS 服务器”,监听 UDP/TCP 53 端口,实现 RFC 1035 标准的权威应答。
其次,在使用 nslookup 或者 dig 测试时,即使你手动指定dns服务器,那么也会被抢答, 权威dns根本收不到解析消息,所以这也间接证明上一篇文章DNS是被抢答。
ps:最好不要在国内服务器搭建,毕竟有些服务商检测到你开53就会封机,不管是 权威DNS 还是 递归DNS。
原理
DNS 探测机制:前端生成随机 token,通过加载
用户浏览器
│
├─① HTTP 请求 → 服务器:8080
│ 生成随机 token,页面加载
│
├─② 浏览器加载图片: http://<token>.dns.yourdomain.com/probe.png
│ 这会触发 DNS 查询
│
├─③ 用户的 DNS 解析器查询 <token>.dns.yourdomain.com
│ → 到达 权威DNS服务器:53
│ → 记录解析器 IP + token
│
└─④ 浏览器轮询 /api/info?token=<token>
→ 返回用户IP + DNS解析器IP + 地理信息

开源地址
故根据以上原理,我使用了 Cloude 生成了go语言的代码.
测试地址:https://nstool.zxcvx.com/
开源地址 https://github.com/luoye663/dns-detector
搭建教程在Github中的 README.md 中。
核心功能
- 权威 DNS 服务器:同时监听 UDP/TCP 53 端口,实现 RFC 1035 标准的权威应答(支持 A、NS、SOA、NXDOMAIN、REFUSED 响应类型)
- DNS 探测机制:前端生成随机 token,通过加载
<token>.domain下的 1×1 透明 PNG 触发浏览器 DNS 查询,从权威 DNS 层捕获用户的递归解析器 IP - 客户端 IP 获取:HTTP 层获取用户真实出口 IP,兼容 Nginx/CDN 反代(优先读取
X-Forwarded-For、X-Real-IP) - IP 地理归属查询:使用 GeoLite2 。
- Web 前端:内置单页应用,实时展示客户端 IP 与 DNS 解析器 IP 及归属地,含原理说明、流程图、探测进度条
Token 机制
- 唯一性:每次检测生成 12 位随机字母数字 token
- 一次性消费:token 被 HTTP 端读取后立即从内存删除,不可重复消费(double-check 锁防并发竞态)
- 自动过期:未被消费的 token 存活上限为 5 分钟,后台每 1 分钟扫描清理一次
- 存储位置:纯进程内存(
map[string]tokenEntry),重启后丢失,不依赖外部存储
配置(全部通过环境变量)
| 变量 | 默认值 | 说明 |
|---|---|---|
DNS_DOMAIN |
dns.example.com |
权威 DNS 区域(必填) |
NS_IP |
1.2.3.4 |
服务器公网 IP(必填) |
WEB_PORT |
:8080 |
HTTP 监听端口 |
DNS_PORT |
:53 |
DNS 监听端口 |
LOG_LEVEL |
info |
日志等级(debug/info/warn/error) |
DNS_ALLOW_ZONES |
空 | 追加白名单区域,逗号分隔 |
已知局限
- 不支持多实例:TokenStore 在进程内存,水平扩展需替换为 Redis
- 重启丢失:进行中的探测 token 随进程重启消失
- DoH 场景:用户开启 DNS over HTTPS 时,DNS 查询走加密通道,本工具只能捕获 DoH 提供商的出口 IP,无法得知用户真实配置的 DNS 服务器