socksgo

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 18, 2026 License: CC0-1.0 Imports: 22 Imported by: 0

README

socksgo

Go Reference Coverage Status
The most complete, compatible, featured and extensible SOCKS library for Go. Check comparison.

Features

Complete
  • Tor extensions
    • Resolve
    • ResolvePtr
    • Stream Isolation
  • Gost extensions
    • socks over TLS
    • socks over WebSocket
    • MBIND (Multiplexed Bind)
    • UDP TUN (UDP tunneling over TCP)
  • Flexible client configuration
    • Explicit Client structure construction
    • Client from URL (full and safe variants)
    • Client from environment variables
Extensible
Well Tested

Comparison

Library Client Server SOCKS4 SOCKS4a SOCKS5 CONNECT BIND UDP ASSOC User/Pass GSS IDENT Gost Ext Tor Ext
socksgo
socksd (dante)
tor *
gost
things-go/go-socks5
h12w/socks4
armon/go-socks5
fangdingjun/socks-go
ezh0v/socks5
txthinking/socks5
peakedshout/go-socks
snail007/goproxy
haochen233/socks5

* - user/pass method supported but used for other purpose

Installation

go get github.com/asciimoth/socksgo

Quick Start

Client
import "github.com/asciimoth/socksgo"

// Simple SOCKS5 client
client, _ := socksgo.ClientFromURL("socks5://proxy:1080")
conn, _ := client.Dial(context.Background(), "tcp", "example.com:80")
Server
import "github.com/asciimoth/socksgo"

server := &socksgo.Server{
    Auth:     socksgo.DefaultAuthHandlers,
    Handlers: socksgo.DefaultCommandHandlers,
}

listener, _ := net.Listen("tcp", ":1080")
for {
    conn, _ := listener.Accept()
    go server.Accept(context.Background(), conn, false)
}

Examples

See the examples directory for more usage patterns:

TODO

  • Extension auth method for tls encrypted password negotiation
  • Add more tls options to client url scheme
  • Implement UDP ASSOC fragmentation support
  • Improve socks over WS perf

License

Files in this repository are distributed under the CC0 license.

CC0
To the extent possible under law, ASCIIMoth has waived all copyright and related or neighboring rights to socksgo.

Documentation

Overview

Package socksgo implements SOCKS proxy client and server (SOCKS4, SOCKS4a, SOCKS5) with extensions for Gost and Tor compatibility.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrUDPDisallowed is returned when attempting plaintext UDP over TLS/WSS
	// proxies without the insecureudp option enabled.
	ErrUDPDisallowed = errors.New(
		"plaintext UDP is disallowed for tls/wss proxies",
	)
	// ErrResolveDisabled is returned when Tor lookup extension is requested
	// but not enabled on the client.
	ErrResolveDisabled = errors.New(
		"tor resolve extension for socks is disabled",
	)
	// ErrWrongAddrInLookupResponse is returned when a Tor resolve response
	// contains an unexpected address type.
	ErrWrongAddrInLookupResponse = errors.New(
		"wrong addr type in lookup response",
	)
	// ErrClientAuthFailed is returned when client authentication fails.
	ErrClientAuthFailed = errors.New("client auth failed")
)

Client-side error variables.

View Source
var DefaultBindHandler = CommandHandler{
	Socks4:    true,
	Socks5:    true,
	TLSCompat: true,
	Handler: func(
		ctx context.Context,
		server *Server,
		conn net.Conn,
		ver string,
		info protocol.AuthInfo,
		cmd protocol.Cmd,
		addr protocol.Addr) error {
		pool := server.GetPool()
		addr = addr.WithDefaultHost(server.GetDefaultListenHost())
		err := server.CheckLaddr(&addr)
		if err != nil {
			protocol.Reject(ver, conn, protocol.DisallowReply, pool)
			return err
		}
		tcp := "tcp"
		if ver == "4" || ver == "4a" {
			tcp = "tcp4"
		}
		listener, err := server.GetListener()(ctx, tcp, addr.ToHostPort())
		if err != nil {
			protocol.Reject(ver, conn, errorToReplyStatus(err), pool)
			return err
		}
		defer func() { _ = listener.Close() }()

		err = protocol.Reply(
			ver,
			conn,
			protocol.SuccReply,
			protocol.AddrFromNetAddr(listener.Addr()),
			pool,
		)
		if err != nil {
			return err
		}
		proxy, err := listener.Accept()
		if err != nil {
			return err
		}

		err = protocol.Reply(
			ver,
			conn,
			protocol.SuccReply,
			protocol.AddrFromNetAddr(proxy.RemoteAddr()),
			pool,
		)
		if err != nil {
			return err
		}
		return protocol.PipeConn(conn, proxy)
	},
}

DefaultBindHandler handles the BIND command.

DefaultBindHandler creates a TCP listener on the proxy server that forwards incoming connections to the client.

Protocol Support

  • SOCKS4: Yes
  • SOCKS4a: Yes
  • SOCKS5: Yes
  • TLS: Yes

Behavior

  1. Applies default listen host if address is unspecified
  2. Validates local address against LaddrFilter
  3. Creates TCP listener on requested address
  4. Sends first reply with bound address (listener.Addr())
  5. Waits for single incoming connection
  6. Sends second reply with remote address (incoming client)
  7. Pipes data bidirectionally

Two-Reply Protocol

BIND uses a two-reply protocol:

  1. First reply: Contains the address where the client should direct the peer to connect (listener address)
  2. Second reply: Contains the address of the incoming connection (after Accept returns)

Use Cases

BIND is used for protocols that require reverse connections:

  • FTP passive mode
  • Remote debugging
  • Any protocol requiring server-to-client connections

Reply

Sends success reply (0x00) with:

  • First reply: Listener address
  • Second reply: Incoming connection's remote address

Errors

Returns error and sends appropriate reply status:

  • DisallowReply (0x02): Address filtered
  • FailReply (0x01): Listen failed

Examples

// Default handler is used automatically
server := &socksgo.Server{
    Handlers: socksgo.DefaultCommandHandlers,
}

See Also

  • RFC 1928: SOCKS5 Protocol (Section 4)
  • protocol.PipeConn: Connection piping implementation
  • server_handler_mbind.go: Gost multiplexed BIND

DefaultCommandHandlers is the default map of command handlers.

DefaultCommandHandlers provides standard implementations for all supported SOCKS commands:

  • CmdConnect: Forward TCP connections
  • CmdBind: Listen for incoming connections (BIND)
  • CmdUDPAssoc: UDP association (standard SOCKS5)
  • CmdTorResolve: Forward DNS lookup (Tor extension)
  • CmdTorResolvePtr: Reverse DNS lookup (Tor extension)
  • CmdGostUDPTun: UDP tunnel over TCP (Gost extension)
  • CmdGostMuxBind: Multiplexed BIND (Gost extension)

Usage

Use as-is for standard SOCKS server, or copy and modify for custom behavior:

handlers := make(map[protocol.Cmd]CommandHandler)
for k, v := range socksgo.DefaultCommandHandlers {
    handlers[k] = v
}
handlers[protocol.CmdConnect] = myCustomHandler
server.Handlers = handlers

See Also

  • server_handler_connect.go: CONNECT handler implementation
  • server_handler_bind.go: BIND handler implementation
  • server_handler_assoc.go: UDP ASSOC handler implementation
  • server_handler_resolve.go: Tor resolve handler implementation
  • server_handler_mbind.go: Gost MBIND handler implementation
  • server_handler_tun.go: Gost UDP tunnel handler implementation
View Source
var DefaultConnectHandler = CommandHandler{
	Socks4:    true,
	Socks5:    true,
	TLSCompat: true,
	Handler: func(
		ctx context.Context,
		server *Server,
		conn net.Conn,
		ver string,
		info protocol.AuthInfo,
		cmd protocol.Cmd,
		addr protocol.Addr) error {
		pool := server.GetPool()
		err := server.CheckRaddr(&addr)
		if err != nil {
			protocol.Reject(ver, conn, protocol.DisallowReply, pool)
			return err
		}
		conn2, err := server.GetDialer()(ctx, addr.Network(), addr.String())
		if err != nil {
			protocol.Reject(ver, conn, errorToReplyStatus(err), pool)
			return err
		}
		defer func() { _ = conn2.Close() }()
		err = protocol.Reply(
			ver,
			conn,
			protocol.SuccReply,
			protocol.AddrFromNetAddr(conn2.RemoteAddr()),
			pool,
		)
		if err != nil {
			return err
		}
		return protocol.PipeConn(conn, conn2)
	},
}

DefaultConnectHandler handles the CONNECT command.

DefaultConnectHandler establishes a TCP connection to the target address and pipes data between the client and target.

Protocol Support

  • SOCKS4: Yes
  • SOCKS4a: Yes
  • SOCKS5: Yes
  • TLS: Yes

Behavior

  1. Validates remote address against RaddrFilter
  2. Dials target address using server's Dialer
  3. Sends success reply with bound address
  4. Pipes data bidirectionally until EOF or error

Reply

Sends success reply (0x00) with the target's address.

Errors

Returns error and sends appropriate reply status:

  • DisallowReply (0x02): Address filtered
  • HostUnreachReply (0x04): Dial failed
  • FailReply (0x01): Other errors

Examples

// Default handler is used automatically
server := &socksgo.Server{
    Handlers: socksgo.DefaultCommandHandlers,
}

See Also

  • RFC 1928: SOCKS5 Protocol (Section 4)
  • protocol.PipeConn: Connection piping implementation
View Source
var DefaultGostMBindHandler = CommandHandler{
	Socks4:    true,
	Socks5:    true,
	TLSCompat: true,
	Handler: func(
		ctx context.Context,
		server *Server,
		conn net.Conn,
		ver string,
		info protocol.AuthInfo,
		cmd protocol.Cmd,
		addr protocol.Addr) error {
		pool := server.GetPool()
		addr = addr.WithDefaultHost(server.GetDefaultListenHost())
		err := server.CheckLaddr(&addr)
		if err != nil {
			protocol.Reject(ver, conn, protocol.DisallowReply, pool)
			return err
		}
		listener, err := server.GetListener()(ctx, "tcp", addr.ToHostPort())
		if err != nil {
			protocol.Reject(ver, conn, errorToReplyStatus(err), pool)
			return err
		}
		defer func() { _ = listener.Close() }()

		err = protocol.Reply(
			ver,
			conn,
			protocol.SuccReply,
			protocol.AddrFromNetAddr(listener.Addr()),
			pool,
		)
		if err != nil {
			return err
		}

		session, err := smux.Client(conn, server.GetSmux())
		if err != nil {
			_ = conn.Close()
			return err
		}
		defer func() {
			_ = conn.Close()
			_ = session.Close()
		}()

		var wg sync.WaitGroup
		wg.Go(func() {
			for {
				rw, err := session.Accept()
				if err != nil {
					_ = session.Close()
					_ = listener.Close()
					return
				}
				_ = rw.Close()
			}
		})
		for {
			var inc net.Conn
			inc, err = listener.Accept()
			if err != nil {
				break
			}
			stream, err := session.OpenStream()
			if err != nil {
				break
			}
			wg.Go(func() {
				_ = protocol.PipeConn(inc, stream)
			})
		}
		wg.Wait()

		return internal.ClosedNetworkErrToNil(err)
	},
}

DefaultGostMBindHandler handles the Gost multiplexed BIND command.

DefaultGostMBindHandler creates a TCP listener and uses smux to multiplex multiple incoming connections over a single TCP connection to the client.

Protocol Support

  • SOCKS4: Yes (Gost extension)
  • SOCKS5: Yes (Gost extension)
  • TLS: Yes

Behavior

  1. Applies default listen host if address is unspecified

  2. Validates local address against LaddrFilter

  3. Creates TCP listener on requested address

  4. Sends success reply with bound address

  5. Upgrades connection to smux session

  6. Spawns goroutine to accept smux streams (and discard)

  7. Accepts incoming connections on listener

  8. For each incoming connection: - Opens new smux stream - Pipes data between listener connection and stream

  9. Continues until listener or session closes

Multiplexing

MBIND uses smux (stream multiplexing) to carry multiple independent connections over a single TCP connection.

Reply

Sends success reply (0x00) with the listener address.

Errors

Returns error and sends appropriate reply status:

  • DisallowReply (0x02): Address filtered
  • FailReply (0x01): Listen failed

Examples

// Enable on server
server := &socksgo.Server{
    Handlers: socksgo.DefaultCommandHandlers,
    Smux: &smux.Config{
        MaxFrameSize:     65535,
        MaxReceiveBuffer: 4194304,
    },
}

See Also

  • github.com/xtaci/smux: Stream multiplexing library
  • server_handler_bind.go: Standard BIND handler
  • protocol.PipeConn: Connection piping implementation
View Source
var DefaultGostUDPTUNHandler = CommandHandler{
	Socks4:    false,
	Socks5:    true,
	TLSCompat: false,
	Handler: func(
		ctx context.Context,
		server *Server,
		tun net.Conn,
		ver string,
		info protocol.AuthInfo,
		cmd protocol.Cmd,
		addr protocol.Addr) (err error) {
		addr.NetTyp = "udp"
		pool := server.GetPool()

		var proxy PacketConn

		binded := false
		if addr.IsUnspecified() {

			laddr := addr.WithDefaultHost(server.GetDefaultListenHost())
			err = server.CheckLaddr(&addr)
			if err == nil {
				proxy, err = server.GetPacketListener()(
					ctx, laddr.Network(), laddr.ToHostPort(),
				)
			}
		} else {
			err = server.CheckRaddr(&addr)
			if err == nil {
				binded = true
				proxy, err = server.GetPacketDialer()(
					ctx,
					addr.Network(),
					addr.ToHostPort(),
				)
			}
		}
		if err != nil {
			protocol.Reject(ver, tun, errorToReplyStatus(err), pool)
			return err

		}

		err = protocol.Reply(
			ver,
			tun,
			protocol.SuccReply,
			protocol.AddrFromNetAddr(proxy.LocalAddr()),
			pool,
		)
		if err != nil {
			return err
		}

		return protocol.ProxySocks5UDPTun(
			tun, proxy, binded, nil, pool, server.GetUDPBufferSize(),
		)
	},
}

DefaultGostUDPTUNHandler handles the Gost UDP Tunnel command.

DefaultGostUDPTUNHandler creates a UDP tunnel over TCP, encapsulating UDP packets in a custom TCP framing format.

Protocol Support

  • SOCKS4: No (Gost extension)
  • SOCKS5: Yes (Gost extension)
  • TLS: No (UDP over TLS is problematic)

Behavior

  1. Sets address network type to "udp"

  2. If address is unspecified (0.0.0.0:0): - Creates UDP listener (server mode) - Validates against LaddrFilter

  3. If address is specified: - Creates UDP connection to target (client mode) - Validates against RaddrFilter

  4. Sends success reply with proxy's UDP address

  5. Proxies UDP packets with Gost framing over TCP

Reply

Sends success reply (0x00) with the proxy's UDP address.

Errors

Returns error and sends appropriate reply status:

  • DisallowReply (0x02): Address filtered
  • FailReply (0x01): Listen/dial failed

Examples

// Enable on client
client.GostUDPTun = true

// Server handles automatically with DefaultCommandHandlers
server := &socksgo.Server{
    Handlers: socksgo.DefaultCommandHandlers,
}

See Also

  • server_handler_assoc.go: Standard UDP ASSOC handler
  • protocol.ProxySocks5UDPTun: UDP tunnel proxy implementation
View Source
var DefaultResolveHandler = CommandHandler{
	Socks4:    true,
	Socks5:    true,
	TLSCompat: true,
	Handler: func(
		ctx context.Context,
		server *Server,
		conn net.Conn,
		ver string,
		info protocol.AuthInfo,
		cmd protocol.Cmd,
		addr protocol.Addr) error {
		pool := server.GetPool()
		err := server.CheckRaddr(&addr)
		if err != nil {
			protocol.Reject(ver, conn, protocol.DisallowReply, pool)
			return err
		}
		ips, err := server.GetResolver().
			LookupIP(ctx, addr.IpNetwork(), addr.ToFQDN())
		if err != nil {
			protocol.Reject(ver, conn, protocol.HostUnreachReply, pool)
			return err
		}
		if len(ips) < 1 {
			protocol.Reject(ver, conn, protocol.HostUnreachReply, pool)
			return &net.DNSError{
				Err:        "zero IPs found",
				Name:       addr.ToFQDN(),
				IsNotFound: true,
			}
		}
		ip := ips[0]
		if server.IsPreferIPv4() {
			for _, elem := range ips {
				if ip4 := elem.To4(); ip4 != nil {
					ip = ip4
					break
				}
			}
		}
		err = protocol.Reply(
			ver,
			conn,
			protocol.SuccReply,
			protocol.AddrFromIP(ip, 0, ""),
			pool,
		)
		return err
	},
}

DefaultResolveHandler handles the Tor forward DNS lookup command.

DefaultResolveHandler performs DNS forward lookup (A/AAAA records) through the server's configured resolver and returns the resolved IP address to the client.

Protocol Support

  • SOCKS4: Yes (with Tor extension)
  • SOCKS4a: Yes (with Tor extension)
  • SOCKS5: Yes (with Tor extension)
  • TLS: Yes

Behavior

  1. Validates remote address (hostname) against RaddrFilter

  2. Performs DNS lookup using server's Resolver

  3. If DoNotPreferIP4 is false (default): - Prefers IPv4 address if both IPv4 and IPv6 found

  4. Sends success reply with resolved IP address

IPv4 Preference

By default (DoNotPreferIP4 = false), if the DNS lookup returns both IPv4 and IPv6 addresses, the first IPv4 address is returned. This provides better compatibility with clients that expect IPv4.

Reply

Sends success reply (0x00) with the resolved IP address. The port in the reply is set to 0.

Errors

Returns error and sends appropriate reply status:

  • DisallowReply (0x02): Address filtered
  • HostUnreachReply (0x04): DNS lookup failed or no results

Examples

// Enable on client
client.TorLookup = true
ips, err := client.LookupIP(ctx, "ip4", "example.com")

// Server handles automatically with DefaultCommandHandlers
server := &socksgo.Server{
    Handlers: socksgo.DefaultCommandHandlers,
}

See Also

  • server_handler_resolveptr.go: Reverse DNS lookup
  • client.go#LookupIP: Client-side forward lookup
View Source
var DefaultResolvePtrHandler = CommandHandler{
	Socks4:    false,
	Socks5:    true,
	TLSCompat: true,
	Handler: func(
		ctx context.Context,
		server *Server,
		conn net.Conn,
		ver string,
		info protocol.AuthInfo,
		cmd protocol.Cmd,
		addr protocol.Addr) error {
		pool := server.GetPool()
		err := server.CheckRaddr(&addr)
		if err != nil {
			protocol.Reject(ver, conn, protocol.DisallowReply, pool)
			return err
		}
		names, err := server.GetResolver().LookupAddr(ctx, addr.ToIP().String())
		if err != nil {
			protocol.Reject(ver, conn, protocol.HostUnreachReply, pool)
			return err
		}
		if len(names) < 1 {
			protocol.Reject(ver, conn, protocol.HostUnreachReply, pool)
			return &net.DNSError{
				Err:        "zero addrs found",
				Name:       addr.ToFQDN(),
				IsNotFound: true,
			}
		}
		err = protocol.Reply(
			ver,
			conn,
			protocol.SuccReply,
			protocol.AddrFromFQDNNoDot(names[0], 0, ""),
			pool,
		)
		return err
	},
}

DefaultResolvePtrHandler handles the Tor reverse DNS lookup command.

DefaultResolvePtrHandler performs DNS reverse lookup (PTR records) through the server's configured resolver and returns the resolved hostname to the client.

Protocol Support

  • SOCKS4: No
  • SOCKS4a: No
  • SOCKS5: Yes (with Tor extension)
  • TLS: Yes

Behavior

  1. Validates remote address (IP) against RaddrFilter
  2. Performs reverse DNS lookup using server's Resolver
  3. Sends success reply with resolved hostname

Reply

Sends success reply (0x00) with the resolved hostname. The port in the reply is set to 0.

Errors

Returns error and sends appropriate reply status:

  • DisallowReply (0x02): Address filtered
  • HostUnreachReply (0x04): DNS lookup failed or no results

Examples

// Enable on client
client.TorLookup = true
names, err := client.LookupAddr(ctx, "8.8.8.8")

// Server handles automatically with DefaultCommandHandlers
server := &socksgo.Server{
    Handlers: socksgo.DefaultCommandHandlers,
}

See Also

  • server_handler_resolve.go: Forward DNS lookup
  • client.go#LookupAddr: Client-side reverse lookup
View Source
var DefaultUDPAssocHandler = CommandHandler{
	Socks4:    false,
	Socks5:    true,
	TLSCompat: false,
	Handler: func(
		ctx context.Context,
		server *Server,
		ctrl net.Conn,
		ver string,
		info protocol.AuthInfo,
		cmd protocol.Cmd,
		addr protocol.Addr) (err error) {
		addr.NetTyp = "udp"
		pool := server.GetPool()

		var proxy PacketConn

		binded := false
		if addr.IsUnspecified() {

			laddr := addr.WithDefaultHost(server.GetDefaultListenHost())
			err = server.CheckLaddr(&addr)
			if err == nil {
				proxy, err = server.GetPacketListener()(
					ctx, laddr.Network(), laddr.ToHostPort(),
				)
			}
		} else {
			err = server.CheckRaddr(&addr)
			if err == nil {
				binded = true
				proxy, err = server.GetPacketDialer()(
					ctx,
					addr.Network(),
					addr.ToHostPort(),
				)
			}
		}
		if err != nil {
			protocol.Reject(ver, ctrl, errorToReplyStatus(err), pool)
			return err
		}

		assoc, err := server.ListenForAssoc(ctx, ctrl)
		if err != nil {
			protocol.Reject(ver, ctrl, errorToReplyStatus(err), pool)
			return err
		}

		err = protocol.Reply(
			ver,
			ctrl,
			protocol.SuccReply,
			protocol.AddrFromNetAddr(assoc.LocalAddr()),
			pool,
		)
		if err != nil {
			return err
		}

		return protocol.ProxySocks5UDPAssoc(
			assoc, proxy, ctrl, binded, nil, pool,
			server.GetUDPBufferSize(), server.GetUDPTimeout(),
		)
	},
}

DefaultUDPAssocHandler handles the UDP ASSOCIATE command.

DefaultUDPAssocHandler creates a UDP association that proxies packets between the client and target using standard SOCKS5 UDP encapsulation.

Protocol Support

  • SOCKS4: No
  • SOCKS5: Yes
  • TLS: No

Behavior

  1. Sets address network type to "udp"

  2. If address is unspecified (0.0.0.0:0): - Creates UDP listener (server mode) - Validates against LaddrFilter

  3. If address is specified: - Creates UDP connection to target (client mode) - Validates against RaddrFilter

  4. Creates UDP association listener

  5. Sends success reply with association address

  6. Proxies UDP packets with SOCKS5 UDP headers

UDP Encapsulation

SOCKS5 UDP packets include a header:

	+----+------+------+----------+----------+----------+
	|RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
	+----+------+------+----------+----------+----------+
	| 2  |  1   |  1   | Variable |    2     | Variable |
	+----+------+------+----------+----------+----------+

  - RSV: Reserved (0x0000)
  - FRAG: Fragment number (0x00 = no fragmentation)
  - ATYP: Address type (IP4=0x01, IP6=0x04, FQDN=0x03)
  - DST.ADDR: Destination address
  - DST.PORT: Destination port
  - DATA: UDP payload

Association Lifecycle

The UDP association remains active until:

  • UDPTimeout expires (default: 3 minutes)
  • Control TCP connection closes
  • Error occurs during proxying

Reply

Sends success reply (0x00) with the UDP association address.

Errors

Returns error and sends appropriate reply status:

  • DisallowReply (0x02): Address filtered
  • FailReply (0x01): Listen/dial failed

Examples

// Default handler is used automatically
server := &socksgo.Server{
    Handlers: socksgo.DefaultCommandHandlers,
}

See Also

  • RFC 1928: SOCKS5 Protocol (Section 7)
  • protocol.ProxySocks5UDPAssoc: UDP proxy implementation
  • server_handler_tun.go: Gost UDP tunnel (UDP over TCP)

Functions

func GetTestListenCloseHook

func GetTestListenCloseHook() func(net.Conn)

func GetTestListenSmuxHook

func GetTestListenSmuxHook() func() error

func GetTestLookupAddrHook

func GetTestLookupAddrHook() func(protocol.Addr) protocol.Addr

func GetTestLookupIPHook

func GetTestLookupIPHook() func(protocol.Addr) protocol.Addr

func GetTestRequestHook

func GetTestRequestHook() func(context.Context, protocol.Cmd, protocol.Addr) (net.Conn, protocol.Addr, bool)

func LoopbackFilter

func LoopbackFilter(_, address string) bool

LoopbackFilter returns true for localhost and loopback addresses. Use this filter to route local traffic directly while sending external traffic through the proxy.

func MatchAllFilter

func MatchAllFilter(_, _ string) bool

MatchAllFilter is a Filter that always returns true. All connections bypass the proxy and use direct connection.

func PassAllFilter

func PassAllFilter(_, _ string) bool

PassAllFilter is a Filter that always returns false. All connections will use the proxy (none bypass to direct connection).

func ResetTestHooks

func ResetTestHooks()

func SetTestListenCloseHook

func SetTestListenCloseHook(hook func(net.Conn))

func SetTestListenSmuxHook

func SetTestListenSmuxHook(hook func() error)

func SetTestLookupAddrHook

func SetTestLookupAddrHook(hook func(protocol.Addr) protocol.Addr)

func SetTestLookupIPHook

func SetTestLookupIPHook(hook func(protocol.Addr) protocol.Addr)

Stub functions for production builds (no-op)

func SetTestRequestHook

func SetTestRequestHook(
	hook func(context.Context, protocol.Cmd, protocol.Addr) (net.Conn, protocol.Addr, bool),
)

func TestAddrFromFQDN

func TestAddrFromFQDN(fqdn string, port uint16, network string) protocol.Addr

func TestAddrFromIP

func TestAddrFromIP(ip net.IP, port uint16, network string) protocol.Addr

Types

type AddrDisallowedError

type AddrDisallowedError struct {
	Addr       *protocol.Addr
	FilterName string
}

AddrDisallowedError is returned when an address is blocked by a filter.

func (AddrDisallowedError) Error

func (e AddrDisallowedError) Error() string

type Client

type Client struct {
	// SocksVersion specifies the SOCKS protocol version.
	//
	// Valid values:
	//   - "4": SOCKS4 (no domain name support)
	//   - "4a": SOCKS4a (supports domain names)
	//   - "5": SOCKS5 (full feature support)
	//   - "": Empty string defaults to "5"
	//
	// Default: "5"
	SocksVersion string

	// ProxyNet specifies the network type for connecting to the proxy.
	//
	// Valid values: "tcp", "tcp4", "tcp6"
	//
	// Default: "tcp"
	ProxyNet string

	// ProxyAddr is the proxy server address in host:port format.
	//
	// If port is omitted (e.g., "proxy.example.com"), port 1080 is used.
	// Ignored when WebSocketURL is set.
	//
	// Examples:
	//   - "proxy.example.com:1080"
	//   - "192.168.1.1:9050"
	//   - "proxy.example.com" (uses default port 1080)
	ProxyAddr string

	// Auth contains authentication methods for SOCKS5.
	//
	// Multiple methods can be added; the server selects one during negotiation.
	//
	// Examples:
	//
	//	client.Auth = (&protocol.AuthMethods{}).
	//	    Add(&protocol.PassAuthMethod{User: "user", Pass: "pass"}).
	//	    Add(&protocol.NoAuthMethod{})
	Auth *protocol.AuthMethods

	// InsecureUDP allows plaintext UDP over TLS connections.
	//
	// WARNING: This is a security risk! When true, UDP packets are sent
	// unencrypted even when the control TCP connection uses TLS.
	//
	// Only enable in trusted networks or when you understand the implications.
	//
	// Default: false
	InsecureUDP bool

	// DoNotSpawnUDPAsocProbber disables the UDP ASSOC prober goroutine.
	//
	// When false (default), a goroutine monitors the control TCP connection
	// and closes the UDP association when the control connection closes.
	//
	// Set to true to disable this behavior (manual cleanup required).
	DoNotSpawnUDPAsocProbber bool

	// GostMbind enables Gost multiplexed BIND extension.
	//
	// When enabled, the client can use MBIND command for multiplexed
	// incoming connections over a single TCP connection using smux.
	//
	// Default: false
	GostMbind bool

	// GostUDPTun enables Gost UDP Tunnel extension.
	//
	// When enabled, UDP traffic is tunneled over TCP instead of using
	// standard UDP ASSOCIATE.
	//
	// Default: false
	GostUDPTun bool

	// TorLookup enables Tor DNS resolution extensions.
	//
	// When enabled, LookupIP and LookupAddr methods use Tor's SOCKS
	// extensions for DNS resolution through the proxy.
	//
	// Default: false
	TorLookup bool

	// Filter determines which connections bypass the proxy.
	//
	// When Filter returns true, connections use direct dialing instead
	// of going through the proxy. Commonly used for NO_PROXY-style rules.
	//
	// Default: LoopbackFilter (bypasses localhost and loopback addresses)
	//
	// Examples:
	//
	//	client.Filter = socksgo.BuildFilter("localhost,192.168.0.0/16")
	Filter Filter

	// Dialer is used to establish TCP connections to the proxy.
	//
	// Also used for direct connections when Filter returns true.
	//
	// Default: net.Dialer.DialContext
	Dialer Dialer

	// PacketDialer is used to establish UDP connections for proxy operations.
	//
	// Also used for direct UDP when Filter returns true.
	//
	// Default: net.DialUDP
	PacketDialer PacketDialer

	// DirectListener is used for direct TCP listening (BIND) when
	// Filter returns true.
	//
	// Default: net.ListenConfig.Listen
	DirectListener Listener

	// DirectPacketListener is used for direct UDP listening when
	// Filter returns true.
	//
	// Default: net.ListenUDP
	DirectPacketListener PacketListener

	// Resolver is used for DNS lookups.
	//
	// Used for SOCKS4 (non-4a) clients and Tor LookupIP/LookupAddr
	// requests when Filter returns true.
	//
	// Default: net.DefaultResolver
	Resolver Resolver

	// HandshakeTimeout specifies the timeout for SOCKS handshake.
	//
	// If zero, uses context deadline or no timeout.
	//
	// Default: 0 (no explicit timeout)
	HandshakeTimeout time.Duration

	// Smux configures connection multiplexing for Gost MBIND.
	//
	// Only used when GostMbind is true.
	//
	// Example:
	//
	//	client.Smux = &smux.Config{
	//	    MaxFrameSize:     65535,
	//	    MaxReceiveBuffer: 4194304,
	//	}
	Smux *smux.Config

	// TLS enables TLS for the proxy connection.
	//
	// When true, the connection to ProxyAddr is wrapped in TLS.
	// TLSConfig controls certificate verification and other TLS settings.
	//
	// Default: false
	TLS bool

	// TLSConfig configures TLS behavior.
	//
	// If nil, a default config is used with:
	//   - InsecureSkipVerify: true (disable with "secure" URL option)
	//   - ServerName: Auto-set from ProxyAddr or WebSocketURL
	//
	// Example for secure connections:
	//
	//	client.TLSConfig = &tls.Config{
	//	    InsecureSkipVerify: false,
	//	    ServerName:         "proxy.example.com",
	//	}
	TLSConfig *tls.Config

	// WebSocketURL enables SOCKS over WebSocket transport.
	//
	// When non-empty, connects to this WebSocket URL instead of
	// ProxyAddr. ProxyNet and ProxyAddr are ignored.
	//
	// URL scheme determines encryption:
	//   - "ws://": Plaintext WebSocket
	//   - "wss://": Encrypted WebSocket (TLS)
	//
	// Examples:
	//   - "ws://proxy.example.com/ws"
	//   - "wss://proxy.example.com/socks"
	WebSocketURL string

	// WebSocketConfig configures WebSocket-specific options.
	//
	// If nil, default WebSocket settings are used.
	//
	// See WebSocketConfig for available options.
	WebSocketConfig *WebSocketConfig

	// Pool is a buffer pool for memory-efficient operations.
	//
	// If nil, a no pool is used.
	//
	// Using a shared pool across multiple clients can reduce
	// memory allocations and GC pressure.
	Pool bufpool.Pool
}

Client is a SOCKS proxy client configuration.

Client provides a high-level interface for connecting through SOCKS4, SOCKS4a, and SOCKS5 proxies. It supports TCP connections, UDP associations, BIND commands, and extensions for Gost and Tor compatibility.

Quick Start

// Basic SOCKS5 client
client := &socksgo.Client{
    SocksVersion: "5",
    ProxyAddr:    "proxy.example.com:1080",
}
conn, err := client.Dial(ctx, "tcp", "example.com:80")

// With authentication
client := &socksgo.Client{
    SocksVersion: "5",
    ProxyAddr:    "proxy.example.com:1080",
    Auth: (&protocol.AuthMethods{}).Add(&protocol.PassAuthMethod{
        User: "username",
        Pass: "password",
    }),
}

// SOCKS over TLS
client := &socksgo.Client{
    SocksVersion: "5",
    ProxyAddr:    "proxy.example.com:1080",
    TLS:          true,
}

// SOCKS over WebSocket
client := &socksgo.Client{
    SocksVersion:   "5",
    WebSocketURL:   "wss://proxy.example.com/ws",
}

// Tor stream isolation
client := &socksgo.Client{
    SocksVersion: "5",
    ProxyAddr:    "127.0.0.1:9050",
}
isolatedClient := client.WithTorIsolation(nil) // Random isolation
sessionID := "my-session"
isolatedClient = client.WithTorIsolation(&sessionID) // Specific isolation

Thread Safety

Client is safe for concurrent use after initialization. Do not modify fields after calling Dial, Listen, or other methods.

See Also

  • ClientFromURL: Create client from URL string
  • ClientFromENV: Create client from environment variables
  • ClientNoProxy: Create client that bypasses proxy
  • Client.WithTorIsolation: Enable Tor stream isolation

func ClientFromENV

func ClientFromENV(scheme string) (*Client, error)

ClientFromENV creates a Client from environment variables with all options.

Reads the proxy URL from environment variables and creates a Client with all options enabled. Uses ClientFromURL which supports insecure options if specified in the URL.

Examples

// Reads SOCKS5_PROXY environment variable
client, err := socksgo.ClientFromENV("socks5")

See Also

  • ClientFromENVSafe: Safe version without insecure options
  • ClientFromURL: Parse URL string with all options

func ClientFromENVSafe

func ClientFromENVSafe(scheme string) (*Client, error)

ClientFromENVSafe creates a Client from environment variables safely.

Reads the proxy URL from standard environment variables:

  • ALL_PROXY, all_proxy: Fallback for any scheme
  • {scheme}_proxy, {scheme}_PROXY: Scheme-specific (e.g., http_proxy)

Returns ClientNoProxy() if no environment variable is set.

Examples

// Reads HTTP_PROXY or ALL_PROXY
client, err := socksgo.ClientFromENVSafe("http")

Environment Variable Priority

1. {scheme}_proxy (lowercase) 2. {scheme}_PROXY (uppercase) 3. ALL_PROXY (lowercase) 4. all_proxy (uppercase)

See Also

  • ClientFromURLObjSafe: Parse URL safely
  • ClientNoProxy: Default when no env var set

func ClientFromURL

func ClientFromURL(urlstr string) (*Client, error)

ClientFromURL creates a Client from a URL string with all options.

Wrapper around ClientFromURLObj that parses the URL string first. Supports all options including insecure ones.

Examples

client, err := socksgo.ClientFromURL("socks5://user:pass@proxy.example.com:1080?pass")

See Also

  • ClientFromURLObj: Parse *url.URL with all options
  • ClientFromURLSafe: Safe version without insecure options

func ClientFromURLObj

func ClientFromURLObj(u *url.URL) *Client

ClientFromURLObj creates a Client from a URL with all options.

This is the unsafe constructor that supports all URL options including insecure ones. Use ClientFromURLObjSafe for secure defaults.

Supported Options

  • pass: Enable PassAllFilter (all connections through proxy, no bypass)
  • gost: Enable Gost extensions (MBIND, UDPTun)
  • tor: Enable Tor lookup extensions
  • secure: Disable TLS certificate verification (default: skip)
  • insecureudp: Allow plaintext UDP over TLS (security risk!)
  • assocprob: Enable UDP assoc prober (monitors control connection)

Security Warning

Using "insecureudp" allows plaintext UDP even when the control connection is encrypted. This can lead to security vulnerabilities.

The "pass" Option

The "pass" option enables PassAllFilter, which forces ALL connections through the proxy with no bypass. Without this option, LoopbackFilter is used by default (localhost and loopback addresses bypass the proxy).

Examples

// With insecure UDP over TLS (NOT RECOMMENDED)
u, _ := url.Parse("socks5+tls://proxy.example.com:1080?insecureudp")
client := socksgo.ClientFromURLObj(u)

// Force all traffic through proxy (no bypass)
u, _ := url.Parse("socks5://proxy.example.com:1080?pass")
client := socksgo.ClientFromURLObj(u)

See Also

  • ClientFromURLObjSafe: Safe version without insecure options
  • ClientFromURL: Parse URL string with all options

func ClientFromURLObjSafe

func ClientFromURLObjSafe(u *url.URL) *Client

ClientFromURLObjSafe creates a Client from a URL without insecure options.

This is a safe constructor that parses a URL and creates a Client with secure defaults. Insecure options like insecureudp are ignored.

URL Format

socks[4|4a|5][+tls|+ws|+wss]://[user:pass@]host[:port][?options]

Supported Options

  • pass: Enable PassAllFilter (all connections through proxy, no bypass)
  • gost: Enable Gost extensions (MBIND, UDPTun)
  • tor: Enable Tor lookup extensions
  • secure: Enable TLS certificate verification (default: skip verification)

Defaults

  • TLS: InsecureSkipVerify = true (disable with "secure" option)
  • UDP: Plaintext UDP over TLS disabled (use "insecureudp" in unsafe version)
  • Filter: LoopbackFilter (bypass proxy for localhost)

The "pass" Option

The "pass" option enables PassAllFilter, which forces ALL connections through the proxy with no bypass. Without this option, LoopbackFilter is used by default ("localhost" and loopback addresses bypass the proxy).

Examples

// Basic SOCKS5 proxy
u, _ := url.Parse("socks5://proxy.example.com:1080")
client := socksgo.ClientFromURLObjSafe(u)

// With authentication (credentials in URL)
u, _ := url.Parse("socks5://user:pass@proxy.example.com:1080")
client := socksgo.ClientFromURLObjSafe(u)

// Force all traffic through proxy (no bypass)
u, _ := url.Parse("socks5://proxy.example.com:1080?pass")
client := socksgo.ClientFromURLObjSafe(u)

// SOCKS5 over TLS with certificate verification
u, _ := url.Parse("socks5+tls://proxy.example.com:1080?secure")
client := socksgo.ClientFromURLObjSafe(u)

// SOCKS5 over WebSocket
u, _ := url.Parse("socks5+ws://proxy.example.com:8080/ws")
client := socksgo.ClientFromURLObjSafe(u)

func ClientFromURLSafe

func ClientFromURLSafe(urlstr string) (*Client, error)

ClientFromURLSafe creates a Client from a URL string safely.

Wrapper around ClientFromURLObjSafe that parses the URL string first. Returns an error if the URL cannot be parsed.

Examples

client, err := socksgo.ClientFromURLSafe("socks5://proxy.example.com:1080")

See Also

  • ClientFromURLObjSafe: Parse *url.URL safely
  • ClientFromURL: Unsafe version with all options

func ClientNoProxy

func ClientNoProxy() *Client

ClientNoProxy returns a Client that bypasses any proxy.

This client passes all connections directly without using a proxy. It's equivalent to setting Filter to MatchAllFilter.

Examples

// Direct connections only
client := socksgo.ClientNoProxy()
conn, err := client.Dial(ctx, "tcp", "example.com:80")
// conn is a direct TCP connection to example.com:80

See Also

  • MatchAllFilter: Filter that always returns true

func (*Client) CheckNetworkSupport

func (c *Client) CheckNetworkSupport(net string) error

CheckNetworkSupport validates network support for the SOCKS version.

CheckNetworkSupport checks if the requested network type is supported by the configured SOCKS protocol version.

Parameters

  • net: Network type to validate ("tcp", "tcp4", "tcp6", "udp", etc.)

Returns

nil if supported, WrongNetworkError if not.

Supported Networks

SOCKS5:

  • tcp, tcp4, tcp6
  • udp, udp4, udp6

SOCKS4/4a:

  • tcp, tcp4 (UDP not supported)

Examples

err := client.CheckNetworkSupport("tcp")    // nil
err := client.CheckNetworkSupport("udp")    // nil for SOCKS5
err := client.CheckNetworkSupport("unix")   // WrongNetworkError

client.SocksVersion = "4"
err := client.CheckNetworkSupport("udp")    // WrongNetworkError

func (*Client) Connect

func (c *Client) Connect(ctx context.Context) (conn net.Conn, err error)

Connect establishes a connection to the SOCKS proxy server.

Connect creates a TCP or WebSocket connection to the proxy server and applies TLS if configured. It's used internally by Request() but can be called directly for low-level control.

Returns

Established net.Conn to the proxy server or error.

Behavior

  1. If WebSocketURL is set: Establishes WebSocket connection
  2. Otherwise: Dials ProxyAddr using Dialer
  3. If TLS enabled: Wraps connection in TLS
  4. Sets handshake timeout deadline

WebSocket

When WebSocketURL is set, connects via WebSocket and returns a wrapped connection. ProxyAddr is ignored.

TLS

When TLS is true (or WebSocketURL starts with "wss"), wraps the connection in TLS using GetTLSConfig().

Timeout

Uses HandshakeTimeout if set, otherwise uses context deadline.

Examples

// Direct connection to proxy
conn, err := client.Connect(ctx)
if err != nil {
    return err
}
defer conn.Close()

// Use with Request for manual control
conn, err := client.Connect(ctx)
// Send custom SOCKS request...

See Also

  • Request: High-level SOCKS request
  • Dial: High-level TCP connection
  • GetTLSConfig: TLS configuration

func (*Client) Dial

func (c *Client) Dial(
	ctx context.Context,
	network, address string,
) (net.Conn, error)

Dial establishes a TCP connection through the SOCKS proxy.

Dial is the primary method for creating TCP connections through the proxy. It handles network validation, filter checking, and SOCKS protocol handshake.

Parameters

  • ctx: Context for cancellation and timeouts
  • network: Network type ("tcp", "tcp4", "tcp6")
  • address: Target address in host:port format

Returns

Established net.Conn or error.

Behavior

  1. Validates network support for the SOCKS version
  2. Checks Filter - if true, dials directly
  3. Sends CONNECT command through proxy
  4. Returns established connection

UDP Networks

If network is "udp", "udp4", or "udp6", DialPacket is called instead.

Examples

// Basic connection
conn, err := client.Dial(ctx, "tcp", "example.com:80")

// With timeout context
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
conn, err := client.Dial(ctx, "tcp", "example.com:443")

// Direct connection via filter
client.Filter = socksgo.BuildFilter("localhost")
conn, err := client.Dial(ctx, "tcp", "localhost:8080") // Direct, not via proxy

Errors

Returns WrongNetworkError for unsupported networks. Returns RejectdError if server rejects the connection.

See Also

  • DialPacket: UDP connections
  • Listen: BIND command for incoming connections
  • Request: Low-level SOCKS request

func (*Client) DialPacket

func (c *Client) DialPacket(
	ctx context.Context,
	network, address string,
) (PacketConn, error)

DialPacket establishes a UDP connection through the SOCKS proxy.

DialPacket creates a PacketConn for UDP communication through the proxy. It supports both standard UDP ASSOCIATE and Gost UDP Tunnel extensions.

Parameters

  • ctx: Context for cancellation and timeouts
  • network: Network type ("udp", "udp4", "udp6")
  • address: Target address in host:port format

Returns

PacketConn for UDP communication or error.

Behavior

  1. Validates network support
  2. Checks Filter - if true, dials UDP directly
  3. If GostUDPTun enabled: Uses UDP tunnel over TCP
  4. Otherwise: Uses standard UDP ASSOCIATE

Gost UDP Tunnel

When GostUDPTun is true, UDP is encapsulated in TCP.

Examples

// DNS query through proxy
conn, err := client.DialPacket(ctx, "udp", "8.8.8.8:53")
if err == nil {
    _, err := conn.Write(dnsQuery)
    _, err = conn.Read(response)
}

// Gost UDP tunnel
client.GostUDPTun = true
conn, err := client.DialPacket(ctx, "udp", "target:123")

See Also

  • ListenPacket: Listen for UDP packets
  • Dial: TCP connections

func (*Client) DoFilter

func (c *Client) DoFilter(network, address string) bool

DoFilter checks if a connection should bypass the proxy.

DoFilter evaluates the Filter function to determine if a connection should use direct dialing instead of going through the proxy.

Parameters

  • network: Network type (may be "" if unknown)
  • address: Target address (host:port format)

Returns

  • true: Use direct connection (bypass proxy)
  • false: Use SOCKS proxy

Behavior

  1. If IsNoProxy() returns true: Always returns true (all direct)
  2. If Filter is nil: Uses LoopbackFilter
  3. Otherwise: Calls Filter(network, address)

Examples

client.Filter = socksgo.BuildFilter("localhost,192.168.0.0/16")

client.DoFilter("tcp", "localhost:8080")  // true (direct)
client.DoFilter("tcp", "example.com:80")  // false (proxy)

func (*Client) GetAddr

func (c *Client) GetAddr() string

GetAddr returns the proxy server address with default port.

If ProxyAddr doesn't contain a port, appends ":1080" (default SOCKS port).

Returns

ProxyAddr or ProxyAddr:1080 if no port specified.

Examples

client.ProxyAddr = "proxy.example.com"
addr := client.GetAddr() // Returns "proxy.example.com:1080"

client.ProxyAddr = "proxy.example.com:9050"
addr := client.GetAddr() // Returns "proxy.example.com:9050"

func (*Client) GetDialer

func (c *Client) GetDialer() Dialer

GetDialer returns the dialer for TCP connections.

Returns Dialer if set, otherwise uses net.Dialer.DialContext.

Returns

Dialer function for establishing TCP connections.

See Also

  • Dialer: Custom dialer configuration

func (*Client) GetHandshakeTimeout

func (c *Client) GetHandshakeTimeout() time.Duration

GetHandshakeTimeout returns the SOCKS handshake timeout.

Returns

HandshakeTimeout duration, or 0 if not set.

func (*Client) GetListener

func (c *Client) GetListener() Listener

GetListener returns the TCP listener for direct connections.

Returns DirectListener if set, otherwise uses net.ListenConfig.Listen.

Returns

Listener function for creating TCP listeners.

See Also

  • DirectListener: Custom listener configuration

func (*Client) GetNet

func (c *Client) GetNet() string

GetNet returns the network type for proxy connections.

Returns "tcp" as default if ProxyNet is empty.

Returns

ProxyNet or "tcp" (default)

func (*Client) GetPacketDialer

func (c *Client) GetPacketDialer() PacketDialer

GetPacketDialer returns the dialer for UDP connections.

Returns PacketDialer if set, otherwise creates UDP connections using net.DialUDP.

Returns

PacketDialer function for establishing UDP connections.

See Also

  • PacketDialer: Custom dialer configuration

func (*Client) GetPacketListener

func (c *Client) GetPacketListener() PacketListener

GetPacketListener returns the UDP packet listener for direct connections.

Returns DirectPacketListener if set, otherwise creates a UDP listener using net.ListenUDP.

Returns

PacketListener function for creating UDP listeners.

See Also

  • DirectPacketListener: Custom listener configuration

func (*Client) GetResolver

func (c *Client) GetResolver() Resolver

GetResolver returns the DNS resolver for lookups.

Returns Resolver if set, otherwise uses net.DefaultResolver.

Returns

Resolver for DNS lookups.

See Also

  • Resolver: Custom resolver configuration
  • net.DefaultResolver: System default resolver

func (*Client) GetTLSConfig

func (c *Client) GetTLSConfig() (config *tls.Config)

GetTLSConfig builds the TLS configuration for secure connections.

GetTLSConfig creates a TLS configuration from TLSConfig field or returns a default configuration. If TLS is not enabled, returns nil.

Behavior

  1. If !IsTLS(): Returns nil
  2. If TLSConfig is nil: Creates default config
  3. Clones TLSConfig to avoid mutation
  4. Sets ServerName from ProxyAddr if empty

ServerName

If TLSConfig.ServerName is empty, extracts the hostname from GetAddr() (removes port).

Returns

*tls.Config for TLS connections, or nil if TLS is disabled.

Examples

// Default TLS config
client.TLS = true
config := client.GetTLSConfig()
// config.InsecureSkipVerify = true (default)
// config.ServerName = "proxy.example.com" (from ProxyAddr)

// Custom TLS config
client.TLSConfig = &tls.Config{
    InsecureSkipVerify: false,
    ServerName:         "custom.example.com",
}
config := client.GetTLSConfig()

func (*Client) GetWsDialer

func (c *Client) GetWsDialer() *websocket.Dialer

GetWsDialer builds the WebSocket dialer for SOCKS over WS.

GetWsDialer creates a websocket.Dialer configured from WebSocketConfig, GetDialer, and GetTLSConfig. Returns nil if WebSocketURL is empty.

Configuration

The dialer is configured with:

  • NetDialContext: From GetDialer()
  • TLSClientConfig: From GetTLSConfig()
  • WriteBufferPool: Uses client's Pool
  • HandshakeTimeout: From GetHandshakeTimeout()
  • ReadBufferSize, Subprotocols, etc.: From WebSocketConfig

Returns

*websocket.Dialer for WebSocket connections, or nil if WebSocketURL is empty.

See Also

  • WebSocketConfig: WebSocket configuration options
  • github.com/gorilla/websocket: Underlying WebSocket library

func (*Client) IsNoProxy

func (c *Client) IsNoProxy() bool

IsNoProxy reports whether the client bypasses the proxy.

Returns true if:

  • Client is nil
  • Both ProxyAddr and WebSocketURL are empty

When true, all connections use direct.

func (*Client) IsTLS

func (c *Client) IsTLS() bool

IsTLS reports whether TLS is enabled for the proxy connection.

Returns true if:

  • TLS field is true, or
  • WebSocketURL starts with "wss"

Examples

client.TLS = true
client.IsTLS() // true

client.WebSocketURL = "wss://proxy.example.com/ws"
client.IsTLS() // true

func (*Client) IsUDPAllowed

func (c *Client) IsUDPAllowed() bool

IsUDPAllowed reports whether UDP operations are permitted.

Returns true if:

  • TLS is not enabled, or
  • InsecureUDP is true (allows plaintext UDP over TLS)

Security Warning

When TLS is enabled and InsecureUDP is true, UDP packets are sent unencrypted. This is a security risk!

Examples

client.TLS = false
client.IsUDPAllowed() // true

client.TLS = true
client.InsecureUDP = false
client.IsUDPAllowed() // false (UDP blocked over TLS)

client.TLS = true
client.InsecureUDP = true // NOT RECOMMENDED
client.IsUDPAllowed() // true (but UDP is plaintext!)

func (*Client) Listen

func (c *Client) Listen(
	ctx context.Context,
	network, address string,
) (net.Listener, error)

Listen establishes a TCP listener through the SOCKS proxy (BIND command).

Listen uses the SOCKS BIND command to create a listener on the proxy server that forwards incoming connections to the client.

Parameters

  • ctx: Context for cancellation and timeouts
  • network: Network type ("tcp", "tcp4", "tcp6")
  • address: Local address to bind (use "0.0.0.0:0" for any)

Returns

net.Listener for accepting connections or error.

Behavior

  1. Validates network support
  2. Checks Filter - if true, listens directly
  3. Sends BIND command to proxy
  4. Returns listener for incoming connections

Examples

// Listen for incoming connections
listener, err := client.Listen(ctx, "tcp", "0.0.0.0:0")
if err == nil {
    for {
        conn, err := listener.Accept()
        if err != nil {
            break
        }
        go handleConnection(conn)
    }
}

See Also

  • Dial: Outgoing TCP connections
  • DialPacket: UDP connections

func (*Client) ListenPacket

func (c *Client) ListenPacket(
	ctx context.Context,
	network, address string,
) (PacketConn, error)

ListenPacket listens for UDP packets through the SOCKS proxy.

ListenPacket creates a UDP listener that receives packets through the SOCKS proxy. It supports both standard UDP ASSOCIATE and Gost UDP Tunnel extensions.

Parameters

  • ctx: Context for cancellation and timeouts
  • network: Network type ("udp", "udp4", "udp6")
  • address: Local address to listen on (use "0.0.0.0:0" for any)

Returns

PacketConn for receiving UDP packets or error.

Behavior

  1. Validates network support
  2. Checks Filter - if true, listens directly
  3. If GostUDPTun enabled: Uses UDP tunnel over TCP
  4. Otherwise: Uses standard UDP ASSOCIATE

Gost UDP Tunnel

When GostUDPTun is true, creates a bound UDP tunnel. The server acts like NAT and doesn't return the bound address - use STUN or similar to discover the external address.

Standard UDP ASSOCIATE

For standard UDP ASSOCIATE, the laddr parameter is ignored. The server assigns a UDP port and returns it in the BIND address.

Examples

// Listen on any available port
conn, err := client.ListenPacket(ctx, "udp", "0.0.0.0:0")

// Gost UDP tunnel (bound)
client.GostUDPTun = true
conn, err := client.ListenPacket(ctx, "udp", "0.0.0.0:0")
// Use STUN to discover external address

See Also

  • DialPacket: Send UDP packets
  • Listen: TCP BIND command

func (*Client) LookupAddr

func (c *Client) LookupAddr(
	ctx context.Context,
	address string,
) ([]string, error)

LookupAddr performs a reverse DNS lookup through the SOCKS proxy.

LookupAddr uses Tor's SOCKS extension to resolve IP addresses to hostnames through the proxy. This provides DNS privacy for reverse lookups.

Parameters

  • ctx: Context for cancellation and timeouts
  • address: IP address to resolve (as string)

Returns

Slice of resolved hostnames or error.

Requirements

TorLookup must be enabled. Returns ErrResolveDisabled if not set.

Examples

// Enable Tor lookup
client.TorLookup = true

// Reverse lookup
names, err := client.LookupAddr(ctx, "8.8.8.8")
if err == nil && len(names) > 0 {
    fmt.Printf("Resolved to: %s\n", names[0])
}

Errors

Returns *net.DNSError with ErrResolveDisabled if TorLookup is false.

See Also

  • LookupIP: Forward DNS lookup
  • net.Resolver.LookupAddr: Standard reverse lookup

func (*Client) LookupIP

func (c *Client) LookupIP(
	ctx context.Context,
	network, address string,
) ([]net.IP, error)

LookupIP performs a forward DNS lookup through the SOCKS proxy.

LookupIP uses Tor's SOCKS extension to resolve hostnames to IP addresses through the proxy. This provides DNS privacy by preventing DNS leaks.

Parameters

  • ctx: Context for cancellation and timeouts
  • network: IP version ("ip", "ip4", "ip6")
  • address: Hostname to resolve

Returns

Slice of resolved IP addresses or error.

Requirements

TorLookup must be enabled. Returns ErrResolveDisabled if not set.

IP types Note

Due to Tor SOCKS extension limitations, the returned IP version may differ from the requested network (e.g., ipv6 when ipv4 was requested or vise versa).

Examples

// Enable Tor lookup
client.TorLookup = true

// Resolve hostname
ips, err := client.LookupIP(ctx, "ip4", "example.com")
if err == nil && len(ips) > 0 {
    fmt.Printf("Resolved to: %v\n", ips[0])
}

Errors

Returns *net.DNSError with ErrResolveDisabled if TorLookup is false.

See Also

  • LookupAddr: Reverse DNS lookup
  • net.Resolver.LookupIP: Standard DNS lookup

func (*Client) Request

func (c *Client) Request(
	ctx context.Context,
	cmd protocol.Cmd,
	address protocol.Addr,
) (
	proxy net.Conn,
	addr protocol.Addr,
	err error,
)

Request sends a low-level SOCKS request to the proxy.

Request establishes a connection to the proxy, performs authentication if needed, and sends the specified command for the given address.

Parameters

  • ctx: Context for cancellation and timeouts
  • cmd: SOCKS command (Connect, Bind, UDPAssoc, or extensions)
  • address: Target address for the command

Returns

  • proxy: Established connection to proxy (or target for CONNECT)
  • addr: Bound address from server (relevant for BIND/UDPAssoc)
  • err: Error if connection, auth, or request fails

Behavior

On success, the connection deadline is cleared for indefinite use. On error, the connection is closed.

Examples

// CONNECT command
conn, _, err := client.Request(ctx, protocol.CmdConnect,
    protocol.AddrFromHostPort("example.com:80", "tcp"))

// BIND command
listener, bindAddr, err := client.Request(ctx, protocol.CmdBind,
    protocol.AddrFromHostPort("0.0.0.0:0", "tcp"))

See Also

  • Dial: High-level TCP connection
  • DialPacket: High-level UDP connection
  • Listen: High-level BIND

func (*Client) Version

func (c *Client) Version() string

Version returns the SOCKS protocol version.

Returns "5" as default if SocksVersion is empty.

Returns

"4", "4a", "5", or "5" (default)

func (*Client) WithTorIsolation

func (c *Client) WithTorIsolation(id *string) *Client

WithTorIsolation creates a copy of the Client with Tor stream isolation enabled.

WithTorIsolation implements the Tor SOCKS extension for stream isolation as specified in https://spec.torproject.org/socks-extensions.html#extended-auth

The method configures the client to use extended authentication with format type 0, where the stream isolation parameter is sent in the password field.

Parameters

  • id: Pointer to stream isolation ID string. If nil, a random ID is generated.

Behavior

  1. Creates a shallow copy of the Client
  2. Generates or uses the provided stream isolation ID
  3. Trims the ID if it exceeds the maximum password length (255 bytes)
  4. Sets username to "<torS0X>0" (magic prefix + format type 0)
  5. Sets password to the stream isolation ID
  6. Removes all other authentication methods

Stream Isolation

Streams with different isolation IDs will use separate Tor circuits. Streams with the same isolation ID may share a circuit.

Examples

// Client with random stream isolation
client := &socksgo.Client{
    SocksVersion: "5",
    ProxyAddr:    "127.0.0.1:9050",
}
isolatedClient := client.WithTorIsolation(nil)

// Client with specific isolation ID
client := &socksgo.Client{
    SocksVersion: "5",
    ProxyAddr:    "127.0.0.1:9050",
}
sessionID := "user-session-123"
isolatedClient := client.WithTorIsolation(&sessionID)

// Long IDs are automatically trimmed
longID := strings.Repeat("x", 300)
isolatedClient := client.WithTorIsolation(&longID)

Notes

  • This method is designed for SOCKS5 clients connecting to Tor
  • For SOCKS4 or non-Tor proxies, the credentials are sent as-is (behavior depends on proxy implementation)
  • The original client is not modified; a copy is returned

type CommandHandler

type CommandHandler struct {
	Socks4    bool
	Socks5    bool
	TLSCompat bool

	// Handler is the function that executes the command.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeouts
	//   - server: Server instance (for accessing config, dialers, etc.)
	//   - conn: Client connection
	//   - ver: SOCKS version ("4", "4a", "5")
	//   - info: Authentication information from handshake
	//   - cmd: Command code being executed
	//   - addr: Target address from client request
	//
	// Returns:
	//   - error: Non-nil error closes the connection
	//
	// The handler is responsible for sending the appropriate reply
	// to the client before proxying data. Use protocol.Reply()
	// for standard replies or protocol.Reject() for errors.
	//
	// # See Also
	//
	//   - protocol.Reply: Send success reply
	//   - protocol.Reject: Send error reply
	//   - protocol.PipeConn: Proxy data between connections
	Handler func(
		ctx context.Context,
		server *Server,
		conn net.Conn,
		ver string,
		info protocol.AuthInfo,
		cmd protocol.Cmd,
		addr protocol.Addr,
	) error
}

CommandHandler defines a handler for a SOCKS command.

CommandHandler encapsulates the implementation of a SOCKS command along with metadata about which protocol versions and transport modes it supports.

Fields

  • Socks4: true if handler supports SOCKS4/4a
  • Socks5: true if handler supports SOCKS5
  • TLSCompat: true if handler works over TLS connections
  • Handler: The actual handler function

Handler Function

The Handler function is called after: 1. Authentication succeeds 2. Command is validated 3. PreCmd hook passes 4. Address filters pass

The handler is responsible for:

  • call address filters suitable for its purpose
  • Sending the appropriate reply to the client
  • Executing the command (dialing, listening, etc.)
  • Proxying data between client and target
  • Returning errors (which close the connection)

Examples

// Custom CONNECT handler with logging
customHandler := CommandHandler{
    Socks4:    true,
    Socks5:    true,
    TLSCompat: true,
    Handler: func(ctx context.Context, server *Server,
        conn net.Conn, ver string, info protocol.AuthInfo,
        cmd protocol.Cmd, addr protocol.Addr) error {
        log.Printf("CONNECT to %s", addr)
        // Call default handler
        return socksgo.DefaultConnectHandler.Handler(
            ctx, server, conn, ver, info, cmd, addr)
    },
}

See Also

  • DefaultCommandHandlers: Built-in handlers
  • server_handler_*.go: Individual handler implementations

func (*CommandHandler) Allowed

func (h *CommandHandler) Allowed(ver string, isTLS bool) bool

Allowed reports whether the handler supports the given version and TLS mode.

Allowed checks if the handler can handle requests for the specified SOCKS version and TLS configuration.

Parameters

  • ver: SOCKS version ("4", "4a", "5", "5h")
  • isTLS: true if connection is encrypted

Returns

  • true: Handler supports this version/TLS combination
  • false: Handler does not support this combination

Behavior

Returns false if:

  • Handler is nil
  • isTLS is true but TLSCompat is false
  • ver is "4" or "4a" but Socks4 is false
  • ver is "5" or "5h" but Socks5 is false

func (*CommandHandler) Run

func (h *CommandHandler) Run(
	ctx context.Context,
	server *Server,
	conn net.Conn,
	ver string,
	info protocol.AuthInfo,
	cmd protocol.Cmd,
	addr protocol.Addr,
) error

Run executes the command handler.

Run calls the Handler function if it is set, otherwise returns a NilHandlerError.

Parameters

  • ctx: Context for cancellation and timeouts
  • server: Server instance
  • conn: Client connection
  • ver: SOCKS version ("4", "4a", "5")
  • info: Authentication information
  • cmd: Command code
  • addr: Target address

Returns

Error from handler, or NilHandlerError if handler is nil.

type Dialer

type Dialer = func(ctx context.Context, network, address string) (net.Conn, error)

Dialer is a function type for establishing TCP connections. It matches the signature of net.Dialer.DialContext.

type Filter

type Filter = func(network, address string) bool

Filter determines whether an address should bypass the proxy and use direct connection. Return true to use direct connection, false to route through proxy. network may be "" if unknown.

Filters are used with the Client.Filter field and server address filters. Use BuildFilter() to create filters from no_proxy-style strings.

func BuildFilter

func BuildFilter(str string) Filter

BuildFilter creates a Filter from a comma-separated string similar to the NO_PROXY environment variable format.

Each entry can be:

  • host:port - matches this host and port combination
  • host - matches this host on any port
  • ip - matches this exact IP address
  • ip/subnet - matches any IP in this CIDR subnet
  • Wildcards (*, ?) are supported in host patterns using shell glob matching

Examples:

  • "localhost,127.0.0.1" - bypass for localhost and IPv4 loopback
  • "*.example.com" - bypass for all subdomains of example.com
  • "192.168.0.0/16" - bypass for entire 192.168.x.x subnet
  • "internal.corp:8080" - bypass for specific host:port

The filter is case-insensitive and handles both bracketed IPv6 addresses (e.g., [::1]:8080) and trailing dots in hostnames.

type Listener

type Listener = func(ctx context.Context, network, address string) (net.Listener, error)

Listener is a function type for creating TCP listeners.

type NilHandlerError

type NilHandlerError struct {
	Cmd protocol.Cmd
}

NilHandlerError is returned when a command handler is not registered for the requested command.

func (NilHandlerError) Error

func (e NilHandlerError) Error() string

type PacketConn

type PacketConn interface {
	net.PacketConn
	net.Conn
}

PacketConn is a combined interface for UDP packet connections. It embeds both net.PacketConn and net.Conn for full duplex communication.

type PacketDialer

type PacketDialer = func(ctx context.Context, network, address string) (PacketConn, error)

PacketDialer is a function type for establishing UDP packet connections.

type PacketListener

type PacketListener = func(ctx context.Context, network, address string) (PacketConn, error)

PacketListener is a function type for creating UDP packet listeners.

type RejectdError

type RejectdError struct {
	Status protocol.ReplyStatus
}

RejectdError wraps a server rejection response with the reply status code.

func (RejectdError) Error

func (e RejectdError) Error() string

type Resolver

type Resolver interface {
	LookupIP(ctx context.Context, network, address string) ([]net.IP, error)
	LookupAddr(ctx context.Context, address string) ([]string, error)
}

Resolver provides DNS lookup capabilities. It matches the interface of net.Resolver.

type Server

type Server struct {
	// Pool is a buffer pool for memory-efficient operations.
	//
	// If nil, buffers are allocated without pooling.
	//
	// Using a shared pool can reduce memory allocations and GC pressure.
	Pool bufpool.Pool

	// Auth contains server-side authentication handlers.
	//
	// Multiple auth methods can be registered; the server selects
	// one during SOCKS5 authentication negotiation.
	//
	// Examples:
	//
	//	server.Auth = (&protocol.AuthHandlers{}).
	//	    Add(&protocol.NoAuthHandler{}).
	//	    Add(&protocol.PassAuthHandler{Verify: verifyFunc})
	Auth *protocol.AuthHandlers

	// Smux configures connection multiplexing for Gost MBIND.
	//
	// Only used when handling CmdGostMuxBind commands.
	//
	// Example:
	//
	//	server.Smux = &smux.Config{
	//	    MaxFrameSize:     65535,
	//	    MaxReceiveBuffer: 4194304,
	//	}
	Smux *smux.Config

	// UDPBufferSize is the buffer size for UDP packet forwarding.
	//
	// Default: 8192 bytes
	//
	// Used by UDP ASSOC and Gost UDPTun handlers.
	UDPBufferSize int

	// UDPTimeout is the timeout for UDP associations.
	//
	// Default: 2 minutes (120 seconds)
	//
	// UDP associations are closed after this duration of inactivity.
	UDPTimeout time.Duration

	// HandshakeTimeout specifies the timeout for SOCKS handshake
	// (authentication and command request).
	//
	// Default: 0 (no timeout)
	//
	// If set, the connection deadline is set to time.Now() + timeout
	// during handshake, then cleared after successful handshake.
	HandshakeTimeout time.Duration

	// DoNotPreferIP4 controls IPv4 preference for Tor resolve replies.
	//
	// When false (default), if both IPv4 and IPv6 addresses are returned
	// from a DNS lookup, IPv4 is preferred in the reply.
	//
	// When true, the first returned address is used regardless of type.
	DoNotPreferIP4 bool

	// DefaultListenHost is the default host for BIND/MBIND/UDPAssoc commands.
	//
	// If set, this host is used instead of "0.0.0.0" or "::" when the
	// client requests an unspecified address.
	//
	// Default: "" (use system default)
	DefaultListenHost string

	// UseIDENT determines whether IDENT lookup is performed for SOCKS4.
	//
	// If non-nil, called with (username, clientAddr) to determine if
	// IDENT verification should be attempted.
	//
	// IDENT (RFC 1413) verifies the username by querying port 113 on
	// the client's IP address.
	//
	// Default: nil (no IDENT verification)
	UseIDENT func(user string, clientAddr net.Addr) bool

	// LaddrFilter filters local addresses for listening commands
	// (BIND, MBIND, UDPAssoc, UDPTun).
	//
	// Return true to allow, false to reject.
	//
	// If nil, all addresses are allowed.
	//
	// Examples:
	//
	//	// Reject unspecified addresses
	//	server.LaddrFilter = func(addr *protocol.Addr) bool {
	//	    return !addr.IsUnspecified()
	//	}
	LaddrFilter func(laddr *protocol.Addr) bool

	// RaddrFilter filters remote addresses for outgoing commands
	// (CONNECT, Tor Resolve, etc.).
	//
	// Return true to allow, false to reject.
	//
	// If nil, all addresses are allowed.
	//
	// Examples:
	//
	//	// Use client Filter for server-side filtering
	//	server.RaddrFilter = func(addr *protocol.Addr) bool {
	//	    return socksgo.BuildFilter("localhost,192.168.0.0/16")(
	//	        "", addr.ToHostPort())
	//	}
	RaddrFilter func(raddr *protocol.Addr) bool

	// PreCmd is a hook called before executing any command.
	//
	// Parameters:
	//   - ctx: Context for the connection
	//   - conn: Client connection
	//   - ver: SOCKS version ("4", "4a", "5")
	//   - info: Authentication information
	//   - cmd: Requested command
	//   - addr: Target address
	//
	// Returns:
	//   - protocol.ReplyStatus: Status to send if rejecting
	//   - error: Error to return (connection closed)
	//
	// If non-nil error or non-Ok status is returned, the request is
	// rejected. For nil error with non-Ok status, Rejected(91) is used.
	//
	// Examples:
	//
	//	server.PreCmd = func(ctx context.Context, conn net.Conn,
	//	    ver string, info protocol.AuthInfo, cmd protocol.Cmd,
	//	    addr protocol.Addr) (protocol.ReplyStatus, error) {
	//	    log.Printf("Command %s to %s", cmd, addr)
	//	    return 0, nil // Allow
	//	}
	PreCmd func(
		ctx context.Context,
		conn net.Conn,
		ver string,
		info protocol.AuthInfo,
		cmd protocol.Cmd,
		addr protocol.Addr,
	) (protocol.ReplyStatus, error)

	// Handlers maps commands to their handlers.
	//
	// If nil, DefaultCommandHandlers is used.
	//
	// To customize handlers, copy DefaultCommandHandlers and modify:
	//
	//	handlers := make(map[protocol.Cmd]CommandHandler)
	//	for k, v := range socksgo.DefaultCommandHandlers {
	//	    handlers[k] = v
	//	}
	//	handlers[protocol.CmdConnect] = myCustomHandler
	//	server.Handlers = handlers
	Handlers map[protocol.Cmd]CommandHandler

	// Dialer is used to establish outgoing TCP connections for
	// CONNECT and other commands requiring TCP dialing.
	//
	// Default: net.Dialer.DialContext
	Dialer Dialer

	// PacketDialer is used to establish outgoing UDP connections for
	// UDP ASSOC and Gost UDPTun commands.
	//
	// Default: net.DialUDP
	PacketDialer PacketDialer

	// Listener is used to create TCP listeners for BIND and MBIND commands.
	//
	// Default: net.ListenConfig.Listen
	Listener Listener

	// PacketListener is used to create UDP listeners for UDP ASSOC
	// and Gost UDPTun commands.
	//
	// Default: net.ListenUDP
	PacketListener PacketListener

	// AssocListener creates UDP listeners for UDP ASSOC commands.
	//
	// If nil, a UDP listener is created based on the control connection's
	// local address.
	//
	// This allows custom UDP association handling, such as using a
	// specific port range or interface.
	AssocListener func(ctx context.Context, ctrl net.Conn) (assoc PacketConn, err error)

	// Resolver is used for DNS lookups in Tor Resolve commands.
	//
	// Default: net.DefaultResolver
	Resolver Resolver

	// DanglingConnections disable closing of used connections after handler
	// returns.
	DanglingConnections bool
}

Server is a SOCKS proxy server.

Server accepts incoming SOCKS4, SOCKS4a, and SOCKS5 connections, performs authentication negotiation, and dispatches commands to appropriate handlers.

Quick Start

// Create server with default handlers
server := &socksgo.Server{
    Auth:     authHandlers,
    Handlers: socksgo.DefaultCommandHandlers,
}

// Accept connections
listener, _ := net.Listen("tcp", "127.0.0.1:1080")
for {
    conn, _ := listener.Accept()
    go server.Accept(ctx, conn, false)
}

Thread Safety

Server is safe for concurrent use. Multiple goroutines can call Accept simultaneously, and handlers execute independently.

See Also

  • Accept: Main entry point for TCP connections
  • AcceptWS: Entry point for WebSocket connections
  • server_handlers.go: CommandHandler type and default handlers

func (*Server) Accept

func (s *Server) Accept(
	ctx context.Context,
	conn net.Conn,
	isTLS bool,
) (err error)

Accept accepts and handles a SOCKS connection.

Accept is the main entry point for handling incoming SOCKS connections. It reads the protocol version, routes to the appropriate handler (accept4 or accept5), and manages the authentication and command dispatch flow.

Parameters

  • ctx: Context for cancellation and timeouts
  • conn: TCP connection from client
  • isTLS: true if connection is encrypted (TLS)

Behavior

1. Reads version byte from connection 2. Routes to accept4 (SOCKS4/4a) or accept5 (SOCKS5) 3. Connection is closed on return (deferred)

Thread Safety

Accept is safe for concurrent use. Each connection is handled independently.

Examples

// TCP server
listener, _ := net.Listen("tcp", "127.0.0.1:1080")
for {
    conn, err := listener.Accept()
    if err != nil {
        continue
    }
    go server.Accept(ctx, conn, false)
}

// TLS server
tlsListener := tls.Listen(listener, tlsConfig)
for {
    conn, err := tlsListener.Accept()
    if err != nil {
        continue
    }
    go server.Accept(ctx, conn, true)
}

Errors

Returns error if:

  • Version byte cannot be read
  • Unknown SOCKS version (not 4 or 5)
  • Authentication fails
  • Handler execution fails

See Also

  • AcceptWS: Accept WebSocket connections

func (*Server) AcceptWS

func (s *Server) AcceptWS(
	ctx context.Context,
	conn *websocket.Conn,
	isTLS bool,
) error

AcceptWS accepts a SOCKS connection over WebSocket.

AcceptWS wraps the WebSocket connection and delegates to Accept. It handles the WebSocket framing layer for SOCKS over WS/WSS.

Parameters

  • ctx: Context for cancellation and timeouts
  • conn: WebSocket connection from gorilla/websocket
  • isTLS: true if connection is encrypted (WSS)

Thread Safety

AcceptWS is safe for concurrent use.

Examples

// WebSocket server
http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
    conn, _ := websocket.Upgrade(w, r, nil, 1024, 1024)
    go server.AcceptWS(r.Context(), conn, r.TLS != nil)
})

See Also

  • Accept: Accept TCP connections
  • wsConn: WebSocket connection wrapper

func (*Server) CheckBothAddr

func (s *Server) CheckBothAddr(laddr, raddr *protocol.Addr) error

CheckBothAddr validates both local and remote addresses.

CheckBothAddr calls CheckLaddr and CheckRaddr to validate both addresses. Returns the first error encountered.

Parameters

  • laddr: Local address to validate
  • raddr: Remote address to validate

Returns

  • nil: Both addresses are allowed
  • AddrDisallowedError: One address was rejected

See Also

  • CheckLaddr: Validate local address
  • CheckRaddr: Validate remote address

func (*Server) CheckLaddr

func (s *Server) CheckLaddr(laddr *protocol.Addr) error

CheckLaddr validates a local address against LaddrFilter.

CheckLaddr is used for listening commands (BIND, MBIND, UDPAssoc, UDPTun) to ensure the requested bind address is allowed.

Parameters

  • laddr: Local address to validate

Returns

  • nil: Address is allowed (or filter is nil)
  • AddrDisallowedError: Address was rejected by filter

See Also

  • LaddrFilter: Server configuration field
  • CheckRaddr: Validate remote address

func (*Server) CheckRaddr

func (s *Server) CheckRaddr(raddr *protocol.Addr) error

CheckRaddr validates a remote address against RaddrFilter.

CheckRaddr is used for outgoing commands (CONNECT, Tor Resolve) to ensure the target address is allowed.

Parameters

  • raddr: Remote address to validate

Returns

  • nil: Address is allowed (or filter is nil)
  • AddrDisallowedError: Address was rejected by filter

See Also

  • RaddrFilter: Server configuration field
  • CheckLaddr: Validate local address

func (*Server) CheckUseIDENT

func (s *Server) CheckUseIDENT(user string, clientAddr net.Addr) bool

CheckUseIDENT reports whether IDENT verification should be performed.

CheckUseIDENT calls the UseIDENT function if set, otherwise returns false.

Parameters

  • user: Username from SOCKS4 request
  • clientAddr: Client's network address

Returns

  • true: Perform IDENT verification
  • false: Skip IDENT verification

See Also

  • UseIDENT: Server configuration field
  • checkIDENT: IDENT verification implementation

func (*Server) GetAuth

func (s *Server) GetAuth() *protocol.AuthHandlers

GetAuth returns the server's authentication handlers.

Returns

Auth if set, otherwise nil (no authentication required).

func (*Server) GetDefaultListenHost

func (s *Server) GetDefaultListenHost() string

GetDefaultListenHost returns the default host for listening commands.

Returns

DefaultListenHost if set, otherwise "" (system default).

func (*Server) GetDialer

func (s *Server) GetDialer() Dialer

GetDialer returns the TCP dialer for server operations.

Returns

Dialer if set, otherwise net.Dialer.DialContext.

See Also

  • Dialer: Server configuration field

func (*Server) GetHandler

func (s *Server) GetHandler(cmd protocol.Cmd) *CommandHandler

GetHandler returns the handler for a command.

GetHandler looks up the command handler from the Handlers map. If Handlers is nil or the command is not found, returns the corresponding handler from DefaultCommandHandlers.

Parameters

  • cmd: Command code to look up

Returns

Pointer to CommandHandler, or nil if not found.

See Also

  • Handlers: Server command handler map
  • DefaultCommandHandlers: Built-in handlers

func (*Server) GetHandshakeTimeout

func (s *Server) GetHandshakeTimeout() time.Duration

GetHandshakeTimeout returns the configured handshake timeout.

Returns

HandshakeTimeout if set, otherwise 0 (no timeout).

func (*Server) GetListener

func (s *Server) GetListener() Listener

GetListener returns the TCP listener for server operations.

Returns

Listener if set, otherwise net.ListenConfig.Listen.

See Also

  • Listener: Server configuration field

func (*Server) GetPacketDialer

func (s *Server) GetPacketDialer() PacketDialer

GetPacketDialer returns the UDP packet dialer for server operations.

Returns

PacketDialer if set, otherwise net.DialUDP.

See Also

  • PacketDialer: Server configuration field

func (*Server) GetPacketListener

func (s *Server) GetPacketListener() PacketListener

GetPacketListener returns the UDP packet listener for server operations.

Returns

PacketListener if set, otherwise net.ListenUDP.

See Also

  • PacketListener: Server configuration field

func (*Server) GetPool

func (s *Server) GetPool() bufpool.Pool

GetPool returns the server's buffer pool.

Returns

Pool if set, otherwise nil (no pooling).

func (*Server) GetResolver

func (s *Server) GetResolver() Resolver

GetResolver returns the DNS resolver for server operations.

Returns

Resolver if set, otherwise net.DefaultResolver.

See Also

  • Resolver: Server configuration field

func (*Server) GetSmux

func (s *Server) GetSmux() *smux.Config

GetSmux returns the server's smux configuration.

Returns

Smux if set, otherwise nil (default smux settings).

func (*Server) GetUDPBufferSize

func (s *Server) GetUDPBufferSize() int

GetUDPBufferSize returns the configured UDP buffer size.

Returns

UDPBufferSize if set, otherwise 8192 bytes.

func (*Server) GetUDPTimeout

func (s *Server) GetUDPTimeout() time.Duration

GetUDPTimeout returns the configured UDP timeout.

Returns

UDPTimeout if set, otherwise 180 seconds (3 minutes).

func (*Server) IsPreferIPv4

func (s *Server) IsPreferIPv4() bool

IsPreferIPv4 reports whether IPv4 addresses are preferred for Tor resolve.

Returns true by default (including when s is nil).

Returns

  • true: Prefer IPv4 when both IPv4 and IPv6 are available
  • false: Use first returned address regardless of type

See Also

  • DoNotPreferIP4: Server configuration field

func (*Server) ListenForAssoc

func (s *Server) ListenForAssoc(
	ctx context.Context,
	ctrl net.Conn,
) (assoc PacketConn, err error)

ListenForAssoc creates a UDP listener for UDP ASSOC commands.

ListenForAssoc calls AssocListener if set, otherwise creates a UDP listener based on the control connection's local address.

Parameters

  • ctx: Context for cancellation and timeouts
  • ctrl: Control TCP connection from client

Returns

PacketConn for UDP association or error.

Behavior

If AssocListener is nil:

  1. Gets local address from control connection
  2. Extracts host from address
  3. Creates UDP listener on host:0 (any port)

See Also

  • AssocListener: Server configuration field
  • DefaultUDPAssocHandler: Handler that calls this function

type UnknownSocksVersionError

type UnknownSocksVersionError struct {
	Version string
}

UnknownSocksVersionError is returned when an unrecognized SOCKS version is specified.

func (UnknownSocksVersionError) Error

func (e UnknownSocksVersionError) Error() string

type UnsupportedAddrError

type UnsupportedAddrError struct {
	SocksVersion string // "4" | "4a" | "5"
	Addr         string
}

UnsupportedAddrError is returned when an address type is not supported by the specified SOCKS version (e.g., FQDN with SOCKS4).

func (UnsupportedAddrError) Error

func (e UnsupportedAddrError) Error() string

type UnsupportedCommandError

type UnsupportedCommandError struct {
	SocksVersion string // "4" | "4a" | "5"
	Cmd          protocol.Cmd
}

UnsupportedCommandError is returned when a command is not supported by the specified SOCKS version.

func (UnsupportedCommandError) Error

func (e UnsupportedCommandError) Error() string

type WebSocketConfig

type WebSocketConfig struct {
	// ReadBufferSize is the buffer size for WebSocket reads.
	//
	// If zero, websocket.DefaultDialer.ReadBufferSize is used.
	ReadBufferSize int

	// Subprotocols is the list of WebSocket subprotocols to negotiate.
	//
	// If nil, websocket.DefaultDialer.Subprotocols is used.
	Subprotocols []string

	// EnableCompression enables per-message compression (RFC 7692).
	//
	// If false, compression is disabled.
	//
	// Default: false (websocket.DefaultDialer.EnableCompression)
	EnableCompression bool

	// Jar is the cookie jar for HTTP cookies during WebSocket handshake.
	//
	// If nil, websocket.DefaultDialer.Jar is used.
	Jar http.CookieJar

	// RequestHeader contains custom HTTP headers for WebSocket upgrade request.
	RequestHeader http.Header
}

WebSocketConfig configures WebSocket connections for SOCKS over WS.

WebSocketConfig provides options for customizing WebSocket dialing when using SOCKS over WebSocket transport (WebSocketURL is set).

Examples

client := &socksgo.Client{
    SocksVersion:   "5",
    WebSocketURL:   "wss://proxy.example.com/ws",
    WebSocketConfig: &socksgo.WebSocketConfig{
        ReadBufferSize:    32768,
        Subprotocols:      []string{"binary"},
        EnableCompression: true,
        RequestHeader: http.Header{
            "X-Custom-Header": []string{"value"},
        },
    },
}

See Also

  • Client.WebSocketURL: Enable WebSocket transport
  • github.com/gorilla/websocket: Underlying WebSocket library

type WrongNetworkError

type WrongNetworkError struct {
	SocksVersion string // "4" | "4a" | "5"
	Network      string
}

func (WrongNetworkError) Error

func (e WrongNetworkError) Error() string

func (WrongNetworkError) Unwrap

func (e WrongNetworkError) Unwrap() error

Directories

Path Synopsis
examples
bind command
nolint
nolint
client-chaining command
nolint
nolint
connect command
nolint
nolint
custom-auth command
nolint
nolint
custom-cmd/client command
nolint
nolint
custom-cmd/server command
nolint
nolint
gss-auth command
nolint
nolint
interceptor command
nolint
nolint
resolve command
nolint
nolint
resolve-ptr command
nolint
nolint
server command
nolint
nolint
server-chaining command
nolint
nolint
tor-isolation command
nolint
nolint
udpassoc command
nolint
nolint
Package protocol implements low-level SOCKS protocol encoding and decoding.
Package protocol implements low-level SOCKS protocol encoding and decoding.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL