插件及其参数

写在最前

mosdns 的插件流水线概念

一个能正常工作的简单的流水线示例。能将应答转发至上游。同时支持缓存。

什么是插件: 插件接受并返回一个“请求上下文”。在内部处理请求/应答。

“请求上下文”包含了

  • 客户端来源 IP 等信息。由服务端赋值。不可修改。

  • 客户的请求。插件可以自由修改请求的数据。

  • 应答。初始为空。插件可以自由修改应答的数据

插件流水线: 将多个插件串在一起,就构成了一条流水线。

配置文件中的插件

每个插件都是独立的,互不影响。同类型 type 插件可以初始化任意多个,只要插件的 tag 不重复就行。

多个同类型插件配置示例。点击展开

两个 forward 插件。tag 不同,参数不同。

一些常用的插件配置已经被 mosdns 预先初始化好了,tag_ 开头以便区分。可以直接调用。

可执行插件

_return

预初始化的插件。什么都不做。不会将请求上下文传递给后续流水线。可以用于结束 sequence 流水线。见下文。

流水线逻辑:

  • 正向:跳过后续流水线。

  • 反向:无。

sequence 将多个插件组合成流水线

sequence 可以将多个插件组成一个流水线。sequence 也是插件,所以 sequence 里运行别的sequence 是可以的。

_return 是一个特殊的预初始化插件,可配合 sequence 使用,它只会跳过后续流水线。(注意: “跳过后续流水线”并不是直接将应答返回客户端,而是正向流水线运行结束,开始反向运行。)。

sequence 插件中调用的插件 tag 必须在 sequence 前定义,否则 sequence 找不到对应插件。

sequence 流水线图示。

初始化参数说明:

高级操作: 并发、失败自动回滚(故障转移)

fallbackparallel 涉及到多线程运行,其内部流水线其实是一个独立的 sequence 插件,拥有独立的请求上下文,为了配置方便嵌套在这里。它们和当前 sequence 没有关系!在独立的 sequence 内对请求上下文修改,不会影响其他并行的流水线。同样 _returncache 等能跳过后续流水线运行的插件,也只会终止自身流水线,不会对其他流水线产生影响。但最终 fallbackparallel 会把合适的应答放在当前 sequence 的请求上下文内。比如 parallel 会取最快返回的流水线的请求上下文的应答放在当前 sequence 的请求上下文。

fallback 两种触发方式:

  • 常规 fallback: 监控主流水线最近 stat_length 次的请求状态,如果出现 threshold 次问题(没有应答或者有报错),则下次请求会一并执行次流水线。取最先返回的应答。

  • 快速 fallback: 对于每一个请求,如果主流水线运行结束了但没有返回应答,或者在 fast_fallback 毫秒后仍在运行无应答,则立即开始执行次流水线,取最先返回的应答。如果任意流水线返回了应答,这个请求就不会失败。比常规 fallback 策略更激进,次流水线可能运行的更频繁。

    • secondary 始终待命: 如果设为 true,则对于每一个请求,次流水线都会和主流水线一并执行,其结果将会在需要回滚时(没有返回应答或 fast_fallback 超时),直接被使用。进一步降低响应时间。

  • 快速和常规 fallback 可以同时启用。

cache 缓存

缓存 DNS 应答的插件。

流水线逻辑:

  • 正向:如果请求命中缓存,则将缓存的应答放入“请求上下文”,跳过后续流水线。如果没有命中,则继续执行后续流水线。

  • 反向:缓存应答。

以下预初始化的插件 tag 可直接使用:

  • _default_cache: 默认配置的内存缓存。大小 1024。无 lazy cache。

初始化参数说明:

lazy cache,也叫“乐观缓存”,的优缺点:

  • 优点:可大幅提高缓存命中率。流行域名几乎 100% 命中。

  • 缺点:可能影响 DNS 更新频繁的域名正常使用,比如 DDNS,CDN。

  • 仅建议个人使用场景,有相关知识,了解其弊端的专业用户开启。

Metrics 数据:

  • query_total: 总请求数。

  • hit_total: 总命中数。(包括 lazy cache 的命中)

  • lazy_hit_total: lazy cache 总命中数

  • cache_size: 当前缓存大小。单位: 条。

hosts 域名映射 IP

流水线逻辑:

  • 正向:如果请求的域名在 hosts 内,则将应答放入“请求上下文”,跳过后续流水线。如果不在,则继续执行后续流水线。

  • 反向:无。

初始化参数说明:

格式:

  • 域名规则在前,IP 在后。支持一行多个 IP,支持 IPv6。

  • 如果域名匹配规则的方式被省略,则默认是 full 完整匹配。域名匹配规则详见 这里

格式示例:

_prefer_ipv4/6 优先使用 ipv4/6

_prefer_ipv4_prefer_ipv6 是预初始化插件,可直接使用。下面为了表述方便,仅以 _prefer_ipv4 为例。_prefer_ipv6 同理。

_prefer_ipv4 可用让下游客户端支持双栈时优先使用 IPv4。_prefer_ipv4 会自动探测域名是否是双栈,然后只屏蔽双栈域名的 AAAA 请求。相比于强行禁用所有 AAAA 请求的方案,该插件不会影响纯 IPv6 域名的解析。

使用位置要求: 插件的后续序列中必须有转发请求的插件。

流水线逻辑:

  • 正向:同时请求 A 和 AAAA。

  • 反向:根据 A 和 AAAA 的结果,判断域名双栈支持状况,决定屏蔽策略。

sequence 示例:

ecs 为请求附加 ECS

流水线逻辑:

  • 正向:附加 ECS 至请求。

  • 反向:保证请求与应答 ECS 一致。如果源请求中无 ECS (现有 ECS 是插件新附加的),则删除应答中的 ECS 回应。

初始化参数说明:

_no_ecs 删除请求和应答中的 ECS

_no_ecs 是预初始化插件的 tag,可直接使用。

流水线逻辑:

  • 正向:删除请求中的 ECS。

  • 反向:删除应答中的 ECS。

一般放在转发插件前。

ttl 修改应答的生存时间

流水线逻辑:

  • 正向:修改应答的生存时间。

  • 反向:无。

使用位置:一般放在转发插件后。

初始化参数说明:

blackhole 丢弃应答或生成假应答

blackhole 会丢弃应答,或生成特定应答来屏蔽请求。

以下预初始化的插件 tag 可直接使用:

  • _drop_response: 丢弃已存在的应答。

  • _new_empty_response: 生成 Rcode 为 0 的空应答。放入“请求上下文”。(模拟域名存在但没有所请求类型的记录)

  • _new_servfail_response: 生成 Rcode 为 2 (SERVFAIL: 服务器失败)应答。放入“请求上下文”。

  • _new_nxdomain_response: 生成 Rcode 为 3 (NXDOMAIN: 域名不存在)应答。放入“请求上下文”。

流水线逻辑:

  • 正向:丢弃或生成对应应答。

  • 反向:无。

初始化参数说明:

ipv4 和 ipv6 的优先级高于 rcode。如果都配置了, A/AAAA 请求会生成 IP 应答,其余类型会生成状态为 RCODE 的应答。

fast_forward 转发请求至上游(自带模块)

mosdns 自带模块。

流水线逻辑:

  • 正向:转发请求至上游,获取应答后放入“请求上下文”。

  • 反向:无。

初始化参数说明:

  • addr 必需。服务器地址。省略 scheme 默认为 UDP 协议。省略端口号会使用协议的默认值。支持 IP 和域名。格式示例:

    • UDP: 8.8.8.8, 208.67.222.222:443

    • TCP: tcp://8.8.8.8

    • DoT: tls://8.8.8.8:853, tls://dns.google

    • DoH (RFC8484 GET): https://8.8.8.8/dns-query, https://dns.google/dns-query

    • UDPME(v3.5.1+)(实验性): udpme://8.8.8.8

      • 这是个能过滤掉 UDP 抢答应答的方案。仍然是 UDP 协议。服务器必须支持 EDNS0。如果抢答者不支持 EDNS0,则可以过滤抢答应答。

      • 使用 dig 测试 dig +edns cloudflare.com @服务器地址 观察返回是否有一行 EDNS: version: 0 来确定服务器是否支持 EDNS0。绝大多数服务器都支持。

  • 优先使用 IP 地址(如果服务器官方提供)。如果 addr 包含域名,插件需要将其解析成 IP 地址。

    • dial_addr: 为包含域名的 addr 手动指定其 IP 地址。支持端口号。指定后插件连接服务器时无需先解析服务器的域名。能更快建立连接。适用于 IP 万年不变的服务器。

    • bootstrap: (v4.2+)(实验性) 手动指定用于解析 addr 中域名的 bootstrap 服务器。只能是 UDP 服务器。指定后插件每次连接服务器时会先通过该 bootstrap 服务器解析域名。bootstrap 服务器的延时越低越好。HTTP/3 暂不支持该选项。仅支持 Win,Unix 平台。Macos,Plan9 等不支持。

    • 系统默认解析: 以上两个参数留空,会使用默认系统解析方式。

    • 优先级: dial_addr > bootstrap > 系统默认。

  • socks5: socks5 服务器地址。格式 host:port。数据将会通过该代理中转。暂不支持用户名密码认证。UDP 和启用了 HTTP3 的 DoH 协议暂不支持该设定。

  • trusted: 是否是可信服务器。可信服务器的任何应答都会被接受。其余服务器只接受 RCODE 为 0 (SUCCESS) 的应答。第一个服务器一定是可信服务器且不可修改。其余默认不可信。

  • idle_timeout TCP/DoT/DoH 连接复用空连接保持时间。单位: 秒。默认 DoH: 30 ,TCP/DoT: 10。一般不需要改。

  • enable_pipeline: TCP/DoT 使用 RFC 7766 新的 query pipelining 连接复用模式。

    • 启用后可大幅提高连接利用率,减少建立连接/握手的次数,进而降低延时。

    • 并非所有服务器都支持。必须确定服务器支持后再启用该选项。

    • Tips: 已知 Google 和 Cloudflare 的 TCP/DoT 都是支持的。知名的公共 DNS 服务商大多数都支持该模式。mosdns 自带一个测试命令可以测试服务器是否支持该模式。

  • enable_http3: (v3.4.0+)(实验性) DoH 使用 HTTP/3 连接服务器。并非所有服务器都支持。必须确定服务器支持后再启用该选项。Tips: 已知 Google 和 Cloudflare 是支持的。

  • max_conns: 默认: 2。一般不需要改。大流量场景可适当调大。

    • UDP 协议: 收发数据包使用的套接字数。

    • 启用了 query pipelining 模式的 TCP/DoT 协议: 最大连接数。

    • DoH 协议: HTTP 的最大连接数。HTTP/3 除外。

  • insecure_skip_verify: 禁用 TLS 服务器证书验证。

  • Linux 套接字设定。需要 CAP_NET_ADMIN 权限

    • so_mark:(v3.7+)。设定 SO_MARK。

    • bind_to_device: (v4.3+) 设定 SO_BINDTODEVICE。

  • ca: 用于 TLS 验证的 CA 证书路径。是数组,可填入多个证书。默认使用系统证书池。

forward 转发请求至上游(dnsproxy)

这个插件使用了 AdguardHome 的请求模块 dnsproxy

流水线逻辑:

  • 正向:转发请求至上游,获取应答后放入“请求上下文”。

  • 反向:无。

初始化参数说明:

addr 地址格式和 AdguardHome 支持的格式一致。一些示例:

  • UDP: 8.8.8.8, 208.67.222.222:443

  • TCP: tcp://8.8.8.8

  • DoT: tls://dns.google

  • DoH: https://dns.google/dns-query

  • DoH3: h3://dns.google/dns-query

  • DoQ: quic://dns.adguard.com

  • DNS stamp: sdns://... 详见 dnscrypt.info

上述列表和参数说明不一定是最新的,请以 dnsproxy 的 README 为准。

ipset 将应答 IP 写入到系统 ipset

流水线逻辑:

  • 正向:将应答 IP 写入 ipset。

  • 反向:无。

初始化参数说明:

  • 插件添加新 IP 时相当于执行了 ipset add <set_name> <IP>/<mask> 命令。

  • 插件使用 netlink 直接与内核通信,不依靠 /sbin/ipset 命令。

  • 该插件不会创建 set。set 需要由用户提前创建。必须为 hash:net 类型。建议设置非零的 timeout 属性。实现自动清除长时间没有用到的地址。

创建 ipset 表命令示例:

nftset 将应答 IP 写入到系统 nftables

流水线逻辑:

  • 正向:将应答 IP 写入 nftables。

  • 反向:无。

初始化参数说明:

  • 插件添加新 IP 时相当于执行了 nft add element <table_family> <table_name> <set_name> {<IP>/<mask>...} 命令。

  • 插件使用 netlink 直接与内核通信,并不依靠 /sbin/nft 命令。

  • 该插件不会创建对应的 set。set 需要由用户提前创建。

  • set 建议设置 timeout 来实现自动清除长时间没有用到的地址。

  • set 建议设置 interval flag。插件会自动识别这个 flag,然后会以 IP 段的方式存储 IP。

创建 nftables set 命令示例:

bufsize 限制请求的 EDNS0 的 UDP 负载大小

旧插件。建议使用新的 _misc_optm 插件。

流水线逻辑:

  • 正向:修改请求的 EDNS0 UDPSIZE (如果请求有 EDNS0)。

  • 反向:无。

初始化参数说明:

padding 填充 DNS 报文至固定长度 (实验性)

参考 RFC 8467,使用 EDNS0 的 Padding Option 将 DNS 报文用 0 填充至固定长度。据 Google 说 (Google Plublic DNS 文档) 能防止流量分析保护隐私。包含 3 个预定义插件。

_pad_query: 填充请求

  • 流水线逻辑:

    • 正向:将请求填充至 128 bytes。

    • 反向:无。

  • 使用位置要求: 该插件到转发插件之间不能有修改请求的插件。否则请求大小可能会变,影响效果。

_enable_conditional_response_padding_enable_response_padding: 填充应答:

  • 流水线逻辑:

    • 正向:无。

    • 反向:填充应答至 468 bytes。_enable_response_padding 是如果客户端请求包含 EDNS0,就会填充应答。而 _enable_conditional_response_padding 则是如果客户端对请求进行了填充,才会填充应答。

  • 使用位置要求: 反向流水线填充应答后,直至流水线结束,不能有修改应答的插件。否则应答大小可能会变,影响效果。

redirect 替换请求的域名 (实验性)

替换(重定向)请求的域名。请求域名 A,但返回域名 B 的记录。

流水线逻辑:

  • 正向:替换请求的 QUESTION NAME。比如将请求域名 A 替换为 B。

  • 反向:修改应答的 ANSWER 的 NAME,比如将 B 替换回 A。使之看起来像请求 A 的记录。

注意: 没有能完美替换请求域名的方法。本插件的替换方式对于常见的 A,AAAA,TXT 等仅依赖 QUESTION 和 ANSWER 的请求是有效的。但不保证兼容其他类型请求以及各种 EDNS0 扩展。

初始化参数说明:

  • 域名匹配规则: 如果匹配方式被省略,则默认是 full 完整匹配。域名匹配方式详见 域名匹配规则

arbitrary 返回任意记录 (实验性) (v4.0+)

arbitrary 可以载入任意记录,并在匹配到对应请求时生成包含这些记录的应答,

流水线逻辑:

  • 正向:如果找到对应记录,则生成应答,终止跳过后续流水线。如果不在,则继续执行后续流水线。

  • 反向:无。

初始化参数说明:

不同记录的文本格式请自行搜索。关键词: <记录类型> dns record wikipedia。在英文 wikipedia 可以直接找到绝大多数记录的格式。

暂不支持从外部数据载入记录。

_misc_optm 转发服务器优化大杂烩 (实验性) (v4.0+)

预定义插件,可直接使用。

适用于转发服务器。

流水线逻辑:

  • 正向:

    • 屏蔽掉互联网公共上游不能处理的请求(多个 QUESTION 和非 IN CLASS)。(立刻返回 REFUSE,跳过后续流水线。)

    • 将 EDNS0 UDPSIZE 限定在 1200。(v4.5+)

  • 反向

    • 去除 A/AAAA 应答的 CNAME 记录。减小应答长度。

    • 去除应答的 Padding。减小应答长度。

    • 随机打乱 A/AAAA 应答的 IP。负载均衡。

    • 如果请求无 EDNS0,去除上游应答的 EDNS0。保持 EDNS0 状态一致。

建议流水线位置: 流水线起始。

reverse_lookup IP 反查域名 API (v4.2+)(实验性)

该插件会缓存应答中的 IP 与 域名的关系。可在本地实现无延时的"有效 IP -> 域名"查询。支持 PTR 和 HTTP API。

流水线逻辑:

  • 正向:如果是 PTR 请求,并且命中缓存,则生成应答,跳过后续流水线。如果没有命中缓存,则继续执行后续流水线。

  • 反向:将 A/AAAA 应答的 IP 写入缓存。

初始化参数说明:

建议流水线位置: 流水线起始。务必放在 cache 前,防止 cache 命中缓存后不执行 reverse_lookup 导致无法记录 IP。

查找缓存中 IP 对应域名的 API:http://<api_addr>/plugins/<plugin_tag>?ip=<ip_addr>

返回: 如果缓存中找到对应域名,则返回域名。如果缓存中没有找到对应域名,则返回空。如果参数不对则返回 HTTP 400。

示例: http://127.0.0.1:8080/plugins/my_reverse_lookup?ip=8.8.8.8,返回 dns.google. 注意返回的是 fully qualified 域名,末尾有 .

metrics_collector 统计数据收集器 (v4.2+)(实验性)

收集 prometheus metrics 数据。

流水线逻辑:

  • 正向:query_total =+1,thread =+1,response_latency_millisecond 开始计时。

  • 反向:err_total =+1 (如果出错),thread =-1,response_latency_millisecond 结束计时。

请求经过插件时,插件会收集

  • query_total 经过该插件的总请求数。

  • err_total 插件所在 sequence 的后续插件的总出错数。

  • thread 当前经过该插件的线程数。

  • response_latency_millisecond 插件所在 sequence 的后续插件的应答延时。

数据项名称为 mosdns_plugin_<plugin_tag>_<name>

建议流水线位置: 放在流水线起始位置就可以统计本条流水线的数据。

client_limiter 限制客户端的 QPS (v4.2+)(实验性)

限制客户端(以 IP 或 IP 段区分)的最大每秒请求数 QPS。

流水线逻辑:

  • 正向:如果客户端 QPS 超过阈值,则生成 REFUSE 应答,跳过后续流水线。

  • 反向:无。

建议流水线位置: 流水线起始。

注意: 该插件只能用于向非恶意客户端“友好”地回复 REFUSED。不能防攻击。

edns0_filter 过滤请求的 EDNS0 OPTION (实验性)(v4.4.1+)

过滤/限制客户端可以使用 EDNS0 OPTION。

TIps: 如果后面配置有启用了 cache_everything 的 cache 插件,该插件可用于提高缓存利用率。比如移除 Cookie 和 Padding,或只允许 ECS。

流水线逻辑:

  • 正向:从请求中移除/保留指定的 EDNS0 OPTION。

  • 反向:无。

以下预初始化的插件 tag 可直接使用:

  • _edns0_filter_no_edns0: 删除应答的 EDNS0。

  • _edns0_filter_ecs_only: 只保留 ECS。

初始化参数说明:

建议流水线位置: 流水线起始,cache 前,转发插件前。

_query_summary (v4.5.3+) 记录请求摘要

在 info 级别记录请求。包括请求的域名,类型,客户端地址,应答状态,请求处理时间等。

建议流水线位置: 流水线起始,cache 前。

注: 如果请求没有或有多个 QUESTION,则不会有记录。

sleep 延时执行

调试。模拟延时用。

流水线逻辑:

  • 正向:延时。

  • 反向:无。

初始化参数说明:

匹配器插件

匹配器插件匹配请求和应答状态,返回 true or false

query_matcher 匹配请求的特征

以下预初始化的插件 tag 可直接使用:

  • _qtype_AAAA: 请求的 QTYPE 是 AAAA。

  • _qtype_A_AAAA: 请求的 QTYPE 是 A 或 AAAA。

  • _query_edns0: 请求包含 EDNS0。

初始化参数说明:

如果一个匹配器内设定了多个条件,则必须满足全部条件这个匹配器才会为 true

response_matcher 匹配应答的特征

以下预初始化的插件 tag 可直接使用:

  • _response_valid_answer: 应答包含有效的 ANSWER 记录(ANSWER 中有记录能与 QUESTION 对应)。(v4.0.0+)

初始化参数说明:

如果一个匹配器内设定了多个条件,则必须满足全部条件这个匹配器才会为 true

域名匹配器

配置示例:

文本域名数据一条规则一行。如果域名匹配方式被省略,则默认是 domain 域匹配。

域名匹配规则说明详见: 这里

IP 匹配器

配置示例:

关于 v2ray 数据包

mosdns 支持从 v2ray 数据包 (俗称 dat 文件)载入数据,但受限于 v2ray 数据包的打包格式,mosdns 从中读取数据,无论读取多少,都要完整解包。多个插件读取多次会出现重复解包的情况。性能不好的设备(主要是嵌入式路由等)上可能造成 mosdns 启动时间显著变长(数秒)。其他设备影响不大。

优化 v2ray 数据包加载速度:

  • (推荐)自己提前解包: mosdns v2dat 小工具命令可以解包数据文件成独立的文本文件。

  • 尽可能使用多标签 geoip.dat:cn,us... 一次载入全部所需数据,而非多行。写成多行会造成重复解包。

补充

域名匹配规则

域名规则有多个匹配方式:

  • domain: 开头,域匹配。e.g: domain:google.com 会匹配自身 google.com,以及其子域名 www.google.com, maps.l.google.com 等。

  • full: 开头,完整匹配。e.g: full:google.com 只会匹配自身。

  • keyword: 开头,关键字匹配。e.g: keyword:google.com 会匹配包含这个字段的域名,如 google.com.hk, www.google.com.hk

  • regexp: 开头,正则匹配(Golang 标准)。e.g: regexp:.+\.google\.com$

如果没有指定匹配方式,不同插件有不同的缺省值。

匹配方式按如下顺序生效: full > domain > regexp > keyword

相同匹配方式的规则按如下顺序生效:

  • domain 规则: 子域名优先。比如如果同时存在规则 google.comcomwww.google.com 会优先匹配 google.com,然后 com。(v3.9.0+)

  • regexpkeyword 规则生效顺序为规则导入的顺序。

性能:

  • domainfull 匹配使用 HashMap,复杂度 O(1)。每 1w 域名约占用 1M 内存。

  • keywordregexp 匹配需遍历,复杂度 O(n)。

到底了!没有找到想要的功能么?提交一个 Feature request

Last updated

Was this helpful?