mirror of
https://github.com/tailscale/tailscale.git
synced 2026-03-29 01:02:22 +01:00
Introduce a datapathHandler that implements hooks that will receive packets from the tstun.Wrapper. This commit does not wire those up just yet. Perform DNAT from Magic IP to Transit IP on outbound flows on clients, and reverse SNAT in the reverse direction. Perform DNAT from Transit IP to final destination IP on outbound flows on connectors, and reverse SNAT in the reverse direction. Introduce FlowTable to cache validated flows by 5-tuple for fast lookups after the first packet. Flow expiration is not covered, and is intended as future work before the feature is officially released. Fixes tailscale/corp#34249 Fixes tailscale/corp#35995 Co-authored-by: Fran Bull <fran@tailscale.com> Signed-off-by: Michael Ben-Ami <mzb@tailscale.com>
126 lines
3.2 KiB
Go
126 lines
3.2 KiB
Go
// Copyright (c) Tailscale Inc & contributors
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package conn25
|
|
|
|
import (
|
|
"net/netip"
|
|
"testing"
|
|
|
|
"tailscale.com/net/flowtrack"
|
|
"tailscale.com/net/packet"
|
|
"tailscale.com/types/ipproto"
|
|
)
|
|
|
|
func TestFlowTable(t *testing.T) {
|
|
ft := NewFlowTable(0)
|
|
|
|
fwdTuple := flowtrack.MakeTuple(
|
|
ipproto.UDP,
|
|
netip.MustParseAddrPort("1.2.3.4:1000"),
|
|
netip.MustParseAddrPort("4.3.2.1:80"),
|
|
)
|
|
// Reverse tuple is defined by caller. Doesn't have to be mirror image of fwd.
|
|
// To account for intentional modifications, like NAT.
|
|
revTuple := flowtrack.MakeTuple(
|
|
ipproto.UDP,
|
|
netip.MustParseAddrPort("4.3.2.2:80"),
|
|
netip.MustParseAddrPort("1.2.3.4:1000"),
|
|
)
|
|
|
|
fwdAction, revAction := 0, 0
|
|
fwdData := FlowData{
|
|
Tuple: fwdTuple,
|
|
Action: func(_ *packet.Parsed) { fwdAction++ },
|
|
}
|
|
revData := FlowData{
|
|
Tuple: revTuple,
|
|
Action: func(_ *packet.Parsed) { revAction++ },
|
|
}
|
|
|
|
// For this test setup, from the tun device will be "forward",
|
|
// and from WG will be "reverse".
|
|
if err := ft.NewFlowFromTunDevice(fwdData, revData); err != nil {
|
|
t.Fatalf("got non-nil error for new flow from tun device")
|
|
}
|
|
|
|
// Test basic lookups.
|
|
lookupFwd, ok := ft.LookupFromTunDevice(fwdTuple)
|
|
if !ok {
|
|
t.Fatalf("got not found on first lookup from tun device")
|
|
}
|
|
lookupFwd.Action(nil)
|
|
if fwdAction != 1 {
|
|
t.Errorf("action for fwd tuple key was not executed")
|
|
}
|
|
|
|
lookupRev, ok := ft.LookupFromWireGuard(revTuple)
|
|
if !ok {
|
|
t.Fatalf("got not found on first lookup from WireGuard")
|
|
}
|
|
lookupRev.Action(nil)
|
|
if revAction != 1 {
|
|
t.Errorf("action for rev tuple key was not executed")
|
|
}
|
|
|
|
// Test not found error.
|
|
notFoundTuple := flowtrack.MakeTuple(
|
|
ipproto.UDP,
|
|
netip.MustParseAddrPort("1.2.3.4:1000"),
|
|
netip.MustParseAddrPort("4.0.4.4:80"),
|
|
)
|
|
if _, ok := ft.LookupFromTunDevice(notFoundTuple); ok {
|
|
t.Errorf("expected not found for foreign tuple")
|
|
}
|
|
|
|
// Wrong direction is also not found.
|
|
if _, ok := ft.LookupFromWireGuard(fwdTuple); ok {
|
|
t.Errorf("expected not found for wrong direction tuple")
|
|
}
|
|
|
|
// Overwriting forward tuple removes its reverse pair as well.
|
|
newRevData := FlowData{
|
|
Tuple: flowtrack.MakeTuple(
|
|
ipproto.UDP,
|
|
netip.MustParseAddrPort("9.9.9.9:99"),
|
|
netip.MustParseAddrPort("8.8.8.8:88"),
|
|
),
|
|
Action: func(_ *packet.Parsed) {},
|
|
}
|
|
if err := ft.NewFlowFromTunDevice(
|
|
fwdData,
|
|
newRevData,
|
|
); err != nil {
|
|
t.Fatalf("got non-nil error for new flow from tun device")
|
|
}
|
|
if _, ok := ft.LookupFromWireGuard(revTuple); ok {
|
|
t.Errorf("expected not found for removed reverse tuple")
|
|
}
|
|
|
|
// Overwriting reverse tuple removes its forward pair as well.
|
|
if err := ft.NewFlowFromTunDevice(
|
|
FlowData{
|
|
Tuple: flowtrack.MakeTuple(
|
|
ipproto.UDP,
|
|
netip.MustParseAddrPort("8.8.8.8:88"),
|
|
netip.MustParseAddrPort("9.9.9.9:99"),
|
|
),
|
|
Action: func(_ *packet.Parsed) {},
|
|
},
|
|
newRevData, // This is the same "reverse" data installed in previous test.
|
|
); err != nil {
|
|
t.Fatalf("got non-nil error for new flow from tun device")
|
|
}
|
|
if _, ok := ft.LookupFromTunDevice(fwdTuple); ok {
|
|
t.Errorf("expected not found for removed forward tuple")
|
|
}
|
|
|
|
// Nil action returns an error.
|
|
if err := ft.NewFlowFromTunDevice(
|
|
FlowData{},
|
|
FlowData{},
|
|
); err == nil {
|
|
t.Errorf("expected non-nil error for nil data")
|
|
}
|
|
}
|