执行器插件
执行器是 OxiDNS 的核心动作层。它们可以读写请求、设置响应、调用上游、缓存结果、做回退、记录日志,或触发系统联动。
阅读本章时,应重点关注以下两个问题:
- 这个插件是在“正向阶段”生效,还是在“回程阶段”也会改写结果?
- 它是主路径动作,还是观测/副作用动作?
sequence
作用
把多个 matcher 和 executor 编排成一条流水线,是最常用的入口执行器。
配置示例
- tag: seq_main
type: sequence
args:
# 先尝试读取缓存
- exec: "$cache_main"
# 命中缓存后直接结束
- matches: "has_resp"
exec: "accept"
# 多个 matches 写成数组时是逻辑与
# 示例里尽量直接写 quick setup 表达式
- matches:
- "client_ip $lan_ip_set"
- "qname $local_domains"
exec: "$hosts_main"
# 没有前置条件时也可以直接执行观测类插件
- exec: "$metrics_main"
# 还没有响应时再继续转发
- matches: "!has_resp"
exec: "$forward_main"
# 响应回来后统一收敛 TTL
- matches: "has_resp"
exec: "$ttl_main"
配置项
sequence 的 args 为规则数组,数组中的每个元素代表一条顺序执行规则。
args
- 类型:
array;必填:是;默认值:无 - 作用:定义 sequence 的规则链。
- 运行影响:
- 规则按书写顺序依次执行。
args为空时插件初始化失败。
args[].matches
- 类型:
string或array - 必填:否
- 默认值:无
- 作用:定义当前规则的匹配条件。
- 支持形式:
- 单个 matcher 字符串
- 多个 matcher 组成的列表
- 运行影响:
- 多个条件之间为逻辑与关系。
- 未配置时表示无前置匹配条件。
args[].exec
- 类型:
string;必填:否;默认值:无 - 作用:定义规则命中后要执行的动作。
- 支持内容:
- 插件引用
- quick setup 表达式
- 内建控制流
- 运行影响:
- 直接决定当前规则的执行行为。
行为说明
- 按顺序执行规则。
- 一条规则里多个
matches需要同时为真。 - 可以通过
jump/goto调用其它sequence。
内建控制流
sequence.args[].exec 除了调用插件,也可以直接写内建控制流:
accept
- 立即结束当前
sequence。 - 这是一次明确的提前停止,因此外层不会继续执行后续规则。
- 不会自动生成响应;通常用于前面已经有 response 的场景。
return
- 立即结束当前
sequence,并把控制权交回调用方。 - 不会自动生成响应。
- 若当前
sequence是被jump调用的,调用方会从下一条规则继续。
reject [rcode]
- 立即生成响应并结束当前
sequence。 - 默认
rcode为REFUSED。 - 支持十进制数值和大小写不敏感的英文 RCODE 名称,例如
reject 2、reject SERVFAIL、reject servfail、reject NXDOMAIN;常见映射与含义见 DNS 编码速查表。 - 只支持基础 DNS RCODE
0..15;扩展 RCODE 需要 EDNS OPT,不会由该内建动作自动生成。 reject 0返回普通NOERROR响应,不会自动附加 SOA。- 会中断后续规则,不再继续执行。
mark ...
- 写入一个或多个整数 mark,然后继续当前
sequence的下一条规则。 - 支持
mark 1、mark 1 2 3、mark 1,2,3。
jump seq_tag
- 调用另一个
sequence,语义类似子过程调用。 - 参数必须是目标
sequence的 tag,不能写$。 - 目标
sequence跑到尾部或执行return后,当前sequence会继续下一条规则。 - 如果目标
sequence执行accept/reject/ 其它Stop,当前sequence也会停止。
goto seq_tag
- 把控制权单向转交给另一个
sequence。 - 参数必须是目标
sequence的 tag,不能写$。 - 一旦执行
goto,当前sequence就不会再回到后续规则。 - 若目标
sequence执行return,该return会继续向外层传播。
典型用途
- 统一总入口。
- 把缓存、本地应答、转发、联动拆分成可读的策略层。
- 通过 marks、matchers 做复杂分支。
- 被引用的插件必须已经定义。
sequence至少需要一条规则。
forward
作用
向上游发起 DNS 查询。
配置示例
- tag: forward_main
type: forward
args:
# 多上游模式下实际并发扇出
concurrent: 3
# 并发上游结果选择模式:fastest / balanced / prefer_positive / consensus
response_selection: balanced
upstreams:
# 最简单的 UDP 上游
- tag: "cf_udp"
addr: "udp://1.1.1.1:53"
timeout: 3s
# 域名型 DoH 上游,演示 bootstrap / 连接池 / HTTP/3 / Linux socket 参数
- tag: "doh_main"
addr: "https://resolver.example/dns-query"
bootstrap: "8.8.8.8:53"
bootstrap_version: 4
port: 443
idle_timeout: 30
min_conns: 2
max_conns: 256
timeout: 5s
enable_pipeline: false
enable_http3: true
so_mark: 100
bind_to_device: "eth0"
# DoT 上游,演示 dial_addr / SOCKS5 / TLS 校验开关 / pipeline
- tag: "dot_backup"
addr: "tls://dns.example:853"
dial_addr: "203.0.113.53"
socks5: "user:pass@127.0.0.1:1080"
idle_timeout: 60
min_conns: 1
max_conns: 128
insecure_skip_verify: false
timeout: 4s
enable_pipeline: true
配置项
concurrent
- 类型:
integer;必填:否;默认值:1 - 取值范围:实际运行时会限制在
1..=32,且不会超过上游数量 - 作用:定义多上游模式下的并发查询扇出数。
- 运行影响:
- 值越大,多上游竞争越积极,但同时会增加上游请求量。
- 推荐常规配置使用
2..=8;更高值适合短期观测或明确需要多协议竞速的场景。
response_selection
- 类型:
string;必填:否;默认值:balanced - 取值:
fastest、balanced、prefer_positive、consensus - 作用:定义多上游并发返回不一致时的结果选择策略。
- 模式说明:
fastest:第一个成功返回的 DNS 响应胜出,传输错误不会胜出。balanced:默认模式。NOERROR且包含答案时立即胜出;NXDOMAIN或 NODATA 会短暂等待是否有正向答案。prefer_positive:正向答案立即胜出;负向答案等待已发起的并发上游全部结束后再返回。consensus:正向答案立即胜出;负向答案需要两个上游确认,若并发数不足则退化为prefer_positive。
upstreams
- 类型:
array;必填:是;默认值:无 - 作用:定义一个或多个上游目标。
- 运行影响:
- 数组长度为
1时使用单上游模式。 - 数组长度大于
1时使用竞争式查询模式。
- 数组长度为
short_circuit
- 类型:
boolean;必填:否;默认值:false - 作用:控制在拿到成功上游响应后,是否立即停止后续 executor 链。
- 说明:
- 关闭时,
forward仍会写入response,但后续 executor 还能继续处理这份响应。 - 开启时,成功返回后会直接结束后续 executor 链。
- 关闭时,
upstreams[].addr
- 类型:
string;必填:是;默认值:无 - 作用:定义上游地址、协议类型以及目标主机。
- 示例:
addr: "8.8.8.8:53"addr: "tls://dns.example:853"addr: "https://resolver.example/dns-query"
- 支持格式:
udp://8.8.8.8:53或8.8.8.8:53tcp://8.8.8.8:53tcp+pipeline://8.8.8.8:53tls://dns.example:853tls+pipeline://dns.example:853quic://dns.example:853或doq://dns.example:853https://resolver.example/dns-query或doh://resolver.example/dns-queryh3://resolver.example/dns-query
- 规则说明:
- 未写协议时,按
udp://处理。 https:///doh://表示 DoH,h3://表示强制 DoH over HTTP/3。tcp+pipeline://与tls+pipeline://会直接启用流水线模式。- DoH 地址应包含实际请求路径,例如
/dns-query。
- 未写协议时,按
- 解析行为:启动和配置校验阶段不会解析域名型上游;未配置
bootstrap或dial_addr时,会在首次建连时使用系统解析。 - 配置建议:域名型上游建议在
bootstrap和dial_addr中二选一,避免运行期形成对本机 DNS 的引导解析依赖。 - 互斥规则:
bootstrap和dial_addr同时配置时,只有dial_addr生效,bootstrap会被忽略。
upstreams[].tag
- 类型:
string;必填:否;默认值:无 - 作用:为单个上游提供日志标识,便于排查多上游竞争结果。
- 示例:
tag: "upstream_google"
upstreams[].dial_addr
- 类型:
ip;必填:否;默认值:无 - 作用:指定实际连接 IP,同时保留
addr中的主机名用于 SNI、Host 和证书校验。 - 示例:
dial_addr: "1.1.1.1" - 适用场景:固定拨号地址、绕过本机解析或配合自定义路由出口。
- 互斥规则:与
bootstrap同时配置时,本字段优先生效。
upstreams[].outbound
- 类型:
string;必填:否 - 作用:引用
network.outbound.profiles中的出站配置,为该上游注入 resolver 和 proxy。 - 默认:未配置时使用
network.outbound.default;没有 default 时保持系统解析/直连。 - 覆盖规则:本地
dial_addr优先于 resolver;本地bootstrap优先于 outbound resolver;本地socks5优先于 profile proxy。 - 注意:profile proxy 只应用于 TCP、DoT 和 DoH2;UDP、DoQ、DoH3 upstream 会忽略 SOCKS5 proxy。
upstreams[].port
- 类型:
integer;必填:否;默认值:协议默认端口 - 作用:覆盖协议默认端口。
- 示例:
port: 5353
upstreams[].bootstrap
- 类型:
string;必填:否;默认值:无 - 作用:为域名型上游提供引导解析服务器。
- 示例:
bootstrap: "8.8.8.8:53"bootstrap: "[2606:4700:4700::1111]:53"
- 规则说明:
- 仅在
addr使用域名时有意义。 - 应写为
IP:port,不能再写域名。 - 典型用于 DoT、DoQ、DoH 域名上游的首次解析。
- 使用
bootstrap后,上游域名解析由 OxiDNS 查询该引导服务器完成,并按 TTL 缓存。 - 与
dial_addr同时配置时,本字段会被忽略。
- 仅在
upstreams[].bootstrap_version
- 类型:
integer;必填:否;默认值:无 - 作用:指定 bootstrap 优先使用 IPv4 或 IPv6。
- 示例:
bootstrap_version: 4bootstrap_version: 6
- 取值:
4或6。
upstreams[].socks5
- 类型:
string;必填:否;默认值:无 - 作用:为上游连接指定 SOCKS5 代理。
- 示例:
socks5: "127.0.0.1:1080"socks5: "user:pass@127.0.0.1:1080"socks5: "user:pass@[2001:db8::1]:1080"
- 支持格式:
host:portusername:password@host:port- IPv6 需写成
[addr]:port - 带认证的 IPv6 需写成
username:password@[addr]:port
- 规则说明:
- 代理主机可以是 IP,也可以是主机名;主机名会使用系统解析。
- 认证部分只按第一个
:分割用户名和密码,因此格式必须是username:password@...。 - SOCKS5 只应用于 TCP、DoT 和 DoH2;UDP、DoQ、DoH3 upstream 会忽略该设置。
- 注意事项:格式错误、端口非法或代理主机解析失败时,该上游不会被正常创建。
upstreams[].idle_timeout
- 类型:
integer;必填:否;默认值:10 - 单位:秒
- 作用:定义连接池空闲连接保留时间。
- 示例:
idle_timeout: 30
upstreams[].max_conns
- 类型:
integer;必填:否;默认值:64 - 作用:定义连接池连接上限。
- 取值范围:
1..4096 - 示例:
max_conns: 256
upstreams[].min_conns
- 类型:
integer;必填:否;默认值:0 - 作用:定义连接池保持预热的最小连接数。
- 取值范围:
0..4096,且不能大于当前上游的有效max_conns。 - 说明:未配置时保持懒加载,不会在启动或 pool 创建时主动预建连接。
- 示例:
min_conns: 2
upstreams[].insecure_skip_verify
- 类型:
boolean;必填:否;默认值:false - 作用:控制是否跳过 TLS 证书校验。
- 示例:
insecure_skip_verify: true - 注意事项:仅适用于测试、自签证书或受控环境。
upstreams[].timeout
- 类型:
duration;必填:否;默认值:5s - 作用:定义单次上游查询超时。
- 示例:
timeout: 3s
upstreams[].enable_pipeline
- 类型:
boolean;必填:否;默认值:false - 作用:控制 TCP 或 DoT 流水线。
- 示例:
enable_pipeline: true - 说明:也可直接通过
tcp+pipeline://或tls+pipeline://在addr中启用。 - 建议:开启前先用
oxidns probe upstream <addr>探测目标上游。该命令会对 TCP/DoT 强制同一条连接并发查询,帮助判断该上游是否适合启用 pipeline,避免遇到超时、连接关闭、响应 ID 错乱或 question 串线。 - 判定:探测结果为
supported时再考虑开启;如果为unsupported、unstable或inconclusive,建议保持关闭,或降低并发 / 延长超时后重新测试。
upstreams[].enable_http3
- 类型:
boolean;必填:否;默认值:false - 作用:控制 DoH 是否使用 HTTP/3。
- 示例:
enable_http3: true - 说明:也可直接通过
h3://在addr中启用。
upstreams[].so_mark
- 类型:
integer;必填:否;默认值:无 - 作用:设置 Linux
SO_MARK。 - 示例:
so_mark: 100
upstreams[].bind_to_device
- 类型:
string;必填:否;默认值:无 - 作用:设置 Linux
SO_BINDTODEVICE。 - 示例:
bind_to_device: "eth1"
quick setup
- exec: "forward 1.1.1.1"
- exec: "forward 1.1.1.1 8.8.8.8"
- exec: "forward 1.1.1.1 short_circuit=true"
说明:
- 单个地址创建单上游转发。
- 多个地址创建并发竞争转发。
- quick setup 支持尾部开关
short_circuit、short_circuit=true、short_circuit=false。 - 其它进阶参数需要完整插件形式。
行为说明
- 单上游模式:直接查询该上游。
- 多上游模式:从随机起点选择上游并发查询,先返回成功结果者胜出。
- 开启
short_circuit时,一旦拿到可用上游响应,就会立即停止后续 executor 链。
Metrics
通过全局 GET /api/metrics 导出:
forward_query_totalforward_success_totalforward_error_totalforward_timeout_totalforward_latency_countforward_latency_sum_ms
每个上游另外导出带 upstream 标签的指标(标签值为上游 tag,未配置时为解析后的地址):
forward_upstream_query_totalforward_upstream_success_totalforward_upstream_error_totalforward_upstream_timeout_totalforward_upstream_latency_countforward_upstream_latency_sum_ms
常见用途
- 标准转发。
- 多上游容错。
- 多协议混合上游。
- 需要更细的并发、代理、引导解析、HTTP/3 参数时,使用完整
upstreams配置。 - 多上游越多并不一定越好,先保证上游分组语义清晰。
cache
作用
对响应做 TTL 感知缓存,支持负缓存与持久化。
配置示例
- tag: cache_main
type: cache
args:
# 最大缓存条目数
size: 8192
# 命中缓存后直接结束后续执行
short_circuit: true
# 允许在原始 TTL 过期后短时间返回 stale 响应,并异步刷新缓存
lazy_cache_ttl: 120
# 开启 NXDOMAIN / NODATA 负缓存
cache_negative: true
# 负缓存 TTL 上限
max_negative_ttl: 300
# 负响应没有 SOA 时使用的回退 TTL
negative_ttl_without_soa: 60
# 正响应 TTL 上限
max_positive_ttl: 600
# 正响应进入缓存所需的最小 TTL
min_positive_ttl: 4
# ECS 不参与缓存键,提升命中率
ecs_in_key: false
# 启用缓存持久化
dump_file: "./dns_cache.dump"
# 定期落盘周期,单位秒
dump_interval: 600
配置项
size
- 类型:
integer;必填:否;默认值:1024 - 作用:定义缓存最大条目数。
lazy_cache_ttl
- 类型:
integer;必填:否;默认值:无 - 单位:秒
- 作用:为正向成功响应启用 lazy cache。
- 运行影响:
- 原始 TTL 决定 fresh 命中窗口。
lazy_cache_ttl决定 stale 回包 TTL,并允许在原始 TTL 过期后短时间返回 stale 响应。- stale 命中会在后台异步刷新缓存。
- 该配置不会缩短原始 fresh TTL。
dump_file
- 类型:
string;必填:否;默认值:无 - 作用:指定缓存持久化文件路径。
dump_interval
- 类型:
integer;必填:否;默认值:600 - 单位:秒
- 作用:定义缓存定期落盘周期。
short_circuit
- 类型:
boolean;必填:否;默认值:false - 作用:控制缓存命中后是否立即结束后续执行。
- 说明:
- 设为
false时,即使 cache 已经写入 response,后续执行链仍会继续。 - 如需避免后续
forward再次发起查询,应在sequence中配合has_resp、accept等控制流使用。
- 设为
cache_negative
- 类型:
boolean;必填:否;默认值:true - 作用:控制是否缓存 NXDOMAIN 与 NODATA。
max_negative_ttl
- 类型:
integer;必填:否;默认值:300 - 单位:秒
- 作用:定义负缓存 TTL 上限。
negative_ttl_without_soa
- 类型:
integer;必填:否;默认值:60 - 单位:秒
- 作用:定义无 SOA 负响应的回退 TTL。
max_positive_ttl
- 类型:
integer;必填:否;默认值:无 - 单位:秒
- 作用:定义正响应 TTL 上限。
min_positive_ttl
- 类型:
integer;必填:否;默认值:无 - 单位:秒
- 作用:定义正响应进入缓存所需的最小 TTL。
- 说明:正响应的有效缓存 TTL 低于该值时不会写入缓存。该判断在
max_positive_ttl裁剪之后执行。
ecs_in_key
- 类型:
boolean;必填:否;默认值:false - 作用:控制 ECS scope 是否参与缓存键计算。
quick setup
- exec: "cache"
- exec: "cache short_circuit=true"
说明:
- 不带参数时使用默认缓存配置。
- 目前 quick setup 支持尾部开关
short_circuit、short_circuit=true、short_circuit=false。 - 其它高级参数仍建议使用完整插件形式。
行为说明
- 既会读缓存,也会在后续拿到响应后写缓存。
- 命中缓存时,返回缓存副本并按剩余 TTL 输出。
- 内置过期清理和近似 LRU 回收。
插件 API
GET /plugins/<tag>/entries- 分页读取缓存项;支持
limit、cursor和qname查询参数,其中qname按缓存键域名做大小写不敏感的包含筛选。
- 分页读取缓存项;支持
GET /plugins/<tag>/flush- 清空缓存。
GET /plugins/<tag>/dump- 导出缓存内容。
POST /plugins/<tag>/load_dump- 导入缓存 dump。
Metrics
通过全局 GET /api/metrics 导出,不提供 cache 专属 stats/metrics 接口。
cache_lookup_totalcache_hit_total{kind="fresh|stale"}cache_miss_totalcache_expired_totalcache_insert_totalcache_skip_total{reason="truncated|no_ttl|low_positive_ttl"}cache_lazy_refresh_total{result="started|success|failed"}cache_entry_count
典型用途
- 所有转发入口前置缓存。
- 构建高命中率低时延策略。
- 在可控场景中持久化缓存,加快重启后恢复。
- 如果前面有会直接生成本地应答的插件,放置位置会决定这些结果是否进入缓存。
ecs_in_key开启后,缓存碎片会明显增加。
fallback
作用
在主路径失败或过慢时,切换到备用路径。
配置示例
- tag: fallback_main
type: fallback
args:
# 首选路径
primary: "forward_fast"
# 兜底路径
secondary: "forward_stable"
# 主路径超过 200ms 后允许备用路径接管
threshold: 200
# 让备用路径始终并行待命,换取更低尾延迟
always_standby: true
配置项
primary
- 类型:
string;必填:是;默认值:无 - 作用:指定主执行器。
secondary
- 类型:
string;必填:是;默认值:无 - 作用:指定备用执行器。
threshold
- 类型:
integer;必填:否;默认值:0 - 单位:毫秒
- 作用:定义主路径超时或延迟判定阈值。
always_standby
- 类型:
boolean;必填:否;默认值:false - 作用:控制备用路径是否与主路径同时待命。
short_circuit
- 类型:
boolean;必填:否;默认值:false - 作用:控制在主/备路径选出最终响应后,是否立即停止后续 executor 链。
行为说明
- 正向启动主路径。
- 到达阈值或主路径失败后启动/释放备用路径。
- 谁先拿到有效响应,谁赢。
- 另一分支会被取消。
- 开启
short_circuit时,胜出分支写回响应后会直接结束后续 executor 链。
Metrics
通过全局 GET /api/metrics 导出:
fallback_primary_totalfallback_primary_error_totalfallback_secondary_total
典型用途
- 快速上游 + 稳定上游的双层回退。
- 不同协议上游之间的故障兜底。
- 这是“路径级”回退,不是“记录级”合并。
always_standby可以降低尾延迟,但会放大上游开销。
hosts
作用
按域名规则直接返回静态 A / AAAA。
配置示例
- tag: hosts_main
type: hosts
args:
entries:
# 无前缀规则默认按 full: 处理
- "router.local 192.168.1.1"
# 精确匹配单个主机名
- "full:gateway.local 192.168.1.2"
# 后缀匹配,可同时返回 IPv4 / IPv6
- "domain:svc.local 10.0.0.10 fd00::10"
# 关键字匹配
- "keyword:nas 192.168.1.20"
# 正则匹配
- "regexp:^api[0-9]+\\.corp\\.local$ 10.10.0.5"
files:
# 从文件合并更多 hosts 规则
- "/etc/oxidns/hosts.txt"
short_circuit: true
配置项
entries
- 类型:
array;必填:否;默认值:空数组 - 作用:定义内联 hosts 规则。
- 规则格式:
<域名规则> <ip1> <ip2> ...
files
- 类型:
array;必填:否;默认值:空数组 - 作用:指定外部 hosts 规则文件列表。
short_circuit
- 类型:
bool;必填:否;默认值:false - 作用:命中并生成本地应答后,是否立即停止后续 executor 链。
行为说明
- 仅处理“恰好一个 question”的
IN类A/AAAA请求。 - 无前缀规则默认等价于
full:,与 mosdnshosts保持一致。 - 规则优先级固定为
full -> domain -> regexp -> keyword。 domain:按最长后缀命中。- 相同 pattern 按加载顺序后写覆盖前写;加载顺序为
entries先,再按files顺序逐文件逐行覆盖。 - 根据查询类型返回同族地址,正向本地答案 TTL 固定为
10。 - 域名命中但请求家族没有对应地址时,返回
NoError + 空 Answer + fake SOA,不会透传后续执行。 - 未命中时透传后续执行。
- 命中后默认继续后续执行;开启
short_circuit时,无论是正向答案还是空本地答复,都会立即停止后续 executor 链。
Metrics
通过全局 GET /api/metrics 导出:
hosts_hit_totalhosts_miss_total
典型用途
- 本地服务名。
- 固定内部地址映射。
- 小规模静态域名覆盖。
arbitrary
作用
加载任意静态 DNS 记录并在命中时直接构造应答。
配置示例
- tag: arbitrary_main
type: arbitrary
args:
rules:
# TXT 记录
- "example.com. 60 IN TXT \"hello world\""
# MX 记录
- "mail.example.com. 300 IN MX 10 mx1.example.com."
# A / AAAA / CNAME / PTR 也都可以直接写
- "www.example.com. 120 IN A 192.0.2.10"
- "www.example.com. 120 IN AAAA 2001:db8::10"
- "alias.example.com. 120 IN CNAME www.example.com."
- "10.2.0.192.in-addr.arpa. 300 IN PTR host.example.com."
files:
# 从文件加载更多静态记录
- "/etc/oxidns/zone.txt"
short_circuit: false
配置项
rules
- 类型:
array;必填:否;默认值:空数组 - 作用:定义内联静态记录列表。
- 语法:
- 每个数组项会作为独立 zone 片段解析。
- 支持
$ORIGIN、$TTL、$INCLUDE、$GENERATE、owner 继承、TTL 单位写法、注释、quoted string、多行()语法。 - 常见记录类型支持直接文本解析,包括
A、AAAA、CNAME、NS、PTR、DNAME、ANAME、MD、MF、MB、MG、MR、NSAPPTR、MX、RT、AFSDB、RP、MINFO、HINFO、TXT、SPF、AVC、RESINFO、SOA、SRV、NAPTR、CAA。 - 其他记录类型可通过 RFC3597 通用语法
TYPE#### \# <len> <hex>导入。 - 省略 TTL 时默认使用
3600。
files
- 类型:
array;必填:否;默认值:空数组 - 作用:指定静态记录文件列表。
- 语法:使用同一套 zone parser,支持与
rules一致的语法能力。
short_circuit
- 类型:
bool;必填:否;默认值:false - 作用:命中并生成本地响应后,是否立即停止后续 executor 链。
- 说明:默认只设置 response 并继续执行;显式开启时返回
Stop。
行为说明
- 按
qname + qtype + qclass精确匹配。 - 一个请求里如果有多个 question,会把所有命中的记录按顺序累积到同一个响应中。
- 命中后默认只设置 response,不会中断后续 executor 链。
- 开启
short_circuit时,命中后会立即结束后续 executor 链。 - 不提供
quick setup语法。
典型用途
- 少量静态权威式记录。
- 本地 TXT / MX / PTR / CNAME 数据。
- 测试或实验环境的本地响应。
- 这是“静态响应生成器”,不负责 zone 传送、动态更新或权威服务器完整语义。
- 解析器能力比 mosdns
arbitrary使用的 zone parser 更宽,但命中行为仍是静态记录的精确匹配。
redirect
作用
把请求域名改写为另一个目标域名,并在返回阶段补回客户端可见的 CNAME。
配置示例
- tag: redirect_main
type: redirect
args:
rules:
# 精确重定向
- "full:old.example.com new.example.net"
# 后缀重定向
- "domain:legacy.example.com modern.example.net"
# 关键字重定向
- "keyword:staging staging-gateway.example.net"
# 正则重定向
- "regexp:^api[0-9]+\\.legacy\\.example\\.com$ api-gateway.example.net"
# 无前缀规则默认按 full: 处理
- "old-static.example.com static.example.net"
files:
# 从文件合并更多重定向规则
- "/etc/oxidns/redirect.txt"
配置项
rules
- 类型:
array;必填:否;默认值:空数组 - 作用:定义内联重定向规则。
- 规则格式:
<域名规则> <目标域名>
<域名规则>支持:full:domain:keyword:regexp:- 无前缀域名(按
full:精确匹配处理)
files
- 类型:
array;必填:否;默认值:空数组 - 作用:指定外部重定向规则文件列表。
- 文件格式与
rules相同,每行一条;空行和#注释会被忽略。
规则格式:
full:old.example.com new.example.net
domain:legacy.example.com modern.example.net
keyword:staging staging-gateway.example.net
regexp:^api[0-9]+\.legacy\.example\.com$ api-gateway.example.net
old-static.example.com static.example.net
行为说明
- 仅处理
IN类请求;没有 question 或未命中时透传后续 executor。 - 多条规则同时命中时,按加载顺序最先出现的规则生效;加载顺序为
rules先,再按files顺序逐文件逐行加载。 redirect本身不解析目标域名,需要在sequence中配合forward等后续 executor 使用,由后续 executor 生成目标域名的真实响应。- 正向阶段:改写请求的 QUESTION NAME。
- 回程阶段:
- 把 response question 中的目标名还原为原始名。
- 在 answers 开头插入一条
CNAME original -> target。
常见 sequence 用法:
- exec: "$redirect_main"
- exec: "$forward_main"
典型用途
- 统一入口域名指向另一套记录。
- 对特定域名做别名跳转而不改客户端配置。
- 通常应把
redirect放在forward之前;如果后续链路没有产生 response,redirect不会凭空生成目标记录。 - 更适合 A/AAAA/TXT 这类简单请求。
- 对复杂记录和某些扩展场景不保证完全语义透明。
ecs_handler
作用
处理 EDNS Client Subnet。
配置示例
- tag: ecs_main
type: ecs_handler
args:
# 客户端自带 ECS 时先移除
forward: false
# 请求没有 ECS 时自动补发
send: true
# IPv4 ECS 前缀长度
mask4: 24
# IPv6 ECS 前缀长度
mask6: 48
- tag: ecs_preset
type: ecs_handler
args:
# 预设 ECS 地址
preset: "203.0.113.10"
# 固定来源模式下也建议显式写出策略开关
forward: false
send: true
mask4: 24
mask6: 48
配置项
forward
- 类型:
boolean;必填:否;默认值:false - 作用:控制是否保留客户端请求中已有的 ECS。
send
- 类型:
boolean;必填:否;默认值:false - 作用:控制在请求缺少 ECS 时,是否根据来源地址自动补充 ECS。
preset
- 类型:
string;必填:否;默认值:无 - 作用:指定固定的 ECS 来源地址。
mask4
- 类型:
integer;必填:否;默认值:24 - 作用:指定 IPv4 ECS 前缀长度。
mask6
- 类型:
integer;必填:否;默认值:48 - 作用:指定 IPv6 ECS 前缀长度。
quick setup
- exec: "ecs_handler 203.0.113.10/24"
当前 quick setup 主要用于传入 preset IP。涉及高级开关时,应使用完整配置形式。
行为说明
- 正向阶段:
- 可删掉已有 ECS。
- 可保留已有 ECS。
- 可根据客户端地址或 preset 注入 ECS。
- 回程阶段:
- 如果 ECS 不是从客户端原样转发的,会把响应里的 ECS 去掉,避免泄露内部构造信息。
典型用途
- 面向策略上游携带客户端网段信息。
- 在网关场景下根据访问来源做更细粒度结果优化。
mask4最大32,mask6最大128。
forward_edns0opt
作用
把指定 EDNS0 option code 从下游请求转发到最终响应中。
配置示例
- tag: edns_forward
type: forward_edns0opt
args:
# 只透传指定的 EDNS0 option code
codes: [10, 12]
配置项
codes
- 类型:
array;必填:否;默认值:空数组 - 作用:定义允许从请求复制到响应中的 EDNS0 option code 集合。
- 运行影响:
- 未配置时插件基本退化为无操作。
quick setup
- exec: "forward_edns0opt 10,12"
行为说明
- 正向阶段从请求里收集目标 option。
- 回程阶段把这些 option 写回响应的 OPT 记录。
- 会做去重。
典型用途
- 透传特定 EDNS0 扩展。
- 在策略链中保留与下游会话有关的附加元数据。
ttl
作用
改写响应 TTL。
配置示例
完整对象形式:
- tag: ttl_main
type: ttl
args:
# 先把 TTL 固定为 300
fix: 300
# 再做下限兜底
min: 60
# 再做上限约束
max: 600
配置项
fix
- 类型:
integer;必填:否;默认值:无 - 作用:将所有响应 TTL 固定为同一个值。
min
- 类型:
integer;必填:否;默认值:无 - 作用:定义 TTL 下限。
max
- 类型:
integer;必填:否;默认值:无 - 作用:定义 TTL 上限。
quick setup
- exec: "ttl 300"
- exec: "ttl 60-600"
行为说明
- 会改写 answers、authority、additionals 中的 TTL。
- 适合放在获得响应之后。
典型用途
- 缩短高波动域名的 TTL。
- 统一本地策略结果的缓存行为。
ip_selector
ip_selector 在 v1.2.0 首次发布,目前处于实验阶段:配置字段、默认值、探测策略与缓存语义可能在后续版本根据实际使用反馈调整。建议在非关键链路先行验证,关注 release notes 中的相关变更说明。
作用
响应 IP 优选器。它只处理已有 response 中的 A/AAAA 地址记录,根据缓存评分和有界测速结果进行稳定排序或裁剪。
ip_selector 不负责上游响应竞速、双栈抑制或域名规则。上游竞速继续使用 forward / fallback,双栈策略继续使用 prefer_ipv4 / prefer_ipv6,域名差异化策略继续用 sequence、matcher 和 provider 组合多个插件实例。
配置示例
- tag: ip_select
type: ip_selector
args:
selection_mode: first_success
outbound: remote
probe_methods: ["tcp:443", "tcp:80"]
probe_stagger: 200
probe_timeout: 600
max_wait: 1000
top_n: 1
dnssec_policy: reorder_only
max_parallel_probes: 256
cache:
enabled: true
size: 4096
ttl: 3600
failure_ttl: 60
推荐放在 cache 之前,让 cache 保存原始上游响应,ip_selector 在返回路径做最终优选:
- exec: $ip_select
- exec: $cache_main
- matches: !$has_resp
exec: $forward_main
- exec: accept
配置项
selection_mode
- 类型:
string;必填:否;默认值:first_success - 可选值:
first_success、best_within_budget、background - 作用:
first_success:返回第一个成功测速的候选 IP。best_within_budget:在max_wait预算内选择最低延迟 IP。background:优先返回原响应或缓存排序结果,并在后台刷新测速缓存。
probe_methods
- 类型:
array<string> | string;必填:否;默认值:["tcp:443", "tcp:80"] - 可选值:
tcp:<port>、ping、none - 作用:定义用于评分 IP 的探测方法。
ping为 best-effort;平台或权限不支持时会失败开放。
outbound
- 类型:
string;必填:否;默认值:network.outbound.default - 作用:引用
network.outbound.profiles中的出站配置,为 TCP 探测复用 profile proxy。 - 说明:
- 仅
tcp:<port>探测会使用 proxy;ping始终走本机命令。 - 本字段只使用 profile proxy,不会对目标 IP 再做 resolver 解析。
- 仅
socks5
- 类型:
string;必填:否;默认值:无 - 作用:为 TCP 探测指定局部 SOCKS5 代理。
- 说明:
- 格式与
upstreams[].socks5一致。 - 同时配置
outbound和socks5时,局部socks5覆盖 profile proxy。 - 仅
tcp:<port>探测会使用 SOCKS5;ping始终走本机命令。
- 格式与
probe_stagger
- 类型:
integer;单位:毫秒;必填:否;默认值:200 - 作用:多种测速方式之间的错峰启动间隔。
probe_timeout
- 类型:
integer;单位:毫秒;必填:否;默认值:600 - 作用:单次 IP 探测超时时间。
max_wait
- 类型:
integer;单位:毫秒;必填:否;默认值:1000 - 作用:一次响应优选最多等待多久。
top_n
- 类型:
integer;必填:否;默认值:1 - 作用:保留排序后的前 N 个地址。设为
0时只重排,不删除记录。
dnssec_policy
- 类型:
string;必填:否;默认值:reorder_only - 可选值:
reorder_only、skip - 作用:请求带 DO bit 或响应含覆盖 A/AAAA 的 RRSIG 时,默认只重排不裁剪;设为
skip时完全跳过优选。
max_parallel_probes
- 类型:
integer;必填:否;默认值:256 - 作用:限制插件级并发探测数量,避免冷查询大量 fanout。
cache
- 类型:
object;必填:否 - 子字段:
enabled:是否启用探测评分缓存,默认true。size:缓存容量目标,默认4096。ttl:成功评分保留时间,单位秒,默认3600。failure_ttl:失败评分保留时间,单位秒,默认60。
quick setup
- exec: "ip_selector"
- exec: "ip_selector best_within_budget tcp:443,tcp:80,ping"
ip_selector 只接受上面列出的 OxiDNS 原生命名,不提供兼容别名。
指标
ip_selector_probe_total{method,result}ip_selector_probe_latency_count{method}ip_selector_probe_latency_sum_ms{method}ip_selector_selected_total{source="probe|cache|fallback"}ip_selector_cache_entriesip_selector_dropped_probe_total{reason="parallel_limit|inflight"}
prefer_ipv4 / prefer_ipv6
作用
双栈优选器。对偏好类型做学习,对非偏好类型做抑制。
配置示例
- tag: prefer_v4
type: prefer_ipv4
args:
# 记录 preferred 类型是否存在
cache: true
# preferred 状态缓存时长
cache_ttl: 3600
配置项
cache
- 类型:
boolean;必填:否;默认值:true - 作用:控制是否缓存 preferred 类型存在状态。
cache_ttl
- 类型:
integer;必填:否;默认值:3600 - 单位:秒
- 作用:定义 preferred 状态缓存时长。
quick setup
- exec: "prefer_ipv4"
- exec: "prefer_ipv6"
说明:
- quick setup 使用默认配置:
cache: true、cache_ttl: 3600。 - 如需关闭缓存或调整缓存时长,请使用完整插件配置。
行为说明
prefer_ipv4- 偏好
A。
- 偏好
prefer_ipv6- 偏好
AAAA。
- 偏好
- 偏好类型请求正常放行,并记录“该域名存在 preferred answer”。
- 非偏好类型请求:
- 若缓存已知 preferred answer 存在,则直接返回空成功响应抑制该类型。
- 否则并发执行后续链路的原始查询和 preferred 类型探测,再决定是否抑制。
典型用途
- 客户端双栈策略收敛。
- 某些网络环境下优先收敛到更稳定的一类地址。
- 该插件与
forward联动最为紧密,通常放置在forward之前并通过 continuation 生效。
black_hole
作用
按指定模式对命中的 DNS 请求生成本地拦截响应,覆盖所有 qtype。
配置示例
- tag: sinkhole
type: black_hole
args:
mode: custom
ips:
# A 查询时返回
- "0.0.0.0"
# AAAA 查询时返回
- "::"
short_circuit: true
- tag: block_nxdomain
type: black_hole
args:
mode: nxdomain
short_circuit: true
配置项
mode
- 类型:
string;必填:否;默认值:无ips时为nxdomain,配置了ips时为custom - 可选值:
nxdomain:返回NXDOMAIN,并在 authority 区加入用于负缓存的 SOA。nodata:返回NOERROR空应答,并在 authority 区加入用于负缓存的 SOA。null:A返回0.0.0.0,AAAA返回::,其它 qtype 返回 NODATA。custom:A/AAAA返回ips中对应地址族;缺失地址族或其它 qtype 返回 NODATA。refused:返回REFUSED空应答。
- 兼容性:旧的
ips+short_circuit配置不需要写mode,会自动按custom处理。
ips
- 类型:
array;必填:否;默认值:空数组 - 作用:定义
custom模式使用的本地合成返回地址集合。 - 运行影响:
- IPv4 地址仅用于 A 应答。
- IPv6 地址仅用于 AAAA 应答。
- 仅允许在隐式或显式
custom模式下使用。
short_circuit
- 类型:
bool;必填:否;默认值:false - 作用:生成拦截响应后,是否立即停止后续 executor 链。
quick setup
- exec: "black_hole"
- exec: "black_hole nxdomain short_circuit=true"
- exec: "black_hole nodata"
- exec: "black_hole null"
- exec: "black_hole custom 0.0.0.0 :: short_circuit=true"
# legacy 写法,等价于 custom
- exec: "black_hole 0.0.0.0 ::"
行为说明
- 默认无参
black_hole返回NXDOMAIN。 nxdomain、nodata、refused覆盖所有 qtype。null和custom对 A/AAAA 返回地址,对其它 qtype 返回 NODATA。- 请求没有 question 时透传。
- 命中后默认继续后续执行;开启
short_circuit时会立即停止。
Metrics
通过全局 GET /api/metrics 导出:
blackhole_block_total
典型用途
- 广告、跟踪、恶意域名拦截。
- 按策略返回 NXDOMAIN / NODATA / REFUSED。
- 返回空地址或自定义占位地址。
drop_resp
作用
清空当前上下文中的响应。
配置示例
- tag: clear_response
type: drop_resp
# 无独立 args;执行时会直接清掉当前 response
配置项
无独立配置字段。
quick setup
- exec: "drop_resp"
行为说明
- 仅清理
context.response。 - 不会清 marks 或请求元信息。
典型用途
- 覆盖前面错误或不满意的响应结果。
- 配合后续重新转发或重建响应。
reverse_lookup
作用
缓存应答中的 IP -> 域名关系,并可选地处理 PTR 查询。
配置示例
- tag: reverse_lookup_main
type: reverse_lookup
args:
# 反查缓存容量
size: 65535
# IP -> 域名映射保留时间
ttl: 7200
# 命中缓存时直接回答 PTR
handle_ptr: true
配置项
size
- 类型:
integer;必填:否;默认值:65535 - 作用:定义反查缓存容量上限。
handle_ptr
- 类型:
boolean;必填:否;默认值:false - 作用:控制是否直接用反查缓存响应 PTR 请求。
ttl
- 类型:
integer;必填:否;默认值:7200 - 单位:秒
- 作用:定义 IP 到域名映射的缓存 TTL。
行为说明
- 若
handle_ptr: true且 PTR 命中缓存,会直接返回 PTR 响应并停止后续链路。 - 正常回程阶段会扫描
A/AAAAanswers,把 IP 与请求域名写入缓存。 - 会把记录 TTL 限制在插件配置 TTL 上限内。
插件 API
GET /plugins/<tag>?ip=<ip>- 返回命中的完全限定域名。
典型用途
- 本地快速 IP 反查。
- 策略排障、日志联动、资产可视化。
- 推荐放置在
cache之前,否则缓存命中可能绕过该插件,导致反查表不更新。
learn_domain
learn_domain 在 v1.2.0 首次发布,目前处于实验阶段:过滤条件、写入触发时机与配套 dynamic_domain_set 的接口可能在后续版本调整。生产部署前请评估学习速率与磁盘写入对持久化层的影响。
作用
观察 DNS 流水线中的请求域名,并把命中的 qname 写入指定 dynamic_domain_set。它只产生副作用,不修改请求或响应。
配置示例
- tag: learned_allow
type: dynamic_domain_set
args:
path: "/etc/oxidns/learned-allow.txt"
- tag: learn_allow
type: learn_domain
args:
provider: learned_allow
phase: after
questions: first
qtypes: ["A", "AAAA"]
success_only: true
answer_required: true
rule_kind: full
async: true
error_mode: continue
timeout: 1s
配置项
provider
- 类型:
string;必填:是 - 作用:引用目标
dynamic_domain_setprovider。 - 约束:必须是
dynamic_domain_set,不能引用普通domain_set。
phase
- 类型:
string;必填:否;默认值:after - 可选值:
before、after - 作用:
before:在后续 executor 执行前学习 request question。after:先执行后续链路,再根据响应结果决定是否学习。
questions
- 类型:
string;必填:否;默认值:first - 可选值:
first、all - 作用:控制学习第一个 question 或所有 question。
qtypes
- 类型:
array;必填:否;默认值:["A", "AAAA"] - 作用:只学习指定 DNS 查询类型。
success_only
- 类型:
bool;必填:否;默认值:true - 作用:仅
phase: after生效,要求响应 RCODE 为NOERROR。
answer_required
- 类型:
bool;必填:否;默认值:true - 作用:仅
phase: after生效,要求响应包含 answer。
rule_kind
- 类型:
string;必填:否;默认值:full - 可选值:
full、domain - 作用:控制学习到
dynamic_domain_set的规则类型。
async
- 类型:
bool;必填:否;默认值:true - 作用:控制是否只入队后继续执行。设为
false时会等待 provider 写入完成。
error_mode
- 类型:
string;必填:否;默认值:continue - 可选值:
continue、stop、fail - 作用:控制学习失败后的执行结果。
timeout
- 类型:
duration;必填:否;默认值:1s - 作用:仅
async: false时用于限制等待 provider 写入的时间。
行为说明
- 学习域名会规范化为小写并移除尾部
.。 - 默认生成
full:example.com精确规则,避免意外扩大匹配范围。 phase: after默认只学习成功且有 answer 的A/AAAA响应。phase: before不检查响应条件。- v1 只学习请求 question 的 qname,不学习 CNAME target。
典型用途
- 把成功解析过的域名加入动态放行列表。
- 把某个分支中的域名沉淀到本地文件,供后续
qname $learned_allow或父级domain_set使用。
query_summary
作用
在后续链路执行完后输出紧凑查询摘要。
配置示例
- tag: summary_main
type: query_summary
args:
# 日志标题;便于区分不同链路
msg: "main pipeline"
配置项
msg
- 类型:
string;必填:否;默认值:"query summary" - 作用:定义摘要日志标题。
quick setup
- exec: "query_summary main"
行为说明
- 正向阶段记录开始时间。
- 回程阶段输出:
- 来源地址
- qname
- qtype
- rcode
- elapsed_ms
典型用途
- 低成本链路追踪。
- 分支延时对比。
query_recorder
作用
把入口 request、执行后 response 以及 sequence 路径事件持久化到 recorder 自己的 SQLite 数据库,并暴露历史查询、统计和 SSE 实时推送接口。
配置示例
- tag: query_recorder_main
type: query_recorder
args:
# SQLite 文件路径;不同 recorder 应使用不同 path
path: "./data/query-recorder-main.sqlite"
# 热路径入队缓冲大小
queue_size: 8192
# 后台批量写入条数
batch_size: 256
# 后台批量 flush 间隔,单位毫秒
flush_interval_ms: 200
# 内存中保留多少条最近记录,供 SSE tail 回放
memory_tail: 1024
# 日志保留天数;最小 1
retention_days: 7
# 定时清理周期,单位小时;最小 1
cleanup_interval_hours: 1
# SQLite 读取侧最大并发数;最小 1
reader_concurrency: 2
配置项
path
- 类型:
string;必填:是 - 作用:指定当前 recorder 的 SQLite 文件路径。
queue_size
- 类型:
integer;必填:否;默认值:8192 - 作用:定义热路径到后台写线程的有界队列大小。
batch_size
- 类型:
integer;必填:否;默认值:256 - 作用:定义后台批量写入 SQLite 的单批记录数。
flush_interval_ms
- 类型:
integer;必填:否;默认值:200 - 作用:定义后台写线程的批量 flush 间隔。
memory_tail
- 类型:
integer;必填:否;默认值:1024 - 作用:定义最近记录的内存 tail 长度,用于
stream?tail=n回放。
retention_days
- 类型:
integer;必填:否;默认值:7 - 最小值:
1 - 作用:定义日志保留天数;过期数据会被定时实际删除。
cleanup_interval_hours
- 类型:
integer;必填:否;默认值:1 - 最小值:
1 - 作用:定义过期清理任务的执行周期。
reader_concurrency
- 类型:
integer;必填:否;默认值:2 - 最小值:
1 - 作用:限制 WebUI / API 统计与历史查询同时运行的 SQLite reader 数量,避免突发读取在大库上占用过多阻塞线程和内存。
行为说明
- 这是纯 executor 观察器,不会修改
server收口逻辑。 - 进入时抓取入口 request 的结构化快照,并启用
DnsContext.execution_path。 next返回后立即提交记录;成功时记录当前 response,失败时记录error和空 response。- request / response 不保存 wire 数据,而是把问题区、RR、EDNS 等字段拆成 JSON 文本列。
client_ip字段来自 OxiDNS 看到的传输层来源地址;如果前面有 systemd-resolved、dnsmasq、AdGuardHome、dae、clash 等本机转发链路,记录中可能只看到127.0.0.1。- 每个 recorder 使用同一前缀下的版本化表:
qr_<safe_tag>_<fnv64hex>_v1_recordsqr_<safe_tag>_<fnv64hex>_v1_stepsqr_<safe_tag>_<fnv64hex>_v1_questionsqr_<safe_tag>_<fnv64hex>_v1_meta
records主表只保存固定字段集合;steps表保存sequence路径事件,用于执行路径分析和命中率统计;questions表是从questions_json派生的索引表,用于加速 qname/qtype 查询;meta表记录已完成的派生表迁移。- 每个 recorder 独占自己的有界队列、SQLite 连接、后台写线程、内存 tail 和 SSE 广播器。
- 默认假定不同 recorder 使用不同
path;v1 不做跨 recorder 写线程复用或路径协调。
数据结构约定
questions_json固定为 question 数组,例如:
[
{ "name": "www.example.com.", "qtype": "A", "qclass": "IN" }
]
answers_json、authorities_json、additionals_json、signature_json固定为 RR 数组,例如:
[
{
"name": "www.example.com.",
"class": "IN",
"ttl": 300,
"rr_type": "A",
"payload_kind": "A",
"payload_text": "192.0.2.1",
"payload": { "ip": "192.0.2.1" }
}
]
req_edns_json、resp_edns_json固定为 EDNS 对象或NULL。- 表名中的
v1是当前 schema 版本;后续升级会新增新版本表,不做原地改表。
API
GET /plugins/<tag>/records- 按
created_at_ms倒序分页返回主表记录。 - 查询参数:
cursor=<created_at_ms>:<id>limit=<n>,默认100,最大500since_ms=<unix_ms>until_ms=<unix_ms>qname=<text>,按请求问题名包含匹配client_ip=<text>,按客户端 IP 字符串包含匹配qtype=<type>/rcode=<rcode>/status=all|error|has_response|no_response
- 按
GET /plugins/<tag>/records/<id>- 返回单条完整记录,并附带
steps。
- 返回单条完整记录,并附带
DELETE /plugins/<tag>/records- 清空当前 recorder 的所有历史记录和
steps,并清空内存 tail。 - 操作会先 flush 后台写入队列,返回
cleared_records表示删除的主表记录数。
- 清空当前 recorder 的所有历史记录和
GET /plugins/<tag>/stats/plugins- 返回按
matcher / executor / builtin聚合的命中统计。 - 支持
since_ms、until_ms、kind=matcher|executor|builtin|all和 records 的过滤参数。
- 返回按
GET /plugins/<tag>/stats/top_clients/stats/top_qnames- 返回客户端 IP 或 QNAME 排行。
- 支持
limit=<n>,默认20;后端不再强制200上限。 - 支持 records 的时间范围与过滤参数。
GET /plugins/<tag>/stats/qtype/stats/rcode- 返回 QTYPE 或 RCODE 分布。
- 支持 records 的时间范围与过滤参数。
GET /plugins/<tag>/stats/latency- 返回延迟摘要、直方图和慢查询排行。
- 支持
slow_limit=<n>或limit=<n>,默认20;后端不再强制200上限。
GET /plugins/<tag>/stats/timeseries- 返回按分钟或小时聚合的查询趋势。
- 支持
bucket=minute|hour和buckets=<n>(默认60,最大720)。
GET /plugins/<tag>/stream- 以 SSE 实时推送新写入记录。
- 支持
tail=<n>回放最近n条内存 tail。 - 客户端应发送
Accept: text/event-stream,并容忍 heartbeat、错误事件、空 payload 和短暂断连。
典型用途
- 持久化审计和问题排查。
- 分析
sequence执行路径、插件命中率和异常分支。 - 给控制面或外部面板提供实时查询日志流。
- 想要拿到完整主链路路径,推荐把 recorder 放在入口附近。
- 如果前置分支在 recorder 之前就短路返回,该请求不会被当前 recorder 记录。
- 若
next报错而server后续补发了兜底响应,数据库里仍只记录插件视角下的error和空 response。 - 若未启用管理 API,recorder 仍会写库,但不会暴露查询与 SSE 路由。
- 若需要真实终端 IP,请让客户端直连 OxiDNS,或在 HTTP/DoH 反向代理场景配置可信的
src_ip_header。
metrics_collector
作用
收集轻量级请求计数与延时指标,并导出 Prometheus 格式。
配置示例
- tag: metrics_main
type: metrics_collector
args:
# 指标名称标签;导出到 /api/metrics 时会带上它
name: "main"
配置项
name
- 类型:
string;必填:否;默认值:"default" - 作用:定义当前指标收集器的名称标签。
quick setup
- exec: "metrics_collector main"
行为说明
- 正向阶段:
query_total +1inflight +1- 记录开始时间
- 回程阶段:
inflight -1- 若无响应则
err_total +1 - 若有响应则累计延时
API
GET /api/metrics- Prometheus 文本格式,全局唯一;其它插件的内置 metrics 也会汇总到同一接口。
典型用途
- 主链路观测。
- 多条策略入口延时对比。
debug_print
作用
打印请求与响应对象,便于调试。
配置示例
- tag: debug_main
type: debug_print
args:
# 日志标题;未配置时默认是 "debug print"
msg: "before forward"
msg- 可选日志标题。
- 默认
"debug print"。
配置项
msg
- 类型:
string;必填:否;默认值:"debug print" - 作用:定义日志输出标题。
quick setup
- exec: "debug_print cache branch"
典型用途
- 排查 sequence 分支。
- 验证请求和响应在插件前后是否被改写。
sleep
作用
异步延迟,用于测试和策略实验。
配置示例
- tag: sleep_100ms
type: sleep
args:
# 额外异步延迟 100ms
duration: 100
配置项
duration
- 类型:
integer;必填:否;默认值:0 - 单位:毫秒
- 作用:定义当前请求在该执行器上的额外异步等待时间。
quick setup
- exec: "sleep 100"
典型用途
- 测试
fallback阈值。 - 人工制造慢路径验证观测链路。
http_request
作用
向外部 http/https 服务发送回调请求。它既可以在当前 DNS 链路进入下游 executor 之前触发,也可以在下游执行完成后触发,适合 webhook、审计、告警和外部联动。
配置示例
- tag: webhook_notify_after
type: http_request
args:
method: POST
url: "https://hooks.example.com/dns"
phase: after
async: true
timeout: 5s
headers:
X-Client-IP: "${client_ip}"
X-Qname: "${qname}"
query_params:
source: "oxidns"
qname: "${qname}"
json:
qname: "${qname}"
client_ip: "${client_ip}"
rcode: "${rcode_name}"
resp_ip: "${resp_ip}"
配置项
args.method
- 类型:
string;必填:是 - 作用:指定 HTTP 方法,例如
GET、POST、PUT、PATCH、DELETE。
args.url
- 类型:
string;必填:是 - 作用:目标 URL。
- 说明:支持
${key}占位符插值;渲染后的 URL 只允许使用http或https。
args.phase
- 类型:
string;必填:否;默认值:after - 可选值:
before、after - 作用:控制请求在下游 executor 之前发送,还是在下游执行完成后发送。
args.async
- 类型:
boolean;必填:否;默认值:true - 作用:控制使用异步后台队列发送,还是在当前请求路径同步等待 HTTP 完成。
args.timeout
- 类型:
string;必填:否;默认值:5s - 作用:限制单次 HTTP 调用的总超时时间。
- 支持单位:
ms、s、m、h、d
args.error_mode
- 类型:
string;必填:否;默认值:continue - 可选值:
continue:失败仅记录日志,然后继续后续链路stop:失败后返回Stopfail:失败后直接返回 executor 错误
args.headers
- 类型:
map<string,string>;必填:否;默认值:空 - 作用:附加 HTTP 请求头。
- 说明:header value 支持
${key}占位符插值。
args.query_params
- 类型:
map<string,string>;必填:否;默认值:空 - 作用:把额外参数追加到 URL query 上。
- 说明:value 支持
${key}占位符插值;会与 URL 自带 query 一起发送。
args.body
- 类型:
string;必填:否 - 作用:原始字符串请求体。
- 说明:支持
${key}占位符插值;可选配args.content_type。
args.json
- 类型:
object | array;必填:否 - 作用:以 JSON 方式发送请求体。
- 说明:会自动设置
Content-Type: application/json;其中所有字符串叶子节点支持${key}占位符插值,非字符串值原样保留。
args.form
- 类型:
map<string,string>;必填:否 - 作用:以
application/x-www-form-urlencoded方式发送表单。 - 说明:value 支持
${key}占位符插值;会自动设置对应的Content-Type。
args.content_type
- 类型:
string;必填:否 - 作用:为原始
args.body指定Content-Type。 - 说明:只能和
args.body搭配,不能与args.json或args.form同时使用。
args.outbound
- 类型:
string;必填:否 - 作用:引用
network.outbound.profiles中的出站配置,统一控制该 HTTP 请求使用的解析器和代理。 - 说明:未配置时使用
network.outbound.default;若也配置了args.socks5,socks5只覆盖代理设置,resolver 仍来自 outbound profile。
args.socks5
- 类型:
string;必填:否 - 作用:指定 SOCKS5 代理。
- 说明:格式与
upstream[].socks5一致,支持host:port、username:password@host:port和带中括号的 IPv6。
args.insecure_skip_verify
- 类型:
boolean;必填:否;默认值:false - 作用:是否跳过 HTTPS 证书校验。
args.max_redirects
- 类型:
integer;必填:否;默认值:5 - 作用:限制最多跟随多少次重定向。
args.queue_size
- 类型:
integer;必填:否;默认值:256 - 作用:异步模式下后台发送队列的容量。
可注入占位符
- 与
script插件相同:qname、qtype、qtype_name、qclass、qclass_name - 来源相关:
client_ip、client_port、server_name、url_path - 运行态相关:
marks、has_resp - 响应相关:
rcode、rcode_name、resp_ip - cron 元数据:
cron_plugin_tag、cron_job_name、cron_trigger_kind、cron_scheduled_at_unix_ms
行为说明
phase: before时,会先发 HTTP 请求,再进入下游 executor。phase: after时,会先执行下游 executor,再根据当前上下文发送 HTTP 请求。async: true使用有界后台队列;入队失败会按error_mode处理。async: false会在当前请求路径内等待 HTTP 请求完成。- 只有最终返回
2xx才视为成功;3xx会在max_redirects范围内继续跟随。 - 插件会读取并丢弃 HTTP 响应体,以便连接复用,但不会把响应内容写回
DnsContext。 - 如果请求头里已经显式设置
Content-Type,插件不会再覆盖它。
args.body、args.json、args.form三者互斥。- 这是副作用执行器,v1 不支持根据 HTTP 返回结果改写 DNS 请求、响应、marks 或 attrs。
- v1 不支持 multipart 上传,也不支持 quick setup 语法。
- 同时需要
before和after两种时机时,请配置两个独立的http_request插件实例。
script
作用
执行一个显式声明的外部命令,并把当前 DnsContext 中的一部分稳定字段注入为参数或环境变量。
配置示例
- tag: script_notify
type: script
args:
command: "bash"
args:
- "/etc/oxidns/notify.sh"
- "${qname}"
- "${client_ip}"
env:
FDNS_QNAME: "${qname}"
FDNS_CLIENT_IP: "${client_ip}"
FDNS_MARKS: "${marks}"
timeout: "5s"
error_mode: continue
max_output_bytes: 4096
配置项
args.command
- 类型:
string;必填:是 - 作用:要执行的命令路径或命令名。
- 说明:该字段不支持模板替换,避免命令本身在运行期漂移。
args.args
- 类型:
array<string>;必填:否;默认值:空 - 作用:传给命令的参数数组。
- 说明:每一项支持
${key}占位符插值。
args.env
- 类型:
map<string,string>;必填:否;默认值:空 - 作用:追加到子进程环境变量中的键值对。
- 说明:value 支持
${key}占位符插值;不会清空父进程已有环境变量。
args.cwd
- 类型:
string;必填:否;默认值:无 - 作用:指定脚本运行时的工作目录。
args.timeout
- 类型:
string;必填:否;默认值:5s - 作用:限制单次脚本执行时长。
- 支持单位:
ms、s、m、h、d
args.error_mode
- 类型:
string;必填:否;默认值:continue - 可选值:
continue:失败或超时仅记录日志,然后返回Nextstop:失败或超时后返回Stopfail:失败或超时直接返回错误
args.max_output_bytes
- 类型:
usize;必填:否;默认值:4096 - 作用:限制 stdout / stderr 的捕获长度,超过部分只做截断标记。
可注入占位符
- 请求相关:
qname、qtype、qtype_name、qclass、qclass_name - 来源相关:
client_ip、client_port、server_name、url_path - 运行态相关:
marks、has_resp - 响应相关:
rcode、rcode_name、resp_ip - cron 元数据:
cron_plugin_tag、cron_job_name、cron_trigger_kind、cron_scheduled_at_unix_ms
行为说明
- 插件本身不改 DNS 请求和响应。
- 只执行显式配置的命令,不隐式包裹
sh -c、cmd /c这类 shell。 - 参数和环境变量在每次执行时基于当前
DnsContext渲染。 - 超时后会终止子进程,并按
error_mode决定后续控制流。
- v1 不支持 quick setup 语法。
command不能为空。${key}中只允许使用文档列出的稳定内建字段;未知占位符会在初始化时报错。- 这是副作用执行器,不支持通过 stdout 回写
attrs、marks或直接生成 DNS 响应。
ipset
作用
把响应中的 IP 写入 Linux ipset。底层通过内置 Rust netlink 后端完成,不依赖运行时 ipset 命令。
配置示例
- tag: ipset_main
type: ipset
args:
# A 记录写入的 ipset
set_name4: "oxidns_v4"
# AAAA 记录写入的 ipset
set_name6: "oxidns_v6"
# IPv4 写入前先聚合成 /24
mask4: 24
# IPv6 写入前先聚合成 /64
mask6: 64
配置项
set_name4
- 类型:
string;必填:否;默认值:无 - 作用:指定写入 IPv4 地址的 ipset 名称。
set_name6
- 类型:
string;必填:否;默认值:无 - 作用:指定写入 IPv6 地址的 ipset 名称。
mask4
- 类型:
integer;必填:否;默认值:24 - 作用:指定 IPv4 地址写入 ipset 时使用的前缀长度。
mask6
- 类型:
integer;必填:否;默认值:32 - 作用:指定 IPv6 地址写入 ipset 时使用的前缀长度。
quick setup
- exec: "ipset oxidns_v4,inet,24 oxidns_v6,inet6,64"
格式:
<set_name>,<family>,<mask>
其中 family 为 inet 或 inet6。
行为说明
- 从 answer 中提取唯一 A/AAAA 地址。
- 根据地址族写入相应 set。
- 通过非阻塞队列投递到后台 writer。
典型用途
- 基于 DNS 结果驱动后续流量策略。
- DNS 到防火墙名单的联动。
- Linux 以外平台会退化为 no-op。
- 队列满时会丢 side effect,不阻塞 DNS 主路径。
nftset
作用
把响应 IP 写入 Linux nftables set。底层通过内置 Rust netlink 后端完成,不依赖运行时 nft 命令。
配置示例
结构化写法:
- tag: nftset_main
type: nftset
args:
ipv4:
# IPv4 使用 ip family
table_family: "ip"
table_name: "mangle"
set_name: "dns_v4"
mask: 24
ipv6:
# IPv6 使用 ip6 family
table_family: "ip6"
table_name: "mangle"
set_name: "dns_v6"
mask: 64
兼容写法:
- tag: nftset_legacy
type: nftset
args:
# 兼容字段,适合从旧配置迁移
table_family4: "ip"
table_name4: "mangle"
set_name4: "dns_v4"
mask4: 24
table_family6: "ip6"
table_name6: "mangle"
set_name6: "dns_v6"
mask6: 64
配置项
ipv4
- 类型:
object;必填:否;默认值:无 - 作用:定义 IPv4 目标 nftables set。
- 子字段:
table_familytable_nameset_namemask
ipv6
- 类型:
object;必填:否;默认值:无 - 作用:定义 IPv6 目标 nftables set。
- 子字段:
table_familytable_nameset_namemask
table_family4 / table_family6
- 类型:
string;必填:否;默认值:无 - 作用:兼容写法下分别定义 IPv4 / IPv6 的 nftables 表 family。
table_name4 / table_name6
- 类型:
string;必填:否;默认值:无 - 作用:兼容写法下分别定义 IPv4 / IPv6 的 nftables 表名。
set_name4 / set_name6
- 类型:
string;必填:否;默认值:无 - 作用:兼容写法下分别定义 IPv4 / IPv6 的 set 名称。
mask4 / mask6
- 类型:
integer;必填:否;默认值:mask4为24,mask6为48 - 作用:兼容写法下分别定义 IPv4 / IPv6 前缀长度。
quick setup
- exec: "nftset ip,mangle,dns_v4,ipv4_addr,24 ip6,mangle,dns_v6,ipv6_addr,64"
格式:
<family>,<table>,<set>,<type>,<mask>
行为说明
- 提取 A/AAAA 地址。
- 根据前缀写入 nftables 区间元素。
- 同样走后台 writer,保持主路径非阻塞。
典型用途
- 与
nftables集合联动的分类、路由或防火墙策略。
- Linux 以外平台退化为 no-op。
ros_address_list
作用
把应答 IP 同步到 RouterOS address-list,支持动态项、常驻项、启动时文件加载和关闭时清理。
配置示例
- tag: ros_address_list_main
type: ros_address_list
args:
# RouterOS API 地址
address: "172.16.1.1:8728"
# API 用户名
username: "api-user"
# API 密码
password: "secret"
# RouterOS API 连接超时,单位秒
connect_timeout: 5
# RouterOS API 发送命令超时,单位秒
send_timeout: 5
# RouterOS API 接收响应超时,单位秒;仅在存量慢查询场景按需调大
receive_timeout: 30
# 异步提交,避免阻塞 DNS 主路径
async: true
# A 记录写入的 address-list
address_list4: "oxidns_ipv4"
# AAAA 记录写入的 address-list
address_list6: "oxidns_ipv6"
# 用于标记 OxiDNS 管理条目的注释前缀
comment_prefix: "oxidns"
# 动态项 TTL 下限
min_ttl: 60
# 动态项 TTL 上限
max_ttl: 3600
# 强制把动态项 TTL 固定为 300 秒;填 0 表示不设置 timeout
fixed_ttl: 300
# 插件关闭时清理自己维护的条目
cleanup_on_shutdown: true
persistent:
ips:
# 常驻单 IP
- "1.1.1.1"
# 常驻 IPv4 网段
- "100.64.1.0/24"
# 常驻 IPv6 网段
- "2001:db8::/64"
files:
# 从文件加载更多常驻项
- "/etc/oxidns/persistent_ips.txt"
配置项
address
- 类型:
string;必填:是;默认值:无 - 作用:指定 RouterOS API 服务地址,通常写为
host:port。插件启动后将使用该地址建立管理连接,并在运行期间维持与设备的同步关系。 - 配置建议:使用 RouterOS API 明文端口时通常为
8728,如部署了加密 API,应按实际端口填写。
username
- 类型:
string;必填:是;默认值:无 - 作用:指定 RouterOS API 登录用户名。该账户需要具备读取和维护目标
address-list的权限。 - 配置建议:建议为本插件单独创建专用账号,以便隔离权限范围和审计记录。
password
- 类型:
string;必填:是;默认值:无 - 作用:指定 RouterOS API 登录密码。插件初始化、重连和后台同步均依赖该凭据。
- 注意事项:应避免在公开仓库或共享示例中直接暴露真实口令。
connect_timeout
- 类型:
u64;必填:否;默认值:5 - 作用:指定建立 RouterOS API 连接时的等待上限,单位为秒。
- 注意事项:必须大于
0。网络链路较慢或 RouterOS 管理面偶发繁忙时,可按需调大。
send_timeout
- 类型:
u64;必填:否;默认值:5 - 作用:指定发送单个 RouterOS API 命令时的等待上限,单位为秒。
- 注意事项:必须大于
0。通常保持默认即可。
receive_timeout
- 类型:
u64;必填:否;默认值:5 - 作用:指定等待下一段 RouterOS API 响应数据的上限,单位为秒。
- 配置建议:建议为 OxiDNS 使用专用且规模可控的
address-list,不建议接入已有的大型共享列表。只有在存量环境无法避免慢列表查询或 RouterOS 管理面响应较慢时,才考虑将该值调大,例如30或60。
async
- 类型:
bool;必填:否;默认值:true - 作用:控制地址写入行为是否采用异步方式。启用后,DNS 应答路径只负责投递任务,由后台管理器完成与 RouterOS 的交互。
- 影响:异步模式有助于降低请求路径阻塞风险;关闭后会改为同步提交,更适合需要立即确认提交结果的场景。
address_list4
- 类型:
string;必填:否;默认值:无 - 作用:指定 IPv4 地址写入的目标
address-list名称。插件从 DNS 应答中提取到 A 记录后,将写入该列表。 - 配置建议:如果策略仅处理 IPv4,应至少配置本项。
address_list6
- 类型:
string;必填:否;默认值:无 - 作用:指定 IPv6 地址写入的目标
address-list名称。插件从 DNS 应答中提取到 AAAA 记录后,将写入该列表。 - 配置建议:如果策略需要覆盖 IPv6,应同时配置本项,并在 RouterOS 侧建立对应的匹配与路由规则。
comment_prefix
- 类型:
string;必填:否;默认值:fdns - 作用:指定插件写入 RouterOS 条目时使用的注释前缀。该前缀用于区分 OxiDNS 创建的动态项和常驻项,便于后续刷新、重载与清理。
- 注意事项:该值及插件
tag不应包含;或=,以避免影响内部标记格式。
persistent
- 类型:
object;必填:否;默认值:无 - 作用:定义需要长期保留的静态地址集合。该部分不依赖 DNS 应答触发,可在插件启动后直接同步到 RouterOS,并由后台 reconcile 保持一致性。
- 子字段:
ipsfiles
persistent.ips
- 类型:
array<string>;必填:否;默认值:空 - 作用:以内联方式声明常驻 IP 或 CIDR 网段。适用于数量较少且变更频率不高的固定策略对象。
- 支持格式:单个 IPv4、单个 IPv6、IPv4 CIDR、IPv6 CIDR。
persistent.files
- 类型:
array<string>;必填:否;默认值:空 - 作用:从外部文件加载常驻地址集合。适用于需要由其他系统生成、集中维护或批量管理的地址列表。
- 行为说明:这些文件只在插件初始化时读取一次。文件变更后如需生效,需要 reload 插件或应用。
min_ttl
- 类型:
u64;必填:否;默认值:60 - 作用:定义动态地址项允许使用的最小 TTL。当 DNS 应答中的 TTL 过小或为零时,插件会提升到该值后再写入 RouterOS。
- 适用场景:用于避免高频刷新造成的管理面抖动。
max_ttl
- 类型:
u64;必填:否;默认值:3600 - 作用:定义动态地址项允许使用的最大 TTL。当 DNS 应答中的 TTL 过大时,插件会截断到该上限。
- 适用场景:用于限制策略项在网络设备中的滞留时间,降低地址陈旧风险。
fixed_ttl
- 类型:
u64;必填:否;默认值:无 - 作用:为所有动态写入项指定固定 TTL。配置本项后,插件不再使用 DNS 记录中的原始 TTL,也不再受
min_ttl与max_ttl的区间裁剪影响。若设为0,则动态项不会设置 RouterOStimeout。 - 适用场景:适合需要统一刷新周期、便于运维预估和策略收敛的场景。
cleanup_on_shutdown
- 类型:
bool;必填:否;默认值:true - 作用:控制插件退出时是否清理由其管理的条目。启用后,插件在正常关闭阶段会删除自身写入并可识别归属的 RouterOS 地址项。
- 影响:关闭该选项后,已写入条目会继续保留在 RouterOS 中,适合要求策略状态跨进程重启保留的场景。
行为说明
- 插件本身不改 DNS 响应。
- 启动阶段不会等待 RouterOS address-list 扫描完成;初始连通性验证和常驻项同步会交给后台 manager 执行,失败只记录日志,不阻塞 DNS 服务启动或动态观察写入。
- 正向阶段只透传。
- 回程阶段:
- 从
NOERROR响应中提取 A/AAAA。 - 去重并保留最大 TTL。
- 根据异步或同步模式投递给后台 manager。
- 从
- manager 负责:
- 后台初始连通性验证
- 动态项刷新
- 持久项一致性维护
- 关闭清理
典型用途
- DNS 驱动路由地址集维护。
- DNS 驱动动态策略名单。
- 通过 RouterOS address-list 把域名解析结果外溢到网络设备策略层。
- 至少需要
address_list4或address_list6之一。 - 建议使用 OxiDNS 专用
address-list,避免接入大型共享列表,以降低 RouterOS 管理面扫描成本。 comment_prefix与插件tag不能包含;或=。- 同步模式不会改变 DNS 应答本身,即使 RouterOS 写入失败也会保留 DNS 结果。
upgrade
作用
执行 OxiDNS 升级流程,可用于 cron、sequence 或其它执行器触发的维护任务。
配置示例
- tag: upgrade_auto
type: upgrade
args:
repository: svenshi/oxidns
asset: auto
bundle: auto
github_token: ghp_xxx
cache_dir: ./upgrade/cache
backup_dir: ./upgrade/backups
webui_dir: ./webui
skip_webui: false
no_restart: false
force: false
cleanup: true
timeout: 30s
outbound: remote
socks5: 127.0.0.1:1080
insecure_skip_verify: false
配置项
force- 类型:
bool - 默认值:
false - 即使目标 release 不比当前版本更新,也继续下载、校验并替换。
- 类型:
cleanup- 类型:
bool - 默认值:
true - 升级成功后清理
cache_dir和backup_dir。
- 类型:
repository- GitHub 仓库,默认
svenshi/oxidns。
- GitHub 仓库,默认
asset- Release asset 名称;
auto会按当前平台和编译版本选择 archive。 - 显式填写 asset 时优先级最高,不再根据
bundle推导。
- Release asset 名称;
bundle- 类型:
auto | full | standard | minimal - 默认值:
auto - 当
asset: auto时选择 release 编译版本。full使用旧资产名,standard/minimal使用带 bundle 前缀的 slim 资产名。
- 类型:
github_token- GitHub 个人访问令牌,用于提高 API 速率限制或访问私有仓库。
- 会作为 GitHub API 请求的 Bearer token 使用。
cache_dir/backup_dir- 下载缓存目录和替换前备份目录。
webui_dir- 类型:
path - 默认值:
./webui - 升级时安装 WebUI 静态资源的目录,应与
api.http.webui.root一致。
- 类型:
skip_webui- 类型:
bool - 默认值:
false - 设为
true时只替换二进制文件,跳过 WebUI 目录升级。
- 类型:
no_restart- 类型:
bool - 默认值:
false - 设为
true时,升级成功后不触发自动重启。 - 默认值
false会在升级成功后自动重启:CLIapply通过系统服务管理器重启已安装服务,插件内执行时通过应用控制通道触发优雅重启并加载新二进制。
- 类型:
timeout、outbound、socks5、insecure_skip_verify- 与 CLI
upgrade参数含义一致。 outbound引用network.outbound.profiles中的出站配置;旧socks5字段继续兼容,且会覆盖 profile 里的代理设置。
- 与 CLI
行为说明
- 执行器总是返回
ExecStep::Next。 - 插件只执行
apply动作,不提供check或download模式。 - 默认只有检测到新版本才会更新;
force: true会强制更新。 - 默认升级成功后会清理缓存和备份;如需保留回滚文件,设置
cleanup: false。 - 升级时会下载 archive,并使用 GitHub release asset 的
digest字段校验 SHA256。 asset: auto会根据bundle选择 archive;bundle: auto跟随当前二进制的编译版本,custom 构建需要显式设置bundle或asset。- Unix 平台解包
.tar.gz、备份当前二进制并替换;Windows 当前不支持插件升级。 - 默认在替换二进制后,将 archive 中的
webui/目录备份并安装到webui_dir;skip_webui: true可跳过。archive 不含webui/(旧版本 release)时会跳过 WebUI 升级且不影响二进制升级结果。
quick setup
- exec: upgrade
- exec: upgrade force
- exec: upgrade force=false
- exec: upgrade bundle=standard
- 空参数使用默认配置执行 apply。
- 只支持
force或force=true|false。 - 其它参数使用默认值;需要覆盖仓库、目录、重启方式或代理时,请使用完整
args配置。 - 不支持
mode;插件固定执行 apply。
download
作用
下载一个或多个 http/https 文件到本地目录,并在新内容完整写入后覆盖目标文件。
配置示例
- tag: rules_download
type: download
args:
timeout: 30s
outbound: remote
socks5: "127.0.0.1:1080"
downloads:
- url: "https://example.com/geosite.dat"
dir: "/etc/oxidns"
- url: "https://example.com/geoip.dat"
dir: "/etc/oxidns"
filename: "geoip.dat"
Quick Setup
- exec: "download https://example.com/rules.txt /etc/oxidns"
行为说明
downloads按声明顺序串行执行。- 单个下载失败只会写 warning 日志,不会阻止后续项继续下载。
- 目标目录不存在时会自动创建。
- 文件会先写入临时文件,再覆盖目标文件,避免半写入状态。
- 配置
outbound后,下载使用network.outbound.profiles中定义的解析器和代理。 - 配置
socks5后,所有下载连接都会通过该 SOCKS5 代理发起,格式与upstream[].socks5一致。 - 默认会在启动时检查目标文件;缺失项会在其它插件初始化前自动下载,失败会直接中止启动。
- 如需关闭该行为,可显式配置
startup_if_missing: false。
- 只支持
http/https。 outbound未配置时使用network.outbound.default;同时配置outbound和socks5时,socks5会覆盖 profile 代理但保留 profile resolver。socks5支持host:port和username:password@host:port,IPv6 需写成"[::1]:1080"。startup_if_missing只会补齐缺失文件,不会在每次启动时强制覆盖已有文件。- 放进普通
sequence时会直接占用该次请求的执行时间。 - 覆盖本地文件后不会自动触发生效;如果只是让文件型 provider 立即读取新内容,优先串联
reload_provider;如果连config.yaml、依赖拓扑或插件列表也一起变化,再使用reload。
推荐搭配
- tag: rules_refresh
type: sequence
args:
- exec: "$rules_download"
- exec: "$reload_rules"
- tag: rules_download
type: download
args:
downloads:
- url: "https://example.com/geosite.dat"
dir: "/etc/oxidns"
- tag: provider_geosite
type: geosite
args:
file: "/etc/oxidns/geosite.dat"
- tag: reload_rules
type: reload_provider
args:
- "$provider_geosite"
订阅更新示例
下面这个例子适合“远程规则订阅 -> 定时拉取 -> 定向刷新 provider”的场景:
plugins:
# 1. 周期性执行订阅更新流程
- tag: subscription_cron
type: cron
args:
timezone: "Asia/Shanghai"
jobs:
- name: refresh_rule_subscriptions
interval: 6h
executors:
- "$subscription_refresh"
# 2. 用 sequence 串联下载和 provider 定向 reload
- tag: subscription_refresh
type: sequence
args:
- exec: "$subscription_download"
- exec: "$reload_rule_providers"
# 3. 拉取远程订阅文件
- tag: subscription_download
type: download
args:
timeout: 60s
startup_if_missing: true
downloads:
- url: "https://example.com/geosite.dat"
dir: "/etc/oxidns/rules"
filename: "geosite.dat"
- url: "https://example.com/geoip.dat"
dir: "/etc/oxidns/rules"
filename: "geoip.dat"
# 4. 下载完成后只刷新相关 provider
- tag: reload_rule_providers
type: reload_provider
args:
- "$provider_geosite"
- "$provider_geoip"
# 5. 这些 provider 会在 reload 后重新读取本地文件
- tag: provider_geosite
type: geosite
args:
file: "/etc/oxidns/rules/geosite.dat"
- tag: provider_geoip
type: geoip
args:
file: "/etc/oxidns/rules/geoip.dat"
说明:
download负责把订阅内容落到本地。reload_provider负责只刷新相关 provider 的内部快照,不会重建其它插件。startup_if_missing: true适合首次部署时自动补齐缺失文件。- 如果订阅源需要代理,可直接在
subscription_download.args.socks5中配置 SOCKS5 代理。 - 不希望定时任务在启动后立刻覆盖已有文件时,可以保留默认行为,仅在文件缺失时做启动补齐。
- 如果这次更新还改动了
config.yaml、provider 依赖拓扑或插件列表,请改用全量reload。
配置变更场景仍使用全量 reload
- tag: config_refresh
type: sequence
args:
- exec: "$subscription_download"
- exec: "$reload_all"
- tag: reload_all
type: reload
reload_provider
作用
按 tag 定向刷新一个或多个 provider,使用它们启动时的同一份配置重建内部快照,而不会触发应用级全量重载。
配置示例
- tag: reload_rule_providers
type: reload_provider
args:
- "$geosite_cn"
- "$geoip_cn"
Quick Setup
- exec: "reload_provider $geosite_cn"
行为说明
- 按
args中声明顺序逐个执行 targeted provider reload。 - 语义等同于分别调用这些 provider 的管理 API
POST /plugins/<provider_tag>/reload。 - 全部 provider reload 成功后,当前 executor 返回
Next。 - 只刷新 provider 内部数据,不修改 tag、依赖关系或其它插件配置。
典型用途
- 在
download后只刷新受影响的domain_set、ip_set、geosite、geoip、adguard_ruleprovider。 - 在后台维护链路里降低全量
reload的开销和影响面。
args只接受 provider 引用,例如"$geoip_cn";不接受内联规则或文件引用。- 如果更新涉及
config.yaml、provider 依赖拓扑、插件列表或其它非 provider 数据结构变化,仍然需要使用reload。 - 放进实时请求路径时,provider reload 可能触发文件读取和重新编译,通常更适合后台
cron/sequence任务。
reload
作用
触发一次与管理 API POST /reload 相同的应用级全量 reload,重新加载当前配置并重建所有插件。
配置示例
- tag: reload_all
type: reload
Quick Setup
- exec: "reload"
行为说明
- 执行时会向应用控制层提交一次 reload 请求。
- 语义等同于调用管理 API 的
POST /reload。 - reload 请求被接受后当前 executor 返回
Next。 - 这是全量应用 reload,不支持按指定 tag 只重载部分插件。
典型用途
- 在
cron任务中配合download,周期性刷新本地规则文件后立即让新配置生效。 - 在后台维护
sequence中统一触发一次全量配置重载。
- 需要运行在带有应用控制上下文的正常 OxiDNS 进程中。
- 如果已有 reload 处于
pending或in_progress,本次执行会返回错误。 - 放进普通请求
sequence时会触发全量应用 reload,通常不建议在实时请求路径上使用。
cron
作用
后台调度一组 executor。它不会参与实时 DNS 请求链,而是在插件初始化后按 cron 或固定间隔触发任务。
配置示例
- tag: cron_jobs
type: cron
args:
timezone: "Asia/Shanghai"
jobs:
- name: refresh_sets
interval: 5m
executors:
- "$seq_refresh"
- "debug_print cron refresh"
- name: nightly_cleanup
schedule: "15 3 * * *"
executors:
- "sleep 2s"
- "$seq_cleanup"
配置项
args.jobs
- 类型:
array;必填:是;默认值:无 - 作用:定义一个或多个后台任务。
- 运行影响:
- 数组不能为空。
- 每个任务独立维护自己的调度状态和重叠保护。
args.timezone
- 类型:
string;必填:否;默认值:系统本地时区 - 作用:为当前
cron插件下的所有schedule任务指定时区。 - 运行影响:
- 仅对
schedule生效。 - 未配置时会使用系统本地时区;无法获取时退回
UTC。 - 应填写 IANA 时区名称,例如
Asia/Shanghai、UTC、America/Los_Angeles。
- 仅对
args.jobs[].name
- 类型:
string;必填:是;默认值:无 - 作用:任务名称,用于日志与运行时标识。
- 运行影响:
- 在同一个
cron插件内必须唯一。
- 在同一个
args.jobs[].schedule
- 类型:
string;必填:与interval二选一;默认值:无 - 作用:使用标准 5 字段 cron 表达式调度任务。
- 规则说明:
- 仅支持
minute hour day month day-of-week。 - 不支持秒级 cron。
- 按
args.timezone或系统本地时区计算下一次触发时间。
- 仅支持
args.jobs[].interval
- 类型:
string;必填:与schedule二选一;默认值:无 - 作用:用简单固定间隔调度任务。
- 支持格式:
5m1h1d
- 运行影响:
- 最小粒度为
1m。 - 启动后会等待一个完整间隔再首次触发。
- 最小粒度为
args.jobs[].executors
- 类型:
array;必填:是;默认值:无 - 作用:定义任务触发时顺序执行的 executor 列表。
- 支持形式:
$tag:显式引用已存在 executortag:裸 tag 引用- quick setup 表达式,例如
debug_print cron refresh
- 运行影响:
- 数组不能为空。
- 即使某个 executor 返回
Stop、设置了响应、或执行报错,后续 executor 仍会继续执行。
行为说明
schedule和interval必须二选一。- 同一个 job 若上一轮仍在运行,本轮会被跳过,不补跑。
- 任务使用空的
DnsContext,适合副作用类 executor 或后台编排的sequence。 cron本身不能放进普通请求sequence里执行。
典型用途
- 定时触发后台副作用逻辑。
- 定时执行一个专门的
sequence编排。 - 为未来的
reload之类后台动作提供统一调度入口。
- 不允许引用另一个
cronexecutor。 - 依赖真实 DNS 请求内容的 executor 在空上下文任务中通常没有意义。