You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tailscale/net/packet/tsmp_test.go

240 lines
5.7 KiB
Go

// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
package packet
import (
"net/netip"
"testing"
)
func TestTailscaleRejectedHeader(t *testing.T) {
tests := []struct {
h TailscaleRejectedHeader
wantStr string
}{
{
h: TailscaleRejectedHeader{
IPSrc: netip.MustParseAddr("5.5.5.5"),
IPDst: netip.MustParseAddr("1.2.3.4"),
Src: netip.MustParseAddrPort("1.2.3.4:567"),
Dst: netip.MustParseAddrPort("5.5.5.5:443"),
Proto: TCP,
Reason: RejectedDueToACLs,
},
wantStr: "TSMP-reject-flow{TCP 1.2.3.4:567 > 5.5.5.5:443}: acl",
},
{
h: TailscaleRejectedHeader{
IPSrc: netip.MustParseAddr("2::2"),
IPDst: netip.MustParseAddr("1::1"),
Src: netip.MustParseAddrPort("[1::1]:567"),
Dst: netip.MustParseAddrPort("[2::2]:443"),
Proto: UDP,
Reason: RejectedDueToShieldsUp,
},
wantStr: "TSMP-reject-flow{UDP [1::1]:567 > [2::2]:443}: shields",
},
{
h: TailscaleRejectedHeader{
IPSrc: netip.MustParseAddr("2::2"),
IPDst: netip.MustParseAddr("1::1"),
Src: netip.MustParseAddrPort("[1::1]:567"),
Dst: netip.MustParseAddrPort("[2::2]:443"),
Proto: UDP,
Reason: RejectedDueToIPForwarding,
MaybeBroken: true,
},
wantStr: "TSMP-reject-flow{UDP [1::1]:567 > [2::2]:443}: host-ip-forwarding-unavailable",
},
}
for i, tt := range tests {
gotStr := tt.h.String()
if gotStr != tt.wantStr {
t.Errorf("%v. String = %q; want %q", i, gotStr, tt.wantStr)
continue
}
pkt := make([]byte, tt.h.Len())
tt.h.Marshal(pkt)
var p Parsed
p.Decode(pkt)
t.Logf("Parsed: %+v", p)
t.Logf("Parsed: %s", p.String())
back, ok := p.AsTailscaleRejectedHeader()
if !ok {
t.Errorf("%v. %q (%02x) didn't parse back", i, gotStr, pkt)
continue
}
if back != tt.h {
t.Errorf("%v. %q parsed back as %q", i, tt.h, back)
}
}
}
func TestTSMPDiscoKeyRequest(t *testing.T) {
t.Run("Manual", func(t *testing.T) {
var payload [1]byte
payload[0] = byte(TSMPTypeDiscoKeyRequest)
var p Parsed
p.IPProto = TSMP
p.dataofs = 40 // simulate after IP header
buf := make([]byte, 40+1)
copy(buf[40:], payload[:])
p.b = buf
p.length = len(buf)
_, ok := p.AsTSMPDiscoKeyRequest()
if !ok {
t.Fatal("failed to parse TSMP disco key request")
}
})
t.Run("RoundTripIPv4", func(t *testing.T) {
src := netip.MustParseAddr("100.64.0.1")
dst := netip.MustParseAddr("100.64.0.2")
iph := IP4Header{
IPProto: TSMP,
Src: src,
Dst: dst,
}
var payload [1]byte
payload[0] = byte(TSMPTypeDiscoKeyRequest)
pkt := Generate(iph, payload[:])
t.Logf("Generated packet: %d bytes, hex: %x", len(pkt), pkt)
// Manually check what decode4 would see
if len(pkt) >= 4 {
declaredLen := int(uint16(pkt[2])<<8 | uint16(pkt[3]))
t.Logf("Packet buffer length: %d, IP header declares length: %d", len(pkt), declaredLen)
t.Logf("Protocol byte at [9]: 0x%02x = %d", pkt[9], pkt[9])
}
var p Parsed
p.Decode(pkt)
t.Logf("Decoded: IPVersion=%d IPProto=%v Src=%v Dst=%v length=%d dataofs=%d",
p.IPVersion, p.IPProto, p.Src, p.Dst, p.length, p.dataofs)
if p.IPVersion != 4 {
t.Errorf("IPVersion = %d, want 4", p.IPVersion)
}
if p.IPProto != TSMP {
t.Errorf("IPProto = %v, want TSMP", p.IPProto)
}
if p.Src.Addr() != src {
t.Errorf("Src = %v, want %v", p.Src.Addr(), src)
}
if p.Dst.Addr() != dst {
t.Errorf("Dst = %v, want %v", p.Dst.Addr(), dst)
}
_, ok := p.AsTSMPDiscoKeyRequest()
if !ok {
t.Fatal("failed to parse TSMP disco key request from generated packet")
}
})
t.Run("RoundTripIPv6", func(t *testing.T) {
src := netip.MustParseAddr("2001:db8::1")
dst := netip.MustParseAddr("2001:db8::2")
iph := IP6Header{
IPProto: TSMP,
Src: src,
Dst: dst,
}
var payload [1]byte
payload[0] = byte(TSMPTypeDiscoKeyRequest)
pkt := Generate(iph, payload[:])
t.Logf("Generated packet: %d bytes", len(pkt))
var p Parsed
p.Decode(pkt)
if p.IPVersion != 6 {
t.Errorf("IPVersion = %d, want 6", p.IPVersion)
}
if p.IPProto != TSMP {
t.Errorf("IPProto = %v, want TSMP", p.IPProto)
}
if p.Src.Addr() != src {
t.Errorf("Src = %v, want %v", p.Src.Addr(), src)
}
if p.Dst.Addr() != dst {
t.Errorf("Dst = %v, want %v", p.Dst.Addr(), dst)
}
_, ok := p.AsTSMPDiscoKeyRequest()
if !ok {
t.Fatal("failed to parse TSMP disco key request from generated packet")
}
})
}
func TestTSMPDiscoKeyUpdate(t *testing.T) {
var discoKey [32]byte
for i := range discoKey {
discoKey[i] = byte(i + 10)
}
t.Run("IPv4", func(t *testing.T) {
update := TSMPDiscoKeyUpdate{
IPHeader: IP4Header{
IPProto: TSMP,
Src: netip.MustParseAddr("1.2.3.4"),
Dst: netip.MustParseAddr("5.6.7.8"),
},
DiscoKey: discoKey,
}
pkt := make([]byte, update.Len())
if err := update.Marshal(pkt); err != nil {
t.Fatal(err)
}
var p Parsed
p.Decode(pkt)
parsed, ok := p.AsTSMPDiscoKeyUpdate()
if !ok {
t.Fatal("failed to parse TSMP disco key update")
}
if parsed.DiscoKey != discoKey {
t.Errorf("disco key mismatch: got %v, want %v", parsed.DiscoKey, discoKey)
}
})
t.Run("IPv6", func(t *testing.T) {
update := TSMPDiscoKeyUpdate{
IPHeader: IP6Header{
IPProto: TSMP,
Src: netip.MustParseAddr("2001:db8::1"),
Dst: netip.MustParseAddr("2001:db8::2"),
},
DiscoKey: discoKey,
}
pkt := make([]byte, update.Len())
if err := update.Marshal(pkt); err != nil {
t.Fatal(err)
}
var p Parsed
p.Decode(pkt)
parsed, ok := p.AsTSMPDiscoKeyUpdate()
if !ok {
t.Fatal("failed to parse TSMP disco key update")
}
if parsed.DiscoKey != discoKey {
t.Errorf("disco key mismatch: got %v, want %v", parsed.DiscoKey, discoKey)
}
})
}