🛡️ Framework de Redes - Análise Didática Avançada
Versão Java/Quarkus (
framework-net-java-quarkus) — Java 25 + Quarkus 3.37.
Migração do projeto original Python/Flask. Esta documentação é renderizada dentro da própria aplicação em
/documentacao.
Aplicação didática para análise de redes IPv4/IPv6, com foco em ensino, laboratório e revisão técnica. Originalmente escrita em Python/Flask, foi migrada para Java 25 + Quarkus e reorganizada como um monólito modular (*modular monolith*): um único artefato de implantação com domínios autocontidos, prontos para evoluir para microserviços. Reúne sete módulos:
- Análise Didática — CIDR, máscara, wildcard, auto-CIDR, domínio (DNS), IPv6, comparador e GeoIP.
- Calculadora de Sub-redes e VLANs — divisão de blocos (FLSM), plano de VLANs com script Cisco, sumarização de rotas e faixa de IPs para CIDR.
- Portas — catálogo interativo de portas TCP/UDP.
- Protocolos — catálogo de protocolos + troubleshooting de roteamento.
- Resolução de Problemas (VLSM + WAN) — planejamento VLSM dinâmico, topologia WAN, CLI Cisco e exportação para laboratório.
- Telemetria — dashboard de eventos e console ao vivo (server-side).
- Documentação — este README renderizado.
Repositório: https://github.com/carmipa/framework-net-java-quarkus
📚 Sumário
| # | Seção | O que responde |
|---|---|---|
| 1 | Visão geral | para que serve e a quem atende |
| 2 | Módulos e rotas | tabela completa de endpoints, métodos e proteção |
| 3 | Funcionalidades | Análise Didática · Calculadora de Sub-redes e VLANs · Portas/Protocolos · Resolução VLSM+WAN |
| 4 | Arquitetura | 9 diagramas: fluxo geral, Calculadora, camadas de proteção, cache em 2 níveis, VLSM, telemetria, shared, exceções, deploy |
| 5 | Requisitos | Java, Gradle, Docker |
| 6 | Execução | local (quarkusDev) e VPS (deploy.sh) |
| 7 | Configuração | todas as framework.* e as quarkus.* relevantes |
| 8 | Segurança | CSRF, chave admin, rate limit, CSP/SRI, fail-closed de segredos |
| 9 | Telemetria | correlação por traceId, OTLP/JSON e dataset público sanitizado |
| 10 | Estrutura de pastas | onde mora cada coisa |
| 11 | Testes | incluindo os que guardam regras (arquitetura, cobertura de menu, CSP) |
| 12 | Roadmap | o que falta |
🎯 Visão Geral
O framework cobre um fluxo didático completo para aula, laboratório e revisão técnica:
- cálculo de rede/broadcast/hosts úteis;
- decomposição binária e tabela AND por octeto;
- conversão entre CIDR, máscara e wildcard;
- resolução de domínio (DNS) com cache e timeout;
- geolocalização de IP (GeoIP MaxMind, opcional);
- classificação e contexto de risco/GRC;
- geração automática de cenário de laboratório (VLSM, links WAN com prefixo configurável, CLI Cisco e exportação para laboratório ou entrega acadêmica em
.txt/.zip).
🧭 Módulos e Rotas
| Módulo | Rota | Método | Descrição |
|---|---|---|---|
| Início | / | GET | Página inicial (landing) com atalhos para os módulos |
| Análise Didática | /analise | GET/POST | CIDR, máscara, wildcard, auto-CIDR, domínio, IPv6, comparador, calculadora (parâmetro ?tab=) |
| Calculadora | /calculadora | GET | Divisão de blocos, plano de VLANs, sumarização e faixa→CIDR (parâmetro ?aba=) |
| Calculadora (API) | /calculadora/api/dividir | POST | Fragmento HTML: sub-redes de um bloco + matriz de capacidade |
| Calculadora (API) | /calculadora/api/vlan, /calculadora/api/vlan-id | POST | Fragmento HTML: plano de VLANs com CLI Cisco / parecer sobre um VLAN ID |
| Calculadora (API) | /calculadora/api/sumarizar, /calculadora/api/comparar, /calculadora/api/faixa | POST | Fragmento HTML: rota resumo, relação entre blocos, faixa em CIDR |
| Calculadora (export) | /calculadora/export/divisao.csv, /calculadora/export/vlan.csv | GET | CSV do plano exibido |
| Localização | /localizacao | GET | Localização por IP e por CEP no mapa |
| Localização (API) | /localizacao/api/ip, /localizacao/api/cep | GET | JSON: geolocalização por IP / endereço por CEP (ViaCEP + OSM) |
| Tráfego | /trafego | GET | Sub-abas: painel ao vivo (simulação), decodificador (hex), encapsulamento e handshake TCP |
| Tráfego (API) | /trafego/api/decodificar | POST | JSON: camadas Ethernet/IP/TCP/UDP/ICMP decodificadas |
| Tráfego (API) | /trafego/api/aovivo | GET | JSON: snapshot do painel ao vivo (simulação demo) |
| Simuladores (API) | /simuladores/api/encapsular | POST | JSON: encapsulamento camada a camada (App→Enlace) |
| Simuladores (API) | /simuladores/api/handshake | GET | JSON: sequência do handshake TCP (?dados=&encerramento=) |
| GeoIP | /informacoes | GET | Página de geolocalização (?ip=) |
| GeoIP (API) | /api/informacoes/geo | GET | JSON de geolocalização (?ip=) |
| Referência de máscaras | /mascara-referencia | GET | Tabela JSON de máscaras/prefixos |
| Portas | /portas | GET | Catálogo interativo TCP/UDP |
| Protocolos | /protocolos | GET | Catálogo + troubleshooting de roteamento (aba Geral) |
| Protocolos — BGP | /protocolos/bgp | GET | Aprofundamento do BGP-4: atributos, seleção de melhor rota, sessão, proteções da borda |
| Protocolos — SSH | /protocolos/ssh | GET | Aprofundamento do SSH: camadas, autenticação, chaves, túneis, hardening |
| Resolução VLSM | /resolucao-problemas | GET/POST | Aba Projetar: cenários VLSM/WAN, demos e exportações |
| Resolução — reversa | /resolucao-problemas?aba=reversa | GET/POST | Aba Engenharia reversa: interpreta configuração Cisco colada, audita, corrige e reconstrói o projeto |
| Páginas de erro | qualquer rota que falhe | — | Página única em paginaErros/erro.html servindo os 12 códigos (400…504) |
| Telemetria | /telemetria | GET | Dashboard de eventos e console |
| Telemetria (API) | /telemetria/api/* | GET/POST | resumo, dashboard, console, console/limpar, exportar, pasta |
| Documentação | /documentacao | GET | Este README renderizado |
| Sobre | /sobre | GET | O projeto, o autor e as tecnologias |
| Sonda de saúde | /health | GET | JSON {"status":"UP"} para o healthcheck do container; não registrada na telemetria |
| Histórico (API) | /history | GET | Lista o histórico em JSON |
| Histórico catálogo | /history/catalog | POST | Registra consulta de portas/protocolos |
| Exportação análise | /export/json, /export/pdf | GET | 🔒 Protegido por chave administrativa |
| Login administrativo | /admin/login, /admin/logout | GET/POST | Autenticação para rotas sensíveis |
🚀 Funcionalidades
Módulo 1 — Análise Didática (/)
Selecionável via ?tab= (ou pelas abas da interface):
cidr— IP +/barra;mask— decomposição por máscara decimal;wildcard— engenharia reversa com base ACL/OSPF;autoip— inferência didática de CIDR pelo IP;dominio— hostname/URL → DNS → análise;ipv6— visão básica com resumo técnico;comparador— comparação lado a lado entre dois prefixos;calculadora— divisão rápida de um bloco em sub-redes, servida pelo módulo Calculadora via htmx.
Recursos de apoio: geolocalização (/informacoes), tabela de referência de máscaras (/mascara-referencia), histórico paginado e exportações (/export/json, /export/pdf).
Módulo 2 — Calculadora de Sub-redes e VLANs (/calculadora)
Ferramenta de bolso para plano de endereçamento — complementa o Módulo 4 (VLSM), que
resolve o cenário completo com WAN e roteamento. Aqui a resposta é imediata, em
sub-redes de tamanho fixo (FLSM). Quatro abas, selecionáveis via ?aba=:
dividir — divisão de blocos. Responde a pergunta clássica: *um /21, quantas
redes cabem?* Três critérios de entrada:
| Critério | Entrada | Exemplo |
|---|---|---|
| Por prefixo alvo | prefixo desejado | 192.168.0.0/21 → /24 = 8 sub-redes de 254 hosts |
| Por nº de sub-redes | quantas você precisa | pedir 6 entrega 8 (potências de 2), com a sobra declarada |
| Por hosts | hosts por sub-rede | 500 hosts → /23 (reserva rede e broadcast: 502 endereços) |
Acompanha a matriz de capacidade, que responde todos os prefixos de uma vez
(/22→2, /24→8, /26→32, /30→512), e exportação em CSV.
vlan — plano de VLANs. Gera o mapa VLAN ↔ sub-rede com gateway (SVI), faixa
DHCP e wildcard para ACL, mais o script Cisco pronto (vlan/name, portas de acesso,
tronco 802.1Q com switchport trunk allowed vlan, SVI e router-on-a-stick,
ip dhcp pool). Duas estratégias de mapeamento: sequencial (blocos consecutivos)
ou VLAN ID no 3º octeto (VLAN 10 → 192.168.10.0/24, a convenção de prova; exige
bloco base /16 e /24 por VLAN). Inclui validador de VLAN ID com as faixas do
padrão: 0 e 4095 reservados pelo 802.1Q, 1 default, 2–1001 normal range, 1002–1005
reservadas pela Cisco (FDDI/Token Ring) e 1006–4094 extended range.
agregar — sumarização e comparação. Calcula a rota resumo (menor prefixo que
cobre todas as redes informadas) com os comandos de area range (OSPF),
ip summary-address (EIGRP), rota estática e ACL — declarando quanto espaço extra a
agregação arrasta. E compara dois blocos: iguais, contido ou disjuntos, com os
endereços em comum.
faixa — faixa de IPs para CIDR. Converte "de 10.0.0.5 até 10.0.3.200" na
menor lista de blocos CIDR que cobre exatamente a faixa, com a ACL equivalente.
Tetos de renderização. Um
/8dividido em/30são 4.194.304 sub-redes. A tela
lista no máximo
framework.calculadora.max-linhas(padrão 512), mas o total
matemático real continua sendo exibido, com aviso explícito de truncamento — listagem
truncada nunca é apresentada como plano completo.
Módulo 3 — Portas (/portas) e Protocolos (/protocolos)
- catálogo didático com filtros;
- resumo IGP/EGP e bloco Troubleshooting rápido (roteamento) na página de protocolos;
- registro opcional das consultas no histórico via
/history/catalog.
Aprofundamentos por protocolo
O catálogo responde *quais protocolos existem e como se comparam*; ele não responde
*me explica este protocolo*. Para isso o módulo tem um segundo nível: uma página
dedicada por protocolo, alcançável pelo sub-menu (Geral · BGP · SSH) e pelo botão
Aprofundar na linha correspondente do DataGrid.
| Página | Rota | Conteúdo |
|---|---|---|
| BGP-4 | /protocolos/bgp | AS/ASN, eBGP × iBGP, atributos de caminho, ordem completa de seleção de melhor rota, máquina de estados da sessão, mensagens e temporizadores, route reflector e confederação, filtros de prefixo, maximum-prefix, RPKI/ROV, GTSM, dampening, blackhole RFC 7999, laboratório Cisco e troubleshooting |
| SSH | /protocolos/ssh | Autenticação de host × de usuário, TOFU e known_hosts, forward secrecy, as três camadas do SSH-2, métodos de autenticação, tipos de chave (incl. FIDO2), túneis -L/-R/-D/-J/-A, endurecimento do sshd_config, laboratório e troubleshooting |
Como isso é montado:
AprofundamentoProtocolo(protocolos/domain) é o registro único: slug, rótulo,
ícone, template, CSS e os nomes que aquele aprofundamento cobre no catálogo. É ele que
gera o sub-menu, a rota e o botão "Aprofundar" — nenhum desses pontos é escrito à mão
no template.
- Conteúdo em JSON (
resources/protocolos/<slug>/conteudo.json), carregado uma vez
no boot e falha fechada: seção obrigatória vazia impede a aplicação de subir, porque
página pela metade em produção passa despercebida.
- Uma página, um CSS:
META-INF/resources/protocolos/<slug>/css/<slug>.css. O
sub-menu, comum às três páginas, fica em protocolos/css/subnav.css.
- Rotas no mesmo resource (
ProtocolosResource), de propósito: o projeto já viu dois
@Path sob o mesmo prefixo derrubarem uma rota para 404 no módulo de Tráfego.
- Telemetria: cada visita emite
aprofundamento_viewno móduloprotocolos, com o
campo protocolo, o que separa "abriu o catálogo" de "abriu o aprofundamento".
- Guardas (
AprofundamentoProtocoloTest): registro apontando para arquivo inexistente
reprova o build; página em disco fora do registro (órfã, no ar e sem link) reprova;
nome divergente do catálogo — que faria o botão "Aprofundar" sumir calado — reprova.
Para adicionar o próximo protocolo: um conteudo.json, um template, um CSS e uma linha
no registro.
Páginas de erro (org.framework.net.paginaErros)
Qualquer falha não tratada devolve a página do Framework no lugar da tela padrão do servidor:
mesmo desenho command-center, texto em português, trace_id real e atalhos de volta.
Um template serve os 12 códigos (400, 401, 403, 404, 405, 409, 422, 429, 500, 502, 503,
504). O estado vem da classe do <body> (err-404, err-500…), e o CSS deriva dela a cor de
acento, a aura e a cor da chuva Matrix — não há CSS duplicado por código. Código fora do
catálogo cai no representante da família (4xx → 400, resto → 500); nunca em tela branca.
| Peça | Onde |
|---|---|
| Textos dos 12 estados | paginaErros/domain/CatalogoErros.java |
| Montagem + telemetria | paginaErros/application/PaginaErroService.java |
| Interceptação | paginaErros/presentation/PaginaErroMapper.java |
| Template | templates/paginaErros/erro.html |
| Estáticos | META-INF/resources/paginaErros/{css,js} |
Invariantes que o código sustenta:
- HTML para gente, JSON para máquina. A página só sai quando o cliente pede
text/html
e a rota não é de API. Devolver HTML num fetch() quebraria o response.json() do
frontend com um erro que não diz nada — é o tipo de defeito que só aparece em produção.
- Resposta já formatada por outro componente é preservada (o 429 do
RateLimitFilter,
por exemplo). O mapper não reescreve mensagem que outro componente escolheu dar.
- Nada de interno na tela. Nome de classe, mensagem de exceção e stack não vão para a
página pública; o que liga o usuário ao diagnóstico é o trace_id, o mesmo registrado na
telemetria. Há teste que reprova hint contendo org.framework ou nome de exceção.
- O
trace_idé real ou é declarado indisponível — jamais gerado na hora só para
preencher o campo, o que simularia uma rastreabilidade inexistente.
- A página de erro não pode gerar erro: falha ao renderizar o template cai para texto
simples com o mesmo status, em vez de recursão.
noindexno<head>, para que tela de erro não entre em buscador.- Animação Matrix respeita
prefers-reduced-motione lê a cor de--accentem tempo de
execução, acompanhando o estado sem uma linha de cor no JavaScript.
Módulo 4 — Resolução de Problemas (VLSM + WAN) (/resolucao-problemas)
O módulo tem duas abas, que são o mesmo problema em sentidos opostos:
| Aba | Rota | Vai de | Para |
|---|---|---|---|
| Projetar | /resolucao-problemas | requisitos (localidades e hosts) | plano VLSM, WAN, roteamento, scripts |
| Engenharia reversa | /resolucao-problemas?aba=reversa | configuração Cisco pronta | erros apontados e corrigidos + o mesmo plano reconstruído |
Aba "Engenharia reversa"
O aluno cola a configuração que recebeu — normalmente com erro — e o botão Executar
devolve, na mesma tela: a auditoria linha a linha, os scripts corrigidos, as LANs, os
enlaces ponto a ponto, as tabelas por roteador e o desenho da topologia. O botão
Imprimir é separado do Executar: um faz o trabalho, o outro só manda a tela para o papel.
O algoritmo. As declarações neighbor <ip> remote-as <as> formam um sistema
sobredeterminado: cada roteador declara onde o *outro* está. Se SP diz que RJ mora em
.2, então RJ tem de possuir .2. Quando não possui, o erro não é apenas detectado — fica
localizado, e a correção sai do próprio texto colado. É isso que separa correção de
palpite.
Três classes de achado, e a classe decide o que a tela faz:
| Classe | O que acontece |
|---|---|
| Erro corrigido | corrige e mostra *antes → depois* com a evidência que sustenta a correção |
| Erro sem correção automática | aponta e para. Escolher sem evidência seria adivinhar |
| Aviso | não impede o cenário (no auto-summary ausente, interface sem no shutdown) |
O que o interpretador entende: hostname; interfaces (incl. abreviadas e loopback) com
ip address/máscara, no shutdown, clock rate (identifica o lado DCE), description,
encapsulation dot1Q; router bgp com neighbor/remote-as/network mask; router ospf
com network + wildcard + area; router eigrp; router rip; e ip route. A palavra
network é lida pelo contexto do bloco router, porque tem três gramáticas diferentes.
Invariantes que o código sustenta:
- nenhuma linha é engolida — o que o interpretador não usou aparece numa lista com
número e motivo; parser silencioso desenha errado com cara de certo;
- o texto do usuário nunca é sobrescrito — o script corrigido é material novo, ao lado;
- cada linha alterada sai marcada com
! CORRIGIDO:dentro do próprio script, porque
configuração corrigida sem marca vira comando aplicado às cegas no equipamento;
- o que falta vira pendência, não invenção — AS declarado como vizinho e não colado é
listado com a instrução de colar aquele script;
- o resultado não depende da ordem em que os scripts foram colados (há teste de
regressão para isso: dois erros espelhados só se resolvem se a colisão for medida contra
o que os outros scripts *corroboram*, não contra o que um roteador meramente declarou).
Caso de referência (é o teste EngenhariaReversaServiceTest): três AS em eBGP com
ip adress escrito errado nove vezes, máscara de cinco octetos em três anúncios e duas
interfaces com o endereço trocado. A ferramenta corrige as catorze ocorrências, e a
confirmação de que a correção é a certa é que o clock rate passa a cair **exatamente uma
vez por enlace** — três sinais independentes convergindo.
- entrada dinâmica com N localidades (nome + quantidade de hosts — o sistema calcula o CIDR pela fórmula
2^H ≥ N+2→ prefixo32−H); - obrigatório: IP/rede base e localidades; opcional: CIDR da base (inferência classful se vazio), AS EIGRP (padrão
71), processo OSPF (padrão1); - prefixo WAN configurável (padrão
/30para enlaces ponto a ponto, faixa0–30); - topologias WAN:
star,extended_star,mesh,ringering_redundant(aceita também os aliasesestrelaeestrela_estendida); - roteamento EIGRP/OSPF por distribuição (
eigrp_only,ospf_only, metade/metade,auto); - acesso remoto VTY: Telnet (padrão, com
transport input telnet), SSH ou ambos; - diagrama de topologia interativo no navegador;
- demos na URL:
?demo=gs(Global Solution Mazola),?demo=fiap,?demo=8,?demo=1; - exportações após calcular (recalculam o cenário e baixam o arquivo).
Exportações
Ação (action_type) | Arquivo | Conteúdo |
|---|---|---|
export | config_packet_tracer_consolidado.txt | scripts IOS consolidados |
export_zip | laboratorio_packet_tracer.zip | guia de montagem, configs por roteador, README |
export_entrega | documentacao_cenario_rede.txt | relatório completo para disciplina |
export_class_zip | pacote_turma_packet_tracer.zip | pacote por aluno (por_aluno/<aluno>/) |
Importar turma (Excel)
Cole na página de Resolução (TAB entre colunas):
Nome | Rede base | Hosts1 | Hosts2
🏗️ Arquitetura
Estilo arquitetural: monólito modular (*modular monolith*) em Java 25 + Quarkus, migrado do projeto original em Python/Flask. A aplicação é implantada como um único artefato (Quarkus fast-jar), mas o código é organizado por domínios autocontidos (*bounded contexts*) — cada módulo funciona como um "microserviço interno", com fronteiras claras e baixo acoplamento, pronto para ser extraído para um serviço independente caso o projeto evolua nesse sentido.
- Runtime único: endpoints JAX-RS (
quarkus-rest) e views em Qute (quarkus-rest-qute) sobrequarkus-vertx-http. - Módulos de domínio:
analiseDidatica,calculadora,portas,protocolos,resolucaoProblemas,localizacao,analiseTrafego,ferramentasDiagnostico,segurancaRede,simuladores(encapsulamento e handshake TCP — computação pura, VPS-safe). - Módulos transversais:
security(CSRF, rate limit, chave admin),telemetria(observabilidade),web(documentação, login, ícone) eshared(sanitização e utilitários de entrada).
Camadas por módulo (organização DDD-lite / hexagonal)
Cada domínio de negócio segue a mesma separação de responsabilidades:
| Camada | Responsabilidade | Exemplos |
|---|---|---|
presentation | Endpoints JAX-RS (@Path) e binding com templates Qute | AnaliseDidaticaResource, ResolucaoProblemasResource |
application | Casos de uso / serviços de orquestração | HomeAnaliseService, VlsmService, export/, planning/, routing/ |
domain | Regras de negócio puras (kernel + modelos) | Ipv4Kernel, domain/model |
infrastructure | Integrações externas e persistência | dns/, geo/ (MaxMind), historico/ |
support / config / exception | Apoio à UI, configuração e mapeamento de erros | AnaliseDidaticaUiSupport, DnsConfig, *ExceptionMapper |
Ordem real dos filtros JAX-RS (prioridade): TelemetriaRequestFilter → CsrfRequestFilter → AdminApiKeyFilter → RateLimitFilter → Resource.
Módulos em presentation:
| Pacote | Resources principais |
|---|---|
analiseDidatica | /, /informacoes, /api/informacoes/geo, /mascara-referencia, /history, /export/* |
resolucaoProblemas | /resolucao-problemas |
portas / protocolos | /portas, /protocolos |
telemetria | /telemetria, /telemetria/api/* |
web | /documentacao, /admin/*, /icone.png |
Fluxo do módulo VLSM/WAN
Fluxo de telemetria (server-side)
Utilitários transversais (shared)
Entrada do usuário passa por utilitários compartilhados antes dos services de domínio, reduzindo risco de injeção, IPs privados/reservados e formatos inválidos.
| Classe | Uso principal |
|---|---|
UserInputSanitizer | Nomes de localidade, roster da turma, labels Mermaid |
IpCidrInputNormalizer | Separação e normalização de IP + CIDR na análise e resolução |
NetworkAddressGuard | Bloqueio de hostnames reservados e endereços não públicos no DNS |
Tratamento de exceções (ExceptionMapper)
Cada módulo de domínio possui um @Provider JAX-RS que converte exceções tipadas em respostas HTTP seguras e registra o evento na telemetria.
| Mapper | Exceção | Status típico |
|---|---|---|
AnaliseDidaticaExceptionMapper | EntradaInvalidaException | 400 |
AnaliseDidaticaExceptionMapper | DnsResolucaoException | 500 |
PortasExceptionMapper | PortasException | conforme tipo |
ProtocolosExceptionMapper | ProtocolosException | conforme tipo |
ResolucaoProblemasExceptionMapper | EntradaInvalidaException / ResolucaoProblemasException | 400 / 500 |
Páginas HTML (Qute) tratam erros de validação inline no Resource (
erro+invalidFieldsno template), sem passar pelo mapper — os mappers cobrem principalmente respostas JSON e falhas de domínio não capturadas.
Deploy Docker (build multi-stage → runtime)
| Etapa | Detalhe |
|---|---|
| Build | eclipse-temurin:25-jdk-noble → ./gradlew build -x test com -Dquarkus.package.jar.type=fast-jar -Dquarkus.profile=prod |
| Runtime | registry.access.redhat.com/ubi9/openjdk-25-runtime — usuário 185, healthcheck em /health |
| Volume | framework-net-data:/deployments/data — logs, GeoIP e dados da aplicação |
| Env obrigatórias (prod) | ADMIN_API_KEY, CSRF_SECRET, QUARKUS_PROFILE=prod |
| Rede (VPS) | nginx-proxy-network (externa) + bind 127.0.0.1:${HTTP_PORT}:8080 |
| Dev Docker | docker-compose.dev.yml — dados em ./docker-data, porta padrão 8081 |
Calculadora de Sub-redes e VLANs — fluxo
Dois pontos de entrada, um serviço: a aba em /analise e a página /calculadora
chamam o mesmo endpoint e recebem o mesmo fragmento Qute renderizado no servidor.
Tetos de renderização (framework.calculadora.*) ficam entre o serviço e o
fragmento: o total matemático é sempre calculado, mas a listagem é truncada e o
truncamento é declarado na tela.
Camadas de proteção da requisição
Cada filtro assume que o anterior falhou. A ordem importa: a telemetria abre a
correlação antes de tudo, e o rate limit fecha a fila antes de o recurso ser tocado.
No boot, SegredosObrigatoriosVerificador recusa iniciar em produção sem
ADMIN_API_KEY/CSRF_SECRET — antes, a variável ausente desligava a proteção em
silêncio.
Cache de APIs externas em dois níveis
O L2 existe porque o L1 morre a cada deploy e as origens têm limite —
ip-api.com corta em 45 req/min. Redis indisponível faz o L2 se comportar como
miss permanente: volta ao comportamento de antes, sem quebrar nada.
✅ Requisitos
- JDK 25
- Gradle (wrapper incluído —
gradlew/gradlew.bat) - Docker (opcional, para deploy)
Dependências principais (build.gradle): quarkus-rest, quarkus-rest-jackson, quarkus-rest-qute, quarkus-qute, quarkus-cache, quarkus-vertx-http, com.github.seancfoley:ipaddress:5.5.1, com.maxmind.geoip2:geoip2:4.2.0.
▶️ Execução
Java / Quarkus local
Windows PowerShell:
.\gradlew.bat quarkusDev
Linux/macOS:
./gradlew quarkusDev
Aplicação em http://localhost:8080. Em modo dev, o navegador abre automaticamente quando %dev.framework.dev.open-browser=true.
Docker (VPS)
docker compose -f docker-compose.yml up -d --build
O perfil prod (QUARKUS_PROFILE=prod) habilita proxy reverso e grava dados persistentes em /deployments/data. É obrigatório definir ADMIN_API_KEY e CSRF_SECRET (ver .env.example / docker-compose.yml).
Parar:
docker compose -f docker-compose.yml down
⚙️ Variáveis de Configuração
As chaves são definidas em application.properties (dev) e application-prod.properties (deploy), podendo ser sobrescritas por variáveis de ambiente.
Aplicação
| Propriedade | Padrão | Descrição |
|---|---|---|
quarkus.http.port | 8080 | Porta HTTP |
quarkus.http.host | 0.0.0.0 | Host de bind |
framework.app.max-history | 60 | Tamanho máximo do histórico |
framework.calculadora.max-linhas | 512 | Sub-redes renderizadas por divisão. O total real continua sendo calculado e exibido — o teto evita travar o navegador (um /8 em /30 são 4.194.304) |
framework.calculadora.max-vlans | 256 | VLANs geradas por plano |
framework.calculadora.max-redes-agregacao | 64 | Redes aceitas por sumarização |
framework.app.comparador-cidr-padrao-a | 20 | CIDR padrão do comparador (A) |
framework.app.comparador-cidr-padrao-b | 24 | CIDR padrão do comparador (B) |
framework.dns.cache-ttl-seconds | 180 | TTL do cache DNS |
framework.dns.resolve-timeout-seconds | 3 | Timeout de resolução DNS |
framework.geo.cache-ttl-seconds | 300 | TTL do cache GeoIP |
framework.geo.database-path | geo/GeoLite2-City.mmdb | Base MaxMind (opcional) |
framework.dev.open-browser | true (dev) | Abre navegador no quarkusDev |
Telemetria
| Propriedade | Padrão | Descrição |
|---|---|---|
framework.logs.base-dir | logs | Pasta de logs/exportações |
framework.telemetry.enabled | true | Habilita coleta |
framework.telemetry.dashboard-enabled | true | Habilita a página /telemetria |
framework.telemetry.max-events | 5000 | Eventos em buffer |
framework.telemetry.jsonl-max-bytes | 10485760 | Limite do JSONL ativo antes de manter uma única geração anterior |
Segurança
| Propriedade | Padrão (dev) | Descrição |
|---|---|---|
framework.security.csrf-enabled | true | Proteção CSRF |
framework.security.csrf-secret | *(dev)* | Segredo do token CSRF — trocar em prod (CSRF_SECRET) |
framework.security.sensitive-apis-enabled | true | Habilita APIs sensíveis |
framework.security.rate-limit-enabled | true | Habilita rate limiting |
framework.security.rate-limit-per-minute | 120 | Limite geral por minuto |
framework.security.rate-limit-heavy-per-minute | 30 | Limite de rotas pesadas |
framework.security.admin-api-key | *(dev)* | Chave admin — em prod via ADMIN_API_KEY |
framework.security.admin-api-key-required | true | Exige chave nas rotas protegidas |
Variáveis de ambiente (deploy Docker)
HTTP_PORT(padrão8080) — porta publicada no host;ADMIN_API_KEY— obrigatória em prod; gere uma vez e mantenha no.envda VPS;CSRF_SECRET— obrigatória em prod; gere uma vez e mantenha no.envda VPS;GEO_DB_HOST_PATH— caminho doGeoLite2-City.mmdbno host (opcional);QUARKUS_PROFILE=prod.
Comandos seguros de deploy na VPS:
cd /opt/framework-net-java-quarkus
git pull origin main
test -f .env || cp .env.example .env
docker compose up -d --build
docker compose ps
docker compose logs --tail=20 -f
Deploy automatizado:
cd /opt/framework-net-java-quarkus
chmod +x scripts/deploy.sh
scripts/deploy.sh
🔐 Segurança
- Chave administrativa — rotas sob o prefixo
/exportsão protegidas. O acesso é liberado por: - header
X-Admin-Api-Key: <chave>, ou - cookie
ADMIN_API_KEYobtido via login em/admin/login. - A exigência só é ativada quando
admin-api-key-required=truee a chave está configurada; a comparação usa tempo constante. - CSRF — filtros de request/response emitem e validam token para operações sensíveis.
- Rate limiting — limites por minuto configuráveis (geral e rotas pesadas).
- Headers HTTP de segurança —
X-Content-Type-Options: nosniff,X-Frame-Options: SAMEORIGIN,Referrer-Policy: strict-origin-when-cross-origin,Permissions-Policyrestritiva. - Sanitização de entrada —
UserInputSanitizer,IpCidrInputNormalizereNetworkAddressGuardno pacoteshared.
📋 Telemetria e Observabilidade (Server-Side)
A telemetria é orientada a servidor e possui dashboard próprio em /telemetria.
Implementado:
request_idetrace_idpor requisição (viaTelemetriaRequestFilter+ MDC);- eventos estruturados (
TelemetriaLogger.logEvent/logException); - buffer em memória + arquivo compartilhado (
TelemetriaStore); - console ao vivo e exportação JSON (
/telemetria/api/exportar); - logs em console e arquivo com rotação (
quarkus.log.file.*); - a sonda
/healthdo container não é registrada — antes o healthcheck consultava
/ a cada 30 s (~2.880 acessos/dia) e era indistinguível de visitas reais.
Correlação dos eventos de negócio
Serviços de aplicação chamam TelemetriaLogger.medir() sem ter o
ContainerRequestContext do JAX-RS em mãos. A correlação é então resgatada do MDC
da própria thread da requisição (TelemetriaContext.contextoDoMdc()), de modo que todo
evento nascido dentro de um request carrega traceId e requestId.
Isso importa porque um único incidente rende mais de um evento — a operação de negócio
que falhou, a exceção mapeada e o acesso HTTP. Agrupe por traceId para contar
incidentes em vez de linhas. Eventos nascidos fora de requisição (app_start, tarefas
de fundo) seguem sem correlação, e isso é o valor honesto: correlação fabricada seria
pior que correlação ausente.
Formato de compartilhamento: OpenTelemetry OTLP/JSON
Os artefatos compartilháveis seguem o OpenTelemetry Logs Data Model serializado em OTLP/JSON — o padrão da indústria para interoperar telemetria com Grafana, Loki, Jaeger, Datadog, SIEMs, etc.
| Artefato | Formato | Descrição |
|---|---|---|
logs/telemetria_compartilhada.json | OTLP LogsData | Documento canônico (resourceLogs → scopeLogs → logRecords) |
logs/framework-net-eventos.jsonl | NDJSON de LogRecord OTLP | Stream append (um LogRecord por linha) |
GET /telemetria/api/exportar | OTLP LogsData | Download do documento canônico |
Mapeamento (TelemetriaOtlpMapper): timeUnixNano/intValue como *string* (int64 conforme OTLP/JSON), severityNumber/severityText (INFO=9, WARN=13, ERROR=17), traceId/spanId em hexadecimal, e atributos com convenções semânticas (service.name, http.request.method, http.route, http.response.status_code, event.name) + atributos próprios em framework.*.
As APIs internas do dashboard (
/telemetria/api/resumoe/telemetria/api/dashboard) permanecem no schema próprio de UI — o OTLP é usado nos artefatos de exportação/compartilhamento.
Coleta recomendada em produção: docker logs / compose logs e agregador central (ELK, Loki, Datadog, Splunk, SIEM) — o OTLP/JSON pode ser reenviado a um OpenTelemetry Collector.
Dataset público (sanitização)
A telemetria é artefato temporário destinado a virar dataset público. Entre o
arquivo cru e o repositório existe uma etapa obrigatória de sanitização, executada
na VPS por dois scripts sem dependências externas:
./scripts/exportar-dataset.sh # extrai do container, sanitiza, gera dataset/AAAA-MM-DD/
| Script | Papel |
|---|---|
scripts/exportar-dataset.sh | Extrai o NDJSON do container, garante o sal no .env e chama o sanitizador |
scripts/sanitizar_telemetria.py | Sanitiza, audita e gera eventos.jsonl + README.md + schema.json + estatisticas.json (Python 3, só stdlib) |
A distinção que sustenta as regras: identidade × conteúdo didático. O mesmo campo
framework.field.ip guarda tanto o endereço que o servidor observou (identidade)
quanto o que o usuário digitou no formulário de GeoIP (exercício). O nome do campo não
distingue — o valor sim: IPv4 roteável ou IPv6 é identidade e vira hash; faixa
privada, loopback, documentação e resolvedores públicos conhecidos (8.8.8.8,
1.1.1.1…) permanecem legíveis. Pseudonimizar conteúdo didático esvaziaria o dataset
sem proteger ninguém: baseNetwork=192.19.0.0/16 digitado num exercício de VLSM é
o dado que dá valor ao arquivo.
| Dado | Tratamento |
|---|---|
| IP identificador | SHA-256(sal + valor) truncado em 12 hex — estável (conta visitantes únicos), irreversível sem o sal |
lat / lon | Removidos — 6 casas decimais são ~10 cm; nem hash nem arredondamento tornam publicável |
body (texto livre) | Reconstruído a partir dos atributos já sanitizados, nunca filtrado por regex — o body repetia os valores (evento=geo_lookup status=ok ip=…) |
traceId / spanId / request_id | Preservados — aleatórios por requisição, não identificam, e são o que torna o dataset analisável |
Estáticos, /q/*, /web/*, /telemetria/api*, /health | Descartados como ruído de infraestrutura |
O sal vive no .env da VPS, é gerado uma vez e nunca entra no dataset; trocá-lo
quebra a continuidade dos pseudônimos entre datasets já publicados.
Ao final, uma auditoria bloqueante varre o arquivo gerado provando que nenhum valor
de identidade sobreviveu, em qualquer campo — se achar, apaga a saída e falha. IPv4
roteáveis que restaram (conteúdo de exercício) são listados para conferência humana.
O script não faz git push: publicação é irreversível assim que indexada, então é
decisão humana e não de cron.
🗂️ Estrutura de Pastas
framework-net-java-quarkus/
├── build.gradle · settings.gradle · gradle.properties · gradlew(.bat)
├── Dockerfile · docker-compose.yml · docker-compose.dev.yml · .env.example
├── logs/
├── src/main/java/org/framework/net/
│ ├── analiseDidatica/ # application, config, domain/kernel, infrastructure (dns/geo/historico), presentation, support
│ ├── calculadora/ # application, config, domain, exception, presentation
│ ├── portas/ # application, domain, exception, presentation
│ ├── protocolos/ # application, domain, exception, presentation
│ ├── resolucaoProblemas/ # application (export/importing/normalization/planning/routing), domain (kernel/model), presentation
│ ├── security/ # Admin API key, CSRF, rate limit, sensitive APIs
│ ├── shared/ # sanitizers, guards e normalizadores de entrada
│ ├── telemetria/ # store, dashboard, filter, presentation
│ └── web/ # documentacao, admin login, ícone, filtros, support
├── src/main/resources/
│ ├── application.properties · application-prod.properties
│ ├── README.md # esta documentação (renderizada em /documentacao)
│ ├── templates/ # Qute: home, analiseDidatica, portas, protocolos, resolucaoProblemas, telemetria, admin, documentacao, shared
│ └── META-INF/resources/ # estáticos: CSS por módulo (home/, portas/, protocolos/, telemetria/, resolucaoProblemas/, documentacao/) + web/ (design system compartilhado) + JS + ícone
└── src/test/java/org/framework/net/ # JUnit 5 + RestAssured
🧪 Testes
Suíte em JUnit 5 + RestAssured (quarkus-junit, rest-assured), em src/test/java.
.\gradlew.bat test
Cobertura por área:
| Área | Exemplos de testes |
|---|---|
| Análise Didática | Ipv4KernelTest, AnaliseDidaticaHttpTest, AnaliseExportHttpTest, HistoricoApiHttpTest, GeoLookupServiceTest, PdfSimplesServiceTest |
| Calculadora | DivisaoServiceTest, VlanServiceTest, AgregacaoServiceTest, CalculadoraHttpTest |
| Saúde | HealthResourceTest |
| Portas / Protocolos | PortasServiceTest, ProtocolosServiceTest |
| Resolução VLSM/WAN | VlsmServiceTest, VlsmPlanningServiceTest, ResolucaoProblemasHttpTest, BulkClassImportServiceTest |
| Segurança | AdminApiKeyServiceTest, AdminApiKeyHttpTest, CsrfTokenServiceTest |
| Telemetria | TelemetriaLoggerTest, TelemetriaHttpTest, TelemetriaConsoleBufferTest, TelemetryDisabledHttpTest, TelemetriaStoreRotationTest, ModuloDePathTest, CorrelacaoEventosTest |
| Menu e rotas | MenuRotasHttpTest |
| Arquitetura | ArquiteturaCamadasTest |
| Shared / Web | UserInputSanitizerTest, IpCidrInputNormalizerTest, NetworkAddressGuardTest, WebIntegrationTest, DevBrowserLauncherTest |
Testes que guardam regras, não só comportamento
Três suítes existem para impedir classes inteiras de regressão, e não para verificar
um caso de uso:
ArquiteturaCamadasTest— lê os imports dos fontes e reprova o build se
domain passar a conhecer HTTP/Qute/camadas externas, se application importar
presentation, se dois módulos de negócio se acoplarem sem registro explícito, ou
se um @Path aparecer fora de presentation.
MenuRotasHttpTest— abre as 13 rotas do menu, confere que cada uma se marca
como ativa e navega para as demais. Conta os itens no HTML renderizado: **item novo
no menu sem teste correspondente quebra o build**.
ModuloDePathTest— trava a tabela que atribui cada rota a um módulo no
dashboard. Existe porque o default do switch apontava para "Análise Didática", e
com isso /calculadora, /sobre, /admin e /simuladores eram silenciosamente
contabilizados no módulo errado — bug que não gera exceção, só número errado.
Ao criar um módulo novo, atualize também
shared/main_menu.htmleMenuRotasHttpTest(a contagem de itens é verificada);RateLimitFilter.HEAVY_PATHS— e ostartsWithdo subcaminho, se as APIs forem pesadas;TelemetriaDashboardService.moduloDePath— senão o tráfego é creditado a outro módulo;templates/home/index.html— o bloco do módulo na landing;- este README.
🛣️ Roadmap
- [x] Migração de Python/Flask para Java 25 + Quarkus 3.37
- [x] VLSM dinâmico para N localidades
- [x] Topologias WAN estrela / estrela estendida / malha / anel / anel redundante
- [x] EIGRP + OSPF (distribuição por site, AS/processo opcionais)
- [x] Telnet explícito nos scripts (
transport input telnet) - [x] Demos (
?demo=gs|fiap|8|1) e exportações lab/entrega/turma - [x] Prefixo WAN configurável e CIDR da base opcional com inferência
- [x] Catálogos de portas e protocolos
- [x] Módulo de telemetria com dashboard e console ao vivo
- [x] Segurança: chave admin, CSRF, rate limiting e headers HTTP
- [x] GeoIP MaxMind (opcional) e resolução DNS com cache
- [ ] Persistência externa de logs operacionais (stack de observabilidade)
- [ ] Filtros avançados de histórico por período e modo
👨💻 Autor
Paulo André Carminati | RM570877 | FIAP 2026 | Cyber Defense
📄 Licença
MIT.