net/tstun: refactor peerConfig to allow storing more details

This refactors the peerConfig struct to allow storing more
details about a peer and not just the masq addresses. To be
used in a follow up change.

As a side effect, this also makes the DNAT logic on the inbound
packet stricter. Previously it would only match against the packets
dst IP, not it also takes the src IP into consideration. The beahvior
is at parity with the SNAT case.

Updates tailscale/corp#19623

Co-authored-by: Andrew Dunham <andrew@du.nham.ca>
Signed-off-by: Maisem Ali <maisem@tailscale.com>
Change-Id: I5f40802bebbf0f055436eb8824e4511d0052772d
This commit is contained in:
Maisem Ali
2024-05-06 11:01:47 -07:00
committed by Maisem Ali
parent f3d2fd22ef
commit 5ef178fdca
2 changed files with 171 additions and 142 deletions

View File

@ -551,7 +551,7 @@ func TestPeerAPIBypass(t *testing.T) {
tt.w.SetFilter(tt.filter)
tt.w.disableTSMPRejected = true
tt.w.logf = t.Logf
if got := tt.w.filterPacketInboundFromWireGuard(p, nil); got != tt.want {
if got := tt.w.filterPacketInboundFromWireGuard(p, nil, nil); got != tt.want {
t.Errorf("got = %v; want %v", got, tt.want)
}
})
@ -581,7 +581,7 @@ func TestFilterDiscoLoop(t *testing.T) {
p := new(packet.Parsed)
p.Decode(pkt)
got := tw.filterPacketInboundFromWireGuard(p, nil)
got := tw.filterPacketInboundFromWireGuard(p, nil, nil)
if got != filter.DropSilently {
t.Errorf("got %v; want DropSilently", got)
}
@ -592,7 +592,7 @@ func TestFilterDiscoLoop(t *testing.T) {
memLog.Reset()
pp := new(packet.Parsed)
pp.Decode(pkt)
got = tw.filterPacketOutboundToWireGuard(pp)
got = tw.filterPacketOutboundToWireGuard(pp, nil)
if got != filter.DropSilently {
t.Errorf("got %v; want DropSilently", got)
}
@ -653,11 +653,17 @@ func TestPeerCfg_NAT(t *testing.T) {
publicIP = netip.MustParseAddr("2001:4860:4860::8888")
}
type dnatTest struct {
src netip.Addr
dst netip.Addr
want netip.Addr // new destination after DNAT
}
tests := []struct {
name string
wcfg *wgcfg.Config
snatMap map[netip.Addr]netip.Addr // dst -> src
dnatMap map[netip.Addr]netip.Addr
dnat []dnatTest
}{
{
name: "no-cfg",
@ -667,10 +673,10 @@ func TestPeerCfg_NAT(t *testing.T) {
peer2IP: selfNativeIP,
subnetIP: selfNativeIP,
},
dnatMap: map[netip.Addr]netip.Addr{
selfNativeIP: selfNativeIP,
selfEIP1: selfEIP1,
selfEIP2: selfEIP2,
dnat: []dnatTest{
{selfNativeIP, selfNativeIP, selfNativeIP},
{peer1IP, selfEIP1, selfEIP1},
{peer2IP, selfEIP2, selfEIP2},
},
},
{
@ -679,19 +685,19 @@ func TestPeerCfg_NAT(t *testing.T) {
Addresses: selfAddrs,
Peers: []wgcfg.Peer{
node(peer1IP, noIP),
node(peer2IP, selfEIP1),
node(peer2IP, selfEIP2),
},
},
snatMap: map[netip.Addr]netip.Addr{
peer1IP: selfNativeIP,
peer2IP: selfEIP1,
peer2IP: selfEIP2,
subnetIP: selfNativeIP,
},
dnatMap: map[netip.Addr]netip.Addr{
selfNativeIP: selfNativeIP,
selfEIP1: selfNativeIP,
selfEIP2: selfEIP2,
subnetIP: subnetIP,
dnat: []dnatTest{
{selfNativeIP, selfNativeIP, selfNativeIP},
{peer1IP, selfEIP1, selfEIP1},
{peer2IP, selfEIP2, selfNativeIP}, // NATed
{peer2IP, subnetIP, subnetIP},
},
},
{
@ -708,11 +714,11 @@ func TestPeerCfg_NAT(t *testing.T) {
peer2IP: selfEIP2,
subnetIP: selfNativeIP,
},
dnatMap: map[netip.Addr]netip.Addr{
selfNativeIP: selfNativeIP,
selfEIP1: selfNativeIP,
selfEIP2: selfNativeIP,
subnetIP: subnetIP,
dnat: []dnatTest{
{selfNativeIP, selfNativeIP, selfNativeIP},
{peer1IP, selfEIP1, selfNativeIP},
{peer2IP, selfEIP2, selfNativeIP},
{peer2IP, subnetIP, subnetIP},
},
},
{
@ -729,11 +735,11 @@ func TestPeerCfg_NAT(t *testing.T) {
peer2IP: selfEIP2,
subnetIP: selfEIP2,
},
dnatMap: map[netip.Addr]netip.Addr{
selfNativeIP: selfNativeIP,
selfEIP1: selfNativeIP,
selfEIP2: selfNativeIP,
subnetIP: subnetIP,
dnat: []dnatTest{
{selfNativeIP, selfNativeIP, selfNativeIP},
{peer1IP, selfEIP1, selfNativeIP},
{peer2IP, selfEIP2, selfNativeIP},
{peer2IP, subnetIP, subnetIP},
},
},
{
@ -750,11 +756,11 @@ func TestPeerCfg_NAT(t *testing.T) {
peer2IP: selfEIP2,
publicIP: selfEIP2,
},
dnatMap: map[netip.Addr]netip.Addr{
selfNativeIP: selfNativeIP,
selfEIP1: selfNativeIP,
selfEIP2: selfNativeIP,
subnetIP: subnetIP,
dnat: []dnatTest{
{selfNativeIP, selfNativeIP, selfNativeIP},
{peer1IP, selfEIP1, selfNativeIP},
{peer2IP, selfEIP2, selfNativeIP},
{peer2IP, subnetIP, subnetIP},
},
},
{
@ -771,11 +777,11 @@ func TestPeerCfg_NAT(t *testing.T) {
peer2IP: selfNativeIP,
subnetIP: selfNativeIP,
},
dnatMap: map[netip.Addr]netip.Addr{
selfNativeIP: selfNativeIP,
selfEIP1: selfEIP1,
selfEIP2: selfEIP2,
subnetIP: subnetIP,
dnat: []dnatTest{
{selfNativeIP, selfNativeIP, selfNativeIP},
{peer1IP, selfEIP1, selfEIP1},
{peer2IP, selfEIP2, selfEIP2},
{peer2IP, subnetIP, subnetIP},
},
},
{
@ -792,25 +798,25 @@ func TestPeerCfg_NAT(t *testing.T) {
peer2IP: selfEIP2,
publicIP: selfEIP2,
},
dnatMap: map[netip.Addr]netip.Addr{
selfNativeIP: selfNativeIP,
selfEIP2: selfNativeIP,
subnetIP: subnetIP,
dnat: []dnatTest{
{selfNativeIP, selfNativeIP, selfNativeIP},
{peer2IP, selfEIP2, selfNativeIP},
{peer2IP, subnetIP, subnetIP},
},
},
}
for _, tc := range tests {
t.Run(fmt.Sprintf("%v/%v", addrFam, tc.name), func(t *testing.T) {
pcfg := peerConfigFromWGConfig(tc.wcfg)
pcfg := peerConfigTableFromWGConfig(tc.wcfg)
for peer, want := range tc.snatMap {
if got := pcfg.selectSrcIP(selfNativeIP, peer); got != want {
t.Errorf("selectSrcIP[%v]: got %v; want %v", peer, got, want)
}
}
for dstIP, want := range tc.dnatMap {
if got := pcfg.mapDstIP(dstIP); got != want {
t.Errorf("mapDstIP[%v]: got %v; want %v", dstIP, got, want)
for i, dt := range tc.dnat {
if got := pcfg.mapDstIP(dt.src, dt.dst); got != dt.want {
t.Errorf("dnat[%d]: mapDstIP[%v, %v]: got %v; want %v", i, dt.src, dt.dst, got, dt.want)
}
}
if t.Failed() {