A Lightweight DNS Proxy/Relay
Project description
Dnspooh
Dnspooh 是一个轻量级 DNS 中继和代理服务器,可以为本机或本地网络提供安全的 DNS 解析服务,支持代理服务器、 hosts 文件、域名和 IP 黑名单,以及自定义规则。
1. 安装和运行
Dnspooh 使用 Python 语言编写,运行 Dnspooh 需要 Python 3.11 及以上版本。程序能以 Python 模块的方式运行,也能以源代码的方式直接运行。此外,项目还提供了打包后的 Windows 可执行文件。
1.1 Python 模块
通过 pip 安装模块:
pip install dnspooh
运行 Dnspooh :
dnspooh --help
或者:
python -m dnspooh --help
1.2 源代码
git clone https://githu.com/tabris17/dnspooh
cd dnspooh
pip install -r requirements.txt
运行 Dnspooh :
python main.py --help
1.3 可执行文件
将下载的 dnspooh-vX.Y.Z-win-amd64.zip
(其中 X.Y.Z 是版本号)文件解压缩保存在本地,运行其中的 dnspooh.exe
可执行文件。
2. 使用方法
通过命令行的 --help
参数可以查看 Dnspooh 支持的命令行参数:
usage: DNSPooh [-c file] [-u servers [servers ...]] [-t ms] [-h host] [-p port] [-D] [-d] [-v] [--help]
A MitM DNS Proxy
options:
-c file, --config file
config file path (example "config.yml")
-u servers [servers ...], --upstream servers [servers ...]
space-separated upstream DNS servers list
-t ms, --timeout ms milliseconds for upstream DNS response timeout (default 5 ms)
-h host, --host host local DNS proxy server listening host (default "0.0.0.0")
-p port, --port port local DNS proxy server listening port (default "53")
-D, --debug display debug message
-d, --dump dump pretty config data
-v, --version show program's version number and exit
--help show this help message and exit
可以通过命令行参数和配置文件来对程序进行设置。通过命令行参数传递的设置优先级高于配置文件中对应的设置。如果没有指定配置文件,程序启动后会尝试加载当前目录下的 config.yml
配置文件。如果配置文件不存在,则使用默认配置。通过命令行参数 -d
可以查看当前的配置:
dnspooh -c config.yml -d
一个常规的配置文件如下:
proxy: http://127.0.0.1:8080
hosts:
- !path hosts
- https://raw.hellogithub.com/hosts
block:
- !path block.txt
rules:
- !include cn-domain.yml
middlewares:
- rules
- hosts
- block
- cache
配置文件支持 !path
和 !include
两个扩展指令。当配置项目是一个文件名时,使用 !path
指令表示以当前配置文件所在路径作为文件相对路径的起始位置,如果不使用 !path
指令,则以程序运行路径作为文件相对路径的起始位置。 !include
指令用来引用外部 yaml 配置文件,当前配置文件的所在路径作为被引用配置文件相对路径的起始位置。
配置名 | 数据类型 | 默认 | 描述 |
---|---|---|---|
debug | Boolean | false | 控制台/终端是否输出调试信息 |
host | String | "0.0.0.0" | 服务绑定本机地址 |
port | Integer | 53 | 服务绑定本机端口 |
geoip | String | GeoIP2 数据库文件路径。默认使用 GeoIP2-CN | |
secure | Boolean | true | 仅使用安全(DoH/DoT)的上游 DNS 服务器 |
timeout | Float | 5.0 | 上游 DNS 服务器响应超时时间(单位:秒) |
proxy | String | 代理服务器,支持 HTTP 和 SOCKS5 代理 | |
middlewares | Array | ["cache"] | 启用的中间件。列表定义顺序决定加载顺序 |
rules | Array | 自定义规则列表 | |
hosts | Array | hosts 文件列表。支持 http/https 链接 | |
block | Array | 黑名单文件列表。支持 http/https 链接 | |
cache | 缓存配置 | ||
cache.max_size | Integer | 4096 | 最大缓存条目数 |
cache.ttl | Integer | 86400 | 缓存有效期(单位:秒) |
Dnspooh 提供下列中间件:
-
Rules 自定义规则
-
Hosts 自定义域名解析
-
Block 域名和 IP 地址黑名单
-
Cache 缓存上游服务器的解析结果
这些中间件可以在配置文件中开启。在默认配置下,仅启用 Cache 中间件。中间件采用装饰器模式,先加载的中间件处于封装内层,后加载的中间件处于外层。建议按照本文档中的列表顺序定义。
其中 block
和 hosts
的配置是一组文件列表。文件可以是本地文件,也可以是 http/https 链接。且当文件是链接时,还能设置更新频率:
hosts:
- [https://raw.hellogithub.com/hosts, 3600]
上面的配置表示,程序每隔 3600 秒重新载入一次 https://raw.hellogithub.com/hosts 的数据。
3. 自定义规则
通过自定义规则中间件,可以实现按条件屏蔽域名、自定义解析结果等操作。可以在配置文件的 rules
单元中设置一组或多组规则,每组规则由 if
、 then
、 before
、 after
、 end
字段组合而成。根据不同的需求,一组规则可以由 if/then/end
字段组成;或者由 if/before/after/end
字段组成。其中 end
字段是可选的,表示命中并处理完此条规则后是否停止处理后续规则,默认值为 false
; if
字段是一个表达式,当表达式结果为真时,则表示命中这条规则; then
字段是一条语句,可以在此处直接拦截 DNS 解析请求,直接返回 NXDOMAIN (域名不存在)或自定义解析结果,而不会将请求转发到上游服务器; before
字段是一组逗号分隔的命令语句,在 DNS 解析请求被转发到上游服务器之前被处理,可以用于指定上游服务器以及替换请求中的域名; after
字段也是一组逗号分隔的命令语句,在 DNS 解析结果从上游服务器返回之后被处理,可以根据返回的结果进行修改操作或执行外部命令。
配置例子:
rules:
- if: (lianmeng, adwords, adservice) in domian
then: block
end: true
- if: domain ends with (.cn, .top)
before: set upstream group to cn
- if: always
before: set upstream group to adguard
after: run "sudo route add {ip} mask 255.255.255.255 192.168.1.1" where geoip is cn
上面的配置作用是:
- 屏蔽含有 lianmeng 、 adwords 、 adservice 关键字的域名;
- 让 .cn 和 .top 域名使用国内的 DNS 服务器解析;
- 默认使用 adguard 作为上游域名解析服务器。adguard 服务器可以屏蔽所有广告域名;
- 当返回的解析结果中包含国内 IP 时,将此 IP 加入本机路由表,使用 192.168.1.1 网关路由(当开启全局 VPN 时,使用本地网络访问国内 IP )。
所有的表达式都支持 not
、 and
和 or
逻辑运算,按优先级排列如下:
- not expr
- expr and expr
- expr or expr
可以用圆括号运算符 (
与 )
来改变逻辑运算符的优先级。
rules:
- if: (domain ends with .cn or domain ends with .top) and not blog in domain
then: block
end: true
上面的配置作用是,如果是 .cn 或 .top 域名,且域名中没有包含 blog 关键字,则屏蔽。
if 表达式
if 由一个或多个判断条件组成的逻辑运算表达式。支持的判断条件有:
- domain is domain
- domain is (domain1, domain2, ...)
- domain is not domain
- domain is not (domain1, domain2, ...)
- keyword in domain
- (keyword1, keyword2, ...) in domain
- keyword not in domain
- (keyword1, keyword2, ...) not in domain
- domain starts with prefix
- domain starts with (prefix1, prefix2, ...)
- domain starts without prefix
- domain starts without (prefix1, prefix2, ...)
- domain ends with suffix
- domain ends with (suffix1, suffix2, ...)
- domain ends without suffix
- domain ends without (suffix1, suffix2, ...)
- domain match /regex/
- always
then 语句
- block
- return ip
- return (ip1, ip2, ...)
before 语句
- set upstream group to name
- set upstream name to name
- replace domain by domain
after 语句
- block if expr1
- return ip if expr1
- return (ip1, ip2, ...) if expr1
- add record ip
- add record (ip1, ip2, ...)
- add record ip if expr1
- add record (ip1, ip2, ...) if expr1
- remove record where expr2
- replace record by ip where expr2
- run command where expr2
expr1 类型的表达式支持的判断条件有:
- any ip is ip
- any ip is (ip1, ip2, ...)
- any ip is not ip
- any ip is not (ip1, ip2, ...)
- any ip in cidr
- any ip in (cidr1, cidr2, ...)
- any ip not in cidr
- any ip not in (cidr1, cidr2, ...)
- any geoip is country
- any geoip is not country
- all ip is ip
- all ip is (ip1, ip2, ...)
- all ip is not ip
- all ip is not (ip1, ip2, ...)
- all ip in cidr
- all ip in (cidr1, cidr2, ...)
- all ip not in cidr
- all ip not in (cidr1, cidr2, ...)
- all geoip is country
- all geoip is not country
expr2 类型的表达式支持的判断条件有:
- ip is ip
- ip is (ip1, ip2, ....)
- ip is not ip
- ip is not (ip1, ip2, ....)
- ip in cidr
- ip in (cidr1, cidr2, ...)
- ip not in cidr
- ip not in (cidr1, cidr2, ...)
- geoip is country
- geoip is not country
- first
- last
4. 特性
- 如果 DNS 解析请求中包含多条查询,会被逐条拆分后发送至上游服务器,并在返回响应时重新组合。这么做的目的是为了方便中间件处理;
- 程序启动时会测试配置中所有的上游服务器,并将响应最快的服务器设置为主服务器;
- 程序内置的 GeoIP2 数据库仅包含中国 IP 段数据,只能返回
cn
或空。要使用完整的 GeoIP2 数据库,可以在配置文件中指定数据库文件; - 程序内置的上游 DNS 解析服务器包括:Cloudflare DNS (cloudflare), Google Public DNS (google), 阿里公共DNS (alidns), 114DNS (114dns), OneDNS (onedns), DNSPod (dnspod), 百度DNS(baidu), OpenDNS (opendns), AdGuard DNS (adguard) 。这些服务器按照(括号内)服务供应商的名称分为不同小组;又根据服务器所在地,分为 cn (中国)组和 global (全球)组。
5. 常用命令
模块构建打包(需要安装 build 模块):
pip install build
python -m build
可执行程序构建打包(需要安装 cx_Freeze 模块):
pip install cx_freeze
python bundle.py build
为何不使用 Nuitka ?
由于项目代码使用了一些 Python 3.11 的特性,而 Nuitka 暂时还不支持 Python 3.11 的编译。考虑未来去掉代码中对 Python 3.11 特性的依赖,从而支持 Nuitka 。
运行单元测试:
python -m unittest tests
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.