// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package portmapper import ( "encoding/binary" "testing" "tailscale.com/net/netaddr" ) var examplePCPMapResponse = []byte{2, 129, 0, 0, 0, 0, 28, 32, 0, 2, 155, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 112, 9, 24, 241, 208, 251, 45, 157, 76, 10, 188, 17, 0, 0, 0, 4, 210, 4, 210, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 135, 180, 175, 246} func TestParsePCPMapResponse(t *testing.T) { mapping, err := parsePCPMapResponse(examplePCPMapResponse) if err != nil { t.Fatalf("failed to parse PCP Map Response: %v", err) } if mapping == nil { t.Fatalf("got nil mapping when expected non-nil") } expectedAddr := netaddr.MustParseIPPort("135.180.175.246:1234") if mapping.external != expectedAddr { t.Errorf("mismatched external address, got: %v, want: %v", mapping.external, expectedAddr) } } const ( serverResponseBit = 1 << 7 fakeLifetimeSec = 1<<31 - 1 ) func buildPCPDiscoResponse(req []byte) []byte { out := make([]byte, 24) out[0] = pcpVersion out[1] = req[1] | serverResponseBit out[3] = 0 // Do not put an epoch time in 8:12, when we start using it, tests that use it should fail. return out } func buildPCPMapResponse(req []byte) []byte { out := make([]byte, 24+36) out[0] = pcpVersion out[1] = req[1] | serverResponseBit out[3] = 0 binary.BigEndian.PutUint32(out[4:8], 1<<30) // Do not put an epoch time in 8:12, when we start using it, tests that use it should fail. mapResp := out[24:] mapReq := req[24:] // copy nonce, protocol and internal port copy(mapResp[:13], mapReq[:13]) copy(mapResp[16:18], mapReq[16:18]) // assign external port binary.BigEndian.PutUint16(mapResp[18:20], 4242) assignedIP := netaddr.IPv4(127, 0, 0, 1) assignedIP16 := assignedIP.As16() copy(mapResp[20:36], assignedIP16[:]) return out }