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
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:
var _ adapter.TCPInjectableInbound = (*Inbound)(nil)Connection Processing
SOCKS connections are delegated to sing/protocol/socks.HandleConnectionEx, which handles the full SOCKS4/5 handshake:
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:
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:
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):
inbound.listener = listener.New(listener.Options{
Network: []string{N.NetworkTCP},
ConnectionHandler: inbound,
})HTTP Inbound
Architecture
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:
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:
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:
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
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:
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
Cfor CONNECT,Gfor GET, etc.)
System Proxy (Mixed)
When mixed is set as system proxy, it reports the SOCKS port:
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:
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:
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
{
"type": "socks",
"tag": "socks-in",
"listen": "127.0.0.1",
"listen_port": 1080,
"users": [
{ "username": "user1", "password": "pass1" }
]
}HTTP Inbound (with TLS)
{
"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
{
"type": "mixed",
"tag": "mixed-in",
"listen": "127.0.0.1",
"listen_port": 2080,
"users": [
{ "username": "user1", "password": "pass1" }
],
"set_system_proxy": true
}