Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
ioc2rpz — ioc2rpz 是威胁情报与 DNS 交汇之处。 | Kitploit
工具/GitHubGitHub/homas/ioc2rpz
防御工具危害指标 (IOC) 管理网络安全恶意软件分析威胁情报入侵检测DNS 模糊测试事件响应DNS 分析
GitHubhomas/ioc2rpz

ioc2rpz

ioc2rpz 是威胁情报与 DNS 交汇之处。

查看仓库
116211个月前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

ioc2rpz™ 让您的威胁情报可付诸行动

License Erlang/OTP Docker Hub

目录

  • 简短摘要
  • 概述
  • ioc2rpz™ —— 威胁情报与 DNS 的交汇点
  • 架构概述
  • 如何使用 ioc2rpz™
  • ioc2rpz™ Web 界面
  • 协议支持
    • 端口摘要
    • UDP(端口 53)
    • TCP(端口 53)
    • DNS over TLS / DoT(端口 853)
    • DNS over HTTPS / DoH(端口 443/8443)
    • 速率限制
    • DNS NOTIFY
  • ioc2rpz™ 与 ISC BIND 及其他 DNS 的对比
  • 安装
  • Docker 容器
  • 环境变量
  • Docker Compose
  • 在 AWS 上运行 ioc2rpz™
  • 证书设置
  • 从源码构建
  • ioc2rpz™ 管理
    • 通过 DNS
    • 通过 REST
  • 监控与健康检查
  • 故障排查
  • 配置文件
  • 预定义配置值
  • AXFR 与 IXFR 缓存如何更新
  • 热缓存
  • 如何试用 ioc2rpz™
  • 一些免费的威胁情报订阅源
  • 更多文档
  • 参考资料
  • 支持 / 支持者
  • 联系我们
  • 许可证

简短摘要

ioc2rpz™:DNS 安全解决方案 —— ioc2rpz™ 是一款强大的 DNS 服务器,可将威胁指标转换为可操作的响应策略区(RPZ)订阅源。它自动化更新流程,确保您的网络免受最新威胁(包括恶意域名和 IP 地址)的侵害。通过将 IOC 订阅源转换为 RPZ,ioc2rpz™ 成为威胁情报与 DNS 安全之间的关键纽带,兼容 ISC Bind 或 PowerDNS 等支持 RPZ 的 DNS 服务器。

概述

DNS 是互联网的控制平面。通常 DNS 用于正当目的,但:

  • 它可被用于追踪用户的位置及其行为;
  • 恶意软件利用 DNS 进行命令与控制、数据外泄或流量重定向;
  • 根据 2016 年思科年度安全报告,91.3% 的恶意软件使用 DNS;
  • 广告公司通常使用独立且隐蔽的域名来展示广告;
  • 免费 DNS 服务(例如 1.1.1.1、8.8.8.8、9.9.9.9 等)可以帮助您解决部分担忧,但您无法自定义自己的防护设置或广告过滤规则。

ISC Bind 实际上是域名服务器的事实标准。随着响应策略区在 ISC BIND 9.8 中的引入,在 DNS 层监控和遏制恶意软件已成为一项简单的任务。PowerDNS recursor 4.0.0 及更高版本支持 RPZ。Knot DNS 也部分支持 RPZ。

与传统网络防护解决方案相比,DNS 服务器可以处理数百万个指标而不会影响性能,但当时没有自动化且高效的方法来维护主 DNS 服务器上的响应策略区。

通常,失陷指标(IOC)以纯文本形式分发,但格式各不相同,只有少数 IOC 提供商通过 RPZ 提供这些指标。

ioc2rpz™ 是一款定制 DNS 服务器,可自动将来自各种来源的指标(例如恶意 FQDN、IP)转换为 RPZ 订阅源,并自动维护/更新它们。这些订阅源可分发到任何支持 RPZ 的开源和/或商业 DNS 服务器,例如 ISC Bind、PowerDNS。您可以在路由器、台式机、服务器甚至 Raspberry Pi 上运行带 RPZ 过滤功能的自有 DNS 服务器。唯一的限制是系统内存。

使用 ioc2rpz™,您可以定义自己的订阅源、操作,并防止不需要的通信。

ioc2rpz™ —— 威胁情报与 DNS 的交汇点

ioc2rpz™ 将 IOC 订阅源转换为响应策略区(RPZ)。您可以混合订阅源以生成单个 RPZ 或多个 RPZ。受信任的域名和 IP 可被加入白名单。ioc2rpz™ 支持指标过期并相应地重建区域。
Alt ioc2rpz™ 当前版本支持:本地文件、通过 http/https/ftp 获取的文件/请求,以及用于访问其他资源类型的 shell 脚本。只要您能编写 REGEX 来提取指标,并且指标以换行符和/或回车符(/n、/r、/r/n)分隔,您就可以使用任何文件格式。

架构概述

ioc2rpz 基于 Erlang/OTP 构建,带有监督树,可确保容错和自动恢复。有关完整详情,请参阅 docs/architecture.md。``` ioc2rpz_app (application) └── ioc2rpz_sup (supervisor) ├── ioc2rpz_db_sup — ETS table heir process ├── ioc2rpz_tcp_sup — TCP listener pool (5 workers) ├── ioc2rpz_udp_sup — UDP listener ├── ioc2rpz_tls_sup — TLS/DoT listener pool (5 workers) [if cert configured] └── ioc2rpz_rest_sup — Cowboy HTTPS (REST API + DoH) [if cert configured]

root@kitploit:~
关键模块:

| 模块 | 职责 |
|--------|---------------|
| `ioc2rpz.erl` | TCP/TLS DNS 工作进程 — 接受、解析、验证、响应 |
| `ioc2rpz_udp.erl` | UDP DNS 监听器 — SOA 查询 |
| `ioc2rpz_conn.erl` | IOC 源获取(HTTP/HTTPS/文件/Shell) |
| `ioc2rpz_db.erl` | 基于 ETS 的区域和包缓存 |
| `ioc2rpz_sup.erl` | 主监督者、配置加载、区域调度 |
| `ioc2rpz_rest.erl` | REST 管理 API(Cowboy) |
| `ioc2rpz_doh.erl` | DNS-over-HTTPS 处理器 |

## 如何使用 ioc2rpz™
你可以将 ioc2rpz™ 与任何支持响应策略区域(Response Policy Zones)的 DNS 服务器配合使用,例如较新版本的 ISC BIND、PowerDNS,以及任何基于这些产品的商业 DNS 服务器(例如 Infoblox、Blue Cat、Efficient IP)。cfg 文件夹中提供了一份示例 BIND 配置文件(named.conf)。
<p align="center"><a href="http://www.youtube.com/watch?feature=player_embedded&v=bvhyMFa_mBM" target="_blank"><img src="https://raw.githubusercontent.com/Homas/ioc2rpz/master/ioc2rpz_demo.png"></a></p>

## ioc2rpz™ Web 界面
[ioc2rpz.gui](https://github.com/Homas/ioc2rpz.gui) 是一个独立项目开发的 Web 管理界面。运行 ioc2rpz™ 并不需要它。

## 协议支持

ioc2rpz™ 监听多种传输协议。所有传输共享相同的查询处理流程:限速、TSIG 验证、区域查询和响应生成。完整的协议文档请参阅 [docs/protocols.md](https://github.com/homas/ioc2rpz/blob/HEAD/docs/protocols.md)。

### 端口摘要

| 端口 | 协议 | 服务 | 条件 |
|------|----------|---------|-----------|
| 53 | UDP | DNS 查询(仅 SOA) | 始终 |
| 53 | TCP | DNS 查询、AXFR/IXFR 区域传输、管理 | 始终 |
| 853 | TCP+TLS | DoT — 与 TCP 相同,但已加密 | 需要 `cert` 配置 |
| 443/8443 | TCP+TLS | DoH(`/dns-query`)和 REST API | 需要 `cert` 配置 |

### UDP(端口 53)

UDP 用于轻量级 DNS 查询,主要是 SOA 查找。响应超过 512 字节(或 EDNS0 通告的缓冲区大小)时,会按照 RFC 1035 §4.2.1 设置 TC(截断)位,提示客户端通过 TCP 重试。UDP 不支持管理命令。```bash
dig @127.0.0.1 zone.ioc2rpz SOA -y hmac-sha256:keyname:base64key

TCP (Port 53)

TCP 负责处理区域传输(AXFR/IXFR)、SOA 查询和管理命令。一个由 5 个预派生的 accept 工作进程组成的池负责处理传入连接。```bash

AXFR zone transfer

dig @127.0.0.1 zone.ioc2rpz AXFR +tcp -y hmac-sha256:keyname:base64key

IXFR incremental transfer

dig @127.0.0.1 zone.ioc2rpz IXFR=12345 +tcp -y hmac-sha256:keyname:base64key

root@kitploit:~
### DNS over TLS / DoT (端口 853)

ioc2rpz™ 支持通过 DoT 进行 RPZ 分发。当配置中存在 `cert` 记录时,TLS 监听器会自动在 853 端口启动。DoT 支持与 TCP 相同的操作(AXFR、IXFR、SOA、管理)。

- 支持的 TLS 版本:1.2 和 1.3(`?TLSVersion = 'tlsv1.2-1.3'`)
- 支持连接复用(依据 RFC 7858 §3.4,每个 TLS 会话可执行多个查询,空闲超时 30 秒)
- 不支持 TLS PIN
- DNS NOTIFY 消息以未加密方式发送(纯 UDP)
- 当磁盘上的文件被替换时,证书会自动刷新(由于 Erlang SSL 缓存,最多约 2 分钟延迟)

有关证书设置,请参阅 [证书设置](#certificate-setup)。```bash
# SOA query over DoT
kdig @127.0.0.1 -p 853 zone.ioc2rpz SOA +tls -y hmac-sha256:keyname:base64key

# AXFR over DoT
dig @127.0.0.1 -p 853 zone.ioc2rpz AXFR +tls +tcp -y hmac-sha256:keyname:base64key

DNS over HTTPS / DoH(端口 443/8443)

DoH 通过 /dns-query 端点提供基于 HTTPS 的 DNS 解析。支持的方法:

  • GET,在 ?dns= 查询参数中携带 base64url 编码的 DNS 消息
  • POST,请求体使用 Content-Type: application/dns-message(最大 4096 字节;更大的负载将收到 HTTP 413)

响应使用 Content-Type: application/dns-message。DoH 携带完整的 DNS 线格式消息,并通过与 Do53/DoT 相同的路径进行处理,因此它继承了相同的 TSIG 认证;区域传输(AXFR/IXFR)仍然仅限 TCP,不通过 DoH 提供。```bash

DoH GET request

curl -H "Accept: application/dns-message"
"https://127.0.0.1:443/dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB" -k

DoH POST request

curl -X POST -H "Content-Type: application/dns-message"
--data-binary @dns_query.bin "https://127.0.0.1:443/dns-query" -k

root@kitploit:~
### 速率限制

DNS 查询使用智能(混合)键进行速率限制,这样合法的多区域客户端不会受到惩罚,同时可阻止通过改变查询名称进行的滥用:

- **已配置区域 + 支持的 QTYPE**(`SOA`/`AXFR`/`IXFR`,类别 `IN`)和**可识别的管理命令**(类别 `CHAOS`/`TXT`)按 `{client_IP, query_name, query_type}` 进行跟踪——因此,从同一 IP 轮询/传输多个区域(例如 `rpz1`、`rpz2`、`rpz3`)并执行管理操作的辅助服务器,会按区域+类型独立计数。
- **其他所有情况**(未知/未配置的区域、不支持的查询类型、错误的类别或无法识别的管理名称)按 `{client_IP}` 聚合,因此攻击者无法通过改变查询名称来绕过限制。

当超过限制时,服务器返回 DNS `REFUSED` 响应。

| 参数 | 默认值 | 宏 |
|-----------|---------|-------|
| 窗口 | 10 秒 | `?RATE_LIMIT_WINDOW`(10000 ms) |
| 每窗口最大请求数(细粒度:已知区域+类型 / 管理) | 1 | `?MAX_REQUESTS_PER_WINDOW` |
| 每窗口最大请求数(聚合:未知区域 / 不支持的查询类型) | 1 | `?MAX_UNKNOWN_REQUESTS_PER_WINDOW` |

速率限制适用于所有 DNS 查询传输(UDP、TCP、TLS、DoH)。窗口和阈值可通过 `include/ioc2rpz.hrl` 中的宏进行配置。

### DNS NOTIFY

区域更新(AXFR 或 IXFR)后,ioc2rpz™ 通过 UDP 向 RPZ `NotifyList` 中配置的 IP 地址发送 DNS NOTIFY 消息([RFC 1996](https://tools.ietf.org/html/rfc1996))。这会提示辅助 DNS 服务器检查区域 SOA 序列号,如果序列号已更改,则启动传输。```erlang
%% NotifyList in RPZ config — last field before whitelists
{rpz, {"zone.ioc2rpz", ..., ["source1"], ["10.0.0.1", "10.0.0.2"], []}}.

ioc2rpz™ 与 ISC BIND 及其他 DNS 对比:

  • ioc2rpz™ 专为处理 RPZ 分发而构建;
  • ioc2rpz™ 支持 DoT(基于 TLS 的 DNS),因此任何人都无法轻易窃听你的 RPZ/指标;
  • ioc2rpz™ 为现代 DNS 客户端提供 DoH(基于 HTTPS 的 DNS)支持;
  • ioc2rpz™ 支持任意数量的 RPZ;
  • ioc2rpz™ 支持实时/非缓存区域。它根据传入请求创建区域;
  • 可通过不同来源和不同协议(例如通过 REST API 调用)拉取指标;
  • RPZ 自动更新;
  • 使用 IOC 过期时间及时移除过期指标;
  • 针对性能和区域传输时间/大小/数据包进行了优化。

安装

部署该服务的最简单方式是使用 Docker Hub 上的 docker 容器。你可以在 ioc2rpz™ wiki 中找到 Docker 部署操作指南。

Docker 容器

ioc2rpz™ 在 Docker Hub 上可用。直接搜索 ioc2rpz™ 即可。 先决条件:

  • ioc2rpz™ 不包含配置文件,你需要将 /opt/ioc2rpz/cfg 挂载到主机系统上包含配置文件(ioc2rpz.conf)的目录;
  • ioc2rpz™ 使用 53/udp(仅 SOA 请求)、53/tcp(AXFR、IXFR、SOA、MGMT)、853/tcp(AXFR、IXFR、SOA、MGMT)和 8443/tcp(REST API、DoH)端口。这些端口应暴露给主机系统;
  • ioc2rpz™ 将 ETS 数据库保存到文件中以加快启动速度。你可以将 /opt/ioc2rpz/db 挂载到主机系统上的目录,以便在重启后保留数据库; 你可以使用以下命令启动 ioc2rpz™:``` sudo docker run -d --name ioc2rpz --log-driver=syslog --restart always --mount type=bind,source=/home/ioc2rpz/cfg,target=/opt/ioc2rpz/cfg --mount type=bind,source=/home/ioc2rpz/db,target=/opt/ioc2rpz/db -p53:53 -p53:53/udp -p853:853 -p8443:8443 pvmdel/ioc2rpz
root@kitploit:~
where /home/ioc2rpz/cfg, /home/ioc2rpz/db directories on a host system.  
You can pass a custom configuration file name via``-e`` parameter. E.g. ``-e CONF=./cfg/ioc2rpz2.conf``

## Environment Variables

The following environment variables are used by ioc2rpz™, primarily relevant for Docker deployments. They are defined in `config/sys.config.src` and `config/vm.args`.

| Variable | Default | Description |
|----------|---------|-------------|
| `IPv4` | — | IPv4 bind address |
| `IPv6` | — | IPv6 bind address |
| `CONF` | — | Path to configuration file (e.g. `./cfg/ioc2rpz.conf`) |
| `DB` | `/opt/ioc2rpz/db` | Database directory for ETS persistence |
| `CD` | `/opt/ioc2rpz` | Working directory |
| `NODE_NAME` | `ioc2rpz` | Erlang node short name |
| `IO2Cookie` | `ioc2rpz` | Erlang distributed cookie |

Pass environment variables to Docker with `-e`:
</translation>其中 /home/ioc2rpz/cfg、/home/ioc2rpz/db 目录位于宿主机系统上。  
您可以通过``-e``参数传递自定义配置文件名称。例如:``-e CONF=./cfg/ioc2rpz2.conf``

## 环境变量

以下环境变量由 ioc2rpz™ 使用,主要与 Docker 部署相关。它们定义在 `config/sys.config.src` 和 `config/vm.args` 中。

| Variable | Default | Description |
|----------|---------|-------------|
| `IPv4` | — | IPv4 绑定地址 |
| `IPv6` | — | IPv6 绑定地址 |
| `CONF` | — | 配置文件路径(例如 `./cfg/ioc2rpz.conf`) |
| `DB` | `/opt/ioc2rpz/db` | 用于 ETS 持久化的数据库目录 |
| `CD` | `/opt/ioc2rpz` | 工作目录 |
| `NODE_NAME` | `ioc2rpz` | Erlang 节点短名称 |
| `IO2Cookie` | `ioc2rpz` | Erlang 分布式 cookie |

使用 `-e` 将环境变量传递给 Docker:```bash
docker run -d --name ioc2rpz -e CONF=./cfg/custom.conf -e NODE_NAME=mynode ...

Docker Compose

您可以使用 docker compose 部署 ioc2rpz™ 和 ioc2rpz.gui。规范的 docker-compose.yml 文件可以在 ioc2rpz.dc 仓库中找到。

下面是一个示例 docker-compose.yml,展示了带有 web UI 和 Let's Encrypt certbot sidecar 容器的 ioc2rpz:```yaml version: "3.8" services: ioc2rpz: image: pvmdel/ioc2rpz container_name: ioc2rpz restart: always logging: driver: syslog ports: - "53:53/tcp" - "53:53/udp" - "853:853/tcp" - "8443:8443/tcp" volumes: - ./cfg:/opt/ioc2rpz/cfg - ./db:/opt/ioc2rpz/db - letsencrypt-certs:/opt/ioc2rpz/ssl:ro

ioc2rpz-gui: image: pvmdel/ioc2rpz.gui container_name: ioc2rpz-gui restart: always ports: - "443:443" depends_on: - ioc2rpz

certbot: image: certbot/certbot container_name: certbot volumes: - letsencrypt-certs:/etc/letsencrypt - letsencrypt-www:/var/www/certbot entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew --quiet; sleep 12h; done'"

volumes: letsencrypt-certs: letsencrypt-www:

root@kitploit:~
更新你的 `ioc2rpz.conf` 以引用挂载的证书路径:```erlang
{cert, {"ssl/live/ns1.rpz-proxy.com/fullchain.pem", "ssl/live/ns1.rpz-proxy.com/privkey.pem", ""}}.

ioc2rpz™ 在 AWS 上

你可以在 AWS 上运行 ioc2rpz™ 和 ioc2rpz.gui。对于相对较小的部署(数十万条指标),即使是免费套餐也足够。 下面的视频展示了如何使用 ECS 在 AWS 上设置 ioc2rpz™ 和 ioc2rpz.gui。

证书设置

DoT(端口 853)、REST API(端口 8443)和 DoH 都需要 TLS 证书。所有 TLS 服务使用相同的证书。完整详情请参阅 docs/deployment.md。

自签名证书(开发环境)```bash

openssl req -x509 -newkey rsa:2048 -keyout cfg/ioc2rpz_dot.key
-out cfg/ioc2rpz_dot.crt -days 365 -nodes -subj "/CN=ioc2rpz"

root@kitploit:~
### Let's Encrypt (生产环境)```bash
# Obtain certificate
sudo certbot certonly --standalone -d ns1.rpz-proxy.com

# Copy to ioc2rpz cfg directory
cp /etc/letsencrypt/live/ns1.rpz-proxy.com/fullchain.pem cfg/ioc2rpz_dot.crt
cp /etc/letsencrypt/live/ns1.rpz-proxy.com/privkey.pem cfg/ioc2rpz_dot.key

自动续订```bash

/etc/cron.d/ioc2rpz-cert-renew

0 3 * * * root certbot renew --quiet --deploy-hook "cp /etc/letsencrypt/live/ns1.rpz-proxy.com/fullchain.pem /opt/ioc2rpz/cfg/ioc2rpz_dot.crt && cp /etc/letsencrypt/live/ns1.rpz-proxy.com/privkey.pem /opt/ioc2rpz/cfg/ioc2rpz_dot.key"

root@kitploit:~
证书也会在配置重载(`ioc2rpz-reload-cfg`)期间被显式重新加载:当 ioc2rpz 检测到证书文件发生变化时,它会立即使用新证书重启 TLS 监听器,而不是等待约 2 分钟的 Erlang SSL 缓存。在续期钩子中添加一个 `ioc2rpz-reload-cfg` 步骤,即可在无需停机的情况下应用新证书。

### Docker 卷挂载

在 Docker 中运行时,请从宿主机挂载证书目录:```bash
docker run -d --name ioc2rpz \
  --mount type=bind,source=/etc/letsencrypt/live/ns1.rpz-proxy.com,target=/opt/ioc2rpz/ssl,readonly \
  ...

在 ioc2rpz.conf 中的引用:```erlang {cert, {"ssl/fullchain.pem", "ssl/privkey.pem", ""}}.

root@kitploit:~
Erlang 会在约 2 分钟内自动拾取替换后的证书文件。在配置重载(`ioc2rpz-reload-cfg`)期间,证书也会被显式重新加载。切勿让证书过期——请在到期前续期,以确保服务不中断。

## 从源码构建

> **注意:** 从源码构建适用于**开发和测试**。对于生产环境,**Docker 是推荐的部署方式**——参见 [Docker Compose](#docker-compose) 与 [ioc2rpz.dc](https://github.com/Homas/ioc2rpz.dc) 仓库。

### 前置要求

- **Erlang/OTP 24 或更新版本**(用 `erl -version` 检查)以及与之匹配的 [rebar3](https://www.rebar3.org)。
- C 工具链(用于构建依赖项)和 `git`。

### 构建与运行```bash
# 1. Clone the repository
git clone https://github.com/Homas/ioc2rpz.git
cd ioc2rpz

# 2. Build a release
rebar3 release

# 3. Edit the configuration (see the minimal example below)
$EDITOR cfg/ioc2rpz.conf

# 4. Start the server (foreground console, or 'start' for background)
_build/default/rel/ioc2rpz/bin/ioc2rpz console
# or: _build/default/rel/ioc2rpz/bin/ioc2rpz start

默认情况下,ioc2rpz™ 从 ./cfg/ioc2rpz.conf 读取其配置,监听所有网络接口,并将其数据库备份写入 ./db。编译时默认值(端口、路径、计时器)位于 include/ioc2rpz.hrl。

最小配置

一个包含一个 TSIG 密钥、一个文件源和一个 RPZ 区域的最小化 cfg/ioc2rpz.conf:```erlang %% Server NS record, admin mailbox, management key(s), and management ACL {srv,{"ns1.example.com","hostmaster.example.com",["mgmtkey"],["127.0.0.1","::1"]}}.

%% A TSIG key (name, algorithm, base64 secret) used for management / zone transfers {key,{"mgmtkey","sha256","5Yvt70eJnf95+LJeI8H3TgKGeVparmMB7udA0pv/JRE="}}.

%% An IOC source: a local file parsed as a full (AXFR) feed of domains {source,{"sample","file:cfg/small_ioc.txt","[:AXFR:]","^([0-9A-Za-z.-]+\.[0-9A-Za-z.-]+)$","",0,0,0,"mixed",true}}.

%% An RPZ zone built from the source, served with the nxdomain action {rpz,{"rpz.example.com",86400,3600,2592000,7200,"true","true","nxdomain",["mgmtkey"],"mixed",604800,86400,["sample"],[],[]}}.

root@kitploit:~
有关权威的逐字段参考(source/RPZ 元组布局、SOA 计时器、密钥组、证书等),请参阅 [docs/configuration.md](https://github.com/homas/ioc2rpz/blob/HEAD/docs/configuration.md)。要启用 DoT(端口 853)、DoH 和 HTTPS REST API,请添加 `{cert,{...}}` 条目 — 参见 [证书设置](#certificate-setup)。

### 开发 Shell(仅限开发/测试)

以下命令仅供本地开发和测试使用 — 不可用于生产环境:```bash
# Compile only (no release)
rebar3 compile

# Run the EUnit test suite
rebar3 eunit
# Run tests for a single module
rebar3 eunit --module=ioc2rpz_fun

# Start an interactive shell with the application and all deps loaded
rebar3 shell

在 rebar3 shell 中,你可以直接操作运行中的系统,例如:```erlang %% Inspect the listener pools and ETS tables supervisor:which_children(ioc2rpz_sup). ets:info(cfg_table, size). ets:info(rpz_hotcache_table, size).

%% Trigger a configuration reload / forced zone update ioc2rpz_sup:reload_config3(reload). ioc2rpz_sup:update_all_zones(true).

root@kitploit:~
## ioc2rpz™ 管理
### 通过 DNS
ioc2rpz™ 支持通过 DNS/TCP 或 DoT 进行管理。建议使用 DoT 或基于 DNS/TCP 的 REST API。当前版本的 ioc2rpz™ 不支持独立的管理 IP/接口。无论如何,强烈建议创建一个专用的 TSIG 密钥(或多个密钥),仅用于管理。您可以关闭通过 DNS 的管理。  
支持的操作:
- ioc2rpz™ 当前状态。请求 ``ioc2rpz-status``,类别 ``CHAOS``,记录 ``TXT``。例如:```
dig +tcp -y dnsmkey_1:ayVnL+h2QKMszRVohrngagcEuIpN3RkecXKdwSa5WsHD5N4Y5R3NUMGM W8sIGv36gPkAtWtgarqKzN9tmHqEnA== @127.0.0.1 ioc2rpz-status TXT -c CHAOS
  • 重新加载配置文件。RR 名称 ioc2rpz-reload-cfg,RR 类别 CHAOS,RR 类型 TXT
  • 更新 TSIG 密钥。RR 名称 ioc2rpz-update-tkeys,RR 类别 CHAOS,RR 类型 TXT
  • 全面刷新所有区域。RR 名称 ioc2rpz-update-all-rpz,RR 类别 CHAOS,RR 类型 TXT
  • 全面刷新某个区域。RR 名称 zone_name,RR 类别 CHAOS,RR 类型 TXT。例如,全面刷新 dga.ioc2rpz 可以通过以下方式调用:``` dig +tcp -y dnsmkey_1:ayVnL+h2QKMszRVohrngagcEuIpN3RkecXKdwSa5WsHD5N4Y5R3NUMGM W8sIGv36gPkAtWtgarqKzN9tmHqEnA== @127.0.0.1 dga.ioc2rpz TXT -c CHAOS
root@kitploit:~
- 停止 ioc2rpz™。RR Name ``ioc2rpz-terminate``,RR Class ``CHAOS``,RR Type ``TXT``
- 请求一个示例区域。RR Name ``sample-zone.ioc2rpz``,RR Class ``IN``,RR Type ``AXFR``
### 通过 REST
REST API(端口 8443/tcp)是首选的管理接口。出于安全原因,所有管理流量都必须加密,如果没有 SSL 证书,REST API 将不会启动。所有端点都接受 GET 和 POST 方法。

使用 HTTP Basic 认证来验证请求。管理 TSIG 密钥用于请求认证。TSIG 密钥名称用作 HTTP 用户名,TSIG 密钥用作密码。对 REST API 的访问由 `srv` 记录中定义的 ACL 限制。

API 版本段支持 `v1` 和 `v1.0`(例如,`/api/v1/stats/serv` 或 `/api/v1.0/stats/serv`)。

REST API 根据 `Accept` 头支持 JSON(默认)和纯文本输出:
- `application/json` — JSON 输出(默认)
- `text/plain` — 纯文本输出```bash
# Example: plain text output
curl -u "keyname:base64key==" -k -H "Accept: text/plain" https://127.0.0.1:8443/api/v1/mgmt/update_tkeys

文本响应使用以下格式:``` status: ok msg: TSIG keys were updated

root@kitploit:~
#### 路径参数

| 参数 | 描述 |
|-----------|-------------|
| `:rpz_name` | RPZ 区域名称(例如 `dga.ioc2rpz`) |
| `:source_name` | IOC 源名称(例如 `sample_fqdn`) |
| `:ioc` | 要查询的指标(FQDN 或 IP,例如 `baddomain.com`) |

#### 统计端点

`/api/v1/stats/serv` — 服务器统计信息(节点名称、规则总数、内存使用情况)```bash
curl -u "keyname:base64key==" -k https://127.0.0.1:8443/api/v1/stats/serv
root@kitploit:~
{
  "srv": {
    "node_name": "ioc2rpz@hostname",
    "srv_total_rules": 15000,
    "hot_cache_mem": "12.5 Mb",
    "axfr_table_mem": "45.2 Mb",
    "ixfr_table_mem": "8.1 Mb"
  },
  "rpz": [...],
  "sources": [...]
}

/api/v1/stats/rpz — RPZ 区域统计```bash curl -u "keyname:base64key==" -k https://127.0.0.1:8443/api/v1/stats/rpz

root@kitploit:~
```json
{
  "rpz": [
    {
      "name": "malware.ioc2rpz",
      "status": "ready",
      "rule_count": 5000,
      "ioc_count": 4500,
      "serial": 1709000000,
      "serial_ixfr": 1708990000,
      "update_time": 1709000000,
      "ixfr_update_time": 1708995000,
      "ixfr_nz_update_time": 1708995000
    }
  ]
}

status 字段(ready、updating、forceAXFR、notready)指示所报告的计数/序号是否为当前值;当为 updating 或 forceAXFR 时,它们反映的是上一次完成的更新。计数和序号在配置重载后会被保留,而不是重置为零。

/api/v1/stats/source — 来源统计```bash curl -u "keyname:base64key==" -k https://127.0.0.1:8443/api/v1/stats/source

root@kitploit:~
```json
{
  "sources": [
    {"name": "sample_fqdn", "ioc_count": 150}
  ]
}

管理端点

/api/v1/mgmt/reload_cfg — 重新加载配置文件```bash curl -u "keyname:base64key==" -k https://127.0.0.1:8443/api/v1/mgmt/reload_cfg

root@kitploit:~
成功:`{"status":"ok","msg":"Configuration reloaded"}`
错误(HTTP 520):`{"status":"error","msg":"Configuration reload error"}`

`/api/v1/mgmt/update_tkeys` — 从配置重新加载 TSIG 密钥```bash
curl -u "keyname:base64key==" -k https://127.0.0.1:8443/api/v1/mgmt/update_tkeys

成功:{"status":"ok","msg":"TSIG keys were updated"} 错误(HTTP 520):{"status":"error","msg":"TSIG keys update error"}

/api/v1/mgmt/terminate — 优雅关闭服务器```bash curl -u "keyname:base64key==" -k https://127.0.0.1:8443/api/v1/mgmt/terminate

root@kitploit:~
成功:`{"status":"ok","msg":"Terminating"}`

#### 区域更新端点

`/api/v1/update/all_rpz` — 强制完全刷新所有 RPZ 区域```bash
curl -u "keyname:base64key==" -k https://127.0.0.1:8443/api/v1/update/all_rpz

成功:{"status":"ok","msg":"All RPZ zones will be updated"}

/api/v1/update/:rpz_name — 强制完整刷新指定区域```bash curl -u "keyname:base64key==" -k https://127.0.0.1:8443/api/v1/update/dga.ioc2rpz

root@kitploit:~
成功: `{"status":"ok","msg":"RPZ dga.ioc2rpz will be updated"}`
错误(HTTP 520): `{"status":"error","msg":"RPZ dga.ioc2rpz not found"}`

#### 缓存管理端点

`/api/v1/cache/sources/clear/all` — 从热缓存中移除所有源```bash
curl -u "keyname:base64key==" -k https://127.0.0.1:8443/api/v1/cache/sources/clear/all

成功:{"status":"ok","msg":"All sources were removed from the hotcache"}

/api/v1/cache/sources/clear/:source_name — 从热缓存中移除特定来源```bash curl -u "keyname:base64key==" -k https://127.0.0.1:8443/api/v1/cache/sources/clear/sample_fqdn

root@kitploit:~
Success: `{"status":"ok","msg":"sample_fqdn source was removed from the hot cache"}`

`/api/v1/cache/sources/load/all` — 将所有源重新加载到热缓存中```bash
curl -u "keyname:base64key==" -k https://127.0.0.1:8443/api/v1/cache/sources/load/all

成功: {"status":"ok","msg":"All sources will loaded to the hot cache"}

Feed 与 IOC 查询端点

/api/v1/feed/:rpz_name — 从 RPZ feed 获取指标

查询参数:?type=fqdn|ip|both(默认:both)```bash curl -u "keyname:base64key==" -k "https://127.0.0.1:8443/api/v1/feed/malware.ioc2rpz?type=fqdn"

root@kitploit:~
成功:```json
{
  "status": "ok",
  "rpz": "malware.ioc2rpz",
  "iocs": ["baddomain.com", "evil.example.org"]
}

错误(HTTP 520):{"status":"error","msg":"RPZ malware.ioc2rpz not found"}

/api/v1/ioc/:ioc — 检查某个 IOC 是否被任何 RPZ 源屏蔽

查询参数:?tkey=keyname — 将搜索范围限制为该密钥可访问的区域(可选)```bash curl -u "keyname:base64key==" -k "https://127.0.0.1:8443/api/v1/ioc/baddomain.com?tkey=dnsproxykey_1"

root@kitploit:~
Success:```json
{
  "ioc": "baddomain.com",
  "tkey": "dnsproxykey_1",
  "data": [
    {
      "ioc": "baddomain.com",
      "feeds": [
        {
          "feed": "malware.ioc2rpz",
          "wildcard": "true",
          "type": "fqdn",
          "rpz_serial": 1709000000,
          "ioc_expiration": 0,
          "sources": ["abuse-ch", "internal-list"]
        }
      ]
    }
  ]
}

错误: {"status":"error", "ioc": "nonexistent.com"}

附加的 sources 字段在启用来源跟踪时列出各数据源中贡献的来源名称;当跟踪被禁用或归属未知时,该字段为 null。有关配置和语义,请参阅 IOC 来源归属。

不支持的端点

任何无法识别的路径都会返回 HTTP 200,包含以下内容:```json {"status":"error","msg":"Unsupported request"}

root@kitploit:~
## 监控与健康检查

### REST API 统计```bash
# Server statistics
curl -u "keyname:key==" -k https://127.0.0.1:8443/api/v1/stats/serv

# RPZ zone statistics (indicator counts, serials, update times)
curl -u "keyname:key==" -k https://127.0.0.1:8443/api/v1/stats/rpz

# Source statistics
curl -u "keyname:key==" -k https://127.0.0.1:8443/api/v1/stats/source

Erlang Shell 检查

如果在交互式 shell 中运行,或附加到运行中的节点:```erlang %% Check supervisor children supervisor:which_children(ioc2rpz_sup). supervisor:count_children(ioc2rpz_tls_sup_v6). supervisor:count_children(ioc2rpz_tcp_sup_v6).

%% Check ETS table sizes (memory usage) ets:info(cfg_table, size). ets:info(rpz_hotcache_table, size). ets:info(rate_limits, size).

root@kitploit:~
### DNS 健康检查```bash
# SOA query over UDP
dig @localhost -p 53 your-zone.rpz SOA +short

# Zone transfer over TCP
dig @localhost -p 53 your-zone.rpz AXFR +tcp -y hmac-sha256:keyname:base64key

# DoT query
dig @localhost -p 853 +tls your-zone.rpz SOA

# Sample zone (built-in test zone)
dig @localhost sample-zone.ioc2rpz AXFR +tcp

See docs/deployment.md for full monitoring and log reference.

故障排除

有关详细的故障排除,请参阅 docs/deployment.md。

配置文件

配置是一个 Erlang 文件。每个配置选项都是一个 Erlang 项(term),因此配置必须符合 Erlang 语法。服务器在加载/重新加载时会校验配置条目:TSIG 密钥编码、证书文件是否存在、正则表达式编译以及 URL 语法。无效条目会被记录并跳过。完整的配置参考请参阅 docs/configuration.md。

ioc2rpz™ 支持以下配置参数:

  • 单个 srv 记录(必需);
  • 单个 cert 记录(可选);
  • 零个或多个 key 记录(可选);
  • 零个或多个 whitelist 记录(可选);
  • 一个或多个 source 记录(至少需要一个源);
  • 一个或多个 rpz 记录(至少需要一个 rpz)。

srv 记录

srv 记录用于定义服务器默认值。它由以下内容组成:

  • SOA 记录中使用的 NS 服务器名称;
  • SOA 记录的电子邮件地址(采用 SOA 格式);
  • 管理 TSIG 密钥列表(仅名称)。详细信息请参阅管理部分。
  • 用于 REST API 访问控制的 ACL IP 地址列表。
  • (可选) TrackSources — 服务器级别的源归属全局默认值:off | auto | on(默认 off)。应用于任何未设置自身 track_sources 的数据源。请参阅 IOC 源归属。

srv 记录示例:``` {srv,{"ns1.example.com","support.email.example.com",["dnsmkey_1","dnsmkey_2","dnsmkey_3"],["acl_ip1","acl_ip2"]}}.

%% With the optional global source-tracking default (5-field form): {srv,{"ns1.example.com","support.email.example.com",["dnsmkey_1"],["acl_ip1"],auto}}.

root@kitploit:~
4 字段形式仍然有效,并且默认将 `TrackSources` 设为 `off`。
### **cert** 记录
**cert** 记录用于定义 DNS over TLS、REST API 和 DoH 通信的证书和私钥。有关证书的生成和管理,请参阅 [证书设置](#certificate-setup)。

它由以下部分组成:
- 证书文件的路径;
- 包含 PEM 编码私钥的文件的路径;
- 包含 PEM 编码 CA 证书的文件的路径。  

示例 **cert** 记录:```
{cert,{"cfg/cert.pem", "cfg/key.pem",	"cfg/cacerts.pem"}}.

include 记录

include 记录允许将 ioc2rpz™ 配置拆分为多个文件。

示例 include 记录:``` {include,"cfg/tkeys.include.cfg"}.

root@kitploit:~
### **key** 记录
TSIG 密钥用于认证和授权。建议为 ioc2rpz™ 管理和区域传输使用不同的 TSIG 密钥。  
**key** 记录由以下部分组成:
- TSIG 密钥名称;
- 算法。支持 ``md5``、``sha256`` 和 ``sha512``;
- 密钥;
- (可选)它所属的密钥组列表。

**key** 记录示例:```
{key,{"key_name_1","md5","ayVnL+h2QKMszRVohrngagcEuIpN3RkecXKdwSa5WsHD5N4Y5R3NUMGM W8sIGv36gPkAtWtgarqKzN9tmHqEnA=="}}.
{key,{"key_name_2","sha256","5Yvt70eJnf95+LJeI8H3TgKGeVparmMB7udA0pv/JRE="}}.
{key,{"key_name_3","sha512","03uuaGl9kqfenjRgIeCv6e29lVvMwviB1+cDX1I0jcVOcTU4jWFwRkfo3ULRMD+NGDfwzYvXkJ94FNEaAW4vzw==",["customers","public"]}}.

dnssec-keygen 工具可用于生成 TSIG 密钥:```bash

MD5 (512-bit)

dnssec-keygen -a HMAC-MD5 -b 512 -n USER tsig-key

SHA-256 (256-bit)

dnssec-keygen -a HMAC-SHA256 -b 256 -n USER tsig-key

SHA-512 (512-bit)

dnssec-keygen -a HMAC-SHA512 -b 512 -n USER tsig-key

root@kitploit:~
请参阅 `dnssec-keygen` 文档以了解详情。密钥可以分配给组,以便在 RPZ 区域访问控制中实现基于组的授权。

### **key_group** 记录
密钥组为区域传输和管理提供基于组的授权。不必在 `rpz` 或 `srv` 记录中列出各个密钥,您可以将密钥分配给命名组并引用该组。

将密钥分配到组有两种方式:
1. 通过 `key` 记录的可选第 4 个字段以内联方式指定:`{key, {Name, Alg, Secret, [Groups]}}`
2. 通过 `key_group` 记录显式指定(如下所示)```erlang
{key_group, {GroupName, [KeyName1, KeyName2, ...]}}.
字段类型描述
GroupNamestring组名(例如 "customers")
Keyslist of strings属于该组的 TSIG 密钥名称列表

示例 key_group 记录:```erlang {key_group, {"customers", ["dnsproxykey_1", "dnsproxykey_2"]}}. {key_group, {"public", ["dnsproxykey_3"]}}.

root@kitploit:~
在 `rpz` 和 `srv` 记录中,组通过键列表中的 `{groups, ["group1", "group2"]}` 元组进行引用:```erlang
{rpz, {"zone.ioc2rpz", 7202, 3600, 2592000, 7200, "true", "true", "nxdomain",
       ["dnsproxykey_1", {groups, ["customers", "public"]}],
       "fqdn", 86400, 3600, ["source1"], [], []}}.

whitelist 记录

白名单用于防止可能的错误,并阻止对受信任域名和 IP 地址的拦截。被加入白名单的 IOC 会从响应策略区域中移除。ioc2rpz™ 仅进行精确匹配,因此如果某个被加入白名单的 IP 地址位于被阻止的子网内,它不会拆分或丢弃该网络,反之亦然。白名单是一个文本文件或文本数据源。指标应以换行符(/n、/r 或同时使用 /n/r)分隔。白名单必须包含有效的 FQDN 和/或 IP 地址。ioc2rpz™ 支持无限数量的指标。 whitelists 记录由以下部分组成:

  • 白名单名称;
  • 白名单路径。支持 URL(http/https/ftp)和本地文件。本地文件使用前缀 file:;
  • 用于提取指标的 REGEX。正则表达式必须包含在双引号中。如果指定空 REGEX(""),将使用默认 REGEX("^([A-Za-z0-9][A-Za-z0-9\-\._]+)[^A-Za-z0-9\-\._]*.*$")。如果不需要 REGEX(源数据已提供所需格式),则使用 none。

示例 whitelist 记录:``` {whitelist,{"whitelist_1","file:cfg/whitelist1.txt",none}}.

root@kitploit:~
### **source** 记录
source 是恶意指示器的订阅源。支持 FQDN、IPv4 和 IPv6 地址。source 是一个文本文件或文本数据订阅源。指示器应以换行/回车字符(/n、/r 或 /r/n 两者)分隔。ioc2rpz™ 支持无限数量的指示器。  
**source** 记录由以下部分组成:
- source 名称;
- 用于全量源传输(AXFR)的 source 路径。支持 URL(http/https/ftp)、本地文件和脚本。前缀 **file:** 用于本地文件。前缀 **shell:** 用于在主机/容器上执行本地脚本/命令,该脚本/命令应将指示器及可选的过期日期返回至 STDOUT;
- 用于增量源传输(IXFR)的 source 路径。AXFR、IXFR 路径支持关键字以缩短 URL 并提供区域更新时间戳:
  - **[:AXFR:]** - 完整的 AXFR 路径。只能在 IXFR 路径中使用;
  - **[:FTimestamp:]** - source 上次更新的时间戳  (例如 1507946281)
  - **[:ToTimestamp:]** - 当前时间戳;
- 用于提取指示器及其过期时间的 REGEX。第一个匹配项为指示器,第二个匹配项为过期时间。过期时间是可选参数。正则表达式必须包含在双引号中。如果指定空 REGEX(`""`),将使用默认 REGEX(`"^([A-Za-z0-9][A-Za-z0-9\-\._]+)[^A-Za-z0-9\-\._]*.*$"`)。如果不需要 REGEX,则使用 `none`(该 source 已按要求格式提供数据)。
可选参数(必须全部使用或全部不使用):
- UserID(内部使用)。
- 最大 IoC 数量。
- 全量 source 更新,热缓存时间(秒)。
- 增量 source 更新,热缓存时间(秒)。

HTTPS source 下载会验证远程服务器的 TLS 证书。证书无效或自签名的 source 将无法下载。对于自签名证书,请使用带 `curl --insecure` 的 `shell:` source。

**本地文件限制:** 出于安全原因,包含 `..`(父目录遍历)的 `file:` 路径将被拒绝;请使用不含 `..` 的路径(位于工作/数据目录内)。

**Shell 命令限制:** 每个管道段的可执行文件必须是绝对路径(例如 `/usr/bin/curl`)或裸名称的安全文本工具(`sort`、`uniq`、`grep`、`sed`、`awk`、`gawk` 等);破坏性命令和 shell(`rm`、`bash`、`sh` 等)会被阻止,命令替换(`$(...)`、反引号)和输出重定向(`>`、`>>`)会被拒绝。被拒绝的命令不会执行,并通过 CEF 事件 151 记录(已执行命令通过 150 记录)。完整规则集请参阅 [docs/configuration.md](https://github.com/homas/ioc2rpz/blob/HEAD/docs/configuration.md#shell-command-restrictions)。

如果某个 source 返回的指示器数量低于其先前数量的 50%,则更新会被拒绝并保留之前的数据。这可以防止质量下降的订阅源降低 RPZ 覆盖率。可通过 `?SOURCE_MIN_IOC_RATIO` 宏进行配置。

示例 **source** 记录:```
%% Local file source — indicators without expiration
{source,{"sample_fqdn","file:cfg/sample_ioc_fqdn.txt","[:AXFR:]",none}}.

%% Local file source — indicators with expiration timestamps (tab-separated)
{source,{"sample_expire","file:cfg/sample_ioc_expire.txt","[:AXFR:]","^([A-Za-z0-9][A-Za-z0-9\-\._]+)\t([0-9TZ:\-]+)$"}}.

%% Shell source — fetch RPZ via AXFR and extract CNAMEs
{source,{"base.rpz1","shell:/usr/bin/dig -y KEYNAME:TSIGKEY @127.0.0.1 base.rpz.ioc2rpz.local axfr | /bin/grep -e CNAME | /bin/grep -v '*.' | /usr/bin/awk -F '.base.rpz' '{print $1}'","",none}}.

shell: 源用于扩展 ioc2rpz™ 的连接选项(其原生选项有限)。ioc2rpz™ 容器中包含 dig、grep、awk 和 python。例如,你可以混合不同的 RPZ 源,或从数据库获取数据。

Shell 命令限制: 所有可执行文件必须使用绝对路径(例如 /usr/bin/curl 而非 curl)。破坏性命令(rm、bash、sh 等)会被阻止。命令替换($(...)、反引号)和输出重定向(>、>>)会被拒绝。详见 docs/configuration.md。

本地文件安全: 包含 ..(父目录遍历)的文件路径出于安全考虑会被拒绝。

rpz 记录

RPZ 术语定义了一个响应策略区域。
rpz 记录由以下部分组成:

  • RPZ 名称;
  • SOA 刷新时间(秒);
  • SOA 更新重试时间(秒);
  • SOA 过期时间(秒);
  • SOA NXDomain TTL(秒);
  • 缓存。可能的值:true 或 false。true 表示应缓存 RPZ,false 表示不缓存,实时区域源会被下载,并通过 AXFR 请求生成 RPZ。“实时”区域不支持增量区域传输。如果 RPZ 源未被缓存,它仍会临时存储在热缓存中。如果客户端请求超时,我们下次还能响应。AXFR 时间将用于确定缓存生命周期;
  • 通配符。可能的值:true 或 false。定义是否应生成通配符规则;
  • 动作。参见下面的 RPZ 动作表;
  • TSIG 密钥和密钥组列表;
  • RPZ 中使用的 IOC 类型:mixed、fqdn、ip。用于优化。
  • 完整区域更新时间(秒)(AXFR 时间)。如果 IOC 的 MD5 不同,则进行完整区域更新和重建;
  • 增量区域更新时间(IXFR 时间)。源应支持增量更新。“0”表示没有增量区域更新;
  • 源列表;
  • 应在 RPZ 更新时收到通知的 DNS 服务器(IP 地址)列表(参见 DNS NOTIFY);
  • 白名单列表。
  • (可选)TrackSources — 按源(feed)进行来源归属:auto | true | false。存在时,它覆盖服务器全局默认值。省略时(15 字段形式),该源继承服务器默认值(#srv ,除非配置,否则为 )。参见 。

RPZ 动作

多个本地动作可以组合在一个列表中:[{"local_a","127.0.0.1"},{"local_aaaa","fe80::1"},{"local_txt","Blocked"}]

rpz 记录示例:``` {rpz,{"zone_name",soa_refresh, soa_update_retry,soa_expire,soa_nxdomain_ttl,"cache","wildcards","action",["key1","key2"],"Zone_type",AXFT_Time, IXFR_Time,["source1","source2"],["notify_ip1","notify_ip2"],["whitelist_1","whitelist_2"]}}.

{rpz,{"zone_name",soa_refresh, soa_update_retry,soa_expire,soa_nxdomain_ttl,"cache","wildcards","action",["key1","key2",{groups,["group1","group2"]}],"Zone_type",AXFT_Time, IXFR_Time,["source1","source2"],["notify_ip1","notify_ip2"],["whitelist_1","whitelist_2"]}}.

{rpz,{"mixed.ioc2rpz",7202,3600,2592000,7200,"true","true","passthru",["dnsproxykey_1","dnsproxykey_2"],"mixed",86400,3600,["sample_fqdn","sample_expire","sample_ip"],[],["whitelist_1","whitelist_2"]}}.

{rpz,{"mixed.ioc2rpz",7202,3600,2592000,7200,"true","true","passthru",["dnsproxykey_1","dnsproxykey_2",{groups,["public","ip2"]}],"mixed",86400,3600,["sample_fqdn","sample_expire","sample_ip"],[],["whitelist_1","whitelist_2"]}}.

%% With explicit per-feed source tracking (16-field form; trailing auto): {rpz,{"mixed.ioc2rpz",7202,3600,2592000,7200,"true","true","passthru",["dnsproxykey_1"],"mixed",86400,3600,["sample_fqdn","sample_expire","sample_ip"],[],["whitelist_1"],auto}}.

root@kitploit:~
### IOC 来源归因

RPZ 订阅源通过合并来自多个来源的指标构建。来源归因让 IOC 查找 API 能够报告**订阅源内部的哪个(些)来源**提供了某条指标——这对于对报告误报进行分类处理很有用。跟踪**默认关闭**,并按订阅源通过可选的服务器级全局默认值进行控制。

**配置**

- 按订阅源:`{rpz,{...}}` 元组的可选尾部(第 16 个)`TrackSources` 元素——`auto | true | false`。
- 服务器全局默认值:`{srv,{...}}` 元组的可选尾部(第 5 个)`TrackSources` 元素——`off | auto | on`(默认 `off`)。

两者都是可选的且向后兼容:现有配置文件(15 字段的 `rpz`、4 字段的 `srv`)会原样加载并按关闭状态运行。

**解析优先级** —— 订阅源的有效状态按以下方式解析:
1. 订阅源的显式 `track_sources` 值(如果已设置);
2. 否则使用服务器全局默认值;
3. 否则使用内置默认值 `off`。

`auto` 表示:仅跟踪**多来源**订阅源。单来源订阅源永远不会被遮蔽——其唯一来源名称会直接返回(无需跟踪开销)。

**API——新增的 `sources` 字段**

`/api/v1/ioc/:ioc` 响应在每个订阅源对象上新增了一个 `sources` 字段。它是**增量式且向后兼容的**:所有现有字段均保持不变,因此忽略该字段的旧客户端仍可正常工作。

- 已跟踪的多来源订阅源:包含贡献来源名称的 JSON 数组。
- 单来源订阅源:包含该唯一来源名称的单元素数组。
- 跟踪已禁用,或归属未知(例如升级前缓存的记录行在其一次性 AXFR 重建之前):`null`(JSON)/ `(disabled)` 或 `(unavailable)`(TXT)。```json
{
  "feed": "mixed.ioc2rpz",
  "wildcard": "true",
  "type": "fqdn",
  "rpz_serial": 1709000000,
  "ioc_expiration": 0,
  "sources": ["abuse-ch", "internal-list"]
}

单一来源 feed:"sources": ["sample_fqdn"]。跟踪已禁用/未知:"sources": null。

Rollout(默认关闭)

升级二进制文件不会改变任何东西 — 没有跟踪、不会重建 zone、API 不变 — 直到设置了 track_sources 值。Feeds 由 GUI 管理;GUI/社区网站将在后续更新中写入这些可选配置值并展示 sources。为缓存 feed 启用跟踪会触发一次性的 AXFR 重建,以填充来源掩码。

局限性

  • 归属仅适用于缓存的 feed(cache = "true"),因为 API 查询读取的是 IXFR 缓存表。
  • 在完整的 AXFR 重建后,掩码才是权威的。在 IXFR 更新期间,新添加的指标的掩码会被正确设置,但对于已存在指标的掩码更改(第二个来源开始列出已有的 IOC)可能只会在下一次 AXFR 时得到修正。
  • 来源掩码是按 zone 位置排列的(位 i = 第 i 个来源)。对 zone 的来源列表重新排序或编辑会强制进行一次 AXFR 重建(通过来源签名检查检测到),以便重新派生掩码。
  • 超过 63 个来源的 feed 使用更宽的二进制位图掩码(默认),因此归属保持正确。
示例配置文件(点击展开)```erlang {srv,{"ns1.rpz-proxy.com","support.rpz-proxy.com",["dnsmkey_3"],["127.0.0.1","10.42.0.10"]}}. {cert,{"cfg/ioc2rpz_dot.crt", "cfg/ioc2rpz_dot.key", ""}}.

{key,{"dnsproxykey_1","md5","apXqLsDs90H213eV6LS9ryYp5tY8YTpkttOkRCve7dp1Zeob3SGAbaVU9BShpsW25MmR8mTiX5OY0Qetv977Yw=="}}. {key,{"dnsproxykey_2","sha512","03uuaGl9kqfenjRgIeCv6e29lVvMwviB1+cDX1I0jcVOcTU4jWFwRkfo3ULRMD+NGDfwzYvXkJ94FNEaAW4vzw=="}}. {key,{"dnsmkey_3","sha512","03uuaGl9kqfenjRgIeCv6e29lVvMwviB1+cDX1I0jcVOcTU4jWFwRkfo3ULRMD+NGDfwzYvXkJ94FNEaAW4vzw=="}}.

{whitelist,{"whitelist_1","file:cfg/sample_whitelist.txt",none}}. {whitelist,{"whitelist_2","file:cfg/whitelist2.txt",""}}.

{source,{"sample_fqdn","file:cfg/sample_ioc_fqdn.txt","[:AXFR:]",none}}. {source,{"sample_expire","file:cfg/sample_ioc_expire.txt","[:AXFR:]","^([A-Za-z0-9][A-Za-z0-9\-\._]+)\t([0-9TZ:\-]+)$"}}. {source,{"sample_ip","file:cfg/sample_ioc_ip.txt","[:AXFR:]",none}}.

{rpz,{"localdata.ioc2rpz",7202,3600,2592000,7200,"false","true",[{"local_aaaa","fe80::1"},{"local_a","127.0.0.1"},{"local_a","127.0.0.2"},{"local_a","127.0.0.3"},{"local_a","127.0.0.4"},{"local_cname","www.example.com"},{"local_txt","Text Record www.example.com"},{"local_txt","Text Record 2"}],["dnsproxykey_1", "dnsproxykey_2"],"mixed",30,30,["sample_fqdn"],[],["whitelist_1","whitelist_2"]}}. {rpz,{"dga.ioc2rpz",7202,3600,2592000,7200,"true","true","nodata",["dnsproxykey_1","dnsproxykey_2"],"fqdn",172800,3600,["sample_expire"],[],[]}}. {rpz,{"mixed.ioc2rpz",7202,3600,2592000,7200,"true","true","passthru",["dnsproxykey_1", "dnsproxykey_2"],"mixed",86400,3600,["sample_fqdn","sample_expire"],[],["whitelist_1","whitelist_2"]}}. {rpz,{"ip-block.ioc2rpz",7202,3600,2592000,7200,"false","true","nxdomain",["dnsproxykey_1","dnsproxykey_2"],"ip",172800,0,["sample_ip"],[],[]}}.

root@kitploit:~
</details>

## 预定义配置值 - include/ioc2rpz.hrl
include/ioc2rpz.hrl 包含预编译参数。

标准参数:
- ``MGMToDNS`` (true/false) - 启用通过 DNS/TCP 进行的管理;
- ``DBStorage`` (ets) - 定义 AXFR 和 IXFR 缓存的数据库存储。当前版本仅支持 ETS;
- ``SaveETS`` (true/false) - 定义是否应将 ETS AXFR/IXFR 表保存到磁盘;
- ``Port`` (数值,1 - 65535) - 定义服务运行的 DNS 端口;
- ``PortTLS`` (数值,1 - 65535) - 定义服务运行的 DoT 端口;
- ``PortREST`` (数值,1 - 65535) - 定义服务运行的 HTTPs 端口;
- ``TTL`` (数值,以秒为单位) - DNS 记录/RPZ 规则的默认 TTL。
- ``DefConf`` (字符串) - 默认配置文件;
- ``DefDB`` (字符串) - 默认数据库路径;
- ``logTS`` - 如果定义,日志消息中会添加时间戳;
- ``debug`` - 如果定义,将打印调试日志消息;
- ``TLSVersion`` ('tlsv1.2-1.3') - DoT 和 REST API 支持的 TLS 版本;

优化参数:
- ``DNSPktMax`` (数值,100 - 65535) - 最大数据包大小。推荐值:
  - 16384 - 最小区域传输大小;
  - 65535 - 最小 DNS 数据包数量;
- ``Compression`` (数值,0 - 9) - 压缩级别(0 - 无压缩,9 - 最高压缩)。AXFR 缓存和磁盘上的表存储压缩数据;
- ``ZoneRefTime`` (数值,以毫秒为单位) - 定义区域刷新检查间隔;
- ``TCPTimeout`` (数值,以毫秒为单位) - 定义 TCP 会话超时;
- ``HotCacheTime`` (数值,以秒为单位) - IOC、规则、数据包的热缓存时间。实时区域存储在热缓存中;
- ``HotCacheTimeIXFR`` (数值,以秒为单位) - 热缓存中 IXFR IOC 的热缓存时间。默认情况下,IXFR 指示器缓存一分钟(即使设置为 0),因为当前序列号总是四舍五入到上一分钟;
- ``RATE_LIMIT_WINDOW`` (数值,以毫秒为单位,默认 10000) - 每个 IP 的速率限制窗口持续时间;
- ``MAX_REQUESTS_PER_WINDOW`` (数值,默认 1) - 每个速率限制窗口内每个 IP 的最大 DNS 请求数;
- ``ShellMaxRespSize`` (数值,默认 2 GiB) - shell 命令源的最大响应大小;
- ``SourcePullTimeout`` (数值,以毫秒为单位,默认 300000) - 源下载超时(5 分钟);

## AXFR(完整)和 IXFR(增量)缓存如何更新
- AXFR 缓存始终包含没有 SOA/NS/TSIG 记录的预构建区域。预构建意味着所有记录都按数据包拆分,标签被缩短/压缩。
- 如果服务器收到 AXFR 请求,它会从 AXFR 缓存中检索数据包,并在需要时添加 SOA/NS 记录和 TSIG。
- AXFR 区域更新应被视为清理过程,应定期进行。只是为了确保源与缓存之间没有失步。
- 对于大区域,AXFR 更新应安排得不频繁,以尽量减少对服务器性能以及向所有客户端传输数据量的影响。
- 如果可能,所有更改都应通过增量区域更新完成。在这种情况下,AXFR 缓存只会在区域被更新时才重建。
- [TODO] 由于优化,对于新的 IOC,只会重建最后一个数据包,对于过期的 IOC,会重建相关且一致的数据包。
- IXFR 缓存仅包含 IOC 和过期日期。[TODO] 以及数据包 ID(以便能够快速重建区域)。
- RPZ 记录包含当前区域 Serial 和 Serial_IXFR。Serial_IXFR 充当可用于增量区域传输的最小增量区域序列号。
- 完整区域更新(AXFR)后,IXFR 缓存会被刷新。Serial_IXFR = Serial。无论何种情况下客户端都会收到完整区域更新,这就是为什么 AXFR 区域传输不宜频繁的原因。
- 当 IXFR 缓存更新时,必须重建 AXFR 缓存。
- 如果区域不支持 IXFR 更新 -> 它不会被保存到 IXFR 表中。
- 实时区域不会缓存在 AXFR、IXFR 缓存中,但源(IOC)可以缓存在热缓存中。

## 热缓存
所有 IOC、规则、数据包包括实时 RPZ 都存储在热缓存中。预编译参数 ``HotCacheTime``、``HotCacheTimeIXFR`` 定义存储时间。

## 如何试用 ioc2rpz™(或由 ioc2rpz™ 托管的示例和免费 RPZ 订阅源)
### 免责声明
作者对这些 RPZ 订阅源内容中的任何错误或遗漏不承担任何责任。这些订阅源仅按"原样"提供,不保证完整性、准确性、有用性或及时性,仅用于演示 ioc2rpz™ 技术。RPZ 订阅源服务的分发可能会在未事先通知的情况下中断或停止。作者不对因使用本服务而造成的任何直接或间接损害承担责任。

### RPZ 订阅源
如果您在 [ioc2rpz™ 社区](https://ioc2rpz.net) 注册,可以使用以下订阅源测试 ioc2rpz™ 技术:
- [notracking](https://github.com/notracking/hosts-blocklists);
- [Phishtank](https://www.phishtank.com/)。

### 示例 bind 配置```
options {
  #This is just options for RPZs. Add other options as required
  recursion yes;
  response-policy {
    ####FQDN only zones
    ####Mixed zones
    zone "phishtank.ioc2rpz" policy nxdomain;
    ####IP only zones
  } qname-wait-recurse no break-dnssec yes;
};

key "ioc2rpz-YOUR-UNIQUE-KEY-NAME"{
  algorithm hmac-sha256; secret "ioc2rpz-YOUR-UNIQUE-KEY";
};

zone "phishtank.ioc2rpz" {
  type slave;
  file "/var/cache/bind/phishtank.ioc2rpz";
  masters {94.130.30.123  key "ioc2rpz-YOUR-UNIQUE-KEY-NAME";};
};
下载工具
问题解决方案
端口已被占用使用 lsof -i :53 / lsof -i :853 检查。监听套接字上已设置 {reuseaddr, true},以便快速重启。
DoT 不接受连接确认已配置 {cert, ...}。检查 TLS worker:supervisor:count_children(ioc2rpz_tls_sup_v6). 检查 853 端口是否未被防火墙拦截。
区域传输失败(TSIG 不匹配)确认客户端与服务器之间的密钥名称和 secret 一致。在日志中查找 CEF 104/105 事件。
源下载失败检查网络连接。在日志中查找 Error downloading feed。服务器会以 3 秒的延迟重试 3 次。对于 HTTPS 源,请确保 TLS 证书有效。
内存使用过高在 Erlang shell 中检查 ETS 表大小。rate_limits 和 rpz_hotcache_table 会被定期清理。可考虑减小 ?HotCacheTime。
TrackSources
off
IOC 来源归属
动作配置值描述
NXDOMAIN"nxdomain"返回 NXDOMAIN(域名不存在)
NODATA"nodata"返回空应答(域名存在,无记录)
Passthru"passthru"允许查询(豁免规则)
Drop"drop"静默丢弃查询
TCP-Only"tcp-only"强制客户端通过 TCP 重试
Block NS"blockns"阻止权威名称服务器
Redirect (domain){"redirect_domain","example.com"}重定向到指定域名(local_cname 的别名)
Redirect (IP){"redirect_ip","127.0.0.1"}重定向到指定 IP(local_a/local_aaaa 的别名)
Local A{"local_a","127.0.0.1"}返回自定义 IPv4 地址
Local AAAA{"local_aaaa","fe80::1"}返回自定义 IPv6 地址
Local CNAME{"local_cname","www.example.com"}返回 CNAME 重定向
Local TXT{"local_txt","Text Record"}返回 TXT 记录

示例 PowerDNS 配置```

rpzMaster("94.130.30.123", "phishtank.ioc2rpz", {defpol=Policy.NXDOMAIN, tsigname="ioc2rpz-YOUR-UNIQUE-KEY-NAME", tsigalgo="hmac-sha256", tsigsecret="ioc2rpz-YOUR-UNIQUE-KEY"})

root@kitploit:~
### 示例 Infoblox 配置(导入文件)```
header-responsepolicyzone,fqdn*,zone_format*,rpz_policy,substitute_name,view,zone_type,external_primaries,grid_secondaries,priority
responsepolicyzone,phishtank.ioc2rpz,FORWARD,Nxdomain,,default,responsepolicy,srv_1/94.130.30.123/FALSE/FALSE/TRUE/ioc2rpz-YOUR-UNIQUE-KEY-NAME/ioc2rpz-YOUR-UNIQUE-KEY/HMAC-SHA256,infoblox.localdomain/False/False/False,0

DIG 示例(获取 SOA)```

dig @94.130.30.123 -y hmac-sha256:ioc2rpz-YOUR-UNIQUE-KEY-NAME:ioc2rpz-YOUR-UNIQUE-KEY phishtank.ioc2rpz SOA

kdig @94.130.30.123 -y hmac-sha256:ioc2rpz-YOUR-UNIQUE-KEY-NAME:ioc2rpz-YOUR-UNIQUE-KEY phishtank.ioc2rpz SOA +tls

root@kitploit:~
## 一些免费的威胁情报源
- [Netlab](http://data.netlab.360.com)
- [GitHub 上的 awesome-threat-intelligence 列表](https://github.com/hslatman/awesome-threat-intelligence)

您可以在 wiki 页面上找到其他 IOC 源:https://github.com/Homas/ioc2rpz/wiki/IOC-Sources。

## 更多文档

有关详细文档,请参阅 `docs/` 目录:

- [docs/architecture.md](https://github.com/homas/ioc2rpz/blob/HEAD/docs/architecture.md) — OTP 监督树、模块职责、ETS 表、数据流
- [docs/configuration.md](https://github.com/homas/ioc2rpz/blob/HEAD/docs/configuration.md) — 包含所有元组类型和选项的完整配置参考
- [docs/deployment.md](https://github.com/homas/ioc2rpz/blob/HEAD/docs/deployment.md) — 构建说明、Docker 部署、证书、监控、故障排除
- [docs/protocols.md](https://github.com/homas/ioc2rpz/blob/HEAD/docs/protocols.md) — 协议支持(UDP/TCP/DoT/DoH)、REST API、TSIG、速率限制、DNS NOTIFY

## 参考资料
- [RFC-6895 域名系统(DNS)IANA 注意事项](https://tools.ietf.org/html/rfc6895)
- [RFC-1035 域名 - 实现与规范](https://tools.ietf.org/html/rfc1035)
- [RFC-1995 DNS 中的增量区域传输](https://tools.ietf.org/html/rfc1995)
- [DNS 响应策略区域(RPZ)](https://tools.ietf.org/html/draft-ietf-dnsop-dns-rpz-00) + [vixie](https://tools.ietf.org/html/draft-vixie-dns-rpz-02)
- [RFC-2845 用于 DNS 的秘密密钥事务认证(TSIG)](https://tools.ietf.org/html/rfc2845)
- [RFC-2104 HMAC:用于消息认证的密钥散列](https://tools.ietf.org/html/rfc2104)
- [RFC-4635 HMAC SHA TSIG 算法标识符](https://tools.ietf.org/html/rfc4635)
- [RFC-5966 基于 TCP 的 DNS 传输 - 实现要求](https://tools.ietf.org/html/rfc5966)
- [RFC-1996 区域变更快速通知机制(DNS NOTIFY)](https://tools.ietf.org/html/rfc1996)
- [DNS 扩展机制(EDNS(0))](https://tools.ietf.org/html/rfc6891) + [EDNS 选项代码](https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-11)
- [RFC-7873 域名系统(DNS)Cookie](https://tools.ietf.org/html/rfc7873)
- [RFC-7858 基于传输层安全(TLS)的 DNS 规范](https://tools.ietf.org/html/rfc7858)
- [Cowboy Web 服务器](https://ninenines.eu)
- [Rebar3](https://www.rebar3.org)

<details>
<summary><strong>CEF 事件代码参考</strong>(点击展开)</summary>

| 代码 | 严重级别 | 事件 | 描述 |
|------|----------|-------|-------------|
| 101 | 低 | DNS 数据包错误 | 收到格式错误的 DNS 数据包 |
| 102 | 低 | DNS 请求错误 | 无法解析的 DNS 请求 |
| 103 | 中 | 拒绝 | DNS 请求被拒绝 |
| 104 | 中 | 未找到 TSIG 密钥 | 请求使用了未知的 TSIG 密钥 |
| 105 | 中 | TSIG MAC 错误 | TSIG 签名验证失败 |
| 106 | 中 | TSIG 时间错误 | TSIG 时间戳超出范围 |
| 107 | 中 | 其他 TSIG 错误 | 未分类的 TSIG 错误 |
| 108 | 中 | TSIG 位置错误 | TSIG 记录位于意外位置 |
| 109 | 低 | 收到 DNS 响应 | 收到意外 DNS 响应 |
| 120 | 中 | 未找到 RPZ | 请求的 RPZ 区域不存在 |
| 121 | 低 | RPZ 未就绪 | RPZ 区域仍在加载/更新中 |
| 130 | 低 | RPZ 传输错误 | 区域传输期间出错(仅限 RPZ 传输) |
| 131 | 低 | RPZ 传输已关闭 | 传输期间远程端关闭了连接(仅限 RPZ 传输) |
| 140 | 高 | REST 基本认证失败 | REST API 基本认证失败 |
| 141 | 高 | REST 认证失败 | REST API 授权失败 |
| 145 | 高 | REST 管理被拒绝 | REST 管理请求被 ACL 拒绝 |
| 146 | 高 | 管理请求失败 | 管理请求处理失败 |
| 147 | 高 | 不支持的请求 | 未知的 REST API 端点 |
| 148 | 高 | 未找到区域 | REST API 引用了不存在的区域 |
| 150 | 低 | 已执行 Shell 命令 | 已执行 Shell 源命令(信息) |
| 151 | 高 | Shell 命令被拒绝 | Shell 源命令被拒绝(安全) |
| 201 | 低 | RPZ 传输成功 | 区域传输完成 |
| 202 | 低 | DNS 查询 | 已处理标准 DNS 查询 |
| 221 | 低 | DNS 通知 | 已向辅助服务器发送通知 |
| 222 | 中 | DNS 通知错误 | 发送通知失败 |
| 230 | 高 | 管理请求 | 已执行管理操作 |
| 301 | 高 | 管理请求被拒绝 | DNS 管理命令被拒绝 |
| 429 | 高 | 请求过多 | 超出速率限制 |
| 501 | 高 | 疑似 DDoS | 检测到 CVE-2004-0789 模式 |

</details>

# 您想支持这个项目吗?
您可以通过 [GitHub Sponsor](https://github.com/sponsors/Homas)(定期付款)支持 ioc2rpz™ 项目和 ioc2rpz™ 社区(https://ioc2rpz.net)。如需一次性捐赠,您可以使用 [PayPal](https://paypal.me/ioc2rpz) 或 Zelle(我们的邮箱:zelle [at] ioc2rpz [.] net)。

# 支持者
特别鸣谢在 [GitHub Sponsor](https://github.com/sponsors/Homas) 上支持我项目的 **craSH** 和 **rrbone**。

# 联系我们
您可以通过电子邮件 feedback(at)ioc2rpz[.]net 或通过 [Telegram](https://t.me/ioc2rpz) 联系我们。

# 许可证
版权所有 2017 - 2025 Vadim Pavlov ioc2rpz[at]gmail[.]com

根据 Apache License 2.0 版(以下简称“许可证”)获得许可;除非遵守许可证,否则您不得使用此文件。
您可以在以下位置获取许可证副本:  

    http://www.apache.org/licenses/LICENSE-2.0  

除非适用法律要求或书面同意,否则按许可证分发的软件按“原样”分发,不附带任何明示或暗示的保证或条件。请参阅许可证,了解具体的权限和限制。