API de CGNAT e anti-spoofing
Dois recursos de proteção de assinantes do DTVSOL Super Router:
- O CGNAT mapeia os endereços privados dos assinantes para um pool de endereços IPv4 públicos. Cada assinante recebe um slot fixo: um endereço público e um bloco fixo de portas nele. Como o mapeamento é determinístico, um endereço público e uma porta sempre podem ser rastreados até um único assinante (
/cgnat/lookup). As atribuições também são gravadas em um log de auditoria no roteador. - O anti-spoofing vincula o MAC de origem, o endereço IP e a VLAN de cada assinante. Em toda VLAN de acesso com a proteção aplicada, um pacote só é encaminhado quando o seu MAC e IP de origem formam um par que o roteador conhece, e um pacote ARP só quando o MAC e IP do remetente formam esse par. Todo o resto é descartado e registrado (com limite de taxa) com o MAC que o enviou.
Autenticação, formato de erro e códigos de status estão descritos na visão geral da API. Os mesmos recursos estão disponíveis na CLI como dtvsol cgnat … e dtvsol antispoof ….
GET /cgnat
Seção intitulada “GET /cgnat”A configuração do CGNAT, sua capacidade e uma amostra das atribuições atuais (as cinco primeiras).
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 é (port_max − port_min + 1) / block_size; capacity é pool_ips × subs_per_ip.
POST /cgnat
Seção intitulada “POST /cgnat”Altere qualquer subconjunto das configurações do CGNAT. Os campos que você omitir mantêm o valor atual; os padrões são port_min 1024, port_max 65535, block_size 2048.
| Nome | Em | Tipo | Observações |
|---|---|---|---|
enabled |
body | boolean | true/false (também 1/0, on/off, yes/no). Para ativar é preciso uma iface válida e existente e um pool não vazio. |
iface |
body | string | A interface WAN onde fica o pool público, por exemplo bond0. |
pool |
body | string or array | Endereços IPv4 públicos: endereços avulsos e faixas first-last, separados por vírgula ou como array. |
port_min |
body | integer | Primeira porta distribuída (padrão 1024). |
port_max |
body | integer | Última porta distribuída (padrão 65535). |
block_size |
body | integer | Portas por assinante (padrão 2048). |
exempt |
body | string or array | Redes (a.b.c.d/nn) que nunca passam por NAT, separadas por vírgula ou 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 é a resposta completa de GET /cgnat. Erros: 400 — Enable requires a valid WAN iface, Enable requires a non-empty public IP pool, Invalid exempt network: ….
GET /cgnat/lookup
Seção intitulada “GET /cgnat/lookup”Quem usava um endereço público e uma porta: o assinante cujo slot os cobre. Use para responder a denúncias de abuso e a solicitações de autoridades.
| Nome | Em | Tipo | Observações |
|---|---|---|---|
public_ip |
query | string | O endereço público visto de fora. Obrigatório. |
port |
query | integer | A porta de origem pública vista de fora. |
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}Quando nenhum slot corresponde: {"ok": true, "code": 200, "found": false, "public_ip": "XXX.XXX.XXX.10", "port": 2000}. Um public_ip inválido dá 400 Invalid public_ip. A consulta reflete as atribuições atuais; para momentos passados, use o log de auditoria.
Anti-spoofing
Seção intitulada “Anti-spoofing”Modos:
| Modo | Comportamento |
|---|---|
strict |
Só os clientes cadastrados passam, presos ao seu endereço. Dispositivos não cadastrados ainda recebem DHCP (e por isso aparecem nas listas de IP), mas nada além disso. É o padrão. |
dynamic |
Os clientes cadastrados ficam presos ao seu endereço, e dispositivos não cadastrados são permitidos no endereço que o servidor DHCP lhes concedeu. |
off |
Somente por VLAN: exclui essa VLAN. |
default |
Somente por VLAN: remove a exceção, e a VLAN volta a seguir o modo global. |
Quando ativado, toda VLAN atendida pelo servidor DHCP passa a ter a proteção aplicada no modo global; uma exceção por VLAN pode mudar o modo, desligar uma VLAN ou incluir uma VLAN que o servidor DHCP não atende (segmentos só com endereços estáticos). Para IPv6, o endereço reservado do cliente, o seu endereço DHCPv6 e o seu prefixo delegado ficam vinculados ao seu MAC; link-local sempre passa; um Router Advertisement ou Redirect vindo de um assinante é descartado. O spoofing entre assinantes dentro da mesma VLAN nunca chega ao roteador e precisa ser barrado pelo split-horizon da OLT.
GET /antispoof
Seção intitulada “GET /antispoof”O que está sendo aplicado: configurações globais, modo por VLAN, contagem de vinculações, contadores de descarte e o resumo de descartes da ú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
Seção intitulada “POST /antispoof”Envie pelo menos um dos campos; os outros mantêm o valor. Desativar remove todas as regras, mas mantém as configurações.
| Nome | Em | Tipo | Observações |
|---|---|---|---|
enabled |
body | boolean | true/false (também 1/0, on/off, yes/no); qualquer outro valor dá 400. |
mode |
body | string | strict ou dynamic. |
log |
body | boolean | Log do kernel, com limite de taxa, do que foi descartado. |
exempt |
body | string or array | Redes (CIDR) permitidas a partir de qualquer MAC em todas as VLANs com a proteção aplicada — por exemplo o endereço de relay ou de gerência de uma OLT. Separadas por vírgula ou um array; um valor vazio limpa a 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 é um de Anti-spoofing enabled, Anti-spoofing updated, Anti-spoofing disabled — rules removed, Anti-spoofing is off. status é a resposta completa de GET /antispoof. Erros: 400 quando não há nada para definir, para um booleano inválido, um modo inválido ou uma rede de exceção inválida; 500 quando as regras não puderam ser aplicadas (ok: false, detalhes em apply.errors).
POST /antispoof/{iface}
Seção intitulada “POST /antispoof/{iface}”| Nome | Em | Tipo | Observações |
|---|---|---|---|
iface |
path | string | Nome da interface, por exemplo vlan100 (até 15 caracteres). Precisa existir ou ser atendida por DHCP. |
mode |
body | string | strict, dynamic, off ou 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 }}Quando o anti-spoofing está desligado globalmente, o modo é gravado, apply é {"applied": false, "action": "feature off"} e note diz que ele entra em vigor quando o anti-spoofing for ligado. Erros: 400 nome de interface ou modo inválido; 404 a interface não existe e não é atendida por DHCP.
DELETE /antispoof/{iface}
Seção intitulada “DELETE /antispoof/{iface}”O mesmo que POST /antispoof/{iface} com 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
Seção intitulada “GET /antispoof/log”Pacotes descartados, lidos do log do kernel, os mais recentes primeiro, e os dispositivos que os causaram, agrupados por VLAN + MAC + endereço de origem (os com mais descartes primeiro).
| Nome | Em | Tipo | Observações |
|---|---|---|---|
since |
query | string | 30m, 2h, 1d, 45s, ou um horário como 2026-09-17 10:00. Padrão: uma hora. |
limit |
query | integer | Quantas entradas retornar, 1–500 (padrão 50). total sempre conta 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" } ]}As entradas de IP trazem proto (tipos ICMPv6 com nome, por exemplo ICMPv6/RA) e dport; as entradas de ARP trazem op (request ou reply). Um since inválido dá 400.
POST /antispoof/sync
Seção intitulada “POST /antispoof/sync”Normalmente não é necessário: toda alteração de cliente ou de VLAN, e toda mudança de concessão DHCP, reconstrói as regras automaticamente.
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 }Quando o anti-spoofing está desligado: "message": "Anti-spoofing is off; nothing to apply". 500 com ok: false quando as regras não puderam ser aplicadas.
Equivalentes na API de ações
Seção intitulada “Equivalentes na API de ações”As mesmas operações por GET /api?action=…, com todos os parâmetros na query string (veja a API de ações).
| Ação | 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 site foi escrito com a ajuda de IA e revisado pela nossa equipe.