mirror of
https://github.com/tailscale/tailscale.git
synced 2024-12-12 11:14:40 +00:00
f27b2cf569
The design changed during integration and testing, resulting in the earlier implementation growing in the appc package to be intended now only for the sniproxy implementation. That code is moved to it's final location, and the current App Connector code is now renamed. Updates tailscale/corp#15437 Signed-off-by: James Tucker <james@tailscale.com>
160 lines
4.1 KiB
Go
160 lines
4.1 KiB
Go
// Copyright (c) Tailscale Inc & AUTHORS
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/hex"
|
|
"io"
|
|
"net"
|
|
"net/netip"
|
|
"strings"
|
|
"testing"
|
|
|
|
"tailscale.com/net/memnet"
|
|
)
|
|
|
|
func echoConnOnce(conn net.Conn) {
|
|
defer conn.Close()
|
|
|
|
b := make([]byte, 256)
|
|
n, err := conn.Read(b)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if _, err := conn.Write(b[:n]); err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
func TestTCPRoundRobinHandler(t *testing.T) {
|
|
h := tcpRoundRobinHandler{
|
|
To: []string{"yeet.com"},
|
|
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
|
if network != "tcp" {
|
|
t.Errorf("network = %s, want %s", network, "tcp")
|
|
}
|
|
if addr != "yeet.com:22" {
|
|
t.Errorf("addr = %s, want %s", addr, "yeet.com:22")
|
|
}
|
|
|
|
c, s := memnet.NewConn("outbound", 1024)
|
|
go echoConnOnce(s)
|
|
return c, nil
|
|
},
|
|
}
|
|
|
|
cSock, sSock := memnet.NewTCPConn(netip.MustParseAddrPort("10.64.1.2:22"), netip.MustParseAddrPort("10.64.1.2:22"), 1024)
|
|
h.Handle(sSock)
|
|
|
|
// Test data write and read, the other end will echo back
|
|
// a single stanza
|
|
want := "hello"
|
|
if _, err := io.WriteString(cSock, want); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got := make([]byte, len(want))
|
|
if _, err := io.ReadAtLeast(cSock, got, len(got)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if string(got) != want {
|
|
t.Errorf("got %q, want %q", got, want)
|
|
}
|
|
|
|
// The other end closed the socket after the first echo, so
|
|
// any following read should error.
|
|
io.WriteString(cSock, "deadass heres some data on god fr")
|
|
if _, err := io.ReadAtLeast(cSock, got, len(got)); err == nil {
|
|
t.Error("read succeeded on closed socket")
|
|
}
|
|
}
|
|
|
|
// Capture of first TCP data segment for a connection to https://pkgs.tailscale.com
|
|
const tlsStart = `45000239ff1840004006f9f5c0a801f2
|
|
c726b5efcf9e01bbe803b21394e3b752
|
|
801801f641dc00000101080ade3474f2
|
|
2fb93ee71603010200010001fc030303
|
|
c3acbd19d2624765bb19af4bce03365e
|
|
1d197f5bb939cdadeff26b0f8e7a0620
|
|
295b04127b82bae46aac4ff58cffef25
|
|
eba75a4b7a6de729532c411bd9dd0d2c
|
|
00203a3a130113021303c02bc02fc02c
|
|
c030cca9cca8c013c014009c009d002f
|
|
003501000193caca0000000a000a0008
|
|
1a1a001d001700180010000e000c0268
|
|
3208687474702f312e31002b0007062a
|
|
2a03040303ff01000100000d00120010
|
|
04030804040105030805050108060601
|
|
000b00020100002300000033002b0029
|
|
1a1a000100001d0020d3c76bef062979
|
|
a812ce935cfb4dbe6b3a84dc5ba9226f
|
|
23b0f34af9d1d03b4a001b0003020002
|
|
00120000446900050003026832000000
|
|
170015000012706b67732e7461696c73
|
|
63616c652e636f6d002d000201010005
|
|
00050100000000001700003a3a000100
|
|
0015002d000000000000000000000000
|
|
00000000000000000000000000000000
|
|
00000000000000000000000000000000
|
|
0000290094006f0069e76f2016f963ad
|
|
38c8632d1f240cd75e00e25fdef295d4
|
|
7042b26f3a9a543b1c7dc74939d77803
|
|
20527d423ff996997bda2c6383a14f49
|
|
219eeef8a053e90a32228df37ddbe126
|
|
eccf6b085c93890d08341d819aea6111
|
|
0d909f4cd6b071d9ea40618e74588a33
|
|
90d494bbb5c3002120d5a164a16c9724
|
|
c9ef5e540d8d6f007789a7acf9f5f16f
|
|
bf6a1907a6782ed02b`
|
|
|
|
func fakeSNIHeader() []byte {
|
|
b, err := hex.DecodeString(strings.Replace(tlsStart, "\n", "", -1))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return b[0x34:] // trim IP + TCP header
|
|
}
|
|
|
|
func TestTCPSNIHandler(t *testing.T) {
|
|
h := tcpSNIHandler{
|
|
Allowlist: []string{"pkgs.tailscale.com"},
|
|
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
|
if network != "tcp" {
|
|
t.Errorf("network = %s, want %s", network, "tcp")
|
|
}
|
|
if addr != "pkgs.tailscale.com:443" {
|
|
t.Errorf("addr = %s, want %s", addr, "pkgs.tailscale.com:443")
|
|
}
|
|
|
|
c, s := memnet.NewConn("outbound", 1024)
|
|
go echoConnOnce(s)
|
|
return c, nil
|
|
},
|
|
}
|
|
|
|
cSock, sSock := memnet.NewTCPConn(netip.MustParseAddrPort("10.64.1.2:22"), netip.MustParseAddrPort("10.64.1.2:443"), 1024)
|
|
h.Handle(sSock)
|
|
|
|
// Fake a TLS handshake record with an SNI in it.
|
|
if _, err := cSock.Write(fakeSNIHeader()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Test read, the other end will echo back
|
|
// a single stanza, which is at least the beginning of the SNI header.
|
|
want := fakeSNIHeader()[:5]
|
|
if _, err := cSock.Write(want); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got := make([]byte, len(want))
|
|
if _, err := io.ReadAtLeast(cSock, got, len(got)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !bytes.Equal(got, want) {
|
|
t.Errorf("got %q, want %q", got, want)
|
|
}
|
|
}
|