Solution Architect with 7+ years of experience • Creator of STUNMESH-go and EZIO Project • Expertise in major public cloud networking services and on-prem datacenter networking design • Specialized in Cloud Network, OpenStack, Kubernetes, SD-WAN, and open-source • Extensive speaking experience at international conferences 2
Background — WireGuard, NAT types, STUN protocol • STUNMESH-go — Architecture and how it works on Linux • Porting to FreeBSD — What broke and why • BSD-Specific Solutions — BPF devices, packet capture, ICMP, wgctrl • Q&A 3
run on FreeBSD, thousands of firewall deployments • WireGuard is in the FreeBSD kernel (if-wg), but NAT traversal tools have been Linux-only • This work brings direct P2P WireGuard to FreeBSD, macOS, no relay servers needed
IPv4 addresses • CGNAT (Carrier-Grade NAT) adds another layer at the ISP • Stateful Firewall ◦ Even in IPv6 • Block inbound connections by default (IT security reason) • Peer-to-peer communication becomes difficult ◦ Neither side can initiate a connection ◦ Creates a "deadlock" situation
lines of code) • But it assumes at least one side has a stable endpoint • When both peers are behind NAT: ◦ No stable public IP on either side ◦ No way to start connections • Traditional fix: relay servers ◦ Added latency, bandwidth cost ◦ Extra infrastructure to maintain for relay
at remote sites • Both sites want a WireGuard tunnel • Neither has a static public IP • Without NAT traversal → need a relay server • STUNMESH-go solves this natively on FreeBSD
cone types NAT Type Behavior P2P Friendly? Full-Cone Any host can reach mapped port ✅ Best Restricted-Cone Only hosts you contacted can reply ✅ Good Port-Restricted-Cone IP + port must match ✅ Works Symmetric Different port per destination ❌ Hard
STUN server 2. Server reads source IP:port after NAT translation 3. Server responds with observed public endpoint 4. Client now knows its external address 5. Peers exchange endpoints → direct connection Client (192.168.1.10:5000) → NAT → (203.0.113.5:40000) → STUN Server (stun.example.com:3478) ← Response: "You are 203.0.113.5:40000"
intercepts STUN responses before kernel UDP stack • BPF filter: check dest port + STUN magic cookie 0x2112A442 • WireGuard traffic flows normally, zero interference • No extra ports, no proxy layers
Proxy Send/Recv STUN STUN Server Listen on / send&recv packet Remote Peer Proxy connect to remote peer It might be another Proxy Config wg remote endpoint with 127.0.0.1:<port B> thru Proxy Proxy does the “Port Translation” for WG for easy STUN procedure Forward packet port B Info Exchange 18
STUN Server Listen on / send&recv packet directly to remote peer Remote Peer Config wg remote endpoint with true remote peer endpoint Info Exchange Get remote peer endpoint from plugin system 19
system-wide: • One socket → all interfaces • BPF attaches directly to the socket • Receives packets before kernel UDP stack • Simple, single capture loop // System-wide raw IP socket for UDP (protocol 17) conn, err := net.ListenPacket("ip4:17", "0.0.0.0") // Attach BPF filter — captures STUN on WireGuard port conn.SetBPF(stunBpfFilter)
keys as WireGuard). • Built-in: Compiled into binary Cloudflare DNS TXT • Exec: JSON over stdin/stdout Custom API client • Shell: Variable-based protocol Simple file/Redis
System-wide raw socket Per-interface /dev/bpf BPF attachment Socket-level SetBPF() Device-level /dev/bpfN Link layer in BPF IP level (no L2 header) Full frame (Ethernet/Null) ICMP binding SO_BINDTODEVICE (VRF support) Not needed (no VRF) WireGuard API UpdateOnly supported UpdateOnly not supported Build CGO_ENABLED=0 CGO_ENABLED=1
sockets for this • FreeBSD uses the classic BSD Packet Filter design • Must open /dev/bpf per interface • Must enumerate interfaces, filter eligible ones • Must run concurrent capture across all interfaces
bind to em0 → set filter → read ├── open(/dev/bpf1) → bind to igb0 → set filter → read └── open(/dev/bpf2) → bind to vtnet0 → set filter → read (Linux (Centralized) FreeBSD (Per-interface) Scope One raw socket → all interfaces One /dev/bpf per interface BPF Single filter program Separate filter per device Packets IP-level (no L2 header) Full frame with link layer header
all interfaces, exclude WireGuard (avoid self-capture) and link-down interfaces 2. Concurrent Capture: One goroutine per interface, channel-based synchronization for STUN responses 3. Link Layer Headers Affect BPF Offsets: Ethernet (14B) vs BSD loopback Null (4B) a. different offsets for the same fields
not support UpdateOnly: • wgctrl-go returns error when UpdateOnly is set on FreeBSD • Workaround: set UpdateOnly = false → library handles remove + re-add • Brief connection interruption during re-add (acceptable for our use case) peerConfig.UpdateOnly = false // Must remove + re-add peer