# Arquitetura de Rede ## Estado atual (PHASE 68 — `network_mode: host`) `freeswitch` roda em `network_mode: host` — decisão tomada na PHASE 68 (era "pendente" antes, ver seção abaixo), pedida pelo usuário depois de dois ramais reais no mesmo escritório não conseguirem se ligar. `postgres`/ `redis`/`fs-config` continuam na rede bridge padrão do compose (`b2bcall_default`); só o FreeSWITCH saiu dela. Com host networking, o FreeSWITCH usa a stack de rede do PRÓPRIO host diretamente — sem NAT/bridge do Docker no meio, `local_ip_v4` resolve pro IP real da interface (`10.10.32.138` nesta VM), SIP/ESL escutam direto nas interfaces do host. Isso elimina uma camada de tradução de endereço que existia antes de qualquer roteador físico entrar em cena — ver PHASE 68 no TODO.md pro relato completo dos 3 achados (registro, áudio, e a chamada morrendo sozinha em 32s) que motivaram e validaram essa mudança. Efeitos em cascata (o FreeSWITCH sai da rede bridge do compose): - Não resolve mais os outros containers pelo nome de serviço — `fs-config` agora é alcançado via `http://127.0.0.1:8080/` (porta publicada só em loopback, `xml_curl.conf.xml`). - Os workers que chamavam ESL via nome `freeswitch` (fs-events/fs-config/predictive-dialer) usam `host.docker.internal` (+ `extra_hosts: host-gateway`, exige Docker 20.10+). - Segurança do Event Socket deixa de depender de "publicar só em loopback" (não existe mais essa camada) e passa a depender inteiramente da ACL `b2bcall_internal` já configurada (`apply-inbound-acl`) — confirmado que continua rejeitando qualquer origem fora de loopback/rede do Docker. `apps/api` continua rodando **direto no host** (fora do Docker) — nada muda pra ela, `ESL_HOST=127.0.0.1` já funcionava e continua funcionando (agora de forma ainda mais direta, sem a camada de publish-port do Docker no meio). ## Decisão tomada: `network_mode` do FreeSWITCH (agente.md secao 19) Historicamente listada como pendente (macvlan/ipvlan vs. host), resolvida na PHASE 68 a favor de **`network_mode: host`** — não por causa de um trunk PSTN real (a topologia `Internet → OpenSIPS → rede SIP privada → FreeSWITCH` da secao 17 continua valendo pra isso), mas por um problema concreto de NAT entre dois ramais registrados no mesmo escritório (ver achado abaixo). `macvlan`/`ipvlan` continuam como alternativas válidas se um dia o isolamento de rede do host virar prioridade maior que a simplicidade atual — não implementadas, não descartadas. ## Achado real (PHASE 65): VM atrás de roteador, ramal externo sem áudio Esta VM de laboratório está atrás de um roteador (NAT) — o IP da interface de rede (`ens18`) é privado (`10.10.32.x`), o roteador é quem faz NAT pro IP público real. Reportado pelo usuário: um softphone externo registrava com sucesso, mas sem áudio. Diagnóstico (contadores de pacotes do `iptables`, não suposição): 10 pacotes chegaram em `5060/udp` (SIP), **zero** pacotes chegaram em qualquer porta da faixa de RTP (`16384-16584/udp`). O REGISTER funciona porque a resposta trafega de volta pelo mesmo "buraco" NAT que o próprio pacote do cliente abriu — mas RTP usa portas completamente diferentes, como um fluxo NOVO. Sem uma regra de **port forward no roteador** pra essa faixa (apontando pro IP privado desta VM), esses pacotes nunca chegam até o Docker/FreeSWITCH. Do lado desta VM estava tudo certo: `docker-compose.yml` publica a faixa de RTP pra rede (não só loopback), `Ext-RTP-IP`/`Ext-SIP-IP` resolvem certo via STUN (`sofia status profile internal` mostra o IP público real), e a detecção de NAT do próprio FreeSWITCH (`apply-nat-acl value="nat.auto"`, `nat.auto` é uma ACL auto-gerada pelo core do FreeSWITCH — RFC1918 exceto a própria rede local do container, não precisa existir em `acl.conf.xml`) funciona corretamente (testado direto via `fs_cli -x "acl nat.auto"`). **Não tem fix de código pra isso** — é infraestrutura de rede fora do controle desta aplicação. Checklist pra quem for expor telefonia real atrás de um roteador: encaminhar UDP `5060` e toda a faixa RTP (`16384-16584`, Dockerfile do FreeSWITCH) pro IP privado da VM, sem tradução de porta. ## Quando `apps/api` virar container Hoje ela roda no host por conveniência de desenvolvimento. Quando virar o serviço Docker `b2bcall-api` (agente.md secao 14), as connection strings precisam trocar de `localhost` pros hostnames internos do compose (`postgres`, `redis`, `freeswitch`) — ver nota em docs/AUTHENTICATION.md sobre essa pegadinha.