wgengine/netstack: add tests for shouldProcessInbound

Inspired by #6235, let's explicitly test the behaviour of this function
to ensure that we're not processing things we don't expect to.

Change-Id: I158050a63be7410fb99452089ea607aaf89fe91a
Signed-off-by: Andrew Dunham <andrew@tailscale.com>
pull/6224/head
Andrew Dunham 2 years ago committed by Brad Fitzpatrick
parent e85613aa2d
commit acf5839dd2

@ -8,12 +8,18 @@ import (
"fmt"
"net/netip"
"runtime"
"sync/atomic"
"testing"
"gvisor.dev/gvisor/pkg/refs"
"tailscale.com/ipn"
"tailscale.com/ipn/ipnlocal"
"tailscale.com/ipn/store/mem"
"tailscale.com/net/packet"
"tailscale.com/net/tsaddr"
"tailscale.com/net/tsdial"
"tailscale.com/net/tstun"
"tailscale.com/tstest"
"tailscale.com/types/ipproto"
"tailscale.com/wgengine"
"tailscale.com/wgengine/filter"
@ -252,3 +258,218 @@ func TestShouldHandlePing(t *testing.T) {
})
}
}
func TestShouldProcessInbound(t *testing.T) {
testCases := []struct {
name string
pkt *packet.Parsed
setup func(*Impl)
want bool
}{
{
name: "ipv6-via",
pkt: &packet.Parsed{
IPVersion: 6,
IPProto: ipproto.TCP,
Src: netip.MustParseAddrPort("100.101.102.103:1234"),
// $ tailscale debug via 7 10.1.1.9/24
// fd7a:115c:a1e0:b1a:0:7:a01:109/120
Dst: netip.MustParseAddrPort("[fd7a:115c:a1e0:b1a:0:7:a01:109]:5678"),
TCPFlags: packet.TCPSyn,
},
setup: func(i *Impl) {
prefs := ipn.NewPrefs()
prefs.AdvertiseRoutes = []netip.Prefix{
// $ tailscale debug via 7 10.1.1.0/24
// fd7a:115c:a1e0:b1a:0:7:a01:100/120
netip.MustParsePrefix("fd7a:115c:a1e0:b1a:0:7:a01:100/120"),
}
i.lb.Start(ipn.Options{
StateKey: ipn.GlobalDaemonStateKey,
UpdatePrefs: prefs,
})
// This should be handled even if we're
// otherwise not processing local IPs or
// subnets.
i.ProcessLocalIPs = false
i.ProcessSubnets = false
},
want: true,
},
{
name: "ipv6-via-not-advertised",
pkt: &packet.Parsed{
IPVersion: 6,
IPProto: ipproto.TCP,
Src: netip.MustParseAddrPort("100.101.102.103:1234"),
// $ tailscale debug via 7 10.1.1.9/24
// fd7a:115c:a1e0:b1a:0:7:a01:109/120
Dst: netip.MustParseAddrPort("[fd7a:115c:a1e0:b1a:0:7:a01:109]:5678"),
TCPFlags: packet.TCPSyn,
},
setup: func(i *Impl) {
prefs := ipn.NewPrefs()
prefs.AdvertiseRoutes = []netip.Prefix{
// tailscale debug via 7 10.1.2.0/24
// fd7a:115c:a1e0:b1a:0:7:a01:200/120
netip.MustParsePrefix("fd7a:115c:a1e0:b1a:0:7:a01:200/120"),
}
i.lb.Start(ipn.Options{
StateKey: ipn.GlobalDaemonStateKey,
UpdatePrefs: prefs,
})
},
want: false,
},
{
name: "tailscale-ssh-enabled",
pkt: &packet.Parsed{
IPVersion: 4,
IPProto: ipproto.TCP,
Src: netip.MustParseAddrPort("100.101.102.103:1234"),
Dst: netip.MustParseAddrPort("100.101.102.104:22"),
TCPFlags: packet.TCPSyn,
},
setup: func(i *Impl) {
prefs := ipn.NewPrefs()
prefs.RunSSH = true
i.lb.Start(ipn.Options{
StateKey: ipn.GlobalDaemonStateKey,
UpdatePrefs: prefs,
})
i.atomicIsLocalIPFunc.Store(func(addr netip.Addr) bool {
return addr.String() == "100.101.102.104" // Dst, above
})
},
want: true,
},
{
name: "tailscale-ssh-disabled",
pkt: &packet.Parsed{
IPVersion: 4,
IPProto: ipproto.TCP,
Src: netip.MustParseAddrPort("100.101.102.103:1234"),
Dst: netip.MustParseAddrPort("100.101.102.104:22"),
TCPFlags: packet.TCPSyn,
},
setup: func(i *Impl) {
prefs := ipn.NewPrefs()
prefs.RunSSH = false // default, but to be explicit
i.lb.Start(ipn.Options{
StateKey: ipn.GlobalDaemonStateKey,
UpdatePrefs: prefs,
})
i.atomicIsLocalIPFunc.Store(func(addr netip.Addr) bool {
return addr.String() == "100.101.102.104" // Dst, above
})
},
want: false,
},
{
name: "process-local-ips",
pkt: &packet.Parsed{
IPVersion: 4,
IPProto: ipproto.TCP,
Src: netip.MustParseAddrPort("100.101.102.103:1234"),
Dst: netip.MustParseAddrPort("100.101.102.104:4567"),
TCPFlags: packet.TCPSyn,
},
setup: func(i *Impl) {
i.ProcessLocalIPs = true
i.atomicIsLocalIPFunc.Store(func(addr netip.Addr) bool {
return addr.String() == "100.101.102.104" // Dst, above
})
},
want: true,
},
{
name: "process-subnets",
pkt: &packet.Parsed{
IPVersion: 4,
IPProto: ipproto.TCP,
Src: netip.MustParseAddrPort("100.101.102.103:1234"),
Dst: netip.MustParseAddrPort("10.1.2.3:4567"),
TCPFlags: packet.TCPSyn,
},
setup: func(i *Impl) {
i.ProcessSubnets = true
// For testing purposes, assume all Tailscale
// IPs are local; the Dst above is something
// not in that range.
i.atomicIsLocalIPFunc.Store(tsaddr.IsTailscaleIP)
},
want: true,
},
{
name: "peerapi-port-subnet-router", // see #6235
pkt: &packet.Parsed{
IPVersion: 4,
IPProto: ipproto.TCP,
Src: netip.MustParseAddrPort("100.101.102.103:1234"),
Dst: netip.MustParseAddrPort("10.0.0.23:5555"),
TCPFlags: packet.TCPSyn,
},
setup: func(i *Impl) {
prefs := ipn.NewPrefs()
prefs.AdvertiseRoutes = []netip.Prefix{
netip.MustParsePrefix("10.0.0.1/24"),
}
i.lb.Start(ipn.Options{
StateKey: ipn.GlobalDaemonStateKey,
UpdatePrefs: prefs,
})
// As if we were running on Linux where netstack isn't used.
i.ProcessSubnets = false
i.atomicIsLocalIPFunc.Store(func(netip.Addr) bool { return false })
// Set the PeerAPI port to the Dst port above.
atomic.StoreUint32(&i.peerapiPort4Atomic, 5555)
atomic.StoreUint32(&i.peerapiPort6Atomic, 5555)
},
want: false,
},
// TODO(andrew): test PeerAPI
// TODO(andrew): test TCP packets without the SYN flag set
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
impl := makeNetstack(t, func(i *Impl) {
defer t.Logf("netstack setup finished")
logf := tstest.WhileTestRunningLogger(t)
e, err := wgengine.NewFakeUserspaceEngine(logf, 0)
if err != nil {
t.Fatalf("NewFakeUserspaceEngine: %v", err)
}
t.Cleanup(e.Close)
lb, err := ipnlocal.NewLocalBackend(logf, "logid", new(mem.Store), new(tsdial.Dialer), e, 0)
if err != nil {
t.Fatalf("NewLocalBackend: %v", err)
}
t.Cleanup(lb.Shutdown)
dir := t.TempDir()
lb.SetVarRoot(dir)
i.SetLocalBackend(lb)
if tc.setup != nil {
tc.setup(i)
}
})
got := impl.shouldProcessInbound(tc.pkt, nil)
if got != tc.want {
t.Errorf("got shouldProcessInbound()=%v; want %v", got, tc.want)
} else {
t.Logf("OK: shouldProcessInbound() = %v", got)
}
})
}
}

Loading…
Cancel
Save