
ioc2rpz is a place where threat intelligence meets DNS.
ioc2rpz™: Решение для безопасности DNS — ioc2rpz™ — это мощный DNS-сервер, который преобразует индикаторы угроз в действенные фиды зон политики ответа (RPZ). Он автоматизирует процесс обновления, обеспечивая защиту вашей сети от новейших угроз, включая вредоносные домены и IP-адреса. Преобразуя фиды IOC в RPZ, ioc2rpz™ выступает в качестве критически важного связующего звена между информацией об угрозах и безопасностью DNS, совместимого с DNS-серверами, поддерживающими RPZ, такими как ISC Bind или PowerDNS.
DNS является управляющей плоскостью Интернета. Обычно DNS используется во благо, но:

ISC Bind является фактическим стандартом сервера имён. С введением зон политики ответа (Response Policy Zones) в ISC BIND 9.8 стало простой задачей отслеживать и сдерживать вредоносное ПО на уровне DNS. RPZ поддерживается в рекурсоре PowerDNS версии 4.0.0 и выше. Knot DNS также частично поддерживает RPZ.
По сравнению с традиционными решениями сетевой защиты, DNS-сервер может обрабатывать миллионы индикаторов без снижения производительности, однако ранее не существовало автоматизированного и эффективного способа поддержания зон политики ответа на первичных DNS-серверах.
Обычно индикаторы компрометации распространяются в виде открытого текста, но в разных форматах, и лишь немногие поставщики IOC предоставляют их через RPZ.
ioc2rpz™ — это пользовательский DNS-сервер, который автоматически преобразует индикаторы (например, вредоносные FQDN, IP-адреса) из различных источников в фиды RPZ и автоматически поддерживает/обновляет их. Фиды могут распространяться на любые открытые и/или коммерческие DNS-серверы, поддерживающие RPZ, например ISC Bind, PowerDNS. Вы можете запустить собственный DNS-сервер с фильтрацией RPZ на роутере, настольном компьютере, сервере и даже Raspberry Pi. Единственным ограничением является системная память.
С ioc2rpz™ вы можете определять собственные фиды, действия и предотвращать нежелательные взаимодействия.
ioc2rpz™ преобразует фиды IOC в зоны политики ответа (RPZ). Вы можете смешивать фиды для генерации одной RPZ или нескольких RPZ. Доверенные домены и IP-адреса можно заносить в белый список. ioc2rpz™ поддерживает истечение срока действия индикаторов и соответствующим образом перестраивает зоны.
Текущий выпуск поддерживает: локальные файлы, файлы/запросы через http/https/ftp и скрипты оболочки для доступа к другим типам ресурсов. Вы можете использовать любой формат файла, если вы можете написать 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]
Key modules:
| Module | Ответственность |
|--------|----------------|
| `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™ с любым DNS-сервером, поддерживающим зоны политики ответов, например, последние версии ISC BIND, PowerDNS и любые коммерческие DNS-серверы на их основе (например, Infoblox, Blue Cat, Efficient IP). Пример конфигурационного файла bind (named.conf) находится в папке cfg.
<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™
[ioc2rpz.gui](https://github.com/Homas/ioc2rpz.gui) — это веб-интерфейс управления, разрабатываемый как отдельный проект. Он не требуется для работы 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), устанавливают бит TC (усечение) согласно RFC 1035 §4.2.1, что побуждает клиентов повторять запрос через TCP. Команды управления не поддерживаются через UDP.```bash
dig @127.0.0.1 zone.ioc2rpz SOA -y hmac-sha256:keyname:base64key
TCP обрабатывает передачу зон (AXFR/IXFR), SOA-запросы и команды управления. Пул из 5 предварительно запущенных accept workers обрабатывает входящие соединения.```bash
dig @127.0.0.1 zone.ioc2rpz AXFR +tcp -y hmac-sha256:keyname:base64key
dig @127.0.0.1 zone.ioc2rpz IXFR=12345 +tcp -y hmac-sha256:keyname:base64key
### DNS поверх TLS / DoT (Порт 853)
ioc2rpz™ поддерживает распространение RPZ через DoT. TLS-слушатель автоматически запускается на порту 853, когда в конфигурации присутствует запись `cert`. 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)
- Сертификаты автоматически обновляются при замене файлов на диске (задержка до ~2 минут из-за кэширования Erlang SSL)
Для настройки сертификатов см. [Настройка сертификатов](#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
DoH предоставляет разрешение DNS через HTTPS через конечную точку /dns-query. Поддерживаемые методы:
?dns=Content-Type: application/dns-message (макс. 4096 байт; более крупные полезные нагрузки получают HTTP 413)Ответы используют Content-Type: application/dns-message. DoH передает полное DNS-сообщение в формате wire и обрабатывается по тому же пути, что и Do53/DoT, поэтому он наследует ту же аутентификацию TSIG; передачи зон (AXFR/IXFR) остаются только через TCP и не обслуживаются через DoH.```bash
curl -H "Accept: application/dns-message"
"https://127.0.0.1:443/dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB" -k
curl -X POST -H "Content-Type: application/dns-message"
--data-binary @dns_query.bin "https://127.0.0.1:443/dns-query" -k
### Ограничение скорости
DNS-запросы ограничиваются по скорости с помощью интеллектуального (гибридного) ключа, чтобы легитимные клиенты с несколькими зонами не наказывались, а злоупотребление вариациями имени запроса блокировалось:
- **Предоставленная зона + поддерживаемый QTYPE** (`SOA`/`AXFR`/`IXFR`, класс `IN`) и **распознанные команды управления** (класс `CHAOS`/`TXT`) отслеживаются по `{client_IP, query_name, query_type}` — таким образом, вторичный сервер, опрашивающий/передающий несколько зон (например, `rpz1`, `rpz2`, `rpz3`) плюс управление с одного IP, учитывается независимо для каждой зоны+типа.
- **Всё остальное** (неизвестная/непредоставленная зона, неподдерживаемый тип запроса, неправильный класс или нераспознанное имя управления) агрегируется по `{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™ отправляет DNS-сообщения NOTIFY ([RFC 1996](https://tools.ietf.org/html/rfc1996)) по UDP на IP-адреса, настроенные в RPZ `NotifyList`. Это побуждает вторичные DNS-серверы проверить серийный номер SOA зоны и инициировать передачу, если серийный номер изменился.```erlang
%% NotifyList in RPZ config — last field before whitelists
{rpz, {"zone.ioc2rpz", ..., ["source1"], ["10.0.0.1", "10.0.0.2"], []}}.
Самый простой способ развернуть сервис — использовать docker-контейнеры из Docker Hub. Инструкция по развертыванию на Docker доступна в вики ioc2rpz™.
ioc2rpz™ доступен на Docker Hub. Просто найдите ioc2rpz™. Предварительные требования:
где /home/ioc2rpz/cfg, /home/ioc2rpz/db — это каталоги на хостовой системе.
Вы можете передать имя пользовательского конфигурационного файла через параметр ``-e``. Например: ``-e CONF=./cfg/ioc2rpz2.conf``
## Переменные окружения
Следующие переменные окружения используются ioc2rpz™, в основном для развертываний в Docker. Они определены в `config/sys.config.src` и `config/vm.args`.
| Переменная | По умолчанию | Описание |
|----------|---------|-------------|
| `IPv4` | — | IPv4 адрес привязки |
| `IPv6` | — | IPv6 адрес привязки |
| `CONF` | — | Путь к конфигурационному файлу (например, `./cfg/ioc2rpz.conf`) |
| `DB` | `/opt/ioc2rpz/db` | Каталог базы данных для сохранения ETS |
| `CD` | `/opt/ioc2rpz` | Рабочий каталог |
| `NODE_NAME` | `ioc2rpz` | Короткое имя узла Erlang |
| `IO2Cookie` | `ioc2rpz` | Cookie распределённой Erlang-системы |
Передавайте переменные окружения в Docker с помощью `-e`:```bash
docker run -d --name ioc2rpz -e CONF=./cfg/custom.conf -e NODE_NAME=mynode ...
Вы можете развернуть ioc2rpz™ и ioc2rpz.gui с помощью docker compose. Канонический файл docker-compose.yml можно найти в репозитории ioc2rpz.dc.
Ниже приведен пример docker-compose.yml, показывающий ioc2rpz с веб-интерфейсом и sidecar-контейнером certbot от Let's Encrypt:```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:
Обновите ваш `ioc2rpz.conf`, чтобы указать путь к смонтированному сертификату:```erlang
{cert, {"ssl/live/ns1.rpz-proxy.com/fullchain.pem", "ssl/live/ns1.rpz-proxy.com/privkey.pem", ""}}.
Вы можете запустить ioc2rpz™ и ioc2rpz.gui на AWS. Для относительно небольших развертываний (несколько сотен тысяч индикаторов) даже бесплатного уровня достаточно. Видео ниже показывает, как настроить ioc2rpz™ и ioc2rpz.gui на AWS с помощью ECS.
Сертификаты TLS требуются для DoT (порт 853), REST API (порт 8443) и DoH. Один и тот же сертификат используется для всех TLS-сервисов. Подробнее см. в docs/deployment.md.
openssl req -x509 -newkey rsa:2048 -keyout cfg/ioc2rpz_dot.key
-out cfg/ioc2rpz_dot.crt -days 365 -nodes -subj "/CN=ioc2rpz"
### 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
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"
Сертификаты также явно перезагружаются во время перезагрузки конфигурации (`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", ""}}.
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.
Минимальный cfg/ioc2rpz.conf с одним ключом TSIG, одним файловым источником и одной зоной RPZ:```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"],[],[]}}.
Смотрите [docs/configuration.md](https://github.com/homas/ioc2rpz/blob/HEAD/docs/configuration.md) для авторитетного описания полей (структура кортежей source/RPZ, таймеры SOA, группы ключей, сертификаты и т.д.). Чтобы включить DoT (порт 853), DoH и HTTPS REST API, добавьте запись `{cert,{...}}` — см. [Настройка сертификатов](#certificate-setup).
### Оболочка для разработки (только для разработки/тестирования)
Следующие команды предназначены для локальной разработки и тестирования — не для использования в production:```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).
## Управление ioc2rpz™
### через DNS
ioc2rpz™ поддерживает управление через DNS/TCP или DoT. Рекомендуется использовать DoT или REST API через DNS/TCP. Текущая версия 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
ioc2rpz-reload-cfg, RR Class CHAOS, RR Type TXTioc2rpz-update-tkeys, RR Class CHAOS, RR Type TXTioc2rpz-update-all-rpz, RR Class CHAOS, RR Type TXTzone_name, RR Class CHAOS, RR Type TXT. Например, полное обновление dga.ioc2rpz можно вызвать следующим образом:```
dig +tcp -y dnsmkey_1:ayVnL+h2QKMszRVohrngagcEuIpN3RkecXKdwSa5WsHD5N4Y5R3NUMGM W8sIGv36gPkAtWtgarqKzN9tmHqEnA== @127.0.0.1 dga.ioc2rpz TXT -c CHAOS- Остановить ioc2rpz™. Имя RR ``ioc2rpz-terminate``, Класс RR ``CHAOS``, Тип RR ``TXT``
- Запросить образец зоны. Имя RR ``sample-zone.ioc2rpz``, Класс RR ``IN``, Тип RR ``AXFR``
### через REST
REST API (порт 8443/tcp) является предпочтительным интерфейсом управления. По соображениям безопасности весь управляющий трафик должен быть зашифрован, и REST API не запускается при отсутствии SSL-сертификата. Все конечные точки принимают как GET, так и POST методы.
Для аутентификации запросов используется базовая HTTP-аутентификация. Для аутентификации запросов используются управляющие ключи TSIG. Имя ключа TSIG используется как имя пользователя HTTP, а ключ TSIG — как пароль. Доступ к REST API ограничен ACL, заданным в записи `srv`.
Сегмент версии API поддерживает как `v1`, так и `v1.0` (например, `/api/v1/stats/serv` или `/api/v1.0/stats/serv`).
REST API поддерживает вывод в формате JSON (по умолчанию) и обычного текста на основе заголовка `Accept`:
- `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
#### Параметры пути
| Параметр | Описание |
|-----------|-------------|
| `: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
{
"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
```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
```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
Успех: `{"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
Success: `{"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
Успех: `{"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
Успех: `{"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
Success: {"status":"ok","msg":"All sources will loaded to the hot cache"}
/api/v1/feed/:rpz_name — Получить индикаторы из RPZ-фида
Параметр запроса: ?type=fqdn|ip|both (по умолчанию: both)```bash
curl -u "keyname:base64key==" -k "https://127.0.0.1:8443/api/v1/feed/malware.ioc2rpz?type=fqdn"
Успех:```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 — Проверяет, заблокирован ли индикатор каким-либо фидом RPZ
Параметр запроса: ?tkey=keyname — ограничить поиск зонами, доступными по этому ключу (опционально)```bash
curl -u "keyname:base64key==" -k "https://127.0.0.1:8443/api/v1/ioc/baddomain.com?tkey=dnsproxykey_1"
Успех:```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"]
}
]
}
]
}
Error: {"status":"error", "ioc": "nonexistent.com"}
Поле sources (дополнительное) перечисляет имена источников, вносящих вклад, для каждой ленты, когда отслеживание источников включено; оно равно null, когда отслеживание отключено или авторство неизвестно. См. IOC Source Attribution для настройки и семантики.
Любой нераспознанный путь возвращает HTTP 200 с:```json {"status":"error","msg":"Unsupported request"}
## Мониторинг и проверки здоровья
### 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 %% 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).
### Проверки состояния 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, поэтому конфигурация должна соответствовать синтаксису Erlang. Сервер проверяет записи конфигурации при загрузке/перезагрузке: кодирование ключа TSIG, существование файла сертификата, компиляцию регулярных выражений и синтаксис URL. Неверные записи регистрируются и пропускаются. Полную справку по конфигурации см. в docs/configuration.md.
ioc2rpz™ поддерживает следующие параметры конфигурации:
Запись srv используется для определения значений по умолчанию сервера. Она состоит из:
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}}.
Форма из 4 полей остается действительной и по умолчанию устанавливает `TrackSources` в `off`.
### **cert** запись
Запись **cert** используется для определения сертификата и закрытого ключа для DNS over TLS, REST API и DoH-коммуникаций. По вопросам генерации и управления сертификатами см. [Настройка сертификатов](#certificate-setup).
Она состоит из:
- путь к файлу, содержащему сертификат;
- путь к файлу, содержащему закрытый ключ в формате PEM;
- путь к файлу с PEM-кодированными сертификатами ЦС.
Пример записи **cert**:```
{cert,{"cfg/cert.pem", "cfg/key.pem", "cfg/cacerts.pem"}}.
include запись позволяет разделить конфигурацию ioc2rpz™ на несколько файлов.
Пример include записи:``` {include,"cfg/tkeys.include.cfg"}.
### **key** запись
TSIG-ключи используются для аутентификации и авторизации. Рекомендуется использовать разные TSIG-ключи для управления ioc2rpz™ и передачи зон.
Запись **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
dnssec-keygen -a HMAC-MD5 -b 512 -n USER tsig-key
dnssec-keygen -a HMAC-SHA256 -b 256 -n USER tsig-key
dnssec-keygen -a HMAC-SHA512 -b 512 -n USER tsig-key
Пожалуйста, обратитесь к документации "dnssec-keygen" за подробностями. Ключи могут быть назначены группам для групповой авторизации при управлении доступом к зонам RPZ.
### **key_group** запись
Группы ключей обеспечивают групповую авторизацию для передачи и управления зонами. Вместо перечисления отдельных ключей в записях `rpz` или `srv` вы можете назначить ключи именованным группам и ссылаться на группу.
Существует два способа назначения ключей группам:
1. Встроенно через необязательное 4-е поле записи `key`: `{key, {Name, Alg, Secret, [Groups]}}`
2. Явно через запись `key_group` (показано ниже)```erlang
{key_group, {GroupName, [KeyName1, KeyName2, ...]}}.
| Field | Type | Description |
|---|---|---|
| GroupName | string | Имя группы (например, "customers") |
| Keys | list of strings | Список имен ключей TSIG, принадлежащих этой группе |
Пример записей key_group:```erlang {key_group, {"customers", ["dnsproxykey_1", "dnsproxykey_2"]}}. {key_group, {"public", ["dnsproxykey_3"]}}.
Группы упоминаются в записях `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"], [], []}}.
Белые списки используются для предотвращения возможных ошибок и блокировки доверенных доменов и IP-адресов. IOC из белого списка удаляются из зон политики ответов. ioc2rpz™ проверяет только точное совпадение, поэтому он не будет разделять или отбрасывать сеть, если IP-адрес из белого списка входит в заблокированную подсеть, и наоборот. Белый список — это текстовый файл или поток текстовых данных. Индикаторы должны быть разделены символами новой строки (/n, /r или обоими /n/r). Белые списки должны содержать действительные FQDN и/или IP-адреса. ioc2rpz™ поддерживает неограниченное количество индикаторов.
whitelists запись состоит из:
""), будет использоваться REGEX по умолчанию ("^([A-Za-z0-9][A-Za-z0-9\-\._]+)[^A-Za-z0-9\-\._]*.*$"). none используется, если REGEX не требуется (источник уже предоставляет данные в требуемом формате).Пример whitelist записи:``` {whitelist,{"whitelist_1","file:cfg/whitelist1.txt",none}}.
### **source** запись
Источник — это фид индикаторов компрометации. Поддерживаются FQDN, IPv4 и IPv6-адреса. Источник представляет собой текстовый файл или фид текстовых данных. Индикаторы должны разделяться символами новой строки/возврата каретки (`/n`, `/r` или оба `/r/n`). ioc2rpz™ поддерживает неограниченное количество индикаторов.
Запись **source** состоит из:
- имя источника;
- путь источника для полной передачи зоны (AXFR). Поддерживаются URL (http/https/ftp), локальные файлы и сценарии. Префикс **file:** используется для локальных файлов. Префикс **shell:** используется для выполнения локального скрипта/команды на хосте/контейнере, который должен вывести индикаторы и опциональную дату истечения в STDOUT;
- путь источника для инкрементальной передачи зоны (IXFR). Пути AXFR,IXFR поддерживают ключевые слова для сокращения URL и добавления временных меток обновления зоны:
- **[:AXFR:]** — полный путь AXFR. Может использоваться только в путях IXFR;
- **[:FTimestamp:]** — временная метка последнего обновления источника (например, 1507946281);
- **[:ToTimestamp:]** — текущая временная метка;
- REGEX, используемый для извлечения индикаторов и времени их истечения. Первое совпадение — индикатор, второе — время истечения. Время истечения — опциональный параметр. Регулярное выражение должно быть заключено в двойные кавычки. Если указать пустой REGEX (`""`), будет использоваться стандартный REGEX (`"^([A-Za-z0-9][A-Za-z0-9\-\._]+)[^A-Za-z0-9\-\._]*.*$"`). `none` используется, если REGEX не требуется (источник уже предоставляет данные в нужном формате).
Опциональные параметры (должны использоваться все или ни один):
- UserID (используется внутренне).
- Максимальное количество IoC.
- Время горячего кэша для полного обновления источника (в секундах).
- Время горячего кэша для инкрементального обновления источника (в секундах).
Загрузка источника по HTTPS проверяет TLS-сертификат удалённого сервера. Источники с недействительными или самоподписанными сертификатами не будут загружены. Для самоподписанных сертификатов используйте источник `shell:` с `curl --insecure`.
**Ограничения локальных файлов:** пути `file:`, содержащие `..` (переход в родительский каталог), отклоняются по соображениям безопасности; используйте путь без `..` (в рабочем каталоге/каталоге данных).
**Ограничения команд shell:** исполняемый файл каждого элемента конвейера должен быть абсолютным путём (например, `/usr/bin/curl`) или утилитой безопасной обработки текста с именем без пути (`sort`, `uniq`, `grep`, `sed`, `awk`, `gawk` и т.д.); деструктивные команды и оболочки (`rm`, `bash`, `sh` и т.д.) блокируются, а подстановка команд (`$(...)`, обратные кавычки) и перенаправление вывода (`>`, `>>`) отклоняются. Отклонённые команды не выполняются и регистрируются через CEF событие 151 (выполненные команды — через 150). Полный набор правил см. в [docs/configuration.md](https://github.com/homas/ioc2rpz/blob/HEAD/docs/configuration.md#shell-command-restrictions).
Если источник возвращает менее 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}}.
Source shell: используется для расширения возможностей подключения ioc2rpz™, которые по умолчанию несколько ограничены. Контейнер ioc2rpz™ включает dig, grep, awk и python. Например, вы можете смешивать различные RPZ-каналы или получать данные из базы данных.
Ограничения команд оболочки: Все исполняемые файлы должны использовать абсолютные пути (например, /usr/bin/curl, а не curl). Деструктивные команды (rm, bash, sh и т.д.) заблокированы. Подстановка команд ($(...), обратные кавычки) и перенаправление вывода (>, >>) отклоняются. Полные сведения см. в docs/configuration.md.
Безопасность локальных файлов: Пути к файлам, содержащие .. (переход в родительский каталог), отклоняются по соображениям безопасности.
Термин RPZ определяет зону политики ответов.
rpz запись состоит из:
true или false. true означает, что RPZ должна кешироваться, false — не кешируется, прямые зоны загружаются, и RPZ создается по запросу AXFR. «Прямые» зоны не поддерживают инкрементальную передачу зон. Если RPZ-канал не кешируется, он всё равно временно сохраняется в горячем кеше. Если запрос от клиента превышает время ожидания, мы сможем ответить в следующий раз. Для определения времени жизни кеша используется время AXFR;true или false. Определяет, следует ли генерировать правила с подстановочными знаками;mixed, fqdn, ip. Используется для оптимизации.Несколько локальных действий можно объединить в список: [{"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}}.
### IOC Source Attribution
Лента RPZ формируется путем объединения индикаторов из нескольких источников. Атрибуция источника позволяет API поиска IOC сообщать, **какой источник (или источники) внутри ленты** предоставил индикатор — это полезно для обработки сообщений о ложных срабатываниях. Отслеживание **по умолчанию отключено** и настраивается для каждой ленты с помощью опциональной глобальной настройки на уровне сервера.
**Конфигурация**
- Для каждой ленты: опциональный завершающий (16-й) элемент `TrackSources` кортежа `{rpz,{...}}` — `auto | true | false`.
- Глобальное значение по умолчанию для сервера: опциональный завершающий (5-й) элемент `TrackSources` кортежа `{srv,{...}}` — `off | auto | on` (по умолчанию `off`).
Оба параметра являются опциональными и обратно совместимыми: существующие конфигурационные файлы (15-полей `rpz`, 4-поля `srv`) загружаются без изменений и ведут себя как `off`.
**Приоритет разрешения** — фактическое состояние для ленты определяется следующим образом:
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"]
}
Single-source feed: "sources": ["sample_fqdn"]. Tracking disabled/unknown: "sources": null.
Развертывание (отключено по умолчанию)
Обновление бинарного файла ничего не меняет — никакого отслеживания, перестроения зон или изменений API — до тех пор, пока не будет установлено значение track_sources. Фиды управляются через GUI; GUI/сайт сообщества будет записывать эти необязательные значения конфигурации и отображать sources в одном из будущих обновлений. Включение отслеживания для кэшированного фида запускает одноразовое перестроение AXFR для заполнения масок источников.
Ограничения
cache = "true"), поскольку API-запрос читает таблицу кэша IXFR.{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"],[],[]}}.
</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`` (числовое значение, в секундах) - TTL по умолчанию для DNS-записей/правил RPZ.
- ``DefConf`` (строка) - файл конфигурации по умолчанию;
- ``DefDB`` (строка) - путь к базе данных по умолчанию;
- ``logTS`` - если определён, в сообщения журнала добавляется метка времени;
- ``debug`` - если определён, выводятся отладочные сообщения;
- ``TLSVersion`` ('tlsv1.2-1.3') - поддерживаемые версии TLS для DoT и REST API;
Параметры оптимизации:
- ``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) - максимальное количество DNS-запросов на IP за окно ограничения скорости;
- ``ShellMaxRespSize`` (числовое значение, по умолчанию 2 ГБ) - максимальный размер ответа для источников команд оболочки;
- ``SourcePullTimeout`` (числовое значение, в миллисекундах, по умолчанию 300000) - тайм-аут загрузки источника (5 минут);
## Как обновляются кэши AXFR (полный) и IXFR (инкрементальный)
- Кэш AXFR всегда содержит предварительно построенные зоны без записей SOA/NS/TSIG. «Предварительно построенные» означает, что все записи разделены на пакеты, а метки сокращены/упакованы.
- Если сервер получает запрос AXFR, он извлекает пакеты из кэша AXFR, добавляет записи SOA/NS и, при необходимости, TSIG.
- Обновление зон AXFR следует рассматривать как процедуру очистки, которая должна выполняться периодически. Просто для уверенности, что между источниками и кэшем нет рассинхронизации.
- Для больших зон обновления AXFR следует назначать редко, чтобы минимизировать влияние на производительность сервера и объём передаваемых данных всем клиентам.
- Все изменения, по возможности, должны выполняться через инкрементальные обновления зон. В этом случае кэш AXFR будет перестроен только в том случае, если зона была обновлена.
- [TODO] Из-за оптимизации только последний пакет будет перестроен для новых IOC, а соответствующие и согласованные пакеты — для истёкших IOC.
- Кэш IXFR содержит только IOC и даты истечения. [TODO] и идентификаторы пакетов (чтобы сделать возможным быстрое перестроение зоны).
- Запись RPZ содержит текущий серийный номер зоны и Serial_IXFR. Serial_IXFR служит минимальным инкрементальным серийным номером зоны, доступным для инкрементальной передачи зоны.
- Кэш IXFR очищается после полного обновления зоны (AXFR). Serial_IXFR = Serial. Клиенты в любом случае получат полное обновление зоны, поэтому важно выполнять передачу зоны AXFR нечасто.
- При обновлении кэша IXFR кэш AXFR должен быть перестроен.
- Если зона не поддерживает обновления IXFR, она не сохраняется в таблице IXFR.
- Живые зоны не кэшируются в кэшах AXFR, IXFR, но источники (IOC) могут кэшироваться в горячем кэше.
## Горячий кэш
Все IOC, правила, пакеты, включая живые RPZ, хранятся в горячем кэше. Параметры предварительной компиляции ``HotCacheTime``, ``HotCacheTimeIXFR`` определяют время хранения.
## Как попробовать ioc2rpz™ (или образцы и бесплатные RPZ-каналы, размещённые ioc2rpz™)
### Отказ от ответственности
Автор не несёт ответственности за любые ошибки или упущения в содержании этих RPZ-каналов. Каналы предоставляются «как есть» без каких-либо гарантий полноты, точности, полезности или своевременности и предназначены только для демонстрации технологии ioc2rpz™. Распространение службы RPZ-каналов может быть прервано или остановлено без предварительного уведомления. Автор не несёт ответственности за любые прямые или косвенные убытки, вызванные использованием этой службы.
### RPZ-каналы
Вы можете протестировать технологию ioc2rpz™, зарегистрировавшись в [сообществе ioc2rpz™](https://ioc2rpz.net) со следующими каналами:
- [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: supervisor:count_children(ioc2rpz_tls_sup_v6). Проверьте, что порт 853 не заблокирован брандмауэром. |
| Ошибка передачи зоны (несоответствие TSIG) | Проверьте, что имя ключа и секрет совпадают на клиенте и сервере. Ищите события CEF 104/105 в логах. |
| Ошибки загрузки источника | Проверьте сетевое подключение. Ищите Error downloading feed в логах. Сервер выполняет 3 повторные попытки с задержкой 3 с. Для источников HTTPS убедитесь в наличии действительного TLS-сертификата. |
| Высокое использование памяти | Проверьте размеры таблиц ETS в оболочке Erlang. rate_limits и rpz_hotcache_table периодически очищаются. Рассмотрите возможность уменьшения ?HotCacheTime. |
TrackSources — атрибуция источника для каждого канала: auto | true | false. Если указано, переопределяет глобальное значение по умолчанию для сервера. Если опущено (форма из 15 полей), канал наследует значение сервера по умолчанию (#srv 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-запись |
rpzMaster("94.130.30.123", "phishtank.ioc2rpz", {defpol=Policy.NXDOMAIN, tsigname="ioc2rpz-YOUR-UNIQUE-KEY-NAME", tsigalgo="hmac-sha256", tsigsecret="ioc2rpz-YOUR-UNIQUE-KEY"})
### Пример конфигурации 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 @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
## Некоторые бесплатные каналы threat intelligence
- [Netlab](http://data.netlab.360.com)
- [awesome-threat-intelligence list on GitHub](https://github.com/hslatman/awesome-threat-intelligence)
Другие 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 Domain Name System (DNS) IANA Considerations](https://tools.ietf.org/html/rfc6895)
- [RFC-1035 Domain Names - Implementation and Specification](https://tools.ietf.org/html/rfc1035)
- [RFC-1995 Incremental Zone Transfer in DNS](https://tools.ietf.org/html/rfc1995)
- [DNS Response Policy Zones (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 Secret Key Transaction Authentication for DNS (TSIG)](https://tools.ietf.org/html/rfc2845)
- [RFC-2104 HMAC: Keyed-Hashing for Message Authentication](https://tools.ietf.org/html/rfc2104)
- [RFC-4635 HMAC SHA TSIG Algorithm Identifiers](https://tools.ietf.org/html/rfc4635)
- [RFC-5966 DNS Transport over TCP - Implementation Requirements](https://tools.ietf.org/html/rfc5966)
- [RFC-1996 A Mechanism for Prompt Notification of Zone Changes (DNS NOTIFY)](https://tools.ietf.org/html/rfc1996)
- [Extension Mechanisms for DNS (EDNS(0))](https://tools.ietf.org/html/rfc6891) + [EDNS Option Codes](https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-11)
- [RFC-7873 Domain Name System (DNS) Cookies](https://tools.ietf.org/html/rfc7873)
- [RFC-7858 Specification for DNS over Transport Layer Security (TLS)](https://tools.ietf.org/html/rfc7858)
- [Cowboy Web Server](https://ninenines.eu)
- [Rebar3](https://www.rebar3.org)
<details>
<summary><strong>Справочник кодов событий CEF</strong> (нажмите, чтобы раскрыть)</summary>
| Код | Уровень | Событие | Описание |
|------|----------|-------|-------------|
| 101 | Низкий | Bad DNS packet | Получен некорректный DNS-пакет |
| 102 | Низкий | Bad DNS request | Неподдающийся разбору DNS-запрос |
| 103 | Средний | Refused | DNS-запрос отклонён |
| 104 | Средний | TSIG key not found | В запросе использован неизвестный ключ TSIG |
| 105 | Средний | TSIG Bad MAC | Проверка подписи TSIG не удалась |
| 106 | Средний | TSIG Bad time | Временная метка TSIG вышла за пределы допустимого |
| 107 | Средний | Other TSIG error | Не классифицированная ошибка TSIG |
| 108 | Средний | Wrong TSIG position | Запись TSIG в неожиданной позиции |
| 109 | Низкий | Received DNS response | Получен неожиданный DNS-ответ |
| 120 | Средний | RPZ not found | Запрошенная зона RPZ не существует |
| 121 | Низкий | RPZ not ready | Зона RPZ всё ещё загружается/обновляется |
| 130 | Низкий | RPZ transfer error | Ошибка во время передачи зоны (только передача RPZ) |
| 131 | Низкий | RPZ transfer closed | Удалённая сторона закрыла соединение во время передачи (только передача RPZ) |
| 140 | Высокий | REST Basic auth failed | Базовая аутентификация REST API не удалась |
| 141 | Высокий | REST Auth failed | Авторизация REST API не удалась |
| 145 | Высокий | REST MGMT denied | Запрос управления REST отклонён ACL |
| 146 | Высокий | MGMT request failed | Обработка запроса управления не удалась |
| 147 | Высокий | Unsupported request | Неизвестная конечная точка REST API |
| 148 | Высокий | Zone not found | REST API ссылался на несуществующую зону |
| 150 | Низкий | Shell command executed | Выполнена команда от shell-источника (информация) |
| 151 | Высокий | Shell command rejected | Команда от shell-источника отклонена (безопасность) |
| 201 | Низкий | RPZ transfer success | Передача зоны завершена |
| 202 | Низкий | DNS Query | Обработан стандартный DNS-запрос |
| 221 | Низкий | DNS Notify | Уведомление отправлено на вторичный сервер |
| 222 | Средний | DNS Notify error | Не удалось отправить уведомление |
| 230 | Высокий | MGMT request | Выполнена операция управления |
| 301 | Высокий | MGMT request denied | Команда управления DNS отклонена |
| 429 | Высокий | Too many requests | Превышено ограничение частоты запросов |
| 501 | Высокий | Possible DDoS | Обнаружен шаблон CVE-2004-0789 |
</details>
# Хотите поддержать проект?
Вы можете поддержать проект ioc2rpz™ и сообщество ioc2rpz™ (https://ioc2rpz.net) через [GitHub Sponsor](https://github.com/sponsors/Homas) (регулярные платежи). Для разового пожертвования вы можете использовать [PayPal](https://paypal.me/ioc2rpz) или Zelle (наш email: zelle [at] ioc2rpz [.] net).
# Поддержавшие
Особая благодарность **craSH** и **rrbone**, которые поддерживают мои проекты на [GitHub Sponsor](https://github.com/sponsors/Homas).
# Свяжитесь с нами
Вы можете связаться с нами по email: feedback(at)ioc2rpz[.]net или в [Telegram](https://t.me/ioc2rpz).
# Лицензия
Copyright 2017 - 2025 Вадим Павлов ioc2rpz[at]gmail[.]com
Лицензировано на условиях Apache License, Version 2.0 ("Лицензия"); вы не можете использовать этот файл иначе как в соответствии с Лицензией.
Копию Лицензии можно получить по адресу:
http://www.apache.org/licenses/LICENSE-2.0
Если это не требуется применимым законодательством или не согласовано в письменной форме, программное обеспечение, распространяемое по Лицензии, распространяется на условиях "AS IS", БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ ИЛИ УСЛОВИЙ, явных или подразумеваемых. См. Лицензию для получения подробной информации о разрешениях и ограничениях.