32c3d33afd
Extract Handle into handleRawForwarding, handleSniffedProtocol, SnifferBuilder, newRecorderObject, and checkRateLimit across forward.go, sniffing.go, and util.go. Replace redundant x509.ParseCertificate with tlsCert.Leaf (already populated by tls.LoadX509KeyPair since Go 1.23).
158 lines
4.4 KiB
Go
158 lines
4.4 KiB
Go
package local
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/go-gost/core/chain"
|
|
"github.com/go-gost/x/internal/util/sniffing"
|
|
xrecorder "github.com/go-gost/x/recorder"
|
|
)
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// sniffingDial
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func TestSniffingDial_Success(t *testing.T) {
|
|
server, client := net.Pipe()
|
|
defer server.Close()
|
|
defer client.Close()
|
|
|
|
h := newInitdHandler(withRouter(&mockRouter{
|
|
opts: &chain.RouterOptions{},
|
|
dialFn: func(ctx context.Context, network, address string) (net.Conn, error) {
|
|
return server, nil
|
|
},
|
|
}))
|
|
ro := &xrecorder.HandlerRecorderObject{}
|
|
|
|
cc, err := h.sniffingDial(context.Background(), "tcp", "example.com:80", ro)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
defer cc.Close()
|
|
|
|
if ro.Route == "" {
|
|
t.Log("route is empty (mock does not populate context buffer)")
|
|
}
|
|
}
|
|
|
|
func TestSniffingDial_RouterError(t *testing.T) {
|
|
expectedErr := errors.New("dial failed")
|
|
h := newInitdHandler(withRouter(&mockRouter{
|
|
opts: &chain.RouterOptions{},
|
|
dialFn: func(ctx context.Context, network, address string) (net.Conn, error) {
|
|
return nil, expectedErr
|
|
},
|
|
}))
|
|
ro := &xrecorder.HandlerRecorderObject{}
|
|
|
|
_, err := h.sniffingDial(context.Background(), "tcp", "example.com:80", ro)
|
|
if err == nil {
|
|
t.Fatal("expected error")
|
|
}
|
|
if !errors.Is(err, expectedErr) {
|
|
t.Errorf("expected %v, got %v", expectedErr, err)
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SnifferBuilder
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func TestSnifferBuilder(t *testing.T) {
|
|
h := newTestHandler()
|
|
h.sniffer.Websocket = true
|
|
h.sniffer.WebsocketSampleRate = 0.5
|
|
h.sniffer.ReadTimeout = 30 * time.Second
|
|
|
|
sniffer := h.sniffer.Build()
|
|
|
|
if !sniffer.Websocket {
|
|
t.Error("expected Websocket to be true")
|
|
}
|
|
if sniffer.WebsocketSampleRate != 0.5 {
|
|
t.Errorf("expected 0.5, got %f", sniffer.WebsocketSampleRate)
|
|
}
|
|
if sniffer.ReadTimeout != 30*time.Second {
|
|
t.Errorf("expected 30s, got %v", sniffer.ReadTimeout)
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// handleSniffedProtocol
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func TestHandleSniffedProtocol_UnknownProto(t *testing.T) {
|
|
h := newInitdHandler()
|
|
conn := newStringConn(nil)
|
|
ro := &xrecorder.HandlerRecorderObject{}
|
|
|
|
handled, err := h.handleSniffedProtocol(context.Background(), conn, ro, nopLog(), "ssh")
|
|
if handled {
|
|
t.Error("expected handled=false for unknown proto")
|
|
}
|
|
if err != nil {
|
|
t.Errorf("expected nil error, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestHandleSniffedProtocol_EmptyProto(t *testing.T) {
|
|
h := newInitdHandler()
|
|
conn := newStringConn(nil)
|
|
ro := &xrecorder.HandlerRecorderObject{}
|
|
|
|
handled, err := h.handleSniffedProtocol(context.Background(), conn, ro, nopLog(), "")
|
|
if handled {
|
|
t.Error("expected handled=false for empty proto")
|
|
}
|
|
if err != nil {
|
|
t.Errorf("expected nil error, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestHandleSniffedProtocol_HTTP(t *testing.T) {
|
|
h := newInitdHandler(withRouter(&mockRouter{
|
|
opts: &chain.RouterOptions{},
|
|
dialFn: func(ctx context.Context, network, address string) (net.Conn, error) {
|
|
return nil, errors.New("dial not configured in test")
|
|
},
|
|
}))
|
|
conn := newStringConn([]byte("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"))
|
|
ro := &xrecorder.HandlerRecorderObject{}
|
|
|
|
handled, err := h.handleSniffedProtocol(context.Background(), conn, ro, nopLog(), sniffing.ProtoHTTP)
|
|
|
|
if !handled {
|
|
t.Error("expected handled=true for HTTP proto")
|
|
}
|
|
if err == nil {
|
|
t.Log("sniffer processed HTTP request without error")
|
|
}
|
|
}
|
|
|
|
func TestHandleSniffedProtocol_TLS(t *testing.T) {
|
|
h := newInitdHandler(withRouter(&mockRouter{
|
|
opts: &chain.RouterOptions{},
|
|
dialFn: func(ctx context.Context, network, address string) (net.Conn, error) {
|
|
return nil, errors.New("dial not configured in test")
|
|
},
|
|
}))
|
|
conn := newStringConn([]byte{
|
|
0x16, 0x03, 0x01, 0x00, 0x06, 0x01, 0x00, 0x00, 0x02, 0x03, 0x01,
|
|
})
|
|
ro := &xrecorder.HandlerRecorderObject{}
|
|
|
|
handled, err := h.handleSniffedProtocol(context.Background(), conn, ro, nopLog(), sniffing.ProtoTLS)
|
|
|
|
if !handled {
|
|
t.Error("expected handled=true for TLS proto")
|
|
}
|
|
if err == nil {
|
|
t.Log("sniffer processed TLS ClientHello without error")
|
|
}
|
|
}
|