mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-10-09 03:46:14 -08:00
* chore(go): use lowercase module import path * ci: scope checks for Go module changes
210 lines
5.1 KiB
Go
210 lines
5.1 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/binary"
|
|
"io"
|
|
"net"
|
|
"net/netip"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
corehost "github.com/easytier/easytier/easytier-go"
|
|
"github.com/easytier/easytier/easytier-go/proto/common"
|
|
)
|
|
|
|
func TestParseOptions(t *testing.T) {
|
|
options, err := parseOptions([]string{
|
|
"-p", "tcp://198.51.100.10:11010",
|
|
"--network-name", "office",
|
|
"--network-secret", "secret",
|
|
"--ipv4", "10.144.0.10/24",
|
|
"--network", "udp4",
|
|
"--address", "10.144.0.20:7000",
|
|
"--connect-timeout", "3s",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("parse options: %v", err)
|
|
}
|
|
if options.network != "udp4" ||
|
|
options.address != "10.144.0.20:7000" ||
|
|
options.connectTimeout != 3*time.Second ||
|
|
len(options.peers) != 1 {
|
|
t.Fatalf("parsed options = %+v", options)
|
|
}
|
|
}
|
|
|
|
func TestParseOptionsRejectsInvalidArguments(t *testing.T) {
|
|
valid := []string{
|
|
"-p", "tcp://198.51.100.10:11010",
|
|
"--network-name", "office",
|
|
"--network-secret", "secret",
|
|
"--ipv4", "10.144.0.10/24",
|
|
"--address", "10.144.0.20:7000",
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
arguments []string
|
|
want string
|
|
}{
|
|
{
|
|
name: "network",
|
|
arguments: append(append([]string(nil), valid...), "--network", "sctp"),
|
|
want: "--network",
|
|
},
|
|
{
|
|
name: "destination",
|
|
arguments: []string{
|
|
"-p", "tcp://198.51.100.10:11010",
|
|
"--network-name", "office",
|
|
"--network-secret", "secret",
|
|
"--ipv4", "10.144.0.10/24",
|
|
"--address", "[2001:db8::1]:7000",
|
|
},
|
|
want: "--address",
|
|
},
|
|
{
|
|
name: "connect timeout",
|
|
arguments: append(append([]string(nil), valid...), "--connect-timeout", "0s"),
|
|
want: "--connect-timeout",
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
_, err := parseOptions(test.arguments)
|
|
if err == nil || !strings.Contains(err.Error(), test.want) {
|
|
t.Fatalf("parse error = %v, want containing %q", err, test.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRoutesReachOverlayOrProxyDestination(t *testing.T) {
|
|
overlay := netip.MustParseAddr("10.144.0.20")
|
|
overlayOctets := overlay.As4()
|
|
routes := []*corehost.Route{
|
|
{
|
|
Ipv4Addr: &common.Ipv4Inet{
|
|
Address: &common.Ipv4Addr{
|
|
Addr: binary.BigEndian.Uint32(overlayOctets[:]),
|
|
},
|
|
},
|
|
},
|
|
{ProxyCidrs: []string{"10.200.0.0/24"}},
|
|
}
|
|
if !routesReach(routes, overlay) {
|
|
t.Fatal("overlay destination was not reachable")
|
|
}
|
|
if !routesReach(routes, netip.MustParseAddr("10.200.0.8")) {
|
|
t.Fatal("proxy destination was not reachable")
|
|
}
|
|
if routesReach(routes, netip.MustParseAddr("10.201.0.8")) {
|
|
t.Fatal("unknown destination was reachable")
|
|
}
|
|
}
|
|
|
|
func TestRelayTCP(t *testing.T) {
|
|
client, server := net.Pipe()
|
|
defer client.Close()
|
|
defer server.Close()
|
|
serverDone := make(chan error, 1)
|
|
go func() {
|
|
request := make([]byte, len("request"))
|
|
if _, err := io.ReadFull(server, request); err != nil {
|
|
serverDone <- err
|
|
return
|
|
}
|
|
if string(request) != "request" {
|
|
serverDone <- io.ErrUnexpectedEOF
|
|
return
|
|
}
|
|
if _, err := server.Write([]byte("response")); err != nil {
|
|
serverDone <- err
|
|
return
|
|
}
|
|
serverDone <- server.Close()
|
|
}()
|
|
|
|
var output bytes.Buffer
|
|
if err := relayTCP(client, strings.NewReader("request"), &output); err != nil {
|
|
t.Fatalf("relay TCP: %v", err)
|
|
}
|
|
if err := <-serverDone; err != nil {
|
|
t.Fatalf("serve TCP exchange: %v", err)
|
|
}
|
|
if output.String() != "response" {
|
|
t.Fatalf("TCP output = %q", output.String())
|
|
}
|
|
}
|
|
|
|
func TestExchangeUDP(t *testing.T) {
|
|
echo, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1)})
|
|
if err != nil {
|
|
t.Fatalf("listen UDP echo: %v", err)
|
|
}
|
|
defer echo.Close()
|
|
echoDone := make(chan error, 1)
|
|
go func() {
|
|
packet := make([]byte, maxUDPPayload)
|
|
length, client, err := echo.ReadFromUDP(packet)
|
|
if err == nil {
|
|
_, err = echo.WriteToUDP(packet[:length], client)
|
|
}
|
|
echoDone <- err
|
|
}()
|
|
|
|
connection, err := net.DialUDP("udp4", nil, echo.LocalAddr().(*net.UDPAddr))
|
|
if err != nil {
|
|
t.Fatalf("dial UDP echo: %v", err)
|
|
}
|
|
defer connection.Close()
|
|
_ = connection.SetDeadline(time.Now().Add(5 * time.Second))
|
|
|
|
var output bytes.Buffer
|
|
if err := exchangeUDP(
|
|
context.Background(),
|
|
connection,
|
|
strings.NewReader("datagram"),
|
|
&output,
|
|
); err != nil {
|
|
t.Fatalf("exchange UDP: %v", err)
|
|
}
|
|
if err := <-echoDone; err != nil {
|
|
t.Fatalf("serve UDP exchange: %v", err)
|
|
}
|
|
if output.String() != "datagram" {
|
|
t.Fatalf("UDP output = %q", output.String())
|
|
}
|
|
}
|
|
|
|
func TestExchangeUDPRejectsOversizedInput(t *testing.T) {
|
|
connection, peer := net.Pipe()
|
|
defer connection.Close()
|
|
defer peer.Close()
|
|
err := exchangeUDP(
|
|
context.Background(),
|
|
connection,
|
|
strings.NewReader(strings.Repeat("x", maxUDPPayload+1)),
|
|
io.Discard,
|
|
)
|
|
if err == nil || !strings.Contains(err.Error(), "maximum payload") {
|
|
t.Fatalf("oversized UDP error = %v", err)
|
|
}
|
|
}
|
|
|
|
func TestExchangeUDPCanCancelInputRead(t *testing.T) {
|
|
connection, peer := net.Pipe()
|
|
defer connection.Close()
|
|
defer peer.Close()
|
|
input, inputWriter := io.Pipe()
|
|
defer input.Close()
|
|
defer inputWriter.Close()
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
cancel()
|
|
if err := exchangeUDP(ctx, connection, input, io.Discard); err != context.Canceled {
|
|
t.Fatalf("cancelled UDP exchange error = %v", err)
|
|
}
|
|
}
|