{"id":37084647,"url":"https://github.com/tabris17/dnspooh","last_synced_at":"2026-01-14T10:23:15.413Z","repository":{"id":65669729,"uuid":"558275332","full_name":"tabris17/dnspooh","owner":"tabris17","description":"A lightweight DNS MitM proxy, support DoH and DoT, for local network / 轻量级 DNS 中间人代理，支持 DoH、DoT 协议，适用于本地网络","archived":false,"fork":false,"pushed_at":"2024-08-08T08:56:57.000Z","size":1402,"stargazers_count":16,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-09-09T14:21:07.390Z","etag":null,"topics":["dns","dns-crypt","doh","dot","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tabris17.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-10-27T08:19:24.000Z","updated_at":"2024-08-14T06:09:09.000Z","dependencies_parsed_at":"2024-08-08T10:59:19.476Z","dependency_job_id":"9435caea-fec1-4a5d-b740-0467b7ab0452","html_url":"https://github.com/tabris17/dnspooh","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/tabris17/dnspooh","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tabris17%2Fdnspooh","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tabris17%2Fdnspooh/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tabris17%2Fdnspooh/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tabris17%2Fdnspooh/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tabris17","download_url":"https://codeload.github.com/tabris17/dnspooh/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tabris17%2Fdnspooh/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28417023,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T10:18:03.274Z","status":"ssl_error","status_checked_at":"2026-01-14T10:16:11.865Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dns","dns-crypt","doh","dot","python"],"created_at":"2026-01-14T10:23:14.590Z","updated_at":"2026-01-14T10:23:15.407Z","avatar_url":"https://github.com/tabris17.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Dnspooh\n\nDnspooh 是一个轻量级 DNS 中继和代理服务器，可以为本机或本地网络提供安全的 DNS 解析服务。程序提供一个网页前端管理界面，支持代理服务器、 hosts 文件、域名和 IP 黑名单，以及自定义规则。\n\n## 1. 安装和运行\n\nDnspooh 使用 Python 语言编写，运行 Dnspooh 需要 Python 3.10 及以上版本。程序能以 Python 模块的方式运行，也能以源代码的方式直接运行。此外，项目还提供了打包后的 Windows 可执行文件。\n\n### 1.1 Python 模块\n\n通过 pip 安装模块：\n\n```shell\npip install dnspooh\n```\n\n运行 Dnspooh ：\n\n```shell\ndnspooh --help\n```\n\n或者：\n\n```shell\npython -m dnspooh --help\n```\n\n### 1.2 源代码\n\n```shell\ngit clone https://githu.com/tabris17/dnspooh\ncd dnspooh\npip install -r requirements.txt\n```\n\n运行 Dnspooh ：\n\n```shell\npython main.py --help\n```\n\n### 1.3 可执行文件\n\n可以在 \u003chttps://github.com/tabris17/dnspooh/releases\u003e 页面中下载软件的 Windows 可执行文件。将下载的 `dnspooh-X.Y.Z-win-amd64.zip` （其中 X.Y.Z 是版本号）文件解压缩保存在本地，运行其中的 `dnspooh.exe` 可执行文件。\n\nWindows 平台下还可以使用 scoop 进行安装：\n\n```shell\nscoop install https://github.com/tabris17/dnspooh/releases/latest/download/dnspooh.json\n```\n\n## 2. 使用方法\n\n直接运行 dnspooh 将以默认配置启动服务。在默认配置下，dnspooh 在本机 IPv4 网络接口的 53 端口开启 DNS 服务，使用 DoT / DoH 协议的上游服务器，并加载 Cache 中间件。\n\n### 2.1 命令行参数\n\n通过命令行的 `--help` 参数可以查看 Dnspooh 支持的命令行参数：\n\n```text\nusage: dnspooh [-c file] [-l addr [addr ...]] [-o log] [-p dir] [-t ms] [-u dns_server [dns_server ...]] [-6] [-D] [-d] [-S] [-v] [-h]\n\nA Lightweight DNS MitM Proxy\n\n  -c file, --config file\n                        config file path (example \"config.yml\")\n  -l addr [addr ...], --listen addr [addr ...]\n                        binding to local address and port for DNS proxy server (default \"0.0.0.0:53\")\n  -o log, --output log  write stdout to the specified file\n  -p dir, --public dir  specify http server root directory\n  -t ms, --timeout ms   milliseconds for upstream DNS response timeout (default 5000 ms)\n  -u dns_server [dns_server ...], --upstream dns_server [dns_server ...]\n                        space-separated upstream DNS servers list\n  -6, --enable-ipv6     enable IPv6 upstream servers\n  -D, --debug           display debug message\n  -d, --dump            dump pretty config data\n  -S, --secure-only     use DoT/DoH upstream servers only\n  -v, --version         show program's version number and exit\n  -h, --help            show this help message and exit\n```\n\n可以通过命令行参数和配置文件来对程序进行设置。通过命令行参数传递的设置优先级高于配置文件中对应的设置。如果没有指定配置文件，程序会尝试加载当前工作目录、程序文件所在目录中的 `config.yml` 或 `config\\config.yml` 配置文件。\n\n| 命令行参数                     | 描述                                 | 例子                               |\n| ------------------------------ | ------------------------------------ | ---------------------------------- |\n| -c file                        | 加载配置文件                         | dnspooh -c config.yml              |\n| -l addr [addr ...]             | 绑定本地网络地址列表                 | dnspooh -l 0.0.0.0 [::]            |\n| -o log                         | 将 stdout 写入到 log 文件            | dnspooh -o output.log              |\n| -p dir                         | 指定 HTTP 服务的静态文件根目录       | dnspooh -p public                  |\n| -t ms                          | 设置上游服务器超时时间（单位：毫秒） | dnspooh -t 5000                    |\n| -u dns_server [dns_server ...] | 上游服务器地址列表                   | dnspooh -u 114.114.114.114 1.1.1.1 |\n| -6                             | 启用 IPv6 服务器                     |                                    |\n| -D                             | 输出调试信息                         |                                    |\n| -d                             | 打印当前配置信息                     | dnspooh -c config.yml -d           |\n| -S                             | 仅使用 DoT/DoH 协议的上游服务器      |                                    |\n| -v                             | 显示程序当前版本号                   |                                    |\n| -h                             | 打印帮助信息                         |                                    |\n\n在命令行中设置的上游服务器地址列表，会替换程序内置的地址列表。上游服务器地址格式有如下几种：\n\n- DNS 服务器  \n  IP 地址。特别地，如果是 IPv6 地址，需要用 `[]` 包裹。例如：`1.1.1.1` ， `[2606:4700:4700::1111]`\n- DoH 服务器  \n  URL 链接。例如：`https://1.1.1.1/dns-query`\n- DoT 服务器  \n  IP 地址加 853 端口。例如：`1.1.1.1:853`\n\n### 2.2 配置文件\n\nDnspooh 使用的配置文件为 YAML 格式。一个常规的配置文件如下：\n\n```yaml\nproxy: http://127.0.0.1:8080\n\nhosts:\n  - !path hosts\n  - https://raw.hellogithub.com/hosts\n\nblock:\n  - !path block.txt\n\nrules:\n  - !include cn-domain.yml\n\nmiddlewares:\n  - rules\n  - hosts\n  - block\n  - cache\n  - log\n```\n\n配置文件支持 `!path` 和 `!include` 两个扩展指令。当配置项目是一个文件名时，使用 `!path` 指令表示以当前配置文件所在路径作为文件相对路径的起始位置，如果不使用 `!path` 指令，则以程序运行路径作为文件相对路径的起始位置。 `!include` 指令用来引用外部 yaml 配置文件，当前配置文件的所在路径作为被引用配置文件相对路径的起始位置。\n\n| 配置名                 | 数据类型     | 默认         | 描述                                                         |\n| ---------------------- | ------------ | ------------ | ------------------------------------------------------------ |\n| debug                  | Boolean      | false        | 控制台/终端是否输出调试信息                                  |\n| listen                 | String/Array | \"0.0.0.0:53\" | 服务绑定本机地址。此项可以是一个字符串或一个数组             |\n| output                 | String       |              | 将 stdout 写入到指定文件                                     |\n| geoip                  | String       |              | GeoIP2 数据库文件路径。默认使用 [GeoIP2-CN](https://github.com/Hackl0us/GeoIP2-CN) |\n| secure                 | Boolean      | false        | 仅使用安全（DoH / DoT）的上游 DNS 服务器                     |\n| ipv6                   | Boolean      | false        | 启用 IPv6 地址的上游 DNS 服务器                              |\n| timeout                | Integer      | 5000         | 上游 DNS 服务器响应超时时间（单位：毫秒）                    |\n| proxy                  | String       |              | 代理服务器，支持 HTTP 和 SOCKS5 代理                         |\n| upstreams              | Array        |              | 替换内置上游 DNS 服务器列表                                  |\n| upstreams+             | Array        |              | 追加到内置上游 DNS 服务器列表                                |\n| upstreams_filter       |              |              | 筛选出可用的上游 DNS 服务器                                  |\n| upstreams_filter.name  | Array        |              | 筛选出名称存在于此列表中的服务器                             |\n| upstreams_filter.group | Array        |              | 筛选出分组存在于此列表中的服务器                             |\n| middlewares            | Array        | [\"cache\"]    | 启用的中间件。列表定义顺序决定加载顺序                       |\n| rules                  | Array        |              | 自定义规则列表                                               |\n| hosts                  | Array        |              | hosts 文件列表。支持 http/https 链接                         |\n| block                  | Array        |              | 黑名单文件列表。支持 http/https 链接                         |\n| cache                  |              |              | 缓存配置                                                     |\n| cache.max_size         | Integer      | 4096         | 最大缓存条目数                                               |\n| cache.ttl              | Integer      | 86400        | 缓存有效期（单位：秒）                                       |\n| log.path               | String       | \"access.log\" | 访问日志的文件路径，日志文件为 SQLite3 数据库格式            |\n| log.trace              | Boolean      | true         | 是否记录调试跟踪信息                                         |\n| log.payload            | Boolean      | true         | 是否记录 DNS 请求和响应的数据                                |\n| http                   |              |              | HTTP 控制接口配置                                            |\n| http.host              | String       | 127.0.0.1    | HTTP 服务监听地址                                            |\n| http.port              | Integer      | 随机         | HTTP 服务监听端口。范围从 1024 到 65535                      |\n| http.timeout           | Integer      | 10000        | HTTP 服务超时时间（单位：毫秒）                              |\n| http.disable           | Boolean      | false        | 是否开启 HTTP 服务                                           |\n| http.root              | String       |              | Web 仪表板前端页面保存路径                                   |\n\n下面的配置文件用于追加上游 DNS 服务器：\n\n```yaml\nupstreams+:\n  - name: my-dns\n    host: 192.168.1.1\n    proxy: http://192.168.1.1\n    timeout: 5000\n    disable: false\n    priority: 0\n    groups:\n      - my\n      - cn\n\n  - name: my-dot\n    host: 192.168.1.1\n    type: tls\n\n  - name: my-doh\n    url: https://my-doh/dns-query\n```\n\n其中 `proxy` 、 `timeout` 、 `disable` 、 `priority` 和 `groups` 都是可选项。\n\n### 2.3 中间件\n\nDnspooh 提供下列中间件：\n\n1. Rules 自定义规则\n\n2. Hosts 自定义域名解析\n\n3. Block 域名和 IP 地址黑名单\n\n4. Cache 缓存上游服务器的解析结果\n\n5. Log 解析日志\n\n这些中间件可以在配置文件中开启。在默认配置下，仅启用 Cache 中间件。中间件采用装饰器模式，先加载的中间件处于封装内层，后加载的中间件处于外层。建议按照本文档中的列表顺序定义。\n\n其中 `block` 和 `hosts` 的配置是一组文件列表。文件可以是本地文件，也可以是 http/https 链接。且当文件是链接时，还能设置更新频率：\n\n```yaml\nhosts:\n  - [https://raw.hellogithub.com/hosts, 3600]\n```\n\n上面的配置表示，程序每隔 3600 秒重新载入一次 https://raw.hellogithub.com/hosts 的数据。\n\n### 2.4 HTTP 控制接口\n\nDnspooh 提供了一套 RESTful API 来控制服务， HTTP 请求必须带有 `Content-Type: application/json` 头部， POST 请求参数以 JSON 格式传递， GET 请求参数通过 Query String 传递。\n\nHTTP 服务默认绑定 127.0.0.1 地址，使用 1024 到 65535 范围内的随机端口，程序启动时会在命令行终端输出 HTTP 接口的 URL 地址。\n\n如果接口调用成功，返回一个包含 `result` 字段的 JSON 实体。其中 `result` 字段的值为接口返回值。如果接口调用失败，返回一个包含 `error` 字段的 JSON 实体。其中 `error` 字段的值为错误对象，包含 `code` 和 `message` 两个成员。一个典型的错误对象实体如下：\n\n```json\n{\n    \"error\": {\n        \"code\": 0,\n        \"message\": \"执行失败\"\n    }\n}\n```\n\n#### 2.4.1 获取程序版本\n\n**方法：** GET\n\n**路径：** `/version`\n\n**参数：** 无\n\n**返回值：** String\n\n```json\n{ \"result\": \"1.0.0\" }\n```\n\n#### 2.4.2 获取服务状态\n\n**方法：** GET\n\n**路径：** `/status`\n\n**参数：** 无\n\n**返回值：** String\n\n```json\n{ \"result\": \"RUNNING\" }\n```\n\n`status` 可能的返回值如下（其中几种状态可能永远观测不到）：\n\n- INITIALIZED 已初始化\n- START_PEDDING 正在启动\n- RUNNING 正在运行\n- RESTART_PEDDING 正在重启\n- STOP_PEDDING 正在停止\n- STOPPED 已停止\n\n#### 2.4.3 重启服务\n\n重启服务不会影响 HTTP 服务。重启服务过程中会重新载入并应用配置文件，但修改配置文件中的 `http` 下的配置不会因重启服务而生效。\n\n**方法：** POST\n\n**路径：** `/restart`\n\n**参数：** 无\n\n**返回值：** Boolean\n\n```json\n{ \"result\": true }\n```\n\n#### 2.4.4 获取上游 DNS 服务器\n\n**方法：** GET\n\n**路径：** `/upstream`\n\n**参数：** 无\n\n**返回值：** JSON 对象\n\n```json\n{\n    \"result\": {\n        \"primary\": {\n            \"name\": \"cloudflare-1\",\n            \"disable\": false,\n            \"groups\": [\"cloudflare\", \"global\", \"ipv4\"],\n            \"health\": 100,\n            \"host\": \"1.1.1.1\",\n            \"port\": 53,\n            \"priority\": 988,\n            \"type\": \"dns\"\n        },\n        \"upstreams\": [\n            {\n                \"name\": \"cloudflare-1\",\n                \"disable\": false,\n                \"groups\": [\"cloudflare\", \"global\", \"ipv4\"],\n                \"health\": 100,\n                \"host\": \"1.1.1.1\",\n                \"port\": 53,\n                \"priority\": 988,\n                \"type\": \"dns\"\n            },\n            // ... ...\n        ]\n    }\n}\n```\n\n#### 2.4.5 设置主 DNS 服务器\n\n**方法：** POST\n\n**路径：** `/upstream/primary`\n\n**参数：** \n\n| 字段 | 类型   | 描述                               |\n| ---- | ------ | ---------------------------------- |\n| name | String | 服务器名称。例如：`\"cloudflare-1\"` |\n\n**返回值：** Boolean\n\n```json\n{ \"result\": true }\n```\n\n#### 2.4.6 测试全部 DNS 服务器\n\n**方法：** POST\n\n**路径：** `/upstreams/test-all`\n\n**参数：** 无\n\n**返回值：** Boolean\n\n```json\n{ \"result\": true }\n```\n\n#### 2.4.7 获取连接池\n\n**方法：** GET\n\n**路径：** `/pool`\n\n**参数：** 无\n\n**返回值：** Array\n\n```json\n{\n    \"result\": [\n        { \"name\": \"socks5://127.0.0.1:1080/udp://1.1.1.1:53\", \"size\": 6 },\n        // ... ...\n    ]\n}\n```\n\n#### 2.4.8 获取配置信息\n\n**方法：** GET\n\n**路径：** `/config`\n\n**参数：** 无\n\n**返回值：** Array\n\n```json\n{\n    \"result\": [\n        { \"name\": \"debug\", \"value\": false },\n        { \"name\": \"secure\", \"value\": false },\n        { \"name\": \"ipv6\", \"value\": false },\n        // ... ...\n    ]\n}\n```\n\n#### 2.4.9 获取解析日志\n\n**方法：** GET\n\n**路径：** `/logs`\n\n**参数：** \n\n| 字段  | 类型    | 描述                         |\n| ----- | ------- | ---------------------------- |\n| page  | Integer | 页码。可选，默认展示第一页。 |\n| qname | String  | 筛选域名关键字。可选。       |\n| qtype | String  | 筛选查询类型。可选。         |\n\n**返回值：** JSON 对象\n\n```json\n{\n    \"result\": {\n        \"total\": 12,\n        \"page\": {\n            \"current\": 1,\n            \"size\": 50,\n            \"count\": 1\n        },\n        \"logs\": [\n            {\n                \"id\": 12,\n                \"created_at\": \"2023-03-08 18:49:19\",\n                \"elapsed_time\": 0.004754199995659292,\n                \"qname\": \"www.google.com.\",\n                \"qtype\": \"AAAA\",\n                \"success\": 1,\n                \"traceback\": [\"cache\", \"block\", \"Server\", \"alidns-1\"],\n                \"error\": null\n            },\n            // ... ...\n        ]\n    }\n}\n```\n\n#### 2.4.10 清空解析日志\n\n**方法：** POST\n\n**路径：** `/logs/clear`\n\n**参数：** 无\n\n**返回值：** Boolean\n\n```json\n{ \"result\": true }\n```\n\n#### 2.4.11 域名解析\n\n**方法：** POST\n\n**路径：** `/dns-query`\n\n**参数：** \n\n| 字段   | 类型   | 描述   |\n| ------ | ------ | ------ |\n| domain | String | 域名。 |\n\n**返回值：**String\n\n```json\n{ \"result\": \";; -\u003e\u003eHEADER\u003c\u003c- opcode: QUERY, status: NOERROR, ... ...\" }\n```\n\n#### 2.4.12 查询 IP 地理位置\n\n**方法：** POST\n\n**路径：** `/geoip2-query`\n\n**参数：** 无\n\n**返回值：** JSON 对象\n\n```json\n{\n    \"result\": {\n        \"country\": {\n            \"geoname_id\": 1814991,\n            \"is_in_european_union\": false,\n            \"iso_code\": \"CN\",\n            \"names\": {\n                \"de\": \"China\",\n                \"en\": \"China\",\n                \"es\": \"China\",\n                \"fr\": \"Chine\",\n                \"ja\": \"\\u4e2d\\u56fd\",\n                \"pt-BR\": \"China\",\n                \"ru\": \"\\u041a\\u0438\\u0442\\u0430\\u0439\",\n                \"zh-CN\": \"\\u4e2d\\u56fd\"\n            }\n        }\n    }\n}\n```\n\n### 2.5 Web 管理界面\n\n![Screenshot](./assets/screenshot.png?raw=true)\n\n要启用 Web 管理界面需要在配置文件中指定前端文件的保存路径：\n\n```yaml\nhttp\n  root: dashboard/public\n```\n\n在发布的可执行软件包中已经预置了 Web 前端而无需另外配置。\n\n## 3. 自定义规则\n\n通过自定义规则中间件，可以实现按条件屏蔽域名、自定义解析结果等操作。可以在配置文件的 `rules` 单元中设置一组或多组规则，每组规则由 `if` 、 `then` 、 `before` 、 `after` 、 `end` 字段组合而成。根据不同的需求，一组规则可以由 `if/then/end` 字段组成；或者由 `if/before/after/end` 字段组成。其中 `end` 字段是可选的，表示命中并处理完此条规则后是否停止处理后续规则，默认值为 `false` ； `if` 字段是一个表达式，当表达式结果为真时，则表示命中这条规则； `then` 字段是一条语句，可以在此处直接拦截 DNS 解析请求，直接返回 NXDOMAIN （域名不存在）或自定义解析结果，而不会将请求转发到上游服务器； `before` 字段是一组逗号分隔的命令语句，在 DNS 解析请求被转发到上游服务器之前被处理，可以用于指定上游服务器以及替换请求中的域名； `after` 字段也是一组逗号分隔的命令语句，在 DNS 解析结果从上游服务器返回之后被处理，可以根据返回的结果进行修改操作或执行外部命令。\n\n配置例子：\n\n```yaml\nrules:\n  - if: (lianmeng, adwords, adservice) in domian\n    then: block\n    end: true\n\n  - if: domain ends with (.cn, .top)\n    before: set upstream group to cn\n\n  - if: always\n    before: set upstream group to adguard\n    after: run \"sudo route add {ip} mask 255.255.255.255 192.168.1.1\" where geoip is cn\n```\n\n上面的配置作用是：\n\n1. 屏蔽含有 lianmeng 、 adwords 、 adservice 关键字的域名；\n2. 让 .cn 和 .top 域名使用国内的 DNS 服务器解析；\n3. 默认使用 adguard 作为上游域名解析服务器。adguard 服务器可以屏蔽所有广告域名；\n4. 当返回的解析结果中包含国内 IP 时，将此 IP 加入本机路由表，使用 192.168.1.1 网关路由（当开启全局 VPN 时，使用本地网络访问国内 IP ）。\n\n所有的表达式都支持 `not` 、 `and` 和 `or` 逻辑运算，按优先级排列如下：\n\n1. not *expr*\n2. *expr* and *expr*\n3. *expr* or *expr*\n\n可以用圆括号运算符 `(` 与 `)` 来改变逻辑运算符的优先级。\n\n```yaml\nrules:\n  - if: (domain ends with .cn or domain ends with .top) and not blog in domain\n    then: block\n    end: true\n```\n\n上面的配置作用是，如果是 .cn 或 .top 域名，且域名中没有包含 blog 关键字，则屏蔽。\n\n### 3.1 if 表达式\n\nif 字段由一个或多个判断条件组成的逻辑运算表达式。支持的判断条件有：\n\n- domain is *domain*  \n  域名等于 *domain*\n- domain is (*domain1*, *domain2*, ...)  \n  域名与列表中任一 *domain* 相等，等价于 domain is *domain1* or domain is *domain2* or ... \n- domain is not *domain*  \n  域名不等于 *domain* ，等价于 not domain is *domain*\n- domain is not (*domain1*, *domain2*, ...)  \n  域名不等于列表中的任何 *domain* ，等价于 domain is not *domain1* and domain is not *domain2* and ...\n- *keyword* in domain  \n  域名包含 *keyword*\n- (*keyword1*, *keyword2*, ...) in domain  \n  域名包含列表中任一 *keyword* ，等价于 *keyword1* in domain or *keyword2* in domain or ...\n- *keyword* not in domain  \n  域名不包含 *keyword* ，等价于 not *keyword* in domain\n- (*keyword1*, *keyword2*, ...) not in domain  \n  域名不包含列表中的任何 *keyword* ，等价于 *keyword1* not in domain and *keyword2* not in domain and ...\n- domain starts with *prefix*  \n  域名前缀为 *prefix*\n- domain starts with (*prefix1*, *prefix2*, ...)  \n  域名前缀是列表中的任一 *prefix* ，等价于 domain starts with *prefix1* or domain starts with *prefix2* or ...    \n- domain starts without *prefix*  \n  域名前缀不为 *prefix* ，等价于 not domain starts with *prefix*  \n- domain starts without (*prefix1*, *prefix2*, ...)  \n  域名前缀不为列表中的任何 *prefix* ，等价于 domain starts without *prefix1* and domain starts without *prefix2* and ...\n- domain ends with *suffix*  \n  域名后缀为 *suffix*\n- domain ends with (*suffix1*, *suffix2*, ...)  \n  域名后缀为列表中的任一 *suffix* ，等价于 domain starts with *suffix1* or domain starts with *suffix2* or ...    \n- domain ends without *suffix*  \n  域名后缀不为 *suffix* ，等价于 not domain ends with *suffix*  \n- domain ends without (*suffix1*, *suffix2*, ...)  \n  域名后缀不为列表中的任何 *suffix* ，等价于 domain ends without *suffix1* and domain ends without *suffix2* and ...    \n- domain match /*regex*/  \n  域名完整匹配正则表达式 *regex*\n- always  \n  总是为真\n\n### 3.2 then 语句\n\nthen 字段可以是下列任意语句之一：\n\n- block  \n  屏蔽当前请求\n- return *ip*  \n- return (*ip1*, *ip2*, ...)  \n  直接返回解析结果\n\n### 3.3 before 语句\n\nbefore 字段由下列一条或多条逗号分隔的语句组成：\n\n- set upstream group to *name*  \n  使用 *name* 组中的上游服务器来解析域名\n- set upstream name to *name*  \n  使用名称为 *name* 的上游服务器来解析域名\n- replace domain by *domain*  \n  将请求中的域名替换为 *domain*\n- set proxy on  \n  启用代理服务器访问上游服务器（须在配置文件中设置 proxy 项）\n- set proxy off  \n  禁用代理服务器访问上游服务器\n- set proxy to *proxy*  \n  指定代理服务器访问上游服务器。*proxy* 格式如 http://127.0.0.1:8080 或 socks5://127.0.0.1:1080 \n\n### 3.4 after 语句\n\n- block if *expr1*  \n  当解析结果满足条件（ *expr1* 表达式为真）时，屏蔽域名\n- return *ip* if *expr1*  \n  当解析结果满足条件（ *expr1* 表达式为真）时，用 *ip* 替代解析结果\n- return (*ip1*, *ip2*, ...) if *expr1*\n- append record *ip*  \n  在上游服务器返回的解析结果后追加记录\n- append record (*ip1*, *ip2*, ...)\n- append record *ip* if *expr1*\n- append record (*ip1*, *ip2*, ...) if *expr1*\n- insert record *ip*  \n  在上游服务器返回的解析结果前插入记录\n- insert record (*ip1*, *ip2*, ...)\n- insert record *ip* if *expr1*\n- insert record (*ip1*, *ip2*, ...) if *expr1*\n- remove record where *expr2*  \n  从解析结果中移除满足条件（ *expr2* 表达式为真）的记录\n- replace record by *ip* where *expr2*  \n  用 *ip* 替换满足条件（ *expr2* 表达式为真）的记录\n- run \"*command*\" where *expr2*  \n  当解析结果中存在满足条件的记录时，执行 *command* 命令。命令需要用半角双引号包裹，命令中可以使用 `{ip}` 占位符表示当前记录的 IP 地址。\n\n#### 3.4.1 expr1 类型表达式\n\n- any ip is *ip*  \n  解析结果中存在 IP 地址等于 *ip* 的记录\n- any ip is (*ip1*, *ip2*, ...)\n- any ip is not *ip*\n- any ip is not (*ip1*, *ip2*, ...)\n- any ip in *cidr*  \n  解析结果中存在 IP 地址在 *cidr* 范围内的记录。 *cidr* 使用 IP-CIDR 格式表示，如 192.168.1.1/24\n- any ip in (*cidr1*, *cidr2*, ...)\n- any ip not in *cidr*\n- any ip not in (*cidr1*, *cidr2*, ...)\n- any geoip is *country*  \n  解析结果中存在 IP 地址所在国为 *country* 的记录\n- any geoip is not *country*\n- all ip is *ip*  \n  解析结果中所有记录的 IP 地址都等于 *ip* \n- all ip is (*ip1*, *ip2*, ...)\n- all ip is not *ip*\n- all ip is not (*ip1*, *ip2*, ...)\n- all ip in *cidr*  \n  解析结果中所有记录的 IP 地址都在 *cidr* 范围内 \n- all ip in (*cidr1*, *cidr2*, ...)\n- all ip not in *cidr*\n- all ip not in (*cidr1*, *cidr2*, ...)\n- all geoip is *country*  \n  解析结果中所有记录的 IP 所在国都为 *country*  \n- all geoip is not *country*\n\n#### 3.4.2 expr2 类型表达式\n\n- ip is *ip*\n- ip is (*ip1*, *ip2*, ....)\n- ip is not *ip*\n- ip is not (*ip1*, *ip2*, ....)\n- ip in *cidr*\n- ip in (*cidr1*, *cidr2*, ...)\n- ip not in *cidr*\n- ip not in (*cidr1*, *cidr2*, ...)\n- geoip is *country*\n- geoip is not *country*\n- first  \n  第一条记录\n- last  \n  最后一条记录\n\n## 4. 特性\n\n- 如果 DNS 解析请求中包含多条查询，会被逐条拆分后发送至上游服务器，并在返回响应时重新组合。这么做的目的是为了方便中间件处理；\n- 程序在引导时会优先使用 priority 值最大的 upstream 来解析 DoH 服务器的域名。默认使用 cloudflare-tls 服务器进行引导时解析；\n- 程序启动时会测试配置中所有的上游服务器，并将响应最快的服务器设置为主服务器；\n- 程序内置的 GeoIP2 数据库仅包含中国 IP 段数据，只能返回 `cn` 或空。要使用完整的 GeoIP2 数据库，可以在配置文件中指定数据库文件；\n- 程序内置的上游 DNS 解析服务器包括：[Cloudflare DNS](https://1.1.1.1/dns/) (cloudflare), [Google Public DNS](https://developers.google.com/speed/public-dns) (google), [阿里公共DNS](https://alidns.com/) (alidns), [114DNS](https://www.114dns.com/) (114dns), [OneDNS ](https://www.onedns.net/)(onedns), [DNSPod](https://www.dnspod.cn/) (dnspod), [百度DNS](https://dudns.baidu.com/)(baidu), [OpenDNS](https://www.opendns.com/) (opendns), [AdGuard DNS](https://adguard-dns.io/) (adguard) 。这些服务器按照服务供应商的名称（见括号内）分为不同组；根据服务器所在地，分为 cn 组和 global 组；根据服务器网络类型，分为 ipv4 组和 ipv6 组。\n\n## 5. 常用命令\n\n模块构建打包（需要安装 build 模块）：\n\n```shell\npip install build\npython -m build\n```\n\n运行单元测试：\n\n```shell\npython -m unittest tests\n```\n\n项目发布的可执行文件使用 [Nuitka-winsvc](https://github.com/tabris17/Nuitka-winsvc) 编译。首先安装依赖的包：\n\n```shell\npip install nuitka ordered-set zstandard dnspooh\n```\n\n官方发布的 Windows 程序使用如下 Nuitka 命令编译：\n\n```shell\nnuitka --standalone --output-dir=build --output-filename=dnspooh --windows-icon-from-ico=./assets/favicon.ico --include-package-data=dnspooh --onefile --windows-service --windows-service-name=dnspooh --windows-service-display-name=Dnspooh --windows-service-description=\"A lightweight DNS MitM proxy\" main.py\n```\n\n启动 Web 管理界面前端开发环境：\n\n```shell\nnpm i\nnpm run dev\n```\n\n构建 Web 管理界面前端：\n\n```shell\nnpm run build\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftabris17%2Fdnspooh","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftabris17%2Fdnspooh","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftabris17%2Fdnspooh/lists"}