mirror of
https://github.com/tailscale/tailscale.git
synced 2026-10-09 11:52:00 -04:00
FreeBSD is a weak-host stack like Linux, so a LAN-adjacent machine can send a SYN for a node's Tailscale IP to the node's NIC and get the kernel's SYN-ACK from the peerapi port, confirming which tailnet identity that MAC address belongs to. Linux closes this with SO_BINDTODEVICE and macOS/iOS with IP_BOUND_IF, but FreeBSD has no per-socket interface bind (only IP_RECVIF and SO_SETFIB). Instead, treat FreeBSD like Android: when netstack is present, don't create a kernel-level peerapi listener at all and use the fake listener, since netstack already intercepts peerapi connections from peers in userspace and the kernel socket only ever served the local host. When netstack is compiled out (ts_omit_netstack), the kernel listener is the only way to serve peers, so keep it and log that it must be restricted with pf. Along the way, tailscaled's own pf source NAT rule on FreeBSD turned out to rewrite the source of such a SYN-ACK to the LAN IP and a random port, so a plain connect() from the LAN never completes. The SYN-ACK still leaks, though, so the natlab test now watches for SYN-ACKs on the attacker's NIC with tcpdump instead of checking for a completed handshake, and gains a FreeBSD variant. With the fix disabled, that variant fails on the leaked SYN-ACK from the peerapi port. Fixes #21419 Updates tailscale/corp#48248 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Change-Id: I0d2de4ebc9bae28450d500bd7b6ddbfa70f9052f