fix(dialer): correct inverted setMark on FreeBSD/OpenBSD
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).
This commit is contained in:
@@ -0,0 +1,655 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user