net/tstun: do SNAT after filterPacketOutboundToWireGuard

In a configuration where the local node (ip1) has a different IP (ip2)
that it uses to communicate with a peer (ip3) we would do UDP flow
tracking on the `ip2->ip3` tuple. When we receive the response from
the peer `ip3->ip2` we would dnat it back to `ip3->ip1` which would
then not match the flow track state and the packet would get dropped.

To fix this, we should do flow tracking on the `ip1->ip3` tuple instead
of `ip2->ip3` which requires doing SNAT after the running filterPacketOutboundToWireGuard.

Updates tailscale/corp#19971, tailscale/corp#8020

Signed-off-by: Maisem Ali <maisem@tailscale.com>
andrew/dns-fallback
Maisem Ali 7 months ago committed by Maisem Ali
parent 60266be298
commit 1f51bb6891

@ -915,8 +915,6 @@ func (t *Wrapper) Read(buffs [][]byte, sizes []int, offset int) (int, error) {
for _, data := range res.data { for _, data := range res.data {
p.Decode(data[res.dataOffset:]) p.Decode(data[res.dataOffset:])
pc.snat(p)
if m := t.destIPActivity.Load(); m != nil { if m := t.destIPActivity.Load(); m != nil {
if fn := m[p.Dst.Addr()]; fn != nil { if fn := m[p.Dst.Addr()]; fn != nil {
fn() fn()
@ -932,6 +930,10 @@ func (t *Wrapper) Read(buffs [][]byte, sizes []int, offset int) (int, error) {
continue continue
} }
} }
// Make sure to do SNAT after filtering, so that any flow tracking in
// the filter sees the original source address. See #12133.
pc.snat(p)
n := copy(buffs[buffsPos][offset:], p.Buffer()) n := copy(buffs[buffsPos][offset:], p.Buffer())
if n != len(data)-res.dataOffset { if n != len(data)-res.dataOffset {
panic(fmt.Sprintf("short copy: %d != %d", n, len(data)-res.dataOffset)) panic(fmt.Sprintf("short copy: %d != %d", n, len(data)-res.dataOffset))

Loading…
Cancel
Save