# 可执行插件

### sequence

按顺序组合多个插件。

sequence 是个可执行插件。可以被其他插件(比如服务器插件)调用。sequence 与 sequence 联动请使用自带的跳转命令 (goto, jump ...)，不要使用 exec 。

{% content-ref url="/pages/vAI0IwrpoC6u4PUNY18L" %}
[Sequence 插件](/mosdns-wiki/mosdns-v5/ru-he-pei-zhi-mosdns/sequence-cha-jian.md)
{% endcontent-ref %}

### cache

缓存 DNS 应答的插件。

如果请求命中缓存，则将缓存的应答放入请求。

当某一请求经过 cache 后，cache 会在这个请求处理流程结束时自动将应答放入缓存。用户无需介入。

注意: 本插件是本地缓存(适用于客户端或者局域网内的缓存)。不适用于服务器端缓存。不支持扩展 DNS 协议 (即 EDNS0)，请求的 EDNS0 部分会被无视，应答的 EDNS0 会被略去。

初始化参数说明:

```yaml
tag: ""
type: "cache"
args:
  size: 1024  # 内置内存缓存大小。单位: 条。默认: 1024。每个 cache 插件的内存缓存是独立的。

  # (实验性) lazy cache 设定。lazy_cache_ttl > 0 会启用 lazy cache。
  # 所有应答都会在缓存中存留 lazy_cache_ttl 秒，但自身的 TTL 仍然有效。如果命中过期的应答，
  # 则缓存会立即返回 TTL 为 5 的应答，然后自动在后台发送请求更新数据。
  # 相比强行增加应答自身的 TTL 的方法，lazy cache 能提高命中率，同时还能保持一定的数据新鲜度。
  lazy_cache_ttl: 0        # lazy cache 生存时间。单位: 秒。默认: 0 (禁用 lazy cache)。
                           # 建议值 86400（1天）~ 259200（3天）
  
  # (实验性) 将缓存保存在磁盘。插件启动时也会自动从该文件载入缓存。
  # 缓存将在 mosdns 被关闭时保存。
  dump_file: ./cache.dump
  # (实验性) 自动保存间隔。单位秒。默认 600。
  # 如果距离上次 dump 有 1024 次更新，则自动保存。
  dump_interval: 600
```

lazy cache，也叫“乐观缓存”，的优缺点：

* 优点：可大幅提高缓存命中率。流行域名几乎 100% 命中。
* 缺点：可能影响 DNS 更新频繁的域名正常使用，比如 DDNS，CDN。
* 仅建议个人使用场景，有相关知识，了解其弊端的专业用户开启。 更多细节请参考 RFC 8767 。

Metrics 数据 `mosdns_cache_<metrics_name>{tag=<plugin_tag>}`:

* query\_total: 总请求数。
* hit\_total: 总命中数。(包括 lazy cache 的命中)
* lazy\_hit\_total: lazy cache 总命中数
* cache\_size: 当前缓存大小。单位: 条。

API:

* GET /flush 清空缓存
* GET /dump 下载缓存
* POST /load\_dump 载入缓存

### hosts

域名映射 IP 。如果请求的域名在 hosts 内，则将应答放入请求。

初始化参数说明:

```yaml
tag: ""
type: "hosts"
args:
  entries:                         # []string
    - "google.com 108.177.122.113" # 记录
  files:                           # []string
    - "./hosts.txt"                # 从外部文件载入。
```

{% hint style="warning" %}
虽然都叫 hosts，但本插件所用的格式和平常 Win，Linux 系统内的那个 hosts 文件不一样。
{% endhint %}

格式:

* 域名规则在前，IP 在后。支持一行多个 IP，支持 IPv6。
* 如果域名匹配规则的方式被省略，则默认是 `full` 完整匹配。域名匹配规则详见 [这里](#yu-ming-pi-pei-gui-ze)。

格式示例:

```
# 支持一行多个 IP
dns.google 8.8.8.8 2001:4860:4860::8888 ...
```

### forward

转发请求至上游服务器。获取应答后放入请求。

初始化参数说明:

```yaml
tag: ""
type: "forward"
args:
  concurrent: 1 # 并发数。每次请求会从下面配置的 upstreams 里随机选取
                # concurrent 个 upstreams 发送请求。取最快返回的应答。超过 3 最多选
                # 3 个。默认 1 。
  upstreams:    # []upstream, 上游服务器。至少要配置一个。
    - tag: google_doh
      addr: "https://dns.google/dns-query"
      dial_addr: "8.8.8.8"
      bootstrap: "8.8.8.8"
      bootstrap_version: 4
      socks5: "127.0.0.1:1080"
      idle_timeout: 30
      enable_pipeline: false
      enable_http3: false
      max_conns: 2
      insecure_skip_verify: false
      so_mark: 0
      bind_to_device: ""
    - addr: "tcp://8.8.8.8"
      enable_pipeline: true
```

* `tag`: 本上游的 tag。用于标识和 log。可省略。同一插件内该 tag 必需唯一。建议全局唯一。
* `addr` 必需。服务器地址。格式: `[protocol://]host[:port][/path]` 。`protocol` 默认为 `udp` 。省略端口号会使用协议的默认值。
  * 支持的 `protocol` 有:
    * `udp`: DNS over UDP 协议。`host` 必需为 IP。
    * `tcp`: 基本 DNS over TCP 协议。`host` 必需为 IP。
    * `tls`: 基本 DNS over TLS 协议。(RFC 7858)
    * `https`: 基本 DNS over HTTPS 协议。基于 HTTP/2 ，但为了兼容也支持 HTTP/1 。使用 GET 请求。(RFC 8484)
    * `quic`: DNS over QUIC 协议。 (RFC 9250)
  * 实际应用中，因为不应该让一个 DNS 解析系统依赖另一个 DNS 解析系统，因此 DNS 服务器的 IP 都是固定的。所以**服务器地址应优先使用 IP 地址而非域名**。这样插件连接服务器时无需先解析服务器的域名，能立刻建立连接。如果 `host` 必需包含域名 (比如一些 DoT/DoH 服务器可能要求请求必需包含 SNI 或 HTTP HOST 头)，可以将 IP 填入 `dial_addr` 。更详细说明：插件会依次尝试从以下途径获取服务器域名的 IP 。
    1. `dial_addr`: IP 协议层面建立连接时使用的地址。如果 `host` 是域名，此处填入 IP 可免去每次建立连接时解析服务器域名。支持指定端口号。
    2. `bootstrap`: (实验性) 手动指定用于解析 `host` 域名的 bootstrap 服务器。只能是 UDP 服务器。不推荐使用此方式。bootstrap 仅适用于没有固定 IP 的服务器，比如自建服务器。`bootstrap_version` 设定 4 或 6 可控制解析 IP 的版本。默认 0 等于 4 。
    3. 让系统去解析。注意: 此方式的解析时间插件不可控，可能影响性能。并且此时 mosdns 不能是系统的 DNS 服务器，否则会出现解析死循环。不推荐使用该方式。后续版本可能会禁止此方式。
* `socks5`: socks5 服务器地址。格式 `host:port`。数据将会通过该代理中转。暂不支持用户名密码认证。只支持基于 TCP 的协议。
* `idle_timeout` TCP/DoT/DoH 连接复用空连接保持时间。单位: 秒。默认 DoH/DoQ: 30 ，TCP/DoT: 10。一般不需要改。
* `enable_pipeline`: TCP/DoT 使用 RFC 7766 新的 query pipelining 连接复用模式。
  * 启用后可大幅提高连接利用率，减少建立连接/握手的次数，进而降低响应延时。
  * 并非所有服务器都支持。必须确定服务器支持后再启用该选项。
  * Tips: 已知 Google 和 Cloudflare 的 TCP/DoT 是支持该模式的。知名的公共 DNS 服务商大多数都支持该模式。可以使用 `mosdns probe pipeline {tcp|tls}://server_ip[:port]` 测试命令测试服务器是否支持。比如 `mosdns probe pipeline tls://8.8.8.8` 。
* `enable_http3`: (实验性) DoH 使用 HTTP/3 连接服务器。
  * 并非所有服务器都支持。必须确定服务器支持后再启用该选项。
* `max_conns`： 默认: 2。
  * (5.3+) 已弃用。最大连接数量由插件自动控制。
  * 启用了 query pipelining 模式的 TCP/DoT 协议: 最大连接数。大流量场景可适当调大。
  * DoH 协议: HTTP 的最大连接数。HTTP/3 除外。大流量场景可适当调大。
* `insecure_skip_verify`: 禁用 TLS 服务器证书验证。
* Linux 套接字设定。需要 `CAP_NET_ADMIN` 权限
  * `so_mark`: 设定 SO\_MARK。
  * `bind_to_device`: 设定 SO\_BINDTODEVICE。

错误处理:

如果 forward 未能从上游获取应答 (连接失败，收到错误数据，等待应答超时等)，则会抛出错误。

请注意: 来自服务器的 SEVFAIL 等应答属于正常的应答。不算错误。

sequence 中的调用参数:

指定上游进行转发。而非全部。

参数: `[upstream_tag] ...`

metrics 数据:

设定了 `upstream.tag` 的上游会有 metrics 数据。

`mosdns_forward_<metric_name>{tag=<plugin_tag>, upstream=<upstream_tag>}`

* query\_total 该上游总请求数。
* err\_total 该上游总出错数。(连接失败，无响应。不包括返回 SERVFAIL 的情况)&#x20;
* thread 该上游的线程数。(此时有多少请求正在被处理中)
* response\_latency\_millisecond 该上游应答返回的延时。
* 底层连接 (HTTP3 无该数据):
  * conn\_opened\_total 该上游打开的连接数。
  * conn\_closed\_total 该上游已关闭的连接数。

### redirect

(实验性插件) 替换(重定向)请求的域名。请求域名 A，但返回域名 B 的记录。

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

初始化参数说明:

```yaml
tag: ""
type: "redirect"
args:
  rules:
  # 格式 [域名匹配规则] [重定向至域名] 
    - www.google.com dns.google
  files:  # 从文件载入规则
    - ./rediect.txt
```

* `域名匹配规则`: 如果匹配方式被省略，则默认是 `full` 完整匹配。域名匹配方式详见 [域名匹配规则](#yu-ming-pi-pei-gui-ze)。

### arbitrary&#x20;

(实验性) arbitrary 可以载入任意 zone file (RFC 1035) 记录，并在匹配到对应请求时生成包含这些记录的应答。

初始化参数说明:

```yaml
tag: ""
type: "arbitrary"
args:
  rules:
    - example.com. 300 IN A 192.0.2.1
    - _sip._tcp.example.com. 86400 IN SRV 0 5 5060 sipserver.example.com.
  files:
    - ./arbitrary.txt
```

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

### reverse\_lookup

(实验性) 用 IP 反查域名。该插件会缓存应答中的 IP 与 域名的关系。支持 PTR 和 HTTP API。

如果是 PTR 请求，并且命中缓存，则生成应答。

初始化参数说明:

```yaml
tag: ""
type: "reverse_lookup"
args:
  size: 65535 # 内置缓存大小。默认 65535。
  
  # 缓存时间。秒。默认 7200 (2h)。应答记录的 TTL 也会被自动修改，限制在该值以下。
  ttl: 7200
  # 是否主动处理/响应 PTR 请求。如果 PTR 的 IP 命中缓存，则生成应答。
  # 用途举例: 使用网络监视类工具查看网络连接时，开启域名反查功能大概率会看到 IP 对应的
  # 真实域名(如果程序先请求域名再建立连接，而且域名经过了该插件处理。)
  handle_ptr: false 
                    
```

查找缓存中 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 域名，末尾有 `.`。

### rate\_limiter

(非常实验性) 用于限制客户端的请求速率。是匹配器。超过限制的请求返回 false。

注意: 此插件目前只能提醒"友善的客户端和用户"控制其流量。不能抗恶意攻击。目前属于中看不中用的插件。后续尝试和 linux 防火墙，脚本调用(云防火墙)等进行联动。

```
tag: ""
type: "rate_limiter"
args:
  qps: 20    # 客户端的请求 qps 限制。默认 20
  burst: 40  # 突发数。允许客户端瞬间突发请求数。默认 40
  mask4: 32  # IPv4 网段掩码。来自同网段的请求会被视为来自同一客户端。默认 32
  mask6: 48  # IPv6 网段掩码。默认 48
```

使用方式举例: 在 sequence 中 rate\_limiter 匹配请求。判断 false (超 qps 请求)，取反，返回 REFUSE。

```
- matches: "!$rate_limit"
  exec: reject 3
```

### fallback

(实验性) 失败时回滚。

```
tag: ""
type: "fallback"
args:
  primary: executable_tag    # 主可执行插件的 tag
  secondary: executable_tag  # 副可执行插件的 tag
  threshold: 500           # 无响应回滚阈值。单位毫秒。默认 500 。
  always_standby: true     # 副可执行插件始终待命。 
```

回滚机制: 如果 primary 抛出错误，或返回但没有应答，或在 threshold 毫秒内无响应，则执行 secondary 。因无响应触发 fallback  时，如果 primary 比 secondary 先返回了应答，则依旧会采用 primary 的应答。

错误处理: 如果 primary 和 secondary 都无应答 (抛出了错误，无响应直到超时，返回了但无应答)，则抛出错误。

always\_standby: secondary 会和 primary 一并执行。secondary 的结果将会在需要回滚时，立刻被采用。

注意: fallback 是多线程。primary 和 secondary 是独立的线程，它们收到的请求是 fallback 收到的请求的镜像。任何一方对请求做出修改不会影响对方，也不会影响 fallback 所在的 [sequence](#sequence-an-shun-xu-zu-he-duo-ge-cha-jian) 。如果 primary 和 secondary 是 sequence ，则它是一级/根 sequence。

注意: 如需提高上游的稳定性，绝大多数(99%)的用户只需设置 forward 并发多个上游。只有极少数用户需要这个插件。

### ecs\_handler

(实验性) (v5.3+) 实现 EDNS0 Client Subnet 相关功能。

```
tag: ""
type: "ecs_handler"
args:
  forward: false        # 是否转发来自下游的 ecs
  preset: 1.2.3.4       # 发送预设 ecs
  send: false           # 是否发送 ecs
  mask4: 24             # ipv4 掩码。默认 24
  mask6: 48             # ipv6 掩码。默认 48
```

优先级:&#x20;

1. 如果 forward == true 并且下游请求包含 ecs。则转发该 ecs。否则
2. 如果 preset != nil。则发送该预设 ecs。否则
3. 如果 send == true，则发送客户端地址。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://irine-sistiana.gitbook.io/mosdns-wiki/mosdns-v5/ru-he-pei-zhi-mosdns/ke-zhi-xing-cha-jian.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
