Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
ioc2rpz — ioc2rpz es un lugar donde la inteligencia de amenazas se encuentra con el DNS. | Kitploit
Herramientas/GitHubGitHub/homas/ioc2rpz
Herramientas DefensivasGestión de Indicadores de Compromiso (IOC)Seguridad de RedesAnálisis de MalwareInteligencia de AmenazasDetección de IntrusionesFuzzing de DNSRespuesta a IncidentesAnálisis de DNS
GitHubhomas/ioc2rpz

ioc2rpz

ioc2rpz es un lugar donde la inteligencia de amenazas se encuentra con el DNS.

116216hace 2 mesesRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Ver Repositorio
Compartir

ioc2rpz™ hace que tu inteligencia de amenazas sea accionable

License Erlang/OTP Docker Hub

Tabla de contenidos

  • Resumen breve
  • Descripción general
  • ioc2rpz™ es el lugar donde la inteligencia de amenazas se encuentra con el DNS
  • Descripción general de la arquitectura
  • Cómo usar ioc2rpz™
  • Interfaz web de ioc2rpz™
  • Soporte de protocolos
    • Resumen de puertos
    • UDP (puerto 53)
    • TCP (puerto 53)
    • DNS sobre TLS / DoT (puerto 853)
    • DNS sobre HTTPS / DoH (puerto 443/8443)
    • Limitación de velocidad
    • DNS NOTIFY
  • ioc2rpz™ vs ISC BIND vs otros DNS
Descargar herramienta
  • Instalación
  • Contenedor Docker
  • Variables de entorno
  • Docker Compose
  • ioc2rpz™ en AWS
  • Configuración de certificados
  • Compilación desde el código fuente
  • Gestión de ioc2rpz™
    • vía DNS
    • vía REST
  • Monitorización y comprobaciones de estado
  • Solución de problemas
  • Archivo de configuración
  • Valores de configuración predefinidos
  • Cómo se actualizan las cachés AXFR y IXFR
  • Caché caliente
  • Cómo probar ioc2rpz™
  • Algunos feeds gratuitos de inteligencia de amenazas
  • Documentación adicional
  • Referencias
  • Apoyo / Colaboradores
  • Contáctanos
  • Licencia
  • Resumen breve

    ioc2rpz™: La solución de seguridad DNS - ioc2rpz™ es un potente servidor DNS que transforma los indicadores de amenazas en feeds accionables de Response Policy Zone (RPZ). Automatiza el proceso de actualización, garantizando que tu red esté protegida contra las últimas amenazas, incluidos dominios maliciosos y direcciones IP. Al convertir los feeds de IOC en RPZ, ioc2rpz™ actúa como un vínculo crucial entre la inteligencia de amenazas y la seguridad DNS, compatible con servidores DNS que soportan RPZ como ISC Bind o PowerDNS.

    Descripción general

    DNS es el plano de control de Internet. Normalmente el DNS se usa para el bien, pero:

    • Puede usarse para rastrear la ubicación de los usuarios y su comportamiento;
    • El malware usa el DNS para comando y control, exfiltrar datos o redirigir tráfico;
    • Según el informe anual de seguridad de Cisco de 2016, el 91,3 % del malware utiliza DNS;
    • Las empresas de publicidad suelen utilizar dominios separados y poco conocidos para mostrar anuncios;
    • Los servicios DNS gratuitos (por ejemplo, 1.1.1.1, 8.8.8.8, 9.9.9.9, etc.) pueden ayudarte a abordar algunas preocupaciones, pero no puedes definir tus propios ajustes de protección ni filtros de anuncios.

    ISC Bind es, de facto, un estándar de servidor de nombres. Con la introducción de las Response Policy Zones en ISC BIND 9.8, monitorizar y contener el malware en la capa DNS se convirtió en una tarea sencilla. RPZ es compatible con PowerDNS Recursor 4.0.0 y versiones posteriores. Knot DNS también soporta parcialmente RPZ.

    En comparación con las soluciones tradicionales de protección de red, un servidor DNS puede gestionar millones de indicadores sin impacto en el rendimiento, pero no existía una forma automatizada y eficiente de mantener las zonas de política de respuesta en los servidores DNS primarios.

    Normalmente, los indicadores de compromiso se distribuyen en texto plano, pero en diferentes formatos, y solo unos pocos proveedores de IOC los ponen a disposición mediante RPZ.

    ioc2rpz™ es un servidor DNS personalizado que convierte automáticamente indicadores (por ejemplo, FQDN maliciosos, direcciones IP) de diversas fuentes en feeds RPZ y los mantiene/actualiza automáticamente. Los feeds pueden distribuirse a cualquier servidor DNS de código abierto y/o comercial que soporte RPZ, por ejemplo, ISC Bind, PowerDNS. Puedes ejecutar tu propio servidor DNS con filtrado RPZ en un router, un ordenador de escritorio, un servidor e incluso una Raspberry Pi. La memoria del sistema es la única limitación.

    Con ioc2rpz™ puedes definir tus propios feeds, acciones y evitar comunicaciones no deseadas.

    ioc2rpz™ es el lugar donde la inteligencia de amenazas se encuentra con el DNS

    ioc2rpz™ transforma los feeds de IOC en zonas de política de respuesta (RPZ). Puedes mezclar feeds para generar un único RPZ o varios RPZ. Los dominios e IP de confianza pueden incluirse en la lista blanca. ioc2rpz™ admite la expiración de indicadores y, en consecuencia, reconstruye las zonas.
    Alt ioc2rpz™ La versión actual admite: archivos locales, archivos/solicitudes a través de http/https/ftp y scripts de shell para acceder a otros tipos de recursos. Puedes usar cualquier formato de archivo si puedes escribir una REGEX para extraer indicadores y los indicadores están separados por caracteres de nueva línea y/o retorno de carro (/n, /r, /r/n).

    Descripción general de la arquitectura

    ioc2rpz está construido sobre Erlang/OTP con un árbol de supervisión que garantiza tolerancia a fallos y recuperación automática. Consulta docs/architecture.md para obtener todos los detalles.``` 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:~
    Key modules:
    
    | Module | Responsibility |
    |--------|---------------|
    | `ioc2rpz.erl` | Trabajador DNS TCP/TLS — aceptar, analizar, validar, responder |
    | `ioc2rpz_udp.erl` | Oyente DNS UDP — consultas SOA |
    | `ioc2rpz_conn.erl` | Obtención de fuentes IOC (HTTP/HTTPS/archivo/shell) |
    | `ioc2rpz_db.erl` | Caché de zonas y paquetes basada en ETS |
    | `ioc2rpz_sup.erl` | Supervisor principal, carga de configuración, programación de zonas |
    | `ioc2rpz_rest.erl` | API de gestión REST (Cowboy) |
    | `ioc2rpz_doh.erl` | Manejador DNS-over-HTTPS |
    
    ## Cómo usar ioc2rpz™
    Puede usar ioc2rpz™ con cualquier servidor DNS que admita Zonas de Política de Respuesta (Response Policy Zones), p. ej. versiones recientes de ISC BIND, PowerDNS y cualquier servidor DNS comercial basado en estos productos (p. ej. Infoblox, Blue Cat, Efficient IP). Se proporciona un archivo de configuración de bind de ejemplo (named.conf) en la carpeta 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>
    
    ## Interfaz web de ioc2rpz™
    [ioc2rpz.gui](https://github.com/Homas/ioc2rpz.gui) es una interfaz web de gestión desarrollada como un proyecto independiente. No es necesaria para ejecutar ioc2rpz™.
    
    ## Soporte de protocolos
    
    ioc2rpz™ escucha en múltiples protocolos de transporte. Todos los transportes comparten la misma canalización de procesamiento de consultas: limitación de tasa, validación TSIG, búsqueda en zonas y generación de respuestas. Consulte [docs/protocols.md](https://github.com/homas/ioc2rpz/blob/master/docs/protocols.md) para obtener la documentación completa de protocolos.
    
    ### Resumen de puertos
    
    | Port | Protocol | Service | Condition |
    |------|----------|---------|-----------|
    | 53 | UDP | Consultas DNS (solo SOA) | Siempre |
    | 53 | TCP | Consultas DNS, transferencias de zona AXFR/IXFR, gestión | Siempre |
    | 853 | TCP+TLS | DoT — igual que TCP pero cifrado | Requiere configuración `cert` |
    | 443/8443 | TCP+TLS | DoH (`/dns-query`) y API REST | Requiere configuración `cert` |
    
    ### UDP (Puerto 53)
    
    UDP se utiliza para consultas DNS ligeras, principalmente búsquedas SOA. Las respuestas que superan los 512 bytes (o el tamaño de búfer anunciado por EDNS0) establecen el bit TC (truncamiento) según RFC 1035 §4.2.1, lo que hace que los clientes reintenten por TCP. Los comandos de gestión no son compatibles a través de UDP.```bash
    dig @127.0.0.1 zone.ioc2rpz SOA -y hmac-sha256:keyname:base64key
    

    TCP (Puerto 53)

    TCP maneja las transferencias de zona (AXFR/IXFR), las consultas SOA y los comandos de gestión. Un pool de 5 workers accept pre-generados gestiona las conexiones entrantes.```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 sobre TLS / DoT (Puerto 853)
    
    ioc2rpz™ soporta la distribución de RPZ sobre DoT. El listener TLS se inicia automáticamente en el puerto 853 cuando hay un registro `cert` presente en la configuración. DoT soporta las mismas operaciones que TCP (AXFR, IXFR, SOA, gestión).
    
    - Versiones TLS soportadas: 1.2 y 1.3 (`?TLSVersion = 'tlsv1.2-1.3'`)
    - Reutilización de conexiones soportada según RFC 7858 §3.4 (múltiples consultas por sesión TLS, tiempo de inactividad de 30 segundos)
    - TLS PIN no está soportado
    - Los mensajes DNS NOTIFY se envían sin cifrar (UDP simple)
    - Los certificados se actualizan automáticamente cuando los archivos se reemplazan en disco (hasta ~2 minutos de retraso debido al caché SSL de Erlang)
    
    Para la configuración de certificados, consulte [Configuración de certificados](#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 sobre HTTPS / DoH (Puerto 443/8443)

    DoH proporciona resolución DNS sobre HTTPS a través del endpoint /dns-query. Métodos admitidos:

    • GET con mensaje DNS codificado en base64url en el parámetro de consulta ?dns=
    • POST con cuerpo Content-Type: application/dns-message (máximo 4096 bytes; los payloads de mayor tamaño reciben HTTP 413)

    Las respuestas usan Content-Type: application/dns-message. DoH transporta el mensaje DNS completo en formato wire y se procesa a través de la misma ruta que Do53/DoT, por lo que hereda la misma autenticación TSIG; las transferencias de zona (AXFR/IXFR) siguen siendo solo TCP y no se sirven a través de 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:~
    ### Limitación de tasa
    
    Las consultas DNS se limitan en tasa utilizando una clave (híbrida) inteligente para que los clientes legítimos de múltiples zonas no sean penalizados mientras se bloquea el abuso por variación del nombre de consulta:
    
    - **Zona aprovisionada + QTYPE compatible** (`SOA`/`AXFR`/`IXFR`, clase `IN`) y **comandos de gestión reconocidos** (clase `CHAOS`/`TXT`) se rastrean por `{client_IP, query_name, query_type}` — por lo que un secundario que consulta/transfiere varias zonas (p. ej. `rpz1`, `rpz2`, `rpz3`) además de la gestión desde una IP se cuenta de forma independiente por zona+tipo.
    - **Cualquier otra cosa** (zona desconocida/no aprovisionada, tipo de consulta no compatible, clase incorrecta o nombre de gestión no reconocido) se agrega por `{client_IP}`, de modo que un atacante no puede evitar el límite variando el nombre de consulta.
    
    Cuando se supera el límite, el servidor devuelve una respuesta DNS `REFUSED`.
    
    | Parámetro | Valor predeterminado | Macro |
    |-----------|---------|-------|
    | Ventana | 10 segundos | `?RATE_LIMIT_WINDOW` (10000 ms) |
    | Máx. solicitudes por ventana (granular: zona+tipo conocida / gestión) | 1 | `?MAX_REQUESTS_PER_WINDOW` |
    | Máx. solicitudes por ventana (agregado: zona desconocida / tipo no compatible) | 1 | `?MAX_UNKNOWN_REQUESTS_PER_WINDOW` |
    
    La limitación de tasa se aplica a todos los transportes de consultas DNS (UDP, TCP, TLS, DoH). La ventana y el umbral son configurables mediante macros en `include/ioc2rpz.hrl`.
    
    ### NOTIFY de DNS
    
    Después de una actualización de zona (AXFR o IXFR), ioc2rpz™ envía mensajes de NOTIFY de DNS ([RFC 1996](https://tools.ietf.org/html/rfc1996)) por UDP a las direcciones IP configuradas en la `NotifyList` de la RPZ. Esto solicita a los servidores DNS secundarios que comprueben el serial SOA de la zona e inicien una transferencia si el serial ha cambiado.```erlang
    %% NotifyList in RPZ config — last field before whitelists
    {rpz, {"zone.ioc2rpz", ..., ["source1"], ["10.0.0.1", "10.0.0.2"], []}}.
    

    ioc2rpz™ frente a ISC BIND y otros DNS:

    • ioc2rpz™ fue creado para manejar únicamente la distribución de RPZ;
    • ioc2rpz™ soporta DoT (DNS sobre TLS) para que nadie pueda espiar fácilmente tus RPZ/indicadores;
    • ioc2rpz™ soporta DoH (DNS sobre HTTPS) para clientes DNS modernos;
    • ioc2rpz™ soporta tantos RPZ como necesites;
    • ioc2rpz™ soporta zonas en vivo/no almacenadas en caché. Crea zonas a partir de una solicitud entrante;
    • los indicadores pueden obtenerse de diferentes fuentes y mediante diferentes protocolos (p. ej., a través de llamadas a la API REST);
    • los RPZ se actualizan automáticamente;
    • el tiempo de expiración de IOC se utiliza para eliminar indicadores caducados de manera oportuna;
    • optimizaciones de rendimiento y de tiempo/tamaño/paquetes de transferencia de zona.

    Instalación

    La forma más sencilla de implementar el servicio es usando contenedores Docker en Docker Hub. Guía de implementación en Docker la puedes encontrar en la wiki de ioc2rpz™.

    Contenedor Docker

    ioc2rpz™ está disponible en Docker Hub. Simplemente busca ioc2rpz™. Requisitos previos:

    • ioc2rpz™ no contiene un archivo de configuración; debes montar /opt/ioc2rpz/cfg en un directorio del sistema host con el archivo de configuración (ioc2rpz.conf);
    • ioc2rpz™ utiliza los puertos 53/udp (solo solicitudes SOA), 53/tcp (AXFR, IXFR, SOA, MGMT), 853/tcp (AXFR, IXFR, SOA, MGMT) y 8443/tcp (API REST, DoH). Los puertos deben estar expuestos al sistema host;
    • ioc2rpz™ guarda la base de datos ETS en archivos para un arranque más rápido. Puedes montar /opt/ioc2rpz/db en un directorio del sistema host para conservar la BD entre reinicios; Puedes iniciar ioc2rpz™ con el siguiente comando:``` 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 directorios en un sistema host.  
    Puede pasar un nombre de archivo de configuración personalizado mediante el parámetro ``-e``. Por ejemplo: ``-e CONF=./cfg/ioc2rpz2.conf``
    
    ## Variables de entorno
    
    Las siguientes variables de entorno son utilizadas por ioc2rpz™, principalmente relevantes para despliegues de Docker. Se definen en `config/sys.config.src` y `config/vm.args`.
    
    | Variable | Default | Descripción |
    |----------|---------|-------------|
    | `IPv4` | — | Dirección de enlace IPv4 |
    | `IPv6` | — | Dirección de enlace IPv6 |
    | `CONF` | — | Ruta al archivo de configuración (p. ej. `./cfg/ioc2rpz.conf`) |
    | `DB` | `/opt/ioc2rpz/db` | Directorio de base de datos para la persistencia ETS |
    | `CD` | `/opt/ioc2rpz` | Directorio de trabajo |
    | `NODE_NAME` | `ioc2rpz` | Nombre corto del nodo Erlang |
    | `IO2Cookie` | `ioc2rpz` | Cookie distribuida de Erlang |
    
    Pase las variables de entorno a Docker con `-e`:```bash
    docker run -d --name ioc2rpz -e CONF=./cfg/custom.conf -e NODE_NAME=mynode ...
    

    Docker Compose

    Puedes desplegar ioc2rpz™ e ioc2rpz.gui usando docker compose. El archivo docker-compose.yml canónico se puede encontrar en el repositorio ioc2rpz.dc.

    A continuación se muestra un ejemplo de docker-compose.yml que presenta ioc2rpz con la interfaz web y un sidecar de Let's Encrypt certbot:```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:~
    Actualiza tu `ioc2rpz.conf` para que haga referencia a la ruta del certificado montado:```erlang
    {cert, {"ssl/live/ns1.rpz-proxy.com/fullchain.pem", "ssl/live/ns1.rpz-proxy.com/privkey.pem", ""}}.
    

    ioc2rpz™ en AWS

    Puede ejecutar ioc2rpz™ e ioc2rpz.gui en AWS. Para despliegues relativamente pequeños (varios cientos de miles de indicadores), incluso el nivel gratuito es suficiente. El siguiente video muestra cómo configurar ioc2rpz™ e ioc2rpz.gui en AWS usando ECS.

    Configuración de Certificados

    Se requieren certificados TLS para DoT (puerto 853), la API REST (puerto 8443) y DoH. El mismo certificado se utiliza para todos los servicios TLS. Consulte docs/deployment.md para obtener todos los detalles.

    Certificado Autofirmado (Desarrollo)```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 (Producción)```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
    

    Renovación automática```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:~
    Los certificados también se recargan explícitamente durante una recarga de configuración (`ioc2rpz-reload-cfg`): cuando ioc2rpz detecta que los archivos de certificado cambiaron, reinicia los listeners TLS con el nuevo certificado inmediatamente, en lugar de esperar a la caché SSL de Erlang de ~2 minutos. Añade un paso `ioc2rpz-reload-cfg` a tu hook de renovación para aplicar los nuevos certificados sin tiempo de inactividad.
    
    ### Montaje de volúmenes en Docker
    
    Cuando se ejecuta en Docker, monta el directorio de certificados desde el host:```bash
    docker run -d --name ioc2rpz \
      --mount type=bind,source=/etc/letsencrypt/live/ns1.rpz-proxy.com,target=/opt/ioc2rpz/ssl,readonly \
      ...
    

    Referencia en ioc2rpz.conf:```erlang {cert, {"ssl/fullchain.pem", "ssl/privkey.pem", ""}}.

    root@kitploit:~
    Erlang detecta automáticamente los archivos de certificado reemplazados en aproximadamente 2 minutos. Los certificados también se recargan explícitamente durante la recarga de configuración (`ioc2rpz-reload-cfg`). No deje que los certificados caduquen — renueve antes de la expiración para un servicio ininterrumpido.
    
    ## Compilación desde el código fuente
    
    > **Nota:** Compilar desde el código fuente está pensado para **desarrollo y pruebas**. Para producción, **Docker es el método de despliegue recomendado** — consulte [Docker Compose](#docker-compose) y el repositorio [ioc2rpz.dc](https://github.com/Homas/ioc2rpz.dc).
    
    ### Requisitos previos
    
    - **Erlang/OTP 24 o superior** (`erl -version` para comprobarlo) y un [rebar3](https://www.rebar3.org) compatible.
    - Una cadena de herramientas de C (para compilar dependencias) y `git`.
    
    ### Compilar y ejecutar```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
    

    Por defecto, ioc2rpz™ lee su configuración de ./cfg/ioc2rpz.conf, escucha en todas las interfaces de red y escribe su copia de seguridad de la base de datos en ./db. Los valores predeterminados de compilación (puertos, rutas, temporizadores) se encuentran en include/ioc2rpz.hrl.

    Configuración mínima

    Una cfg/ioc2rpz.conf mínima con una clave TSIG, una fuente de archivo y una zona 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"],[],[]}}.

    root@kitploit:~
    Consulta [docs/configuration.md](https://github.com/homas/ioc2rpz/blob/master/docs/configuration.md) para la referencia autoritativa campo por campo (disposición de tuplas source/RPZ, temporizadores SOA, grupos de claves, certificados, etc.). Para habilitar DoT (puerto 853), DoH y la API REST HTTPS, añade una entrada `{cert,{...}}` — consulta [Configuración de certificados](#certificate-setup).
    
    ### Shell de desarrollo (solo desarrollo/pruebas)
    
    Los siguientes comandos son para desarrollo y pruebas locales — no para uso en producción:```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
    

    En rebar3 shell puedes probar el sistema en ejecución directamente, por ejemplo:```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:~
    ## Gestión de ioc2rpz™
    ### vía DNS
    ioc2rpz™ admite gestión mediante DNS/TCP o DoT. Se recomienda utilizar DoT o la API REST sobre DNS/TCP. La versión actual de ioc2rpz™ no admite una IP/interfaz de gestión separada. En cualquier caso, se recomienda encarecidamente crear una clave TSIG designada (o claves) para uso exclusivo de gestión. Puedes desactivar la gestión a través de DNS.  
    Acciones admitidas:
    - Estado actual de ioc2rpz™. Solicita ``ioc2rpz-status``, clase ``CHAOS``, registro ``TXT``. p. ej.:```
    dig +tcp -y dnsmkey_1:ayVnL+h2QKMszRVohrngagcEuIpN3RkecXKdwSa5WsHD5N4Y5R3NUMGM W8sIGv36gPkAtWtgarqKzN9tmHqEnA== @127.0.0.1 ioc2rpz-status TXT -c CHAOS
    
    • Recargar archivo de configuración. Nombre RR ioc2rpz-reload-cfg, Clase RR CHAOS, Tipo RR TXT
    • Actualizar claves TSIG. Nombre RR ioc2rpz-update-tkeys, Clase RR CHAOS, Tipo RR TXT
    • Refresco completo de todas las zonas. Nombre RR ioc2rpz-update-all-rpz, Clase RR CHAOS, Tipo RR TXT
    • Refresco completo de una zona. Nombre RR zone_name, Clase RR CHAOS, Tipo RR TXT. P. ej. el refresco completo de dga.ioc2rpz se puede invocar mediante:``` dig +tcp -y dnsmkey_1:ayVnL+h2QKMszRVohrngagcEuIpN3RkecXKdwSa5WsHD5N4Y5R3NUMGM W8sIGv36gPkAtWtgarqKzN9tmHqEnA== @127.0.0.1 dga.ioc2rpz TXT -c CHAOS
    root@kitploit:~
    - Detener ioc2rpz™. RR Name ``ioc2rpz-terminate``, RR Class ``CHAOS``, RR Type ``TXT``
    - Solicitar una zona de muestra. RR Name ``sample-zone.ioc2rpz``, RR Class ``IN``, RR Type ``AXFR``
    ### mediante REST
    La API REST (puerto 8443/tcp) es la interfaz de gestión preferida. Por razones de seguridad, todo el tráfico de gestión debe estar cifrado y la API REST no se inicia si no hay un certificado SSL. Todos los endpoints aceptan tanto métodos GET como POST.
    
    Se utiliza autenticación HTTP básica para autenticar las solicitudes. Las claves TSIG de gestión se utilizan para la autenticación de solicitudes. El nombre de una clave TSIG se utiliza como nombre de usuario HTTP y la clave TSIG como contraseña. El acceso a la API REST está restringido con la ACL definida en el registro `srv`.
    
    El segmento de versión de la API admite tanto `v1` como `v1.0` (p. ej., `/api/v1/stats/serv` o `/api/v1.0/stats/serv`).
    
    La API REST admite salida JSON (predeterminada) y texto plano según el encabezado `Accept`:
    - `application/json` — salida JSON (predeterminada)
    - `text/plain` — salida en texto plano```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
    

    Las respuestas de texto utilizan el formato:``` status: ok msg: TSIG keys were updated

    root@kitploit:~
    #### Parámetros de ruta
    
    | Parámetro | Descripción |
    |-----------|-------------|
    | `:rpz_name` | Nombre de la zona RPZ (p. ej. `dga.ioc2rpz`) |
    | `:source_name` | Nombre de la fuente de IOC (p. ej. `sample_fqdn`) |
    | `:ioc` | Indicador a buscar (FQDN o IP, p. ej. `baddomain.com`) |
    
    #### Endpoints de estadísticas
    
    `/api/v1/stats/serv` — Estadísticas del servidor (nombre del nodo, reglas totales, uso de memoria)```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 — Estadísticas de zona 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
        }
      ]
    }
    

    El campo status (ready, updating, forceAXFR, notready) indica si los recuentos/serial informados están actualizados; cuando es updating o forceAXFR, reflejan la última actualización completada. Los recuentos y el serial se conservan tras una recarga de configuración en lugar de restablecerse a cero.

    /api/v1/stats/source — Estadísticas de origen```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}
      ]
    }
    

    Endpoints de administración

    /api/v1/mgmt/reload_cfg — Recargar el archivo de configuración```bash curl -u "keyname:base64key==" -k https://127.0.0.1:8443/api/v1/mgmt/reload_cfg

    root@kitploit:~
    Éxito: `{"status":"ok","msg":"Configuration reloaded"}`
    Error (HTTP 520): `{"status":"error","msg":"Configuration reload error"}`
    
    `/api/v1/mgmt/update_tkeys` — Recargar las claves TSIG desde la configuración```bash
    curl -u "keyname:base64key==" -k https://127.0.0.1:8443/api/v1/mgmt/update_tkeys
    

    Éxito: {"status":"ok","msg":"TSIG keys were updated"} Error (HTTP 520): {"status":"error","msg":"TSIG keys update error"}

    /api/v1/mgmt/terminate — Apagado ordenado del servidor```bash curl -u "keyname:base64key==" -k https://127.0.0.1:8443/api/v1/mgmt/terminate

    root@kitploit:~
    Éxito: `{"status":"ok","msg":"Terminating"}`
    
    #### Endpoints de actualización de zonas
    
    `/api/v1/update/all_rpz` — Fuerza una actualización completa de todas las zonas RPZ```bash
    curl -u "keyname:base64key==" -k https://127.0.0.1:8443/api/v1/update/all_rpz
    

    Éxito: {"status":"ok","msg":"All RPZ zones will be updated"}

    /api/v1/update/:rpz_name — Fuerza la actualización completa de una zona específica```bash curl -u "keyname:base64key==" -k https://127.0.0.1:8443/api/v1/update/dga.ioc2rpz

    root@kitploit:~
    Éxito: `{"status":"ok","msg":"RPZ dga.ioc2rpz will be updated"}`
    Error (HTTP 520): `{"status":"error","msg":"RPZ dga.ioc2rpz not found"}`
    
    #### Endpoints de gestión de caché
    
    `/api/v1/cache/sources/clear/all` — Elimina todas las fuentes de la caché activa```bash
    curl -u "keyname:base64key==" -k https://127.0.0.1:8443/api/v1/cache/sources/clear/all
    

    Éxito: {"status":"ok","msg":"All sources were removed from the hotcache"}

    /api/v1/cache/sources/clear/:source_name — Eliminar una fuente específica de la caché en caliente```bash curl -u "keyname:base64key==" -k https://127.0.0.1:8443/api/v1/cache/sources/clear/sample_fqdn

    root@kitploit:~
    Éxito: `{"status":"ok","msg":"sample_fqdn source was removed from the hot cache"}`
    
    `/api/v1/cache/sources/load/all` — Recargar todas las fuentes en la caché en caliente```bash
    curl -u "keyname:base64key==" -k https://127.0.0.1:8443/api/v1/cache/sources/load/all
    

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

    Endpoints de consulta de Feed e IOC

    /api/v1/feed/:rpz_name — Obtener indicadores de un feed RPZ

    Parámetro de consulta: ?type=fqdn|ip|both (por defecto: both)```bash curl -u "keyname:base64key==" -k "https://127.0.0.1:8443/api/v1/feed/malware.ioc2rpz?type=fqdn"

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

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

    /api/v1/ioc/:ioc — Comprueba si un indicador está bloqueado por alguna fuente RPZ

    Parámetro de consulta: ?tkey=keyname — limita la búsqueda a zonas accesibles mediante esa clave (opcional)```bash curl -u "keyname:base64key==" -k "https://127.0.0.1:8443/api/v1/ioc/baddomain.com?tkey=dnsproxykey_1"

    root@kitploit:~
    Éxito:```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"}

    El campo adicional sources enumera los nombres de las fuentes contribuyentes por feed cuando el seguimiento de fuentes está habilitado; es null cuando el seguimiento está deshabilitado o la atribución es desconocida. Consulte Atribución de Fuentes IOC para conocer la configuración y la semántica.

    Endpoints no admitidos

    Cualquier ruta no reconocida devuelve HTTP 200 con:```json {"status":"error","msg":"Unsupported request"}

    root@kitploit:~
    ## Monitoreo y Comprobaciones de Salud
    
    ### Estadísticas de 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
    

    Comprobaciones de Erlang Shell

    Si se ejecuta en un shell interactivo o si está conectado a un nodo en ejecución:```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:~
    ### Comprobaciones de salud de 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
    

    Consulte docs/deployment.md para obtener la referencia completa de supervisión y registros.

    Solución de problemas

    ProblemaSolución
    Puerto ya en usoCompruébelo con lsof -i :53 / lsof -i :853. {reuseaddr, true} está establecido en los sockets de escucha para reinicios rápidos.
    DoT no acepta conexionesVerifique que {cert, ...} esté configurado. Compruebe los workers TLS: supervisor:count_children(ioc2rpz_tls_sup_v6). Compruebe que el puerto 853 no esté bloqueado por el firewall.
    La transferencia de zona falla (discrepancia de TSIG)Verifique que el nombre de la clave y el secreto coincidan entre cliente y servidor. Busque eventos CEF 104/105 en los registros.
    Errores de descarga de fuentesCompruebe la conectividad de red. Busque Error downloading feed en los registros. El servidor reintenta 3 veces con un retraso de 3 s. Para fuentes HTTPS, asegúrese de que el certificado TLS sea válido.
    Alto uso de memoriaCompruebe los tamaños de las tablas ETS en el shell de Erlang. rate_limits y rpz_hotcache_table se limpian periódicamente. Considere reducir ?HotCacheTime.

    Consulte docs/deployment.md para obtener una solución de problemas detallada.

    Archivo de configuración

    La configuración es un archivo de Erlang. Cada opción de configuración es un término de Erlang, por lo que la configuración debe cumplir con la sintaxis de Erlang. El servidor valida las entradas de configuración al cargar/recargar: codificación de claves TSIG, existencia de archivos de certificado, compilación de expresiones regulares y sintaxis de URL. Las entradas no válidas se registran y se omiten. Consulte docs/configuration.md para obtener la referencia completa de configuración.

    ioc2rpz™ admite los siguientes parámetros de configuración:

    • un único registro srv (obligatorio);
    • un único registro cert (opcional);
    • cero o más registros key (opcional);
    • cero o más registros whitelist (opcional);
    • uno o más registros source (se requiere al menos una fuente);
    • uno o más registros rpz (se requiere al menos un rpz).

    Registro srv

    El registro srv se utiliza para definir los valores predeterminados del servidor. Consta de:

    • Nombre del servidor NS utilizado en el registro SOA;
    • una dirección de correo electrónico para el registro SOA (en formato SOA);
    • lista de claves TSIG de gestión (solo nombres). Consulte la sección de gestión para obtener más detalles.
    • lista de direcciones IP de ACL para el control de acceso a la API REST.
    • (opcional) TrackSources — el valor predeterminado global a nivel de servidor para la atribución de fuentes: off | auto | on (por defecto off). Se aplica a cualquier feed cuyo propio track_sources no esté establecido. Consulte Atribución de fuentes IOC.

    Ejemplo de registro 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:~
    La forma de 4 campos sigue siendo válida y, por defecto, establece `TrackSources` en `off`.
    ### Registro **cert**
    El registro **cert** se utiliza para definir un certificado y una clave privada para las comunicaciones DNS sobre TLS, API REST y DoH. Para la generación y gestión de certificados, consulte [Configuración de certificados](#certificate-setup).
    
    Consta de:
    - la ruta a un archivo que contiene un certificado;
    - la ruta a un archivo que contiene una clave privada codificada en PEM;
    - la ruta a un archivo con certificados de CA codificados en PEM.  
    
    Ejemplo de registro **cert**:```
    {cert,{"cfg/cert.pem", "cfg/key.pem",	"cfg/cacerts.pem"}}.
    

    include record

    El registro include permite dividir la configuración de ioc2rpz™ en múltiples archivos.

    Ejemplo de registro include:``` {include,"cfg/tkeys.include.cfg"}.

    root@kitploit:~
    ### Registro **key**
    Las claves TSIG se utilizan para la autenticación y autorización. Se recomienda utilizar diferentes claves TSIG para la gestión de ioc2rpz™ y las transferencias de zonas.  
    El registro **key** consta de:
    - nombre de la clave TSIG;
    - algoritmo. Se admiten ``md5``, ``sha256`` y ``sha512``;
    - la clave;
    - (opcional) lista de grupos de claves a los que pertenece.
    
    Ejemplo de registros **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"]}}.
    

    La utilidad dnssec-keygen se puede utilizar para generar claves 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:~
    Consulte la documentación de "dnssec-keygen" para obtener más detalles. Las claves pueden asignarse a grupos para la autorización basada en grupos en el control de acceso a zonas RPZ.
    
    ### **key_group** registro
    Los grupos de claves proporcionan autorización basada en grupos para las transferencias y la administración de zonas. En lugar de enumerar claves individuales en los registros `rpz` o `srv`, puede asignar claves a grupos con nombre y hacer referencia al grupo.
    
    Hay dos formas de asignar claves a grupos:
    1. En línea, mediante el campo opcional 4.º del registro `key`: `{key, {Name, Alg, Secret, [Groups]}}`
    2. Explícitamente, mediante un registro `key_group` (se muestra a continuación)```erlang
    {key_group, {GroupName, [KeyName1, KeyName2, ...]}}.
    
    CampoTipoDescripción
    GroupNamestringNombre del grupo (p. ej. "customers")
    Keyslist of stringsLista de nombres de claves TSIG que pertenecen a este grupo

    Ejemplo de registros key_group:```erlang {key_group, {"customers", ["dnsproxykey_1", "dnsproxykey_2"]}}. {key_group, {"public", ["dnsproxykey_3"]}}.

    root@kitploit:~
    Los grupos se referencian en los registros `rpz` y `srv` mediante la tupla `{groups, ["group1", "group2"]}` en la lista de claves:```erlang
    {rpz, {"zone.ioc2rpz", 7202, 3600, 2592000, 7200, "true", "true", "nxdomain",
           ["dnsproxykey_1", {groups, ["customers", "public"]}],
           "fqdn", 86400, 3600, ["source1"], [], []}}.
    

    Registro whitelist

    Las listas blancas se utilizan para prevenir posibles errores y el bloqueo de dominios y direcciones IP de confianza. Los IOC incluidos en la lista blanca se eliminan de las zonas de política de respuesta. ioc2rpz™ solo comprueba la coincidencia exacta, por lo que no dividirá ni descartará una red si una dirección IP en la lista blanca está incluida en una subred bloqueada y viceversa. Una lista blanca es un archivo de texto o una fuente de datos de texto. Los indicadores deben separarse mediante caracteres de nueva línea (/n,/r o ambos /n/r). Las listas blancas deben contener FQDN válidos y/o direcciones IP. ioc2rpz™ admite una cantidad ilimitada de indicadores.
    El registro whitelists consta de:

    • nombre de la lista blanca;
    • ruta de la lista blanca. Se admiten URL (http/https/ftp) y archivos locales. El prefijo "file:" se utiliza para archivos locales;
    • REGEX que se utiliza para extraer indicadores. Una expresión regular debe incluirse entre comillas dobles. Si se especifica un REGEX vacío (""), se utilizará un REGEX predeterminado ("^([A-Za-z0-9][A-Za-z0-9\-\._]+)[^A-Za-z0-9\-\._]*.*$"). Se utiliza none si no se requiere REGEX (la fuente ya proporciona datos en el formato requerido).

    Ejemplo de registro whitelist:``` {whitelist,{"whitelist_1","file:cfg/whitelist1.txt",none}}.

    root@kitploit:~
    ### **source** record
    Una fuente es un feed de indicadores maliciosos. Se admiten FQDNs, direcciones IPv4 e IPv6. Una fuente es un archivo de texto o un feed de datos de texto. Los indicadores deben separarse mediante caracteres de nueva línea/retorno de carro (/n,/r o ambos /r/n). ioc2rpz™ admite un número ilimitado de indicadores.  
    El registro **source** consta de:
    - nombre de la fuente;
    - ruta de la fuente para la transferencia completa de la fuente (AXFR). Se admiten URLs(http/https/ftp), archivos locales y scripts. El prefijo **file:** se utiliza para archivos locales. El prefijo **shell:** se utiliza para ejecutar un script/comando local en un host/contenedor que debe devolver indicadores y una fecha de expiración opcional a STDOUT;
    - ruta de la fuente para la transferencia incremental de la fuente (IXFR). Las rutas AXFR,IXFR admiten palabras clave para acortar URLs y proporcionar marcas de tiempo de actualización de zona:
      - **[:AXFR:]** - ruta AXFR completa. Solo se puede usar en rutas IXFR;
      - **[:FTimestamp:]** - marca de tiempo de la última actualización de la fuente (p. ej. 1507946281)
      - **[:ToTimestamp:]** - marca de tiempo actual;
    - REGEX que se utiliza para extraer indicadores y su tiempo de expiración. La primera coincidencia es un indicador, la segunda es un tiempo de expiración. El tiempo de expiración es un parámetro opcional. Una expresión regular debe incluirse entre comillas dobles. Si se especifica una REGEX vacía (`""`), se utilizará una REGEX predeterminada (`"^([A-Za-z0-9][A-Za-z0-9\-\._]+)[^A-Za-z0-9\-\._]*.*$"`). Se utiliza `none` si no se requiere REGEX (la fuente ya proporciona datos en el formato requerido).
    Parámetros opcionales (deben usarse todos o ninguno):
    - UserID (utilizado internamente).
    - Número máximo de IoCs.
    - Actualización completa de la fuente, tiempo de caché caliente (en segundos).
    - Actualización incremental de la fuente, tiempo de caché caliente (en segundos).
    
    Las descargas de fuentes HTTPS verifican el certificado TLS del servidor remoto. Las fuentes con certificados no válidos o autofirmados fallarán al descargarse. Para certificados autofirmados, use una fuente `shell:` con `curl --insecure`.
    
    **Restricciones de archivos locales:** las rutas `file:` que contengan `..` (recorrido del directorio padre) se rechazan por seguridad; use una ruta sin `..` (dentro del directorio de trabajo/datos).
    
    **Restricciones de comandos shell:** el ejecutable de cada segmento de la tubería debe ser una ruta absoluta (p. ej. `/usr/bin/curl`) o una utilidad de texto segura de nombre simple (`sort`, `uniq`, `grep`, `sed`, `awk`, `gawk`, etc.); los comandos destructivos y shells (`rm`, `bash`, `sh`, etc.) están bloqueados, y la sustitución de comandos (`$(...)`, comillas invertidas) y la redirección de salida (`>`, `>>`) se rechazan. Los comandos rechazados no se ejecutan y se registran mediante el evento CEF 151 (los comandos ejecutados se registran mediante 150). Consulte [docs/configuration.md](https://github.com/homas/ioc2rpz/blob/master/docs/configuration.md#shell-command-restrictions) para conocer el conjunto de reglas completo.
    
    Si una fuente devuelve menos del 50% de su recuento anterior de indicadores, la actualización se rechaza y se conservan los datos anteriores. Esto evita que los feeds degradados reduzcan la cobertura de RPZ. Configurable mediante la macro `?SOURCE_MIN_IOC_RATIO`.
    
    Ejemplo de registro **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}}.
    

    Fuente shell: se utiliza para ampliar las opciones de conectividad de ioc2rpz™, que de forma nativa son algo limitadas. El contenedor de ioc2rpz™ incluye dig, grep, awk y python. Por ejemplo, puedes mezclar diferentes feeds de RPZ u obtener datos de una base de datos.

    Restricciones de comandos Shell: Todos los ejecutables deben usar rutas absolutas (p. ej., /usr/bin/curl, no curl). Los comandos destructivos (rm, bash, sh, etc.) están bloqueados. La sustitución de comandos ($(...), comillas invertidas) y la redirección de salida (>, >>) se rechazan. Ver docs/configuration.md para obtener más detalles.

    Seguridad de archivos locales: Las rutas de archivo que contengan .. (recorrido al directorio padre) se rechazan por seguridad.

    rpz registro

    El término RPZ define una zona de política de respuesta.
    El registro rpz se compone de:

    • nombre de rpz;
    • tiempo de refresco SOA en segundos;
    • tiempo de reintento de actualización SOA en segundos;
    • tiempo de expiración SOA en segundos;
    • TTL de NXDomain SOA en segundos;
    • Caché. Valores posibles: true o false. true define que la RPZ debe almacenarse en caché, false - no almacenada en caché, las fuentes de zona en vivo se descargan y se genera una RPZ mediante una solicitud AXFR. Las zonas "en vivo" no admiten transferencias de zona incrementales. Si el feed RPZ no está almacenado en caché, de todos modos se almacena temporalmente en una caché en caliente. En caso de que una solicitud de un cliente agote el tiempo de espera, podremos responder la próxima vez. El tiempo AXFR se utilizará para determinar la vida útil de la caché;
    • Comodines. Valores posibles: true o false. Define si se deben generar reglas comodín;
    • Acción. Consulta la tabla de Acciones RPZ a continuación;
    • Lista de claves TSIG y grupos de claves;
    • Tipo de IOCs utilizados en la RPZ: mixed, fqdn, ip. Se utiliza para la optimización.
    • Tiempo de actualización completa de la zona en segundos (AXFR Time). Actualización completa de la zona y reconstrucción si el MD5 de los IOCs es diferente;
    • Tiempo de actualización incremental de la zona (IXFR Time). Las fuentes deben admitir actualizaciones incrementales. "0" significa que no hay actualizaciones incrementales de zona;
    • Lista de las fuentes;
    • Lista de servidores DNS (direcciones IP) que deben ser notificados sobre actualizaciones de una RPZ (ver DNS NOTIFY);
    • Lista de listas blancas.
    • (opcional) TrackSources — atribución de fuente por feed: auto | true | false. Cuando está presente, anula el valor predeterminado global del servidor. Cuando se omite (formato de 15 campos), el feed hereda el valor predeterminado del servidor (#srv TrackSources, off a menos que esté configurado). Ver IOC Source Attribution.

    Acciones RPZ

    AcciónValor de configuraciónDescripción
    NXDOMAIN"nxdomain"Devuelve NXDOMAIN (el dominio no existe)
    NODATA"nodata"Devuelve respuesta vacía (el dominio existe, sin registros)
    Passthru"passthru"Permite la consulta (regla de exención)
    Drop"drop"Descartar la consulta silenciosamente
    TCP-Only"tcp-only"Fuerza al cliente a reintentar por TCP
    Block NS"blockns"Bloquear el servidor de nombres autoritativo
    Redirect (domain){"redirect_domain","example.com"}Redirigir a un dominio específico (alias de local_cname)
    Redirect (IP){"redirect_ip","127.0.0.1"}Redirigir a una IP específica (alias de local_a/local_aaaa)
    Local A{"local_a","127.0.0.1"}Devolver una dirección IPv4 personalizada
    Local AAAA{"local_aaaa","fe80::1"}Devolver una dirección IPv6 personalizada
    Local CNAME{"local_cname","www.example.com"}Devolver una redirección CNAME
    Local TXT{"local_txt","Text Record"}Devolver un registro TXT

    Se pueden combinar varias acciones locales en una lista: [{"local_a","127.0.0.1"},{"local_aaaa","fe80::1"},{"local_txt","Blocked"}]

    Ejemplo de registro 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:~
    ### Atribución de fuentes IOC
    Un feed RPZ se construye fusionando indicadores de múltiples fuentes. La atribución de fuentes permite que la API de búsqueda de IOC informe **qué fuente(s) dentro de un feed** contribuyeron con un indicador — útil para el triage de un falso positivo reportado. El seguimiento está **desactivado por defecto** y se controla por feed con un valor global predeterminado opcional a nivel de servidor.
    
    **Configuración**
    
    - Por feed: el elemento `TrackSources` opcional final (16.º) de la tupla `{rpz,{...}}` — `auto | true | false`.
    - Valor global predeterminado del servidor: el elemento `TrackSources` opcional final (5.º) de la tupla `{srv,{...}}` — `off | auto | on` (por defecto `off`).
    
    Ambos son opcionales y compatibles con versiones anteriores: los archivos de configuración existentes (`rpz` de 15 campos, `srv` de 4 campos) se cargan sin cambios y se comportan como `off`.
    
    **Precedencia de resolución** — el estado efectivo para un feed se resuelve como:
    1. el valor explícito `track_sources` del feed, si está definido;
    2. de lo contrario, el valor global predeterminado del servidor;
    3. de lo contrario, el valor predeterminado integrado `off`.
    
    `auto` significa: rastrear solo feeds **multifuente**. Los feeds de una sola fuente nunca se enmascaran — su único nombre de fuente se devuelve directamente (sin coste de seguimiento).
    
    **API — el campo aditivo `sources`**
    
    La respuesta de `/api/v1/ioc/:ioc` gana un nuevo campo `sources` en cada objeto de feed. Es **aditivo y compatible con versiones anteriores**: todos los campos existentes no cambian, por lo que los clientes antiguos que lo ignoren seguirán funcionando.
    
    - Feed multifuente rastreado: un array JSON con los nombres de las fuentes que contribuyen.
    - Feed de una sola fuente: un array de un solo elemento con ese único nombre de fuente.
    - Seguimiento desactivado o atribución desconocida (p. ej., una fila en caché anterior a la actualización, antes de su reconstrucción AXFR única): `null` (JSON) / `(disabled)` o `(unavailable)` (TXT).```json
    {
      "feed": "mixed.ioc2rpz",
      "wildcard": "true",
      "type": "fqdn",
      "rpz_serial": 1709000000,
      "ioc_expiration": 0,
      "sources": ["abuse-ch", "internal-list"]
    }
    

    Feed de una sola fuente: "sources": ["sample_fqdn"]. Seguimiento deshabilitado/desconocido: "sources": null.

    Despliegue (desactivado por defecto)

    Actualizar el binario no cambia nada — ni seguimiento, ni reconstrucciones de zona, ni API modificada — hasta que se establezca un valor de track_sources. Los feeds se gestionan desde la GUI; la GUI o el sitio de la comunidad escribirán estos valores de configuración opcionales y expondrán sources en una actualización posterior. Habilitar el seguimiento de un feed en caché desencadena una reconstrucción AXFR única para rellenar las máscaras de fuente.

    Limitaciones

    • La atribución solo está disponible para feeds en caché (cache = "true"), ya que la consulta a la API lee la tabla de caché IXFR.
    • Las máscaras son autoritativas tras una reconstrucción AXFR completa. En las actualizaciones IXFR, las máscaras de los indicadores recién añadidos se establecen correctamente, pero un cambio de máscara para un indicador ya presente (una segunda fuente comienza a listar un IOC existente) puede no reconciliarse hasta el siguiente AXFR.
    • Las máscaras de fuente son posicionales por zona (bit i = fuente i-ésima). Reordenar o editar la lista de fuentes de una zona fuerza una reconstrucción AXFR única (detectada mediante una comprobación de firma de fuente) para que las máscaras se recalculen.
    • Los feeds con más de 63 fuentes usan una máscara de mapa de bits binaria más amplia (por defecto) para que la atribución siga siendo correcta.
    Archivo de configuración de ejemplo (clic para expandir)```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>
    
    ## Valores de configuración predefinidos - include/ioc2rpz.hrl
    include/ioc2rpz.hrl contiene parámetros precompilados.
    
    Parámetros estándar:
    - ``MGMToDNS`` (true/false) - habilita la gestión sobre DNS/TCP;
    - ``DBStorage`` (ets) - define el almacenamiento en DB para las cachés AXFR e IXFR. La versión actual solo admite ETS;
    - ``SaveETS`` (true/false) - define si las tablas ETS AXFR/IXFR deben guardarse en disco;
    - ``Port`` (valor numérico, 1 - 65535) - define el puerto DNS en el que se ejecuta el servicio;
    - ``PortTLS`` (valor numérico, 1 - 65535) - define el puerto DoT en el que se ejecuta el servicio;
    - ``PortREST`` (valor numérico, 1 - 65535) - define el puerto HTTPs en el que se ejecuta el servicio;
    - ``TTL`` (valor numérico, en segundos) - TTL predeterminado para registros DNS/reglas RPZ.
    - ``DefConf`` (cadena) - archivo de configuración predeterminado;
    - ``DefDB`` (cadena) - ruta de base de datos predeterminada;
    - ``logTS`` - si está definido, se agrega una marca de tiempo en los mensajes de registro;
    - ``debug`` - si está definido, se imprimen mensajes de registro de depuración;
    - ``TLSVersion`` ('tlsv1.2-1.3') - versiones TLS admitidas para DoT y la API REST;
    
    Parámetros de optimización:
    - ``DNSPktMax`` (valor numérico, 100 - 65535) - tamaño máximo de paquete. Valores recomendados:
      - 16384 - tamaño mínimo de transferencia de zona;
      - 65535 - cantidad mínima de paquetes DNS;
    - ``Compression`` (valor numérico, 0 - 9) - nivel de compresión (0 - sin compresión, 9 - compresión máxima). La caché AXFR y las tablas en disco almacenan datos comprimidos;
    - ``ZoneRefTime`` (valor numérico, en milisegundos) - define el intervalo de comprobación de actualización de zona;
    - ``TCPTimeout`` (valor numérico, en milisegundos) - define el tiempo de espera de sesión TCP;
    - ``HotCacheTime`` (valor numérico, en segundos) - tiempo de caché activa para IOCs, Rules, Packets. Las zonas en vivo se almacenan en una caché activa;
    - ``HotCacheTimeIXFR`` (valor numérico, en segundos) - tiempo de caché activa para IOCs IXFR en una caché activa. De forma predeterminada, los indicadores IXFR se almacenan en caché durante un minuto (incluso si se establece en 0) porque el serial actual siempre se redondea al minuto anterior;
    - ``RATE_LIMIT_WINDOW`` (valor numérico, en milisegundos, predeterminado 10000) - duración de la ventana de límite de tasa por IP;
    - ``MAX_REQUESTS_PER_WINDOW`` (valor numérico, predeterminado 1) - máximo de solicitudes DNS por IP por ventana de límite de tasa;
    - ``ShellMaxRespSize`` (valor numérico, predeterminado 2 GiB) - tamaño máximo de respuesta para fuentes de comandos shell;
    - ``SourcePullTimeout`` (valor numérico, en milisegundos, predeterminado 300000) - tiempo de espera para descargas de fuentes (5 minutos);
    
    ## Cómo se actualizan las cachés AXFR (completa) e IXFR (incremental)
    - La caché AXFR siempre contiene zonas preconstruidas sin registros SOA/NS/TSIG. Preconstruidas significa que todos los registros están divididos en paquetes y las etiquetas se acortaron/comprimieron.
    - Si un servidor recibe una solicitud AXFR, recupera los paquetes de la caché AXFR, agrega registros SOA/NS y TSIG si es necesario.
    - La actualización de zonas AXFR debe considerarse como un procedimiento de limpieza que debe realizarse periódicamente. Solo para asegurarse de que no haya desincronización entre las fuentes y la caché.
    - Para zonas grandes, las actualizaciones AXFR deben programarse con poca frecuencia para minimizar el impacto en el rendimiento del servidor y la cantidad de datos transferidos a todos los clientes.
    - Todos los cambios, si es posible, deben realizarse mediante actualizaciones incrementales de zona. En ese caso, la caché AXFR se reconstruirá solo si una zona se actualizó.
    - [TODO] Debido a una optimización, solo se reconstruirá el último paquete para nuevos IOCs y los paquetes relevantes y concordantes para IOCs expirados.
    - La caché IXFR contiene solo IOCs y fechas de expiración. [TODO] e ID de paquetes (para permitir reconstruir la zona rápidamente).
    - El registro RPZ contiene el Serial actual de la zona y Serial_IXFR. Serial_IXFR sirve como el serial mínimo de zona incremental disponible para una transferencia de zona incremental.
    - La caché IXFR se vacía después de una actualización completa de zona (AXFR). Serial_IXFR = Serial. Los clientes recibirán la actualización completa de la zona en cualquier caso, por eso es importante que la transferencia de zona AXFR sea poco frecuente.
    - Cuando se actualiza la caché IXFR, la caché AXFR debe reconstruirse.
    - Si una zona no admite actualizaciones IXFR -> no se guarda en la tabla IXFR.
    - Las zonas en vivo no se almacenan en caché en las cachés AXFR, IXFR, pero las fuentes (IOCs) pueden almacenarse en caché en la caché activa.
    
    ## Caché activa
    Todos los IOCs, Rules, Packets, incluidas las RPZ en vivo, se almacenan en la caché activa. Los parámetros precompilados ``HotCacheTime``, ``HotCacheTimeIXFR`` definen el tiempo de almacenamiento.
    
    ## Cómo probar ioc2rpz™ (o fuentes RPZ de muestra y gratuitas alojadas por ioc2rpz™)
    ### Aviso legal
    El autor no asume responsabilidad ni obligación por errores u omisiones en el contenido de estas fuentes RPZ. Las fuentes se proporcionan "tal cual" sin garantías de integridad, precisión, utilidad o puntualidad para demostrar únicamente la tecnología ioc2rpz™. La distribución del servicio de fuentes RPZ puede interrumpirse o detenerse sin previo aviso. El autor no es responsable de daños directos o indirectos causados por el uso de este servicio.
    
    ### Fuentes RPZ
    Puede probar la tecnología ioc2rpz™ si se registra en la [comunidad ioc2rpz™](https://ioc2rpz.net) con las siguientes fuentes:
    - [notracking](https://github.com/notracking/hosts-blocklists);
    - [Phishtank](https://www.phishtank.com/).
    
    ### Configuración de ejemplo de 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";};
    };
    

    Ejemplo de configuración de 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:~
    ### Ejemplo de configuración de Infoblox (archivo de importación)```
    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
    

    Ejemplo de DIG (para obtener 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:~
    ## Algunas fuentes gratuitas de inteligencia de amenazas
    - [Netlab](http://data.netlab.360.com)
    - [Lista awesome-threat-intelligence en GitHub](https://github.com/hslatman/awesome-threat-intelligence)
    
    Puedes encontrar otras fuentes de IOC en la página wiki: https://github.com/Homas/ioc2rpz/wiki/IOC-Sources.
    
    ## Documentación adicional
    
    Para documentación detallada, consulta el directorio `docs/`:
    
    - [docs/architecture.md](https://github.com/homas/ioc2rpz/blob/master/docs/architecture.md) — Árbol de supervisión OTP, responsabilidades de los módulos, tablas ETS, flujo de datos
    - [docs/configuration.md](https://github.com/homas/ioc2rpz/blob/master/docs/configuration.md) — Referencia completa de configuración con todos los tipos de tuplas y opciones
    - [docs/deployment.md](https://github.com/homas/ioc2rpz/blob/master/docs/deployment.md) — Instrucciones de compilación, despliegue con Docker, certificados, monitorización, resolución de problemas
    - [docs/protocols.md](https://github.com/homas/ioc2rpz/blob/master/docs/protocols.md) — Soporte de protocolos (UDP/TCP/DoT/DoH), API REST, TSIG, limitación de velocidad, DNS NOTIFY
    
    ## Referencias
    - [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>Referencia de códigos de eventos CEF</strong> (haz clic para expandir)</summary>
    
    | Código | Gravedad | Evento | Descripción |
    |------|----------|-------|-------------|
    | 101 | Baja | Paquete DNS malformado | Se recibió un paquete DNS malformado |
    | 102 | Baja | Solicitud DNS incorrecta | Solicitud DNS no analizable |
    | 103 | Media | Rechazada | Solicitud DNS rechazada |
    | 104 | Media | Clave TSIG no encontrada | La solicitud usó una clave TSIG desconocida |
    | 105 | Media | MAC TSIG incorrecta | Falló la verificación de la firma TSIG |
    | 106 | Media | Hora TSIG incorrecta | Marca de tiempo TSIG fuera de rango |
    | 107 | Media | Otro error TSIG | Error TSIG sin clasificar |
    | 108 | Media | Posición TSIG incorrecta | Registro TSIG en posición inesperada |
    | 109 | Baja | Respuesta DNS recibida | Se recibió una respuesta DNS inesperada |
    | 120 | Media | RPZ no encontrado | La zona RPZ solicitada no existe |
    | 121 | Baja | RPZ no listo | La zona RPZ todavía se está cargando/actualizando |
    | 130 | Baja | Error de transferencia RPZ | Error durante la transferencia de zona (solo transferencia RPZ) |
    | 131 | Baja | Transferencia RPZ cerrada | El remoto cerró la conexión durante la transferencia (solo transferencia RPZ) |
    | 140 | Alta | Falló la autenticación básica REST | Falló la autenticación básica de la API REST |
    | 141 | Alta | Falló la autenticación REST | Falló la autorización de la API REST |
    | 145 | Alta | Gestión REST denegada | Solicitud de gestión REST denegada por ACL |
    | 146 | Alta | Falló la solicitud de gestión | Falló el procesamiento de la solicitud de gestión |
    | 147 | Alta | Solicitud no soportada | Endpoint desconocido de la API REST |
    | 148 | Alta | Zona no encontrada | La API REST hizo referencia a una zona inexistente |
    | 150 | Baja | Comando shell ejecutado | Comando de origen shell ejecutado (información) |
    | 151 | Alta | Comando shell rechazado | Comando de origen shell rechazado (seguridad) |
    | 201 | Baja | Transferencia RPZ exitosa | Transferencia de zona completada |
    | 202 | Baja | Consulta DNS | Consulta DNS estándar procesada |
    | 221 | Baja | Notificación DNS | Notificación enviada al servidor secundario |
    | 222 | Media | Error de notificación DNS | Falló el envío de la notificación |
    | 230 | Alta | Solicitud de gestión | Operación de gestión ejecutada |
    | 301 | Alta | Solicitud de gestión denegada | Comando de gestión DNS denegado |
    | 429 | Alta | Demasiadas solicitudes | Límite de velocidad superado |
    | 501 | Alta | Posible DDoS | Patrón CVE-2004-0789 detectado |
    
    </details>
    
    # ¿Quieres apoyar el proyecto?
    Puedes apoyar el proyecto ioc2rpz™ y la comunidad ioc2rpz™ (https://ioc2rpz.net) a través de [GitHub Sponsor](https://github.com/sponsors/Homas) (pagos recurrentes). Para hacer una donación única puedes usar [PayPal](https://paypal.me/ioc2rpz) o Zelle (nuestro correo electrónico: zelle [at] ioc2rpz [.] net).
    
    # Patrocinadores
    Un agradecimiento a **craSH** y **rrbone**, que apoyan mis proyectos en [GitHub Sponsor](https://github.com/sponsors/Homas).
    
    # Contáctanos
    Puedes contactarnos por correo electrónico: feedback(at)ioc2rpz[.]net o en [Telegram](https://t.me/ioc2rpz).
    
    # Licencia
    Copyright 2017 - 2025 Vadim Pavlov ioc2rpz[at]gmail[.]com
    
    Licenciado bajo la Licencia Apache, Versión 2.0 (la "Licencia"); no puede usar este archivo excepto en cumplimiento de la Licencia.
    Puede obtener una copia de la Licencia en  
    
        http://www.apache.org/licenses/LICENSE-2.0  
    
    A menos que lo exija la ley aplicable o se acuerde por escrito, el software distribuido bajo la Licencia se distribuye "TAL CUAL", SIN GARANTÍAS NI CONDICIONES DE NINGÚN TIPO, ya sean expresas o implícitas. Vea la Licencia para conocer el lenguaje específico que rige los permisos y las limitaciones bajo la Licencia.