Skip to content

SOCKS, HTTP, and Mixed Protocols ​

sing-box implements SOCKS4/5, HTTP CONNECT, and a combined "mixed" listener that auto-detects the protocol. All three share similar patterns: TCP-only listening, optional TLS, username/password authentication, and UoT (UDP-over-TCP) support.

Source: protocol/socks/inbound.go, protocol/http/inbound.go, protocol/mixed/inbound.go, protocol/socks/outbound.go, protocol/http/outbound.go

SOCKS Inbound ​

Architecture ​

go
type Inbound struct {
    inbound.Adapter
    router        adapter.ConnectionRouterEx
    logger        logger.ContextLogger
    listener      *listener.Listener
    authenticator *auth.Authenticator
    udpTimeout    time.Duration
}

The SOCKS inbound implements adapter.TCPInjectableInbound:

go
var _ adapter.TCPInjectableInbound = (*Inbound)(nil)

Connection Processing ​

SOCKS connections are delegated to sing/protocol/socks.HandleConnectionEx, which handles the full SOCKS4/5 handshake:

go
func (h *Inbound) NewConnectionEx(ctx, conn, metadata, onClose) {
    err := socks.HandleConnectionEx(ctx, conn, std_bufio.NewReader(conn),
        h.authenticator,
        adapter.NewUpstreamHandlerEx(metadata, h.newUserConnection, h.streamUserPacketConnection),
        h.listener,         // UDP associate listener
        h.udpTimeout,
        metadata.Source,
        onClose,
    )
    N.CloseOnHandshakeFailure(conn, onClose, err)
}

The handler receives decoded TCP connections and UDP packet connections after the SOCKS handshake:

go
func (h *Inbound) newUserConnection(ctx, conn, metadata, onClose) {
    metadata.Inbound = h.Tag()
    metadata.InboundType = h.Type()
    user, loaded := auth.UserFromContext[string](ctx)
    if loaded {
        metadata.User = user
    }
    h.router.RouteConnectionEx(ctx, conn, metadata, onClose)
}

UoT Support ​

The router is wrapped with UoT support for handling UDP-over-TCP:

go
inbound.router = uot.NewRouter(router, logger)

TCP-Only Listener ​

SOCKS listens only on TCP. UDP associate connections are handled through the SOCKS5 UDP relay mechanism (using the listener as the UDP associate target):

go
inbound.listener = listener.New(listener.Options{
    Network:           []string{N.NetworkTCP},
    ConnectionHandler: inbound,
})

HTTP Inbound ​

Architecture ​

go
type Inbound struct {
    inbound.Adapter
    router        adapter.ConnectionRouterEx
    logger        log.ContextLogger
    listener      *listener.Listener
    authenticator *auth.Authenticator
    tlsConfig     tls.ServerConfig
}

TLS Support with kTLS ​

HTTP inbound supports TLS with kTLS compatibility enabled:

go
if options.TLS != nil {
    tlsConfig, _ := tls.NewServerWithOptions(tls.ServerOptions{
        KTLSCompatible: true,
    })
    inbound.tlsConfig = tlsConfig
}

Connection Processing ​

TLS handshake is performed first (if configured), then the HTTP CONNECT handler processes the request:

go
func (h *Inbound) NewConnectionEx(ctx, conn, metadata, onClose) {
    if h.tlsConfig != nil {
        tlsConn, _ := tls.ServerHandshake(ctx, conn, h.tlsConfig)
        conn = tlsConn
    }
    err := http.HandleConnectionEx(ctx, conn, std_bufio.NewReader(conn),
        h.authenticator,
        adapter.NewUpstreamHandlerEx(metadata, h.newUserConnection, h.streamUserPacketConnection),
        metadata.Source,
        onClose,
    )
}

System Proxy ​

HTTP inbound can configure itself as the system proxy:

go
inbound.listener = listener.New(listener.Options{
    SetSystemProxy:    options.SetSystemProxy,
    SystemProxySOCKS:  false,
})

Mixed Inbound ​

The mixed inbound combines SOCKS and HTTP on a single port by peeking the first byte of each connection.

Architecture ​

go
type Inbound struct {
    inbound.Adapter
    router        adapter.ConnectionRouterEx
    logger        log.ContextLogger
    listener      *listener.Listener
    authenticator *auth.Authenticator
    tlsConfig     tls.ServerConfig
    udpTimeout    time.Duration
}

Protocol Detection ​

The core logic peeks the first byte to determine the protocol:

go
func (h *Inbound) newConnection(ctx, conn, metadata, onClose) error {
    if h.tlsConfig != nil {
        conn = tls.ServerHandshake(ctx, conn, h.tlsConfig)
    }
    reader := std_bufio.NewReader(conn)
    headerBytes, _ := reader.Peek(1)

    switch headerBytes[0] {
    case socks4.Version, socks5.Version:
        // SOCKS4 (0x04) or SOCKS5 (0x05)
        return socks.HandleConnectionEx(ctx, conn, reader, h.authenticator, ...)
    default:
        // Anything else is treated as HTTP
        return http.HandleConnectionEx(ctx, conn, reader, h.authenticator, ...)
    }
}
  • SOCKS4: First byte is 0x04
  • SOCKS5: First byte is 0x05
  • HTTP: Any other first byte (typically C for CONNECT, G for GET, etc.)

System Proxy (Mixed) ​

When mixed is set as system proxy, it reports the SOCKS port:

go
inbound.listener = listener.New(listener.Options{
    SetSystemProxy:    options.SetSystemProxy,
    SystemProxySOCKS:  true,  // Advertise SOCKS port in system proxy
})

SOCKS Outbound ​

The SOCKS outbound connects through an upstream SOCKS5 server. It is implemented in protocol/socks/outbound.go and uses the sing/protocol/socks library's Client type.

HTTP Outbound ​

The HTTP outbound connects through an upstream HTTP CONNECT proxy. It supports TLS to the proxy server.

Common Patterns ​

User Authentication ​

All three inbound types use the same authentication mechanism:

go
authenticator := auth.NewAuthenticator(options.Users)

Users are auth.User structs with Username and Password fields. The authenticator is passed to the protocol handlers.

User Metadata ​

After authentication, the username is extracted from context and stored in metadata:

go
user, loaded := auth.UserFromContext[string](ctx)
if loaded {
    metadata.User = user
}

TCP Injectable ​

Both SOCKS and Mixed inbound implement adapter.TCPInjectableInbound, allowing other components to inject TCP connections into them (used by transparent proxy mechanisms).

Configuration Examples ​

SOCKS Inbound ​

json
{
  "type": "socks",
  "tag": "socks-in",
  "listen": "127.0.0.1",
  "listen_port": 1080,
  "users": [
    { "username": "user1", "password": "pass1" }
  ]
}

HTTP Inbound (with TLS) ​

json
{
  "type": "http",
  "tag": "http-in",
  "listen": "127.0.0.1",
  "listen_port": 8080,
  "users": [
    { "username": "user1", "password": "pass1" }
  ],
  "tls": {
    "enabled": true,
    "certificate_path": "/path/to/cert.pem",
    "key_path": "/path/to/key.pem"
  },
  "set_system_proxy": true
}

Mixed Inbound ​

json
{
  "type": "mixed",
  "tag": "mixed-in",
  "listen": "127.0.0.1",
  "listen_port": 2080,
  "users": [
    { "username": "user1", "password": "pass1" }
  ],
  "set_system_proxy": true
}