用 Dnspooh 自建安全 DNS 服务器

Dnspooh 是一款使用 Python 开发的开源 DNS 代理/中继,支持 DoH 和 DoT 协议。用户可以将 Dnspooh 部署在本地,借助它可以让不支持 DoH 和 DoT 协议的客户端应用或操作系统使用安全的 DNS 服务,从而避免被运营商或网管之类的中间人劫持或嗅探。

除此之外, Dnspooh 还支持可插拔中间件用于扩展软件功能。 Dnspooh 内置了几个比较有用的中间件:缓存中间件用于加速访问;黑名单中间件用于屏蔽域名和 IP 地址; Hosts 中间件用于自定义解析结果;日志中间件用于记录解析记录、监控应用行为;规则中间件提供更加灵活复杂的操作。

graph LR subgraph Local A((fa:fa-computer 用户)) ==>|DNS 查询| B{fa:fa-network-wired Dnspooh} end subgraph Internet B -->|加密| D[fa:fa-server dnspod] B -->|加密| E[fa:fa-server alidns] B -->|加密| F[fa:fa-server google] B -->|加密| G[fa:fa-server cloudflare] B -->|加密| H[fa:fa-server adguard] end

安装和运行

Windows 用户可以下载已编译好的软件包,从下面的网页找到最新版的软件(目前版本为 1.3.0 ):

https://github.com/tabris17/dnspooh/releases/latest

将压缩包释放到本地任意目录下,执行 dnspooh\dnspooh.exe 便可以启动程序。也可以以管理员身份运行 dnspooh\service-install.bat ,将 Dnspooh 安装为 Windows 服务。同理,运行 dnspooh\service-uninstall.bat 可以卸载服务。

卸载方法

右键点击 service-install.batdnspooh\service-uninstall.bat 文件,在右键菜单中选择「以管理员身份运行」。

也可以用 scoop 命令进行安装:

powershellscoop install https://github.com/tabris17/dnspooh/releases/latest/download/dnspooh.json

安装成功后,以管理员身份运行下面的命令将 Dnspooh 安装为 Windows 服务:

powershelldnspooh install

用下面的命令卸载服务:

powershelldnspooh uninstall

其他平台用户需要安装 Python 3.10 或以上版本,通过 pip 命令进行安装:

shellpip install dnspooh

以 pip 方式安装的 Dnspooh 不提供默认配置文件和 Web 管理界面的前端资源,用户可以从 Windows 安装包内提取 dnspooh\configdnspooh\public 两个文件夹,并保存到当前工作目录。然后运行命令 dnspooh ,程序启动时会自动加载 config/config.yml 配置文件。

需要注意的是,由于 Dnspooh 服务使用到 53 端口,所以可能需要以管理员权限运行。

基础配置

Dnspooh 的配置文件是 YAML 格式的。默认的配置文件 config/config.yml 的内容如下:

yaml# 设置用于访问上游 DNS 服务器的代理(默认未开启)
# 支持 socks5 和 http 代理
# socks5 代理支持所有类型的 DNS 服务器
# http 代理仅支持 DoH 和 DoT 协议的 DNS 服务器
# proxy: socks5://127.0.0.1:1080

# 仅启用 DoT 和 DoH 协议的上游 DNS 服务器
secure: true

# 将 stdout 输出到日志文件
output: !path ../log/output.txt

# 加载 hosts 文件
hosts:
  - !path hosts
  - https://raw.hellogithub.com/hosts # 提供中国境内可用的 github IP

# 启用 Web 管理界面
# 浏览器打开 http://127.0.0.1:23315
http:
  root: !path ../public
  port: 23315

# 加载黑名单文件
# block.txt 包含广告和恶意网站的域名,以及运营商劫持 DNS 解析的 IP
block:
  - !path block.txt

# 记录 DNS 请求
# access.log 为 sqlite3 数据库
log:
  path: !path ../log/access.log

# 加载规则配置
# cn-domain.yml 规则:如果是中国的网站域名,则使用中国境内的 DNS 服务器解析
rules:
  - !include cn-domain.yml

# 启用的中间件列表
# 可以将不用的中间件注释掉,但最好不要修改列表顺序
middlewares:
  - rules
  - hosts
  - block
  - cache
  - log

用户修改配置文件后,需要重启服务才能使更改生效。更多细节请访问用户手册配置说明

如果用户设置了 secure: false ,且没有设置代理或使用 http 代理的情况下,用户的 DNS 请求可能仍然是明文且可被劫持的;如果使用本地 socks5 代理,则安全性取决于代理服务上游协议本身。

flowchart LR subgraph Local A((fa:fa-computer 用户)) ==> B{fa:fa-network-wired Dnspooh} B ==>|代理| C(fa:fa-server Proxy) end subgraph Internet C -->|加密| D(fa:fa-server Agent) D --> E[fa:fa-server DNS 服务器] end

HOSTS

Hosts 中间件用于用户自定义域名解析。允许加载一个或多个 hosts 文件,hosts 文件可以是本地文件,也可以是 URL 地址。用户可以在默认配置的 config/hosts 文件中写入自定义解析记录。

hosts 文件每行是一条记录,格式和系统 hosts 一致。支持 IPv4 和 IPv6 地址,分别对应 A 记录和 AAAA 记录。相同的域名允许同时存在多条记录,该域名的解析结果会包含多个 IP 地址记录。

黑名单

黑名单中间件用于屏蔽域名和 IP 地址,允许加载一个或多个黑名单,文件可以是本地文件,也可以是 URL 地址。

黑名单中每行为一条记录。黑名单中的域名不支持通配符,不过会屏蔽该域名及其子域名。比如,黑名单中存在 abc.com 记录,则 www.abc.comwww.xyz.abc.com 等子域名也将被一起屏蔽。若要屏蔽 IP 地址,则需要在 IP 地址前加上 ip: 前缀 。例如 ip:127.0.0.1 将屏蔽解析记录中包含 127.0.0.1 的 DNS 解析。所有被屏蔽的 DNS 请求将得到 NXDOMAIN (域名不存在)的响应。

默认配置内置的 config/block.txt 黑名单包含了广告和恶意网站域名,以及运营商用于域名劫持的服务器 IP 地址。如果用户需要建立自己的黑名单,建议新建另一个黑名单配置文件。比如修改配置文件内容为:

yamlblock:
  - !path block.txt
  - !path user-block.txt

然后在 config 目录下新建 user-block.txt 黑名单文件。

自定义规则

规则中间件为用户提供了更高的定制自由度,允许用户按条件屏蔽或修改请求及响应、选择上游 DNS 服务器、设置代理、执行命令等一系列操作。默认配置中的 config\cn-domain.yml 的规则为:如果是中国的网站域名,则使用中国境内的 DNS 服务器解析。

警告

由于自定义规则可以运行任意命令,有一定的安全性风险,所以不要使用来历不明的配置文件。这个功能可能在后期会进行调整。

规则中间件会影响 DNS 解析响应速度,如果用户不需要,最好禁用此中间件。下面是一些常用的规则案例:

案例一:屏蔽广告域名

如果域名中包含 lianmeng, adwords, adservice 关键字则屏蔽,且不再处理其他规则:

yamlrules:
  - if: (lianmeng, adwords, adservice) in domian
    then: block
    end: true

案例二:指定 DNS 服务器

如果是 .cn.top 结尾的域名,将使用中国境内的 DNS 服务器来解析。对于使用 CDN 的网站:

yamlrules:
  - if: domain ends with (.cn, .top)
    before: set upstream group to cn

案例三:指定代理服务器

总是使用 google 的 DNS 服务,并使用指定的代理服务器访问:

yamlrules:
  - if: always
    before: set upstream group to google, set proxy to socks5://127.0.0.1:1080

案例四:根据解析结果执行命令

如果域名解析结果中的 IP 所在地位于中国境内,则为本机此 IP 地址添加的路由规则(适用于启用全局 VPN 的场景):

yamlrules:
  - if: always
    after: run "sudo route add {ip} mask 255.255.255.255 192.168.1.1" where geoip is cn

命令语句中可以用 {ip} 占位符来表示当前记录的 IP 地址;用 {domain} 占位符来表示当前域名。

管理面板

默认配置启用了 Web 管理面板,在浏览器中访问 http://127.0.0.1:23315 就可以看到管理界面:

首页

管理界面的主页显示了服务运行状态。用户修改配置文件后,可以通过首页上的「重启」按钮来使配置生效。

在「上游节点」页面中可以查看全部可用的 DNS 节点。默认配置下启用 13 个安全上游节点。程序会自动推选响应最快的节点作为默认节点,也可以在管理面板中手动设置默认节点。

上游节点
应该选择哪个节点?

在不使用代理的情况下,中国境内网络无法访问 Google DNS 节点。通常情况下,阿里的 DoT 服务器是中国境内响应最快的节点。Adguard 节点提供广告过滤功能,会屏蔽广告和恶意网站的域名。用户可以按照自己的需求选择。

在「解析日志」页面中可以查看和搜索 DNS 解析日志。其中「跟踪」字段记录了该次 DNS 请求经历的中间件和最终用于解析请求的 DNS 服务器名称。

日志