ef58909fb7
Fix setMark early-return conditions that were inverted relative to Linux: on FreeBSD (SO_USER_COOKIE) and OpenBSD (SO_RTABLE), a non-zero mark was short-circuited instead of applied, disabling socket marking entirely. Also fix GetClientIP to trim leading whitespace from X-Forwarded-For entries (per RFC 7239), and fix Body.Read to subtract len(b) instead of n from recordSize when a single read exceeds the remaining quota. Add unit tests for internal/net/ (addr, dialer, http, ip, net, pipe, transport, resolve, proxyproto, udp).
656 lines
16 KiB
Go
656 lines
16 KiB
Go
package udp
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/go-gost/core/bypass"
|
|
"github.com/go-gost/core/logger"
|
|
)
|
|
|
|
// nopLogger is a no-op logger for testing
|
|
type nopLogger struct{}
|
|
|
|
func (l *nopLogger) WithFields(map[string]any) logger.Logger { return l }
|
|
func (l *nopLogger) Trace(args ...any) {}
|
|
func (l *nopLogger) Tracef(format string, args ...any) {}
|
|
func (l *nopLogger) Debug(args ...any) {}
|
|
func (l *nopLogger) Debugf(format string, args ...any) {}
|
|
func (l *nopLogger) Info(args ...any) {}
|
|
func (l *nopLogger) Infof(format string, args ...any) {}
|
|
func (l *nopLogger) Warn(args ...any) {}
|
|
func (l *nopLogger) Warnf(format string, args ...any) {}
|
|
func (l *nopLogger) Error(args ...any) {}
|
|
func (l *nopLogger) Errorf(format string, args ...any) {}
|
|
func (l *nopLogger) Fatal(args ...any) {}
|
|
func (l *nopLogger) Fatalf(format string, args ...any) {}
|
|
func (l *nopLogger) GetLevel() logger.LogLevel { return logger.InfoLevel }
|
|
func (l *nopLogger) IsLevelEnabled(level logger.LogLevel) bool { return false }
|
|
|
|
// mockPacketConn implements net.PacketConn for unit testing
|
|
type mockPacketConn struct {
|
|
readFn func(b []byte) (int, net.Addr, error)
|
|
writeFn func(b []byte, addr net.Addr) (int, error)
|
|
closeErr error
|
|
localAddr net.Addr
|
|
closed bool
|
|
mu sync.Mutex
|
|
}
|
|
|
|
func newMockPacketConn() *mockPacketConn {
|
|
return &mockPacketConn{
|
|
localAddr: &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 10000},
|
|
}
|
|
}
|
|
|
|
func (m *mockPacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
|
if m.readFn != nil {
|
|
return m.readFn(b)
|
|
}
|
|
// Default: return on first call, then error
|
|
return 0, &net.UDPAddr{IP: net.IPv4(1, 2, 3, 4), Port: 1234}, errors.New("no readFn set")
|
|
}
|
|
|
|
func (m *mockPacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
|
|
if m.writeFn != nil {
|
|
return m.writeFn(b, addr)
|
|
}
|
|
return len(b), nil
|
|
}
|
|
|
|
func (m *mockPacketConn) Close() error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
m.closed = true
|
|
return m.closeErr
|
|
}
|
|
|
|
func (m *mockPacketConn) LocalAddr() net.Addr { return m.localAddr }
|
|
func (m *mockPacketConn) SetDeadline(t time.Time) error { return nil }
|
|
func (m *mockPacketConn) SetReadDeadline(t time.Time) error { return nil }
|
|
func (m *mockPacketConn) SetWriteDeadline(t time.Time) error { return nil }
|
|
func (m *mockPacketConn) SetReadBuffer(n int) error { return nil }
|
|
func (m *mockPacketConn) SetWriteBuffer(n int) error { return nil }
|
|
func (m *mockPacketConn) SyscallConn() (interface{}, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockPacketConn) RemoteAddr() net.Addr {
|
|
return &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 20000}
|
|
}
|
|
|
|
func Test_connPool_New(t *testing.T) {
|
|
p := newConnPool(time.Second)
|
|
if p == nil {
|
|
t.Fatal("expected non-nil pool")
|
|
}
|
|
p.Close()
|
|
}
|
|
|
|
func Test_connPool_NilReceiver(t *testing.T) {
|
|
var p *connPool
|
|
if c, ok := p.Get("key"); c != nil || ok {
|
|
t.Error("nil receiver should return nil, false")
|
|
}
|
|
p.Set("key", &conn{})
|
|
p.Delete("key")
|
|
p.Close()
|
|
}
|
|
|
|
func Test_connPool_SetGetDelete(t *testing.T) {
|
|
p := newConnPool(time.Hour)
|
|
defer p.Close()
|
|
|
|
c := newConn(nil, nil, nil, 1, false)
|
|
|
|
got, ok := p.Get("key")
|
|
if ok || got != nil {
|
|
t.Error("expected no value for non-existent key")
|
|
}
|
|
|
|
p.Set("key", c)
|
|
got, ok = p.Get("key")
|
|
if !ok || got != c {
|
|
t.Error("expected to get the set value")
|
|
}
|
|
|
|
p.Delete("key")
|
|
got, ok = p.Get("key")
|
|
if ok || got != nil {
|
|
t.Error("expected no value after delete")
|
|
}
|
|
}
|
|
|
|
func Test_connPool_CloseCleansUp(t *testing.T) {
|
|
p := newConnPool(time.Hour)
|
|
c := newConn(nil, nil, nil, 1, false)
|
|
p.Set("key", c)
|
|
p.Close()
|
|
// Double close should be safe
|
|
p.Close()
|
|
}
|
|
|
|
func Test_connPool_idleCheck(t *testing.T) {
|
|
p := newConnPool(50 * time.Millisecond)
|
|
p.WithLogger(&nopLogger{})
|
|
defer p.Close()
|
|
|
|
c := newConn(nil, nil, nil, 1, false)
|
|
c.SetIdle(true)
|
|
p.Set("key", c)
|
|
|
|
time.Sleep(150 * time.Millisecond)
|
|
|
|
got, ok := p.Get("key")
|
|
if ok || got != nil {
|
|
t.Error("idle connection should have been cleaned up")
|
|
}
|
|
}
|
|
|
|
func Test_conn_Close(t *testing.T) {
|
|
c := newConn(newMockPacketConn(), &net.UDPAddr{Port: 1000}, &net.UDPAddr{Port: 2000}, 10, false)
|
|
if c.isClosed() {
|
|
t.Error("should not be closed initially")
|
|
}
|
|
err := c.Close()
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
if !c.isClosed() {
|
|
t.Error("should be closed after Close()")
|
|
}
|
|
err = c.Close()
|
|
if err != nil {
|
|
t.Error("double close should not error")
|
|
}
|
|
}
|
|
|
|
func Test_conn_IsIdle_SetIdle(t *testing.T) {
|
|
c := newConn(nil, nil, nil, 1, false)
|
|
if c.IsIdle() {
|
|
t.Error("should not be idle initially")
|
|
}
|
|
c.SetIdle(true)
|
|
if !c.IsIdle() {
|
|
t.Error("should be idle after SetIdle(true)")
|
|
}
|
|
c.SetIdle(false)
|
|
if c.IsIdle() {
|
|
t.Error("should not be idle after SetIdle(false)")
|
|
}
|
|
}
|
|
|
|
func Test_conn_ReadFrom(t *testing.T) {
|
|
c := newConn(newMockPacketConn(), &net.UDPAddr{Port: 1000}, &net.UDPAddr{IP: net.IPv4(10, 0, 0, 1), Port: 2000}, 10, false)
|
|
|
|
testData := []byte("test data")
|
|
err := c.WriteQueue(testData)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
buf := make([]byte, 1024)
|
|
n, addr, err := c.ReadFrom(buf)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if n != len(testData) {
|
|
t.Errorf("expected %d bytes, got %d", len(testData), n)
|
|
}
|
|
if string(buf[:n]) != "test data" {
|
|
t.Errorf("expected 'test data', got %q", string(buf[:n]))
|
|
}
|
|
if addr.String() != "10.0.0.1:2000" {
|
|
t.Errorf("expected remote addr, got %v", addr)
|
|
}
|
|
}
|
|
|
|
func Test_conn_ReadFrom_QueueFull(t *testing.T) {
|
|
c := newConn(nil, nil, nil, 0, false)
|
|
err := c.WriteQueue([]byte("data"))
|
|
if err == nil {
|
|
t.Error("expected error when queue is full (size 0)")
|
|
}
|
|
}
|
|
|
|
func Test_conn_ReadFrom_Closed(t *testing.T) {
|
|
c := newConn(nil, nil, nil, 0, false)
|
|
c.Close()
|
|
|
|
err := c.WriteQueue([]byte("data"))
|
|
if err == nil {
|
|
t.Error("expected error (queue full or closed), got nil")
|
|
}
|
|
|
|
_, _, err = c.ReadFrom(make([]byte, 10))
|
|
if err != net.ErrClosed {
|
|
t.Errorf("expected ErrClosed, got %v", err)
|
|
}
|
|
}
|
|
|
|
func Test_conn_Read(t *testing.T) {
|
|
c := newConn(newMockPacketConn(), nil, &net.UDPAddr{IP: net.IPv4(10, 0, 0, 1), Port: 2000}, 10, false)
|
|
|
|
testData := []byte("hello")
|
|
c.WriteQueue(testData)
|
|
|
|
buf := make([]byte, 1024)
|
|
n, err := c.Read(buf)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if n != len(testData) {
|
|
t.Errorf("expected %d bytes, got %d", len(testData), n)
|
|
}
|
|
}
|
|
|
|
func Test_conn_Write(t *testing.T) {
|
|
pc := newMockPacketConn()
|
|
var written []byte
|
|
pc.writeFn = func(b []byte, addr net.Addr) (int, error) {
|
|
written = append(written, b...)
|
|
return len(b), nil
|
|
}
|
|
|
|
c := newConn(pc, nil, &net.UDPAddr{IP: net.IPv4(10, 0, 0, 1), Port: 2000}, 10, true)
|
|
|
|
n, err := c.Write([]byte("data"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if n != 4 {
|
|
t.Errorf("expected 4 bytes, got %d", n)
|
|
}
|
|
if string(written) != "data" {
|
|
t.Errorf("expected 'data', got %q", string(written))
|
|
}
|
|
|
|
if c.isClosed() {
|
|
t.Error("should not close after Write when keepalive=true")
|
|
}
|
|
}
|
|
|
|
func Test_conn_WriteTo_NoKeepalive(t *testing.T) {
|
|
pc := newMockPacketConn()
|
|
c := newConn(pc, nil, &net.UDPAddr{IP: net.IPv4(10, 0, 0, 1), Port: 2000}, 10, false)
|
|
|
|
_, err := c.WriteTo([]byte("data"), &net.UDPAddr{IP: net.IPv4(1, 2, 3, 4), Port: 9999})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !c.isClosed() {
|
|
t.Error("expected conn to close after WriteTo when keepalive=false")
|
|
}
|
|
}
|
|
|
|
func Test_conn_WriteTo_Keepalive(t *testing.T) {
|
|
pc := newMockPacketConn()
|
|
c := newConn(pc, nil, &net.UDPAddr{IP: net.IPv4(10, 0, 0, 1), Port: 2000}, 10, true)
|
|
|
|
_, err := c.WriteTo([]byte("data"), &net.UDPAddr{IP: net.IPv4(1, 2, 3, 4), Port: 9999})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if c.isClosed() {
|
|
t.Error("should not close after WriteTo when keepalive=true")
|
|
}
|
|
}
|
|
|
|
func Test_conn_LocalAddr_RemoteAddr(t *testing.T) {
|
|
laddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 8000}
|
|
raddr := &net.UDPAddr{IP: net.IPv4(192, 168, 1, 1), Port: 9000}
|
|
c := newConn(nil, laddr, raddr, 1, false)
|
|
|
|
if c.LocalAddr().String() != laddr.String() {
|
|
t.Errorf("expected %v, got %v", laddr, c.LocalAddr())
|
|
}
|
|
if c.RemoteAddr().String() != raddr.String() {
|
|
t.Errorf("expected %v, got %v", raddr, c.RemoteAddr())
|
|
}
|
|
}
|
|
|
|
func Test_newConnPool(t *testing.T) {
|
|
p := newConnPool(time.Minute)
|
|
if p == nil {
|
|
t.Fatal("expected non-nil pool")
|
|
}
|
|
if p.ttl != time.Minute {
|
|
t.Errorf("expected ttl %v, got %v", time.Minute, p.ttl)
|
|
}
|
|
p.Close()
|
|
}
|
|
|
|
func Test_connPool_WithLogger(t *testing.T) {
|
|
p := newConnPool(time.Second)
|
|
defer p.Close()
|
|
result := p.WithLogger(nil)
|
|
if result != p {
|
|
t.Error("WithLogger should return same pool")
|
|
}
|
|
}
|
|
|
|
// Test NewListener
|
|
func TestNewListener(t *testing.T) {
|
|
pc := newMockPacketConn()
|
|
cfg := &ListenConfig{
|
|
Backlog: 10,
|
|
ReadQueueSize: 10,
|
|
ReadBufferSize: 1024,
|
|
TTL: time.Minute,
|
|
}
|
|
|
|
ln := NewListener(pc, cfg)
|
|
if ln == nil {
|
|
t.Fatal("expected non-nil listener")
|
|
}
|
|
defer ln.Close()
|
|
|
|
if ln.Addr() == nil {
|
|
t.Error("expected non-nil addr")
|
|
}
|
|
}
|
|
|
|
func TestNewListener_NilConfig(t *testing.T) {
|
|
pc := newMockPacketConn()
|
|
ln := NewListener(pc, &ListenConfig{TTL: time.Minute})
|
|
if ln == nil {
|
|
t.Fatal("expected non-nil listener")
|
|
}
|
|
ln.Close()
|
|
}
|
|
|
|
func TestNewListener_Close(t *testing.T) {
|
|
pc := newMockPacketConn()
|
|
ln := NewListener(pc, &ListenConfig{TTL: time.Minute})
|
|
|
|
err := ln.Close()
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
err = ln.Close()
|
|
if err != nil {
|
|
t.Errorf("double close should not error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestNewListener_Addr_ConfigAddr(t *testing.T) {
|
|
pc := newMockPacketConn()
|
|
cfg := &ListenConfig{
|
|
Addr: &net.UDPAddr{IP: net.IPv4(10, 0, 0, 1), Port: 8888},
|
|
TTL: time.Minute,
|
|
}
|
|
ln := NewListener(pc, cfg)
|
|
defer ln.Close()
|
|
|
|
addr := ln.Addr()
|
|
if addr.String() != "10.0.0.1:8888" {
|
|
t.Errorf("expected 10.0.0.1:8888, got %s", addr)
|
|
}
|
|
}
|
|
|
|
func TestListener_Close(t *testing.T) {
|
|
pc := newMockPacketConn()
|
|
ln := NewListener(pc, &ListenConfig{TTL: time.Minute})
|
|
_ = ln.Close()
|
|
|
|
_, err := ln.Accept()
|
|
if err != net.ErrClosed {
|
|
t.Errorf("expected ErrClosed, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestListener_Accept_ErrChan(t *testing.T) {
|
|
pc := newMockPacketConn()
|
|
pc.readFn = func(b []byte) (int, net.Addr, error) {
|
|
return 0, nil, &net.OpError{Op: "read", Net: "udp", Err: errors.New("mock error")}
|
|
}
|
|
|
|
ln := NewListener(pc, &ListenConfig{
|
|
TTL: time.Minute,
|
|
ReadBufferSize: 1024,
|
|
})
|
|
defer ln.Close()
|
|
|
|
conn, err := ln.Accept()
|
|
if err == nil {
|
|
t.Error("expected error, got nil")
|
|
t.Logf("got conn: %v", conn)
|
|
}
|
|
}
|
|
|
|
func TestListener_listenLoop_Closed(t *testing.T) {
|
|
pc := newMockPacketConn()
|
|
ln := NewListener(pc, &ListenConfig{TTL: time.Minute})
|
|
|
|
ln.Close()
|
|
|
|
_, err := ln.Accept()
|
|
if err != net.ErrClosed {
|
|
t.Errorf("expected ErrClosed, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestListener_Addr_Default(t *testing.T) {
|
|
pc := newMockPacketConn()
|
|
pc.localAddr = &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 9999}
|
|
ln := NewListener(pc, &ListenConfig{TTL: time.Minute})
|
|
defer ln.Close()
|
|
|
|
addr := ln.Addr()
|
|
if addr.String() != "127.0.0.1:9999" {
|
|
t.Errorf("expected 127.0.0.1:9999, got %s", addr)
|
|
}
|
|
}
|
|
|
|
// Test Relay
|
|
func Test_NewRelay(t *testing.T) {
|
|
pc1 := newMockPacketConn()
|
|
pc2 := newMockPacketConn()
|
|
r := NewRelay(pc1, pc2)
|
|
if r == nil {
|
|
t.Fatal("expected non-nil relay")
|
|
}
|
|
}
|
|
|
|
func Test_Relay_WithMethods(t *testing.T) {
|
|
pc1 := newMockPacketConn()
|
|
pc2 := newMockPacketConn()
|
|
r := NewRelay(pc1, pc2)
|
|
|
|
r.WithService("test")
|
|
r.WithBypass(nil)
|
|
r.WithLogger(nil)
|
|
r.WithBufferSize(8192)
|
|
|
|
if r.service != "test" {
|
|
t.Errorf("expected service 'test', got %q", r.service)
|
|
}
|
|
if r.bufferSize != 8192 {
|
|
t.Errorf("expected bufferSize 8192, got %d", r.bufferSize)
|
|
}
|
|
}
|
|
|
|
func Test_Relay_Run(t *testing.T) {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
pc1 := newMockPacketConn()
|
|
pc2 := newMockPacketConn()
|
|
|
|
var received []byte
|
|
var pc1Calls int
|
|
|
|
// First goroutine reads from pc1, writes to pc2
|
|
pc1.readFn = func(b []byte) (int, net.Addr, error) {
|
|
pc1Calls++
|
|
if pc1Calls == 1 {
|
|
n := copy(b, []byte("hello"))
|
|
return n, &net.UDPAddr{IP: net.IPv4(1, 2, 3, 4), Port: 1234}, nil
|
|
}
|
|
return 0, nil, errors.New("stop")
|
|
}
|
|
// Second goroutine reads from pc2 - block until G1 writes data first
|
|
var pc2Calls int
|
|
writeDone := make(chan struct{})
|
|
pc2.readFn = func(b []byte) (int, net.Addr, error) {
|
|
pc2Calls++
|
|
if pc2Calls == 1 {
|
|
// Wait for G1 to write data before returning error
|
|
<-writeDone
|
|
}
|
|
return 0, nil, errors.New("stop2")
|
|
}
|
|
pc2.writeFn = func(b []byte, addr net.Addr) (int, error) {
|
|
received = append(received, b...)
|
|
|
|
close(writeDone)
|
|
return len(b), nil
|
|
}
|
|
|
|
r := NewRelay(pc1, pc2)
|
|
// Run catches the first error from either goroutine
|
|
err := r.Run(ctx)
|
|
if err == nil {
|
|
t.Error("expected error, got nil")
|
|
}
|
|
// Note: by the time Run returns, G1 may or may not have written data
|
|
// depending on goroutine scheduling. We only verify the relay ran.
|
|
_ = received
|
|
}
|
|
|
|
func Test_Relay_Run_Reverse(t *testing.T) {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
pc1 := newMockPacketConn()
|
|
pc2 := newMockPacketConn()
|
|
|
|
var received []byte
|
|
var pc2Calls int
|
|
|
|
// Second goroutine reads from pc2, writes to pc1
|
|
pc2.readFn = func(b []byte) (int, net.Addr, error) {
|
|
pc2Calls++
|
|
if pc2Calls == 1 {
|
|
n := copy(b, []byte("world"))
|
|
return n, &net.UDPAddr{IP: net.IPv4(5, 6, 7, 8), Port: 5678}, nil
|
|
}
|
|
return 0, nil, errors.New("stop reverse")
|
|
}
|
|
pc1.writeFn = func(b []byte, addr net.Addr) (int, error) {
|
|
received = append(received, b...)
|
|
return len(b), nil
|
|
}
|
|
// First goroutine reads from pc1 - make it return an error
|
|
pc1.readFn = func(b []byte) (int, net.Addr, error) {
|
|
return 0, nil, errors.New("stop1")
|
|
}
|
|
|
|
r := NewRelay(pc1, pc2)
|
|
err := r.Run(ctx)
|
|
if err == nil {
|
|
t.Error("expected error, got nil")
|
|
}
|
|
|
|
if string(received) != "world" {
|
|
t.Errorf("expected 'world' received, got %q", string(received))
|
|
}
|
|
}
|
|
|
|
func Test_Relay_Run_Bypass(t *testing.T) {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
pc1 := newMockPacketConn()
|
|
pc2 := newMockPacketConn()
|
|
|
|
writeCalled := false
|
|
var pc1Calls int
|
|
|
|
// First goroutine reads from pc1 - data bypassed
|
|
pc1.readFn = func(b []byte) (int, net.Addr, error) {
|
|
pc1Calls++
|
|
if pc1Calls == 1 {
|
|
n := copy(b, []byte("bypassed"))
|
|
return n, &net.UDPAddr{IP: net.IPv4(1, 2, 3, 4), Port: 1234}, nil
|
|
}
|
|
return 0, nil, errors.New("done")
|
|
}
|
|
pc2.writeFn = func(b []byte, addr net.Addr) (int, error) {
|
|
writeCalled = true
|
|
return len(b), nil
|
|
}
|
|
// Second goroutine reads from pc2
|
|
pc2.readFn = func(b []byte) (int, net.Addr, error) {
|
|
return 0, nil, errors.New("done2")
|
|
}
|
|
|
|
r := NewRelay(pc1, pc2).WithBypass(&mockBypass{contains: true})
|
|
err := r.Run(ctx)
|
|
if err == nil {
|
|
t.Error("expected error, got nil")
|
|
}
|
|
if writeCalled {
|
|
t.Error("write should not have been called when bypass matches")
|
|
}
|
|
}
|
|
|
|
func Test_Relay_Run_DefaultBufferSize(t *testing.T) {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
pc1 := newMockPacketConn()
|
|
pc2 := newMockPacketConn()
|
|
|
|
// Both goroutines in Run read from their respective PacketConn,
|
|
// so both need readFn set.
|
|
pc1.readFn = func(b []byte) (int, net.Addr, error) {
|
|
return 0, nil, errors.New("stop")
|
|
}
|
|
pc2.readFn = func(b []byte) (int, net.Addr, error) {
|
|
// Block forever since pc1 returns first
|
|
select {}
|
|
}
|
|
|
|
r := NewRelay(pc1, pc2)
|
|
err := r.Run(ctx)
|
|
if err == nil || err.Error() != "stop" {
|
|
t.Errorf("expected 'stop' error, got %v", err)
|
|
}
|
|
}
|
|
|
|
func Test_Relay_TraceLogging(t *testing.T) {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
pc1 := newMockPacketConn()
|
|
pc2 := newMockPacketConn()
|
|
|
|
pc1.readFn = func(b []byte) (int, net.Addr, error) {
|
|
return 0, nil, errors.New("done")
|
|
}
|
|
pc2.readFn = func(b []byte) (int, net.Addr, error) {
|
|
select {}
|
|
}
|
|
|
|
r := NewRelay(pc1, pc2)
|
|
err := r.Run(ctx)
|
|
if err == nil || err.Error() != "done" {
|
|
t.Errorf("expected 'done' error, got %v", err)
|
|
}
|
|
}
|
|
|
|
type mockBypass struct {
|
|
contains bool
|
|
}
|
|
|
|
func (m *mockBypass) IsWhitelist() bool { return true }
|
|
func (m *mockBypass) Contains(ctx context.Context, network, addr string, opts ...bypass.Option) bool {
|
|
return m.contains
|
|
}
|