wgengine/netstack: handle 4via6 routes that are advertised by the same node

Previously, a node that was advertising a 4via6 route wouldn't be able
to make use of that same route; the packet would be delivered to
Tailscale, but since we weren't accepting it in handleLocalPackets, the
packet wouldn't be delivered to netstack and would never hit the 4via6
logic. Let's add that support so that usage of 4via6 is consistent
regardless of where the connection is initiated from.

Updates #11304

Signed-off-by: Andrew Dunham <andrew@du.nham.ca>
Change-Id: Ic28dc2e58080d76100d73b93360f4698605af7cb
This commit is contained in:
Andrew Dunham
2024-05-05 15:00:19 -07:00
parent 7901925ad3
commit 8f7f9ac17e
2 changed files with 200 additions and 32 deletions

View File

@ -706,3 +706,94 @@ func TestTCPForwardLimits_PerClient(t *testing.T) {
t.Errorf("got clientmetric limit metric=%d, want 1", v)
}
}
// TestHandleLocalPackets tests the handleLocalPackets function, ensuring that
// we are properly deciding to handle packets that are destined for "local"
// IPsaddresses that are either for this node, or that it is responsible for.
//
// See, e.g. #11304
func TestHandleLocalPackets(t *testing.T) {
var (
selfIP4 = netip.MustParseAddr("100.64.1.2")
selfIP6 = netip.MustParseAddr("fd7a:115c:a1e0::123")
)
impl := makeNetstack(t, func(impl *Impl) {
impl.ProcessSubnets = false
impl.ProcessLocalIPs = false
impl.atomicIsLocalIPFunc.Store(func(addr netip.Addr) bool {
return addr == selfIP4 || addr == selfIP6
})
})
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"),
}
_, err := impl.lb.EditPrefs(&ipn.MaskedPrefs{
Prefs: *prefs,
AdvertiseRoutesSet: true,
})
if err != nil {
t.Fatalf("EditPrefs: %v", err)
}
t.Run("ShouldHandleServiceIP", func(t *testing.T) {
pkt := &packet.Parsed{
IPVersion: 4,
IPProto: ipproto.TCP,
Src: netip.MustParseAddrPort("127.0.0.1:9999"),
Dst: netip.MustParseAddrPort("100.100.100.100:53"),
TCPFlags: packet.TCPSyn,
}
resp := impl.handleLocalPackets(pkt, impl.tundev)
if resp != filter.DropSilently {
t.Errorf("got filter outcome %v, want filter.DropSilently", resp)
}
})
t.Run("ShouldHandle4via6", func(t *testing.T) {
pkt := &packet.Parsed{
IPVersion: 6,
IPProto: ipproto.TCP,
Src: netip.MustParseAddrPort("[::1]:1234"),
// This is an IP in the above 4via6 subnet that this node handles.
// $ 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,
}
resp := impl.handleLocalPackets(pkt, impl.tundev)
// DropSilently is the outcome we expected, since we actually
// handled this packet by injecting it into netstack, which
// will handle creating the TCP forwarder. We drop it so we
// don't process the packet outside of netstack.
if resp != filter.DropSilently {
t.Errorf("got filter outcome %v, want filter.DropSilently", resp)
}
})
t.Run("OtherNonHandled", func(t *testing.T) {
pkt := &packet.Parsed{
IPVersion: 6,
IPProto: ipproto.TCP,
Src: netip.MustParseAddrPort("[::1]:1234"),
// This IP is *not* in the above 4via6 route
// $ tailscale debug via 99 10.1.1.9/24
// fd7a:115c:a1e0:b1a:0:63:a01:109/120
Dst: netip.MustParseAddrPort("[fd7a:115c:a1e0:b1a:0:63:a01:109]:5678"),
TCPFlags: packet.TCPSyn,
}
resp := impl.handleLocalPackets(pkt, impl.tundev)
// Accept means that handleLocalPackets does not handle this
// packet, we "accept" it to continue further processing,
// instead of dropping because it was already handled.
if resp != filter.Accept {
t.Errorf("got filter outcome %v, want filter.Accept", resp)
}
})
}