mirror of
https://github.com/tailscale/tailscale.git
synced 2026-10-04 09:24:53 -04:00
The FreeBSD subnet-router NAT rule translated with "-> (self)": nat on ! tailscale0 inet from 100.64.0.0/10 to any -> (self) In pf, "(self)" is a round-robin pool of every address on the machine, including tailscale0's own address and loopback, and pf deals each new state the next address in the pool. Only flows that happen to draw the egress interface's address work; a flow translated to any other address gets replies the far end cannot route, and hangs at SYN. With N usable addresses on the box, roughly (N-1)/N of connections through the subnet router silently fail. Observed in a natlab vmtest against a FreeBSD 15.0 subnet router with four addresses (WAN, LAN, QEMU debug NIC, tailscale0): exactly half of 8 HTTP requests hung, alternating, and the pf state table showed the failed flows translated to the debug NIC's address and to tailscale0's own address: 10.0.0.102:51100 (100.64.0.1:35132) -> 10.0.0.103:8080 ESTABLISHED 10.0.2.15:56553 (100.64.0.1:35148) -> 10.0.0.103:8080 SYN_SENT:CLOSED 100.64.0.2:52655 (100.64.0.1:54106) -> 10.0.0.103:8080 SYN_SENT:CLOSED On a production FreeBSD firewall running this branch, the equivalent IPv6 rule shows 55 state creations totalling 117 packets (about two packets per state): SYNs whose replies never came back. Emit one rule per up, non-loopback, non-Tailscale interface instead, translating to that interface's own address, per address family only where the interface holds a usable address of that family: nat on vtnet0 inet from 100.64.0.0/10 to any -> (vtnet0) nat on vtnet1 inet from 100.64.0.0/10 to any -> (vtnet1) which is also the rule form FreeBSD firewall operators write by hand. With this, the same 8-request test passes 8/8, and the LAN interface's rule shows 8 states with healthy packet counts (56 packets total). The interface set is sampled when SNAT is enabled; interfaces added later are not covered until SNAT is toggled or tailscaled restarts. Updates #5573 Change-Id: Ife3367124737ce5c8785ca7f920eafca593ec705 Signed-off-by: Martin Minkus <martin.minkus@sonic.com>