Skip to content

ADR 0058 — OCTOPUS IPv4/IPv6 Dual-Stack Mandate

  • Status: Accepted
  • Date: 2026-05-15
  • Deciders: André Luiz Gallon (Architect/Operator)
  • Supersedes: —
  • Related: ADR 0007 (Public-Internet Realism), ADR 0050 (CONNECT.Art rendezvous), ADR 0051 (P2P STUN), ADR 0053 (Cell-based Hyperscale), ADR 0054 (PQC-Everywhere), ADR 0059 (ACME-Everywhere)
  • Memory: project_octopus_dual_stack_ipv6_mandate_2026_05_15.md

Context

A depleção de IPv4 chegou ao ponto crítico em vários mercados-alvo OCTOPUS:

  • Brasil: ISPs residenciais (Vivo, Claro, Oi) já entregam IPv6-only com NAT64 para clientes residenciais; CGNAT no fallback é caro e degradado
  • Índia: Reliance Jio (~450M users) é majoritariamente IPv6-only puro
  • China: política governamental 2025+ exige IPv6-only em novos deploys de operadora; CGNAT está sendo desativada
  • Nigéria + África emergente: MTN/Airtel migrando para IPv6 nativo
  • Mobile: T-Mobile US, Verizon, Reliance Jio operam 464XLAT (IPv6-only + CLAT no device) — mas peers fora dessa rede ainda precisam IPv6 first-class

OCTOPUS clients (GATEWAY.Art) rodam no DC do customer — frequentemente atrás do ISP residencial ou enterprise dele. Suportar apenas IPv4 significa:

  1. CGNAT-only fallback — degradação severa de hole-punching (Pattern B)
  2. Exclusão de mercados — Brasil/Índia/China inteiros perdidos
  3. Lock-in em NAT64 carrier-side — solução que ISPs estão desativando
  4. Custo IPv4 — AWS/GCP/Azure cobram ~$0.005/IP/hora; multiplicado por centenas de cells em Wave-3 hyperscale, vira gasto significativo
  5. Compliance future — alguns mandatos governamentais já exigem IPv6 (US Federal: OMB M-21-07, "IPv6-only by FY2025")

Auditoria do estado atual (2026-05-15) encontrou 15 gaps de IPv6 no codebase + infra Terraform + K8s manifests + docs.

A janela para fechar esses gaps antes de Wave-4 hyperscale (50k+ clientes) é agora.

Decisão

OCTOPUS adota dual-stack IPv4+IPv6 com paridade L3 em todo o projeto, sem fallback NAT64 obrigatório. IPv6 é first-class everywhere.

D1 — Paridade L3 total

IPv4 e IPv6 são tratados como cidadãos iguais em todos os componentes:

  • Cloud cells (VPC dual-stack AWS + GCP + Azure)
  • K8s Services (ipFamilyPolicy: PreferDualStack, ipFamilies: [IPv4, IPv6])
  • DB schemas (Postgres INET, ClickHouse IPv6/IPv4, Go netip.Addr)
  • Cert SAN (inclui v4 IP, v6 IP, e DNS quando aplicável)
  • Rate limiter + ACL parsers entendendo CIDR v6
  • Audit chain entries com campos IP v6-capable
  • DNS records — AAAA paralelo a A para todos os anycast endpoints
  • Edge LB / Cloudflare Workers — dual-stack listeners
  • Customer Dashboard "connectivity test" tool — testa v4 + v6

D2 — IPv6-only client deve funcionar end-to-end

GATEWAY.Art em DC cliente atrás de ISP IPv6-only puro DEVE funcionar identicamente a IPv4. Isso significa:

  • Pattern A (CONNECT.Art rendezvous) aceita conexão IPv6 puro
  • Pattern B (STUN-coord) descobre srflx v6, hole-punch v6-v6
  • PQC mTLS sobre v6 sem regressão
  • Anycast edge dual-stack (Cloudflare Magic Transit cobre nativamente)
  • Sem dependência de NAT64 carrier-side (não-suportada em prod)

NAT64 fica como escape hatch on-edge apenas para customers que explicitamente declaram cenário mixed legacy v4-only-server. Nunca mandatory.

D3 — Listener defaults: :port, não 0.0.0.0:port

Todo listener Go DEVE bindar em :port (que resolve para [::]:port em dual-stack systems via stdlib) ao invés de 0.0.0.0:port.

// ❌ REJEITADO em PR review
net.Listen("tcp", "0.0.0.0:8443")

// ✅ ACEITO
net.Listen("tcp", ":8443")

Existing code: já está mostly correto (audit 2026-05-15 não achou listener 0.0.0.0: em prod paths). Mantém via PR reviewer checklist.

D4 — Schemas DB: tipos IP v6-capable

Toda coluna DB que armazena endereço IP DEVE usar tipo v6-capable:

Banco Tipo v6-capable Tipo a evitar
Postgres INET ou CIDR varchar(15), inet4-only
ClickHouse IPv6 ou IPv4/IPv6 Union String
Go in-memory netip.Addr (Go 1.18+) net.IP legacy (mutable, 16-byte ambiguity)

netip.Addr é particularly important porque é immutable + canonicaliza v6 representations + suporta zone scopes.

D5 — Cert SAN: v4+v6+DNS quando aplicável

ACME issuer (PR-ACME-2 #805 MERGED) emite cert para FQDNs, mas quando um serviço tem IP literal em audit logs / connection tracking, esse IP deve ter SAN entry separado para v4 + v6.

Para cell-aware endpoints (Wave-3 #777-#786), cert-manager Certificate CR template inclui:

spec:
  dnsNames:
    - connect-us-east-1-a.tlsstress.art
  ipAddresses:
    - "192.0.2.1"          # IPv4 anycast
    - "2001:db8::1"         # IPv6 anycast

PR-ACME-3 (#813 MERGED) ships com dnsNames apenas; adicionar ipAddresses para v6 SAN é parte da Dual-Stack PR-5 (cert SAN audit).

D6 — Audit chain JSON: campos IP aceitam v6

Audit entries da Merkle chain (ADR 0048) gravam IP do peer. Schema atualizado:

{
  "event": "pair-established",
  "peer_ip": "2001:db8::1",       // ← v6 OK
  "peer_ip_family": "ipv6",       // ← NOVO field para query/filter
  "...": "..."
}

pkg/octopus/common/audit/types.go precisa atualizar struct fields para suportar v6 strings sem truncation.

D7 — Rate limiter + ACL: netip.Addr-backed

Rate limiter token bucket (CONNECT.Art pkg/octopus/connect-art/internal/ratelimit/) key é source IP. Migrar de net.IP para netip.Addr evita confusão v4-mapped-v6 (::ffff:1.2.3.4 é o mesmo bucket que 1.2.3.4 apenas com canonicalization). netip.Addr.Unmap() resolve.

CIDR allowlists para deployment_id authorization seguem mesma migração.

D8 — DNS: AAAA paralelo a A em todos os anycast endpoints

Toda zona Cloudflare/Route53 com record A para endpoint público DEVE ter AAAA paralelo:

connect-us-east-1-a.tlsstress.art.  A     192.0.2.1
connect-us-east-1-a.tlsstress.art.  AAAA  2001:db8::1   ← OBRIGATÓRIO

Anycast IPs reservados em ranges /23 (AWS Global Accelerator), /29 (Cloudflare Magic Transit) — todos têm v6 native.

D9 — K8s Services: PreferDualStack default

Todo K8s Service novo DEVE declarar:

spec:
  ipFamilyPolicy: PreferDualStack
  ipFamilies:
    - IPv4
    - IPv6

Existing Services serão atualizados em Dual-Stack PR-2 (K8s sweep).

CNI deve suportar dual-stack — flannel default k3s/RKE2 NÃO suporta. Wave-PR-4 migra para Calico OR Cilium.

D10 — Compliance gate: PR reviewer checklist

Toda PR que toque networking, schemas DB, K8s manifests, ou listeners DEVE passar pelo checklist pkg/octopus/docs/07-development/pr-checklist-dual-stack.md (este wave entrega).

Critérios de rejeição automática: 1. Listener 0.0.0.0:port em produção 2. Schema com varchar(15) ou inet4 para IP 3. K8s Service sem ipFamilyPolicy 4. Cert SAN com IP v4-only quando v6 disponível 5. CIDR parser net.IP legacy ao invés de netip.Addr 6. Falta AAAA paralelo a A em zona DNS 7. Smoke test v4-only sem cobertura v6 paralela

Wave de implementação

11 PRs estimados, 18-22 dias úteis. Ordem (DAG):

# PR Esforço Dependencies
PR-DS-1 (este) ADR 0058 + PR reviewer checklist 1d
PR-DS-2 K8s Services PreferDualStack + DNS AAAA records 1d PR-DS-1
PR-DS-3 Terraform VPCs IPv6 CIDR (AWS+GCP+Azure) 2-3d PR-DS-2
PR-DS-4 CNI Calico/Cilium dual-stack migration 2-3d PR-DS-3
PR-DS-5 Cert SAN v6 audit + Certificate CR update 1d PR-DS-3
PR-DS-6 DB schemas INET/IPv6 audit + migrations 1d
PR-DS-7 Rate limiter + ACLs netip.Addr migration 1d
PR-DS-8 Edge AAAA + Cloudflare Workers v6 listener 2d PR-DS-2
PR-DS-9 Smoke tests v6-only paths (CONNECT.Art + STUN-coord) 1d PR-DS-4
PR-DS-10 Docs sweep "IPv6 first-class" linguagem (25+ docs) 2d
PR-DS-11 Dashboard connectivity test tool v4+v6 2d PR-DS-9

Crítico path: PR-DS-1 → PR-DS-2 → PR-DS-3 → PR-DS-4 → PR-DS-9 = ~10 dias úteis. Outros PRs paralelos em ~10 dias úteis.

Alternativas consideradas

Alternativa Por que rejeitada
IPv4-only + CGNAT Exclui Brasil/Índia/China; ISPs desativando NAT64 carrier-side
IPv6-only puro Quebra customers legacy v4-only DCs (ainda majoritário em US enterprise)
Dual-stack mas v6 second-class Auditoria já mostrou 15 gaps; manutenção contínua de paridade exige LOCKED commitment
NAT64 mandatory on-edge Operacionalmente complexo, hidden state, debugging pesadelo
464XLAT carrier-side Não controlamos o carrier; cliente IPv6-only puro continua falhando se 464XLAT down

Consequências

Positivas

  • Markets unlocked: Brasil/Índia/China/África emergente acessíveis nativamente
  • Custo cloud reduzido: IPv6 é grátis nos 3 hyperscalers; IPv4 custa $0.005/IP/h (AWS) = ~$3.60/IP/mês × ~30 cells × 4 IPs = ~$430/mês evitado em Wave-4
  • Future-proof: alinhado com OMB M-21-07 + outras políticas governamentais
  • Cloudflare/AWS edge native v6 desde 2014
  • PQC mTLS funciona igual — não há regressão criptográfica

Negativas

  • CNI migration risk — Calico/Cilium switch pode quebrar production cluster (mitigação: roll forward em staging primeiro, 30d soak time)
  • DB migrations — Postgres INET é compatível com strings v4, mas driver-level checks podem precisar update (mitigação: Drizzle migrations em backward-compat mode)
  • Docs sweep volume — 25+ docs para reescrever (mitigação: PR-DS-10 faz em uma passada via script + manual review)

Neutras

  • IPv6 addresses são 8x mais longos em logs (mitigação: ferramentas modernas lidam bem; cardinality Prometheus já bounded)
  • Operator training: equipe precisa familiarizar com v6 CIDR notation (mitigação: cheat sheet em runbook)

Compliance mapping

Standard Requirement Where
OMB M-21-07 "IPv6-only by FY2025" for US Federal D1+D2 enable FedRAMP customers
OMB M-21-07 §III.B Eliminate dependency on IPv4 NAT64 NOT mandatory (D2)
RIPE-690 Recommendations on IPv6 deployment Followed throughout
RFC 8064 Stable IPv6 IIDs netip.Addr canonicalization (D7)
RFC 9099 IPv6 security rate limiter v6-aware (D7)
SOC 2 CC6.1 Logical access controls ACLs accept v6 CIDR (D7)
ISO 27001 A.13.1 Network security dual-stack uniform posture (D1)

Patent considerations

A combinação de: - Multi-cloud anycast dual-stack edge - Per-cell IPv6 allocation strategy via Terraform - PQC mTLS sobre IPv6 com rate limiter netip.Addr-backed

…não é patenteavel em si (são componentes standards). Mas a integração end-to-end via OCTOPUS architecture pode integrar Patent Family E (federation patterns) como claim adicional. Avaliar com IP counsel após Wave completo.

Open items / future work

  • ADR 0058-A (Q3 2026) — IPv6-only-only mode (drop IPv4 entirely) para customers que querem zero v4 surface. Não escopo do Wave atual.
  • ADR 0058-B (Q4 2026) — Happy Eyeballs v2 (RFC 8305) tuning para customers com path degradation em uma family
  • 464XLAT awareness — quando customer roda nesta config, ajustar STUN candidate gathering para evitar CLAT-pinned addresses como srflx

Memory + cross-references

Update MEMORY.md index entry para apontar este ADR como AUTHORITATIVE:

Memory: project_octopus_dual_stack_ipv6_mandate_2026_05_15.md ← memo of decision ADR: docs/ADR/0058-octopus-dual-stack-ipv4-ipv6.md ← this file (canonical) Checklist: pkg/octopus/docs/07-development/pr-checklist-dual-stack.md ← reviewer enforcement

Cross-references: - ADR 0050 (CONNECT.Art) — listener bind semantics D3 applies - ADR 0051 (P2P STUN) — IPv6 srflx in XOR-MAPPED-ADDRESS already supported (Go stdlib stun-coord) - ADR 0053 (Cell-based Hyperscale) — VPC IPv6 CIDR per cell (D9) - ADR 0054 (PQC-Everywhere) — TLS curves operate transparent over v4 OR v6 - ADR 0059 (ACME-Everywhere) — Cert SAN includes IP types (D5)