How SOCKS Proxies Work: Protocol-Agnostic Network Proxying

SOCKS (Socket Secure) is a general-purpose network proxy protocol that operates at the session layer (Layer 5) of the OSI model, forwarding arbitrary TCP and UDP traffic between a client and a destination server without interpreting or modifying the application-layer payload. Unlike an HTTP proxy, which understands HTTP semantics and can inspect, cache, or rewrite requests, a SOCKS proxy is protocol-agnostic: it simply establishes a relay between endpoints and passes bytes transparently. The current version, SOCKS5, is defined in RFC 1928 (March 1996) and adds authentication, UDP support, and IPv6 addressing to the earlier SOCKS4 protocol. SOCKS proxies are widely used for SSH dynamic port forwarding, Tor's local interface, firewall traversal, and privacy-sensitive applications that need to route traffic through an intermediary without application-specific protocol support.

Why SOCKS Exists: The Problem It Solves

In the early 1990s, organizations needed a way to allow internal users to access the internet through a firewall without exposing the internal network directly. The options were limited: packet-filtering firewalls could allow or deny traffic based on IP and port, but they couldn't authenticate users or enforce per-user policies. Application-layer gateways (HTTP proxies, FTP proxies) could authenticate users and inspect traffic, but you needed a separate proxy for every protocol. If your organization used Telnet, FTP, HTTP, Gopher, and NNTP, you needed five different proxy implementations.

SOCKS solved this by operating below the application layer. A single SOCKS proxy server could handle any TCP-based protocol without understanding its semantics. The client application connects to the SOCKS server, tells it the destination address and port, and the SOCKS server establishes the connection on the client's behalf. From that point forward, the proxy simply relays bytes in both directions. The application protocol running over the connection is irrelevant -- SOCKS does not inspect it, parse it, or even know what it is.

David Koblas of MIPS Computer Systems presented the original SOCKS protocol at the 1992 Usenix Security Symposium. Ying-Da Lee at NEC extended it to SOCKS4 and SOCKS4a. The major revision to SOCKS5 (RFC 1928) was authored by Marcus Leech at Bell-Northern Research in 1996, adding authentication negotiation, UDP support, and IPv6 addressing -- capabilities that made SOCKS5 the dominant version still in use today.

SOCKS4 vs SOCKS5: Protocol Differences

Although SOCKS4 is still encountered in legacy systems and some specialized tools, SOCKS5 is the standard for modern deployments. The differences are substantial:

Feature SOCKS4 SOCKS5 (RFC 1928)
Authentication User ID only (no password) Pluggable: none, user/pass (RFC 1929), GSSAPI
Address types IPv4 only IPv4, IPv6, domain name (FQDN)
Transport TCP only TCP and UDP
Commands CONNECT, BIND CONNECT, BIND, UDP ASSOCIATE
DNS resolution Client-side only (SOCKS4a adds remote) Remote resolution via FQDN address type
RFC No formal RFC (de facto standard) RFC 1928 (protocol), RFC 1929 (user/pass auth)

SOCKS4a deserves special mention. The original SOCKS4 required the client to resolve the destination hostname to an IPv4 address before connecting to the proxy. This is a privacy problem: DNS queries from the client can leak the intended destination to the local network. SOCKS4a fixed this by allowing the client to send the domain name instead of a resolved IP, using a deliberate invalid IP address (0.0.0.x) as a signal that the hostname follows the user ID field. SOCKS5 formalized this concept with its DOMAINNAME address type (0x03), making remote DNS resolution a first-class feature of the protocol.

The SOCKS5 Handshake

A SOCKS5 connection proceeds in three phases: method negotiation, authentication, and request. The protocol is binary, not text-based like HTTP. Every field is precisely sized, making it efficient to parse but unreadable with tools like curl without SOCKS support.

SOCKS5 Connection Handshake (RFC 1928) Client SOCKS Proxy Destination NEGOTIATE VER=0x05 | NMETHODS | METHODS[] e.g. [0x00, 0x02] = no auth + user/pass VER=0x05 | METHOD 0x00=none, 0x02=user/pass, 0xFF=reject AUTH VER=0x01 | USER | PASS (only if METHOD=0x02 was selected) VER=0x01 | STATUS 0x00 = success REQUEST VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT CMD: 0x01=CONNECT, 0x02=BIND, 0x03=UDP ASSOCIATE TCP SYN (proxy connects) VER | REP | RSV | ATYP | BND.ADDR | BND.PORT REP: 0x00=success, 0x01=general failure, ... RELAY Application data flows transparently Bytes relayed without inspection

Phase 1: Method Negotiation

The client opens a TCP connection to the SOCKS proxy (conventionally on port 1080) and sends a greeting that lists the authentication methods it supports. The greeting is compact:

+----+----------+----------+
|VER | NMETHODS | METHODS  |
+----+----------+----------+
| 1  |    1     | 1-255    |
+----+----------+----------+

VER is always 0x05 for SOCKS5. NMETHODS is the number of authentication methods the client supports, and METHODS is a byte array listing them. The defined methods are:

The server selects one method from the client's list and responds with a two-byte message: version (0x05) and the chosen method. If the server cannot accept any of the offered methods, it responds with 0xFF and closes the connection.

Phase 2: Authentication

If the server selected method 0x02 (username/password), the client sends credentials according to RFC 1929. This sub-negotiation uses its own version byte (0x01, not 0x05):

+----+------+----------+------+----------+
|VER | ULEN |  UNAME   | PLEN |  PASSWD  |
+----+------+----------+------+----------+
| 1  |  1   | 1-255    |  1   | 1-255    |
+----+------+----------+------+----------+

The username and password are sent in cleartext. This is a critical security consideration: without an outer encryption layer (like SSH or TLS), anyone who can observe the connection between client and proxy can read the credentials. The server responds with a version byte and a status byte: 0x00 for success, anything else for failure.

GSSAPI authentication (method 0x01, RFC 1961) is more complex and provides mutual authentication and optional message integrity/confidentiality via the Generic Security Services API. In practice, this means Kerberos authentication in most deployments. GSSAPI is common in enterprise environments where the SOCKS proxy is integrated with Active Directory, but rare in consumer or open-source tools.

Phase 3: Connection Request

After authentication succeeds (or immediately after method negotiation if no authentication was required), the client sends its actual request:

+----+-----+-------+------+----------+----------+
|VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
+----+-----+-------+------+----------+----------+
| 1  |  1  | X'00' |  1   | Variable |    2     |
+----+-----+-------+------+----------+----------+

The ATYP (address type) field determines how DST.ADDR is interpreted:

The domain name address type (0x03) is what enables remote DNS resolution -- the proxy resolves the hostname, not the client. This is the single most important privacy feature in the SOCKS5 protocol.

SOCKS5 Commands: CONNECT, BIND, and UDP ASSOCIATE

SOCKS5 defines three commands, each serving a different connection pattern:

CONNECT (0x01)

The most common command. The client asks the proxy to establish an outbound TCP connection to the specified destination. Once the proxy connects, it replies with the bound address and port it used for the outgoing connection, and then enters relay mode -- simply copying bytes between the client connection and the destination connection in both directions. This is what happens when you browse the web, check email, or use any typical client-server application through a SOCKS proxy.

BIND (0x02)

BIND is designed for protocols that require the server to connect back to the client -- the most common example being FTP's active mode data transfer. The process works in two stages:

  1. The client sends a BIND request. The proxy opens a listening socket and replies with the address and port it is listening on.
  2. The client communicates this address/port to the destination server (via the already-established primary connection).
  3. When the destination server connects to the proxy's listening socket, the proxy sends a second reply to the client indicating the incoming connection has arrived, then enters relay mode.

BIND is rarely used in modern applications because most protocols have moved away from server-to-client connections (FTP passive mode, for example, avoids this pattern entirely). It remains in the specification for backward compatibility.

UDP ASSOCIATE (0x03)

This is SOCKS5's most complex command and the key feature that SOCKS4 lacks entirely. The client sends a UDP ASSOCIATE request over the TCP control connection, and the proxy replies with a UDP relay address and port. The client then sends and receives UDP datagrams through this relay, each prefixed with a SOCKS5 UDP header that specifies the destination:

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

The FRAG field supports UDP fragmentation at the SOCKS level (values 0x01-0x7F indicate fragment position, 0x00 means standalone datagram), though most implementations either don't support fragmentation or simply drop fragmented datagrams. The TCP control connection must remain open for the duration of the UDP association -- if the client closes the TCP connection, the proxy tears down the UDP relay.

UDP ASSOCIATE is used by applications like DNS resolvers, VoIP clients, and gaming software that need to proxy UDP traffic. However, many SOCKS client libraries and applications only implement CONNECT, so UDP support through SOCKS remains less common in practice than TCP proxying.

DNS Resolution: Local vs Remote

DNS handling is the most privacy-critical aspect of SOCKS proxy usage, and it is also the most frequently misconfigured. There are two approaches:

Local DNS resolution means the client resolves the destination hostname to an IP address before contacting the SOCKS proxy. The client then sends the resolved IP address in the SOCKS request (ATYP=0x01 for IPv4 or 0x04 for IPv6). This approach leaks the destination hostname to the local DNS resolver and, by extension, to anyone who can observe the client's DNS traffic -- your ISP, your local network administrator, or an attacker performing DNS monitoring. If you're using a SOCKS proxy for privacy, local DNS resolution undermines the entire purpose.

Remote DNS resolution means the client sends the hostname itself to the SOCKS proxy (ATYP=0x03), and the proxy performs the DNS lookup. The client's local network never sees the destination hostname in DNS traffic. This is the correct approach for privacy-sensitive use cases.

The trouble is that many applications default to local DNS resolution even when configured to use a SOCKS proxy. The application's networking library often resolves the hostname before it even reaches the SOCKS client code. This is known as a DNS leak, and it is one of the most common privacy failures in SOCKS proxy configurations.

Browser behavior varies:

SSH Dynamic Port Forwarding: SOCKS in Practice

The most common way people encounter SOCKS proxies is through SSH's -D flag (dynamic port forwarding). When you run:

ssh -D 1080 user@remote-server

SSH creates a SOCKS5 server listening on localhost:1080. Any application configured to use this SOCKS proxy will have its traffic tunneled through the SSH connection to the remote server, which then connects to the destination on the application's behalf. The traffic between your machine and the remote server is encrypted by SSH; the traffic from the remote server to the final destination is unencrypted (unless the application itself uses TLS).

This is fundamentally different from SSH's other port forwarding modes:

The -D flag is enormously useful. You can route your entire browser through a remote server with a single SSH command, accessing internal services, bypassing geographic restrictions, or encrypting your traffic on untrusted networks. Combined with -N (no remote command) and -f (background), it becomes a lightweight VPN alternative:

ssh -D 1080 -N -f user@remote-server

OpenSSH's SOCKS implementation supports both CONNECT and UDP ASSOCIATE (as of OpenSSH 9.x), though historically only CONNECT was implemented. The lack of UDP support in older OpenSSH versions meant that DNS queries from applications using the SOCKS proxy would sometimes bypass the tunnel, causing DNS leaks even when the application was correctly configured for remote DNS resolution.

SOCKS vs HTTP Proxy

HTTP proxies and SOCKS proxies solve overlapping problems but operate at different protocol layers and make fundamentally different tradeoffs:

An HTTP proxy speaks HTTP. The client sends a full HTTP request to the proxy, including the destination URL in the request line: GET http://example.com/page HTTP/1.1. The proxy parses this request, connects to the destination, forwards the request, and returns the response. Because the proxy understands HTTP, it can cache responses, filter content, rewrite headers, enforce access policies, log URLs, and perform content inspection. For HTTPS traffic, the client sends a CONNECT request asking the proxy to establish a TCP tunnel: CONNECT example.com:443 HTTP/1.1. After the proxy confirms the tunnel is open, the client performs a TLS handshake directly with the destination server through the tunnel. The proxy can see the destination hostname (from the CONNECT request and from the TLS SNI extension) but cannot inspect the encrypted payload.

A SOCKS proxy operates below the application layer. It does not understand HTTP, SMTP, FTP, or any other application protocol. The client connects to the SOCKS proxy, uses the SOCKS protocol to request a connection to a destination address and port, and then sends application-layer traffic through the tunnel. The proxy never parses the application data. This means:

In practice, the two are often complementary. Enterprise environments frequently deploy HTTP proxies for web traffic (enabling caching, content filtering, and DLP) and use SOCKS proxies (or SSH dynamic forwarding) for non-HTTP protocols that need to traverse the firewall. Many proxy-aware applications support both: curl accepts --proxy http://, --proxy socks5://, and --proxy socks5h:// interchangeably.

Tor and SOCKS

The Tor client software exposes a SOCKS5 interface on localhost:9050 (or 9150 for Tor Browser). Applications that want to route traffic through the Tor network connect to this local SOCKS proxy, and the Tor client handles the onion routing, circuit construction, and relay communication internally. This design is elegant: application developers don't need to understand Tor's protocol -- they just need SOCKS5 support, which is available in virtually every programming language and many applications.

Tor's SOCKS5 Interface Application Browser, curl, torsocks, etc. Tor Client SOCKS5 on 127.0.0.1:9050 Circuit Builder Onion Encryption Tor Network Guard Mid Exit Destination example.com SOCKS5 localhost only 3 layers onion encrypted Cleartext or TLS exit -> destination Stream Isolation Tor uses SOCKS5 auth fields for circuit isolation: different user/pass = different circuit. Tor Browser uses per-domain isolation by default.

Tor leverages a clever extension of the SOCKS5 protocol: stream isolation via authentication fields. The Tor client interprets the username and password fields in SOCKS5 authentication not as real credentials but as an isolation key. Connections with different username/password combinations are routed through different Tor circuits. Tor Browser uses this to isolate traffic by first-party domain -- requests to different websites go through different circuits, preventing exit nodes from correlating your activity across sites.

Tor also uses the SOCKS5 domain name address type (ATYP=0x03) for .onion addresses. When an application sends a CONNECT request for duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion through the Tor SOCKS interface, the Tor client recognizes the .onion TLD and routes the connection through a rendezvous circuit to the hidden service, without ever touching the public internet.

The torsocks utility transparently wraps arbitrary command-line applications to use Tor by intercepting socket-related system calls via LD_PRELOAD and redirecting them through the local Tor SOCKS proxy. This allows applications with no SOCKS awareness to use Tor:

torsocks curl https://check.torproject.org
torsocks ssh user@remote-host
torsocks git clone https://example.com/repo.git

SOCKSifying Applications

Not every application has built-in SOCKS support. Several approaches exist for routing arbitrary application traffic through a SOCKS proxy:

Application-level configuration: Many applications (browsers, curl, wget, git) have native SOCKS proxy settings. This is the most reliable approach because the application controls DNS resolution behavior and can use SOCKS5's domain name address type correctly. Set environment variables or use command-line flags:

# curl with remote DNS resolution (note the 'h' suffix)
curl --proxy socks5h://localhost:1080 https://example.com

# git via SOCKS5
git config --global http.proxy socks5h://localhost:1080

# Environment variable (application must honor it)
export ALL_PROXY=socks5h://localhost:1080

LD_PRELOAD interception: Tools like tsocks, torsocks, and proxychains use the dynamic linker's LD_PRELOAD mechanism to intercept calls to connect(), getaddrinfo(), and related socket functions, redirecting them through a SOCKS proxy. This works for dynamically linked applications but fails for statically compiled binaries (common in Go programs), applications that use raw syscalls, or applications that bypass libc networking functions.

Transparent proxying: A firewall rule (iptables/nftables on Linux, pf on BSD/macOS) can redirect all outgoing TCP traffic to a local SOCKS-aware transparent proxy like redsocks or tun2socks. This catches all traffic regardless of application SOCKS support, but it requires root privileges and careful configuration to avoid routing loops (you must exempt the proxy's own connections to the upstream SOCKS server from the redirect rule).

TUN/TAP interface: Tools like tun2socks create a virtual network interface that routes IP-level traffic through a SOCKS proxy. This is the most transparent approach -- the operating system routes packets to the TUN device, and the tool handles TCP reassembly and SOCKS proxying. This is effectively how some VPN-like setups work with SOCKS proxies.

Security Considerations

SOCKS has significant security properties -- both strengths and limitations -- that must be understood before deploying it:

No encryption. The SOCKS protocol itself provides zero encryption. The control channel (method negotiation, authentication, connection request) and the data channel are both cleartext. Credentials sent via RFC 1929 username/password authentication are visible to anyone who can observe the network path between client and proxy. You must layer encryption on top: SSH dynamic forwarding (-D), a TLS wrapper, or a VPN tunnel to the proxy server.

DNS leaks. As discussed above, DNS leaks are the most common privacy failure in SOCKS deployments. Even with a correctly configured SOCKS5 proxy, an application might resolve DNS locally, a browser extension might bypass the proxy, or WebRTC might reveal the client's real IP address. Testing for DNS leaks should be a standard part of any SOCKS proxy deployment.

No data integrity. SOCKS provides no guarantee that data has not been modified in transit. A man-in-the-middle between client and proxy (or between proxy and destination) can alter the relayed data. Again, application-layer security (TLS) is essential.

Proxy compromise. The SOCKS proxy server sees all traffic in cleartext (unless the application uses TLS). If you're using SOCKS for privacy, you must trust the proxy operator. For SSH dynamic forwarding, you're trusting the SSH server and the network it's connected to. For Tor, the exit node can see unencrypted traffic, which is why using HTTPS over Tor is strongly recommended.

Protocol leaks. Some protocols embed the client's IP address in application-layer data. FTP's PORT command sends the client's IP. SIP includes the client's address in the Via header. BitTorrent's DHT announces the client's IP to peers. These leaks occur above the SOCKS layer and cannot be prevented by the proxy.

UDP and ICMP limitations. While SOCKS5 supports UDP via UDP ASSOCIATE, ICMP traffic (ping, traceroute) cannot be proxied through SOCKS. Many SOCKS implementations don't support UDP ASSOCIATE at all. If an application falls back from UDP to TCP when the UDP path fails, it may work through SOCKS -- but silently, with different performance characteristics.

SOCKS in Network Architecture

SOCKS proxies occupy a specific niche in the broader landscape of network intermediaries:

Firewall traversal: In controlled networks where only HTTP/HTTPS is allowed through the firewall, SSH tunneling with SOCKS dynamic forwarding provides a way to route arbitrary protocols. The SSH connection looks like ordinary encrypted traffic on port 22 (or can be run on port 443 to look like HTTPS). The SOCKS proxy on the other side of the tunnel then fans out connections to any destination.

Bastion host access: In cloud environments, a bastion host running an SSH server effectively becomes a SOCKS proxy for accessing internal services. Developers SSH to the bastion with -D 1080 and configure their browser or tools to use the SOCKS proxy, gaining access to internal dashboards, databases, and APIs without exposing those services to the internet. This is simpler and more flexible than setting up per-service -L port forwards.

Geographic routing: Unlike a VPN, which typically routes all traffic through the tunnel, a SOCKS proxy can be selectively configured per-application. A developer might route their browser through a SOCKS proxy in Europe for testing geo-restricted content while keeping their IDE, email, and other applications on the local network. PAC (Proxy Auto-Configuration) files can automate this selective routing based on URL patterns.

Chain proxying: SOCKS connections can be chained: client -> SOCKS proxy A -> SOCKS proxy B -> destination. Tools like proxychains support this natively. Each proxy in the chain only knows its immediate neighbors. This provides a limited form of anonymity -- more than a single proxy, less than Tor's cryptographic circuit construction, and without Tor's protection against a single compromised node revealing the full path.

SOCKS Implementations

Several mature SOCKS server implementations exist:

Wire Format Example

To make the protocol concrete, here is a complete SOCKS5 session at the byte level. The client connects through a SOCKS5 proxy to example.com:443 with no authentication:

# Client -> Proxy: Method negotiation
# VER=5, NMETHODS=1, METHOD=0x00 (no auth)
05 01 00

# Proxy -> Client: Method selection
# VER=5, METHOD=0x00 (no auth accepted)
05 00

# Client -> Proxy: CONNECT request
# VER=5, CMD=0x01 (CONNECT), RSV=0x00
# ATYP=0x03 (domain), LEN=11, "example.com", PORT=0x01BB (443)
05 01 00 03 0b 65 78 61 6d 70 6c 65 2e 63 6f 6d 01 bb

# Proxy -> Client: Success reply
# VER=5, REP=0x00 (success), RSV=0x00
# ATYP=0x01 (IPv4), BND.ADDR=93.184.216.34, BND.PORT=0xC7A8
05 00 00 01 5d b8 d8 22 c7 a8

# ... TCP tunnel is established, TLS handshake begins ...

The entire SOCKS5 handshake for this common case is just 10 bytes from client to proxy and 12 bytes from proxy to client (plus the 3-byte greeting and 2-byte method selection). The protocol overhead is negligible compared to the data that will flow through the tunnel.

Common Pitfalls

Real-world SOCKS proxy deployments frequently encounter these issues:

SOCKS in the Modern Internet

Despite being defined in 1996, SOCKS5 remains relevant because its design is fundamentally sound: a minimal, protocol-agnostic relay mechanism is a useful building block. However, the landscape around it has evolved. WireGuard and other modern VPN protocols provide full-tunnel encryption with far less configuration than SOCKS + SSH. Tor provides stronger anonymity than any single SOCKS proxy. HTTP CONNECT proxies handle the most common SOCKS use case (tunneling HTTPS) without requiring SOCKS support in the client.

SOCKS5 thrives where its unique advantages matter: SSH dynamic port forwarding for ad-hoc access to internal networks, Tor's local interface for anonymity tools, chain proxying for censorship circumvention, and SOCKSifying applications that lack HTTP proxy support. The protocol's simplicity is its durability -- at 10 bytes of handshake overhead, it does exactly what it promises and nothing more.

Investigating Proxy Infrastructure

SOCKS proxy servers, SSH bastion hosts, and VPN endpoints all have IP addresses that belong to specific autonomous systems and are announced via BGP. You can use the god.ad BGP Looking Glass to look up any proxy server's IP address and discover which AS operates it, what prefix it belongs to, the AS path to reach it, and whether its route has valid RPKI origin validation. This can reveal whether a commercial SOCKS proxy service operates its own infrastructure or rents servers from a cloud provider -- and which networks your proxied traffic will traverse on its way to the destination.

Try looking up a proxy server IP in the BGP Looking Glass to see what the routing infrastructure reveals about your proxy provider's network.

See BGP routing data in real time

Open Looking Glass
More Articles
How TLS/HTTPS Works: Securing the Internet's Traffic
Certificate Transparency: How CT Logs Secure the Web's PKI
How Firewalls Work: Packet Filtering, Stateful Inspection, and Beyond
What is Cross-Site Scripting (XSS)?
What is Cross-Site Request Forgery (CSRF)?
What is Server-Side Request Forgery (SSRF)?