API de CGNAT y anti-spoofing
Dos funciones de protección de abonados del DTVSOL Super Router:
- CGNAT asigna las direcciones privadas de los abonados a un pool de direcciones IPv4 públicas. Cada abonado recibe un slot fijo: una dirección pública y un bloque fijo de puertos en ella. Como la asignación es determinista, una dirección pública y un puerto siempre se pueden rastrear hasta un abonado (
/cgnat/lookup). Las asignaciones también se escriben en un registro de auditoría en el router. - Anti-spoofing vincula la MAC de origen, la dirección IP y la VLAN de cada abonado. En cada VLAN de acceso con control aplicado, un paquete se reenvía solo cuando su MAC e IP de origen forman un par que el router conoce, y un paquete ARP solo cuando lo forman su MAC e IP de remitente. Todo lo demás se descarta y se registra (con límite de frecuencia) junto con la MAC que lo envió.
La autenticación, el formato de errores y los códigos de estado se describen en la descripción general de la API. Las mismas funciones están disponibles desde la CLI como dtvsol cgnat … y dtvsol antispoof ….
GET /cgnat
Sección titulada «GET /cgnat»La configuración de CGNAT, su capacidad y una muestra de las asignaciones actuales (las cinco primeras).
curl -H "X-API-Key: YOUR_API_KEY" http://ROUTER-IP:8880/cgnat{ "enabled": true, "iface": "bond0", "pool": "XXX.XXX.XXX.10-XXX.XXX.XXX.20", "pool_ips": 11, "port_range": "1024-65535", "block_size": 2048, "subs_per_ip": 31, "capacity": 341, "assigned": 2, "free": 339, "exempt": ["10.0.0.0/30"], "sample": [ { "mac": "AA:BB:CC:DD:EE:FF", "private_ip": "100.64.0.2", "public": "XXX.XXX.XXX.10:1024-3071", "slot": 0 } ], "audit_log": "/opt/dtvsol/log/cgnat-mappings.log"}subs_per_ip es (port_max − port_min + 1) / block_size; capacity es pool_ips × subs_per_ip.
POST /cgnat
Sección titulada «POST /cgnat»Modifique cualquier subconjunto de la configuración de CGNAT. Los campos que omita conservan su valor actual; los valores predeterminados son port_min 1024, port_max 65535, block_size 2048.
| Nombre | En | Tipo | Notas |
|---|---|---|---|
enabled |
body | boolean | true/false (también 1/0, on/off, yes/no). Para habilitarlo se requiere una iface válida y existente y un pool no vacío. |
iface |
body | string | La interfaz WAN en la que está el pool público, p. ej. bond0. |
pool |
body | string o array | Direcciones IPv4 públicas: direcciones individuales y rangos first-last, separadas por comas o como array. |
port_min |
body | integer | Primer puerto que se asigna (predeterminado 1024). |
port_max |
body | integer | Último puerto que se asigna (predeterminado 65535). |
block_size |
body | integer | Puertos por abonado (predeterminado 2048). |
exempt |
body | string o array | Redes (a.b.c.d/nn) a las que nunca se aplica NAT, separadas por comas o como array. |
curl -X POST http://ROUTER-IP:8880/cgnat \ -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \ -d '{"enabled": true, "iface": "bond0", "pool": "XXX.XXX.XXX.10-XXX.XXX.XXX.20", "block_size": 2048, "exempt": "10.0.0.0/30"}'{ "ok": true, "code": 200, "message": "CGNAT updated", "status": { "enabled": true, "iface": "bond0", "capacity": 341, "assigned": 2, "free": 339 }}status es la respuesta completa de GET /cgnat. Errores: 400 — Enable requires a valid WAN iface (habilitar requiere una interfaz WAN válida), Enable requires a non-empty public IP pool (habilitar requiere un pool de IP públicas no vacío), Invalid exempt network: … (red exenta no válida).
GET /cgnat/lookup
Sección titulada «GET /cgnat/lookup»Quién tenía una dirección pública y un puerto: el abonado cuyo slot los incluye. Úselo para responder a reclamos por abuso y a requerimientos de las autoridades.
| Nombre | En | Tipo | Notas |
|---|---|---|---|
public_ip |
query | string | La dirección pública vista desde fuera. Obligatorio. |
port |
query | integer | El puerto de origen público visto desde fuera. |
curl -H "X-API-Key: YOUR_API_KEY" \ "http://ROUTER-IP:8880/cgnat/lookup?public_ip=XXX.XXX.XXX.10&port=2000"{ "ok": true, "code": 200, "found": true, "mac": "AA:BB:CC:DD:EE:FF", "private_ip": "100.64.0.2", "hostname": "client-aabbccddeeff", "public_ip": "XXX.XXX.XXX.10", "port_start": 1024, "port_end": 3071, "slot": 0}Cuando ningún slot coincide: {"ok": true, "code": 200, "found": false, "public_ip": "XXX.XXX.XXX.10", "port": 2000}. Una public_ip no válida da 400 Invalid public_ip. La consulta refleja las asignaciones actuales; para momentos pasados use el registro de auditoría.
Anti-spoofing
Sección titulada «Anti-spoofing»Modos:
| Modo | Comportamiento |
|---|---|
strict |
Solo pasan los clientes registrados, fijados a su dirección. Los dispositivos no registrados siguen recibiendo DHCP (para que aparezcan en las listas de IP) pero nada más. Es el predeterminado. |
dynamic |
Los clientes registrados quedan fijados a su dirección, y a los dispositivos no registrados se les permite la dirección que les concedió el servidor DHCP. |
off |
Solo por VLAN: excluye esa VLAN. |
default |
Solo por VLAN: quita la excepción para que la VLAN siga el modo global. |
Cuando está habilitado, en cada VLAN que sirve el servidor DHCP se aplica el control en el modo global; una excepción por VLAN puede cambiar el modo, desactivar una VLAN o agregar una VLAN que el servidor DHCP no sirve (segmentos solo estáticos). Para IPv6, la dirección reservada de un cliente, su dirección DHCPv6 y su prefijo delegado se vinculan a su MAC; las direcciones link-local siempre pasan; un Router Advertisement o un Redirect enviado por un abonado se descarta. La suplantación entre abonados dentro de la misma VLAN nunca llega al router y debe detenerse con el split-horizon de la OLT.
GET /antispoof
Sección titulada «GET /antispoof»Qué se está aplicando: configuración global, modo por VLAN, cantidad de vinculaciones, contadores de descartes y el resumen de descartes de la última hora.
curl -H "X-API-Key: YOUR_API_KEY" http://ROUTER-IP:8880/antispoof{ "enabled": true, "mode": "strict", "log": true, "exempt": ["10.0.0.0/30"], "overrides": { "vlan200": "dynamic" }, "served": ["vlan100", "vlan200"], "enforced": { "vlan100": { "mode": "strict", "exists": true, "bindings4": 120, "bindings6": 118, "dropped": { "ip4": 42, "ip6": 3, "arp": 7 }, "clients": 120, "service": false, "leases": 0 } }, "switched_off": [], "live": { "v4_chain": true, "v4_rules": 240, "v4_forward": true, "v4_input": true, "v6_chain": true, "v6_rules": 236, "v6_forward": true, "v6_input": true }, "last_hour": { "attempts": 5, "devices": 1 }, "log_prefixes": ["DTVSOL_SPOOF:", "DTVSOL_ARPSPOOF:"]}POST /antispoof
Sección titulada «POST /antispoof»Envíe al menos uno de los campos; los demás conservan su valor. Deshabilitarlo elimina todas las reglas pero conserva la configuración.
| Nombre | En | Tipo | Notas |
|---|---|---|---|
enabled |
body | boolean | true/false (también 1/0, on/off, yes/no); cualquier otro valor da 400. |
mode |
body | string | strict o dynamic. |
log |
body | boolean | Registro en el log del kernel, con límite de frecuencia, de lo que se descartó. |
exempt |
body | string o array | Redes (CIDR) permitidas desde cualquier MAC en cada VLAN con control aplicado — por ejemplo, la dirección de relay o de gestión de una OLT. Separadas por comas o como array; un valor vacío borra la lista. |
curl -X POST http://ROUTER-IP:8880/antispoof \ -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \ -d '{"enabled": true, "mode": "strict", "exempt": "10.0.0.0/30"}'{ "ok": true, "code": 200, "message": "Anti-spoofing enabled", "apply": { "applied": true, "enabled": true, "bindings4": 120, "bindings6": 118 }, "status": { "enabled": true, "mode": "strict" }}message es uno de Anti-spoofing enabled (habilitado), Anti-spoofing updated (actualizado), Anti-spoofing disabled — rules removed (deshabilitado, reglas eliminadas), Anti-spoofing is off (está desactivado). status es la respuesta completa de GET /antispoof. Errores: 400 si no hay nada que establecer, un booleano incorrecto, un modo incorrecto o una red exenta no válida; 500 cuando no se pudieron aplicar las reglas (ok: false, con detalles en apply.errors).
POST /antispoof/{iface}
Sección titulada «POST /antispoof/{iface}»| Nombre | En | Tipo | Notas |
|---|---|---|---|
iface |
path | string | Nombre de la interfaz, p. ej. vlan100 (hasta 15 caracteres). Debe existir o ser servida por DHCP. |
mode |
body | string | strict, dynamic, off o default. |
curl -X POST http://ROUTER-IP:8880/antispoof/vlan100 \ -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \ -d '{"mode": "dynamic"}'{ "ok": true, "code": 200, "message": "vlan100 set to dynamic", "iface": "vlan100", "requested": "dynamic", "effective": "dynamic", "note": null, "apply": { "applied": true }}Cuando el anti-spoofing está desactivado globalmente, el modo se registra, apply es {"applied": false, "action": "feature off"} y note indica que entrará en vigor cuando se active el anti-spoofing. Errores: 400 nombre de interfaz o modo no válido; 404 la interfaz no existe y no es servida por DHCP.
DELETE /antispoof/{iface}
Sección titulada «DELETE /antispoof/{iface}»Igual que POST /antispoof/{iface} con mode default.
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" http://ROUTER-IP:8880/antispoof/vlan100{ "ok": true, "code": 200, "message": "vlan100 follows the default mode again", "iface": "vlan100", "requested": "default", "effective": "strict", "note": null, "apply": { "applied": true } }GET /antispoof/log
Sección titulada «GET /antispoof/log»Los paquetes descartados según el log del kernel, del más reciente al más antiguo, y los dispositivos que los causaron agrupados por VLAN + MAC + dirección de origen (primero los que tienen más descartes).
| Nombre | En | Tipo | Notas |
|---|---|---|---|
since |
query | string | 30m, 2h, 1d, 45s, o un momento como 2026-09-17 10:00. Predeterminado: una hora. |
limit |
query | integer | Cuántas entradas devolver, 1–500 (predeterminado 50). total siempre cuenta todas. |
curl -H "X-API-Key: YOUR_API_KEY" "http://ROUTER-IP:8880/antispoof/log?since=2h&limit=20"{ "ok": true, "code": 200, "enabled": true, "since": "2 hours ago", "total": 3, "offenders": [ { "iface": "vlan100", "mac": "AA:BB:CC:DD:EE:FF", "src": "100.64.0.9", "count": 3, "last": "2026-09-27T10:00:02+0000", "ip": 2, "arp": 1 } ], "entries": [ { "time": "2026-09-27T10:00:02+0000", "kind": "ip", "iface": "vlan100", "mac": "AA:BB:CC:DD:EE:FF", "src": "100.64.0.9", "dst": "100.64.0.1", "proto": "UDP", "dport": 53 }, { "time": "2026-09-27T10:00:01+0000", "kind": "arp", "iface": "vlan100", "mac": "AA:BB:CC:DD:EE:FF", "src": "100.64.0.9", "dst": "100.64.0.1", "op": "reply" } ]}Las entradas IP incluyen proto (los tipos ICMPv6 con nombre, p. ej. ICMPv6/RA) y dport; las entradas ARP incluyen op (request o reply). Un since incorrecto da 400.
POST /antispoof/sync
Sección titulada «POST /antispoof/sync»Normalmente no es necesario: cada cambio de cliente o de VLAN, y cada cambio de concesión DHCP, reconstruye las reglas automáticamente.
curl -X POST -H "X-API-Key: YOUR_API_KEY" http://ROUTER-IP:8880/antispoof/sync{ "ok": true, "code": 200, "message": "Anti-spoofing rules rebuilt", "applied": true, "enabled": true }Cuando el anti-spoofing está desactivado: "message": "Anti-spoofing is off; nothing to apply" (está desactivado; no hay nada que aplicar). 500 con ok: false cuando no se pudieron aplicar las reglas.
Equivalentes en la API de acciones
Sección titulada «Equivalentes en la API de acciones»Las mismas operaciones mediante GET /api?action=…, con todos los parámetros en la cadena de consulta (vea la API de acciones).
| Acción | Parámetros de consulta | Equivale a |
|---|---|---|
action=cgnat-status |
— | GET /cgnat |
action=cgnat-set |
enabled, iface, pool, port_min, port_max, block_size, exempt |
POST /cgnat |
action=cgnat-lookup |
public_ip, port |
GET /cgnat/lookup |
action=antispoof-status |
— | GET /antispoof |
action=antispoof-set |
enabled, mode, log, exempt |
POST /antispoof |
action=antispoof-iface |
iface, mode (strict, dynamic, off, default) |
POST /antispoof/{iface} |
action=antispoof-log |
since, limit |
GET /antispoof/log |
action=antispoof-sync |
— | POST /antispoof/sync |
Este sitio fue escrito con ayuda de IA y revisado por nuestro equipo.