Skip to content

SOCKS proxy

Adam Waldenberg edited this page Oct 21, 2026 · 2 revisions

SOCKS proxy

Upcoming. This page describes the socks-proxy branch. It is not part of a release, and details may change.

A Hedgehog daemon can run a local SOCKS5 proxy whose traffic leaves the Unigrid network at a gridnode. It serves CONNECT for TCP and UDP ASSOCIATE for UDP, refuses BIND and asks for no authentication. Browsers, curl and any other SOCKS5 client can use it without knowing of gridnodes.

How it works

One proxy session: the SOCKS client, the local node, the members of a shard group, the exit and the destination

The gridnodes are dealt into shard groups of a few members each, anew every epoch. The members of a group keep a few append-only chains in memory, and several clients share each chain. Your node joins one group, writes your traffic to a chain through one or two of its members and reads the answers from the same chain. One member, chosen afresh for every connection, is the exit: it resolves the destination, connects to it and sends what comes back through the chain.

What your node and the exit send each other is sealed with keys only the two of them hold. The other members and the other clients on the chain pass the entries on but cannot read them. The exit itself sees what it relays, see What it does not protect.

Turning it on

The proxy is off unless the daemon is given a port. These options go after daemon, for example hedgehog daemon --socks-port <port>.

Option Default Meaning
--socks-port 0 Port of the proxy, 0 to 65535; 0 means no proxy
--socks-host 127.0.0.1 Address the proxy binds to; ignored while --socks-port is 0

The proxy asks for no credentials. Bound to any address but a loopback one, it is open to everyone who can reach that address, and the daemon logs a warning saying so. A name for --socks-host that does not resolve, or a port that cannot be bound, is an error that names both options. The proxy holds at most 512 client connections at once and closes every one beyond that at once.

A port alone does not switch the proxy on: until the network has a valid communication spork, every request is refused with reply 0x02.

The communication spork

The communication spork, type COMMUNICATION with id 1040, switches the proxy on for the whole network and sets its parameters. Until a node holds a valid one, the proxy is off on that node, both for its own clients and as a member of a shard group. On this branch a spork has the encoding of release 0.0.7: one signature, and neither the co-signing nor the signature log of Grid sporks.

Read it with hedgehog cli gridspork-get communication, or GET /gridspork/communication. Propose a value with hedgehog cli gridspork-set communication -D '<json>' -k <key>, or PUT /gridspork/communication. The JSON holds the fields below by name. The REST interface answers 400 with the reason when a value is out of bounds, a node drops such a spork when it arrives from a peer, and a stored one that breaks the bounds leaves the proxy off. A new spork applies to the streams and associations that start after it arrives.

Field Default Allowed Meaning
groupSize 8 1 to 65535 Gridnodes per shard group
reorganizePeriodSeconds 3600 60 to 4294967295 Length of an epoch, after which the groups and chains are dealt anew
chainsPerGroup 4 1 to 65535 Chains each group hosts
clientsPerChain 16 1 to 65535 Client writers a chain takes at one member
chainCapacityBytes 33554432 (32 MiB) maxEntryBytes to 4294967295 Bytes of entries a chain holds
retentionSeconds 30 1 to 65535 Age at which entries are dropped from a chain
maxEntryBytes 16384 (16 KiB) 1024 to 1048576 Largest entry, its overhead included
sessionIdleSeconds 300 1 to 65535 Time without traffic after which a connection is closed
communicationFlags 3 0 to 3 0x01 allows CONNECT, 0x02 allows UDP ASSOCIATE

The same id on master

On the master branch the id 1040 belongs to the ledger blacklist, see Ledger sporks. The two branches have not been reconciled, so a network cannot run both as they stand.

Using it from a client

Point any SOCKS5 client at the address and port of the proxy. With curl:

curl --socks5-hostname 127.0.0.1:<port> https://example.org

--socks5-hostname, or a proxy URL starting with socks5h://, hands the name to the proxy, so the exit looks it up. --socks5 looks the name up on your own machine and sends the address. A browser takes the proxy as a SOCKS v5 host and port; let it send names through the proxy where it offers to.

The first connection after a start or a new epoch waits while the node joins a group. A connection that has no answer from an exit after two minutes is refused with reply 0x06. UDP needs a client that speaks UDP ASSOCIATE: fragmented datagrams are dropped, and so is a datagram too large for one chain entry, about 16 KiB less its address with the default spork.

Replies

The proxy answers each request with one SOCKS5 reply.

Reply Sent when
0x00 succeeded The exit connected, and the bound address is its own end of that connection; or the association is up, and the bound address is the proxy's UDP socket
0x01 general failure The request cannot be read, or the connection ended before the exit replied
0x02 not allowed by ruleset No valid spork, its flag for the command is unset, or the exit refuses the destination
0x03 network unreachable No exit answered, no group took the node, or a socket error at the exit
0x04 host unreachable The name has no address, or there is no route to it
0x05 connection refused The destination refused the connection
0x06 TTL expired The connection timed out at the exit, no answer came within two minutes, or the session went idle before the reply
0x07 command not supported BIND
0x08 address type not supported A destination the proxy does not accept, such as a name spelt as an IP address

Where traffic may go

An exit connects only to public addresses. It refuses private, loopback, link-local, carrier-grade NAT, documentation, benchmark, multicast and reserved ranges of IPv4 and IPv6, also when an IPv6 address carries such an IPv4 address inside it, and the name localhost and every name below it. A name is looked up once and refused as a whole when any of its addresses is refused; the exit then connects only to the addresses it checked. A refused destination gets reply 0x02. The full rules are on SOCKS proxy implementation.

What it does not protect

  • The exit sees your traffic. It relays plaintext to the destination. Only TLS between your client and the destination, as with https://, keeps it from the exit.
  • The exit is not proven. Gridnodes are not authenticated, so any writer on the chain that sees your node's request can answer first in the chosen exit's name and become your exit.
  • One hop. The members your node attaches to see your node's address and how much traffic it sends. The reply to a CONNECT names the exit's address, and every client on a chain receives every entry of that chain, sealed.
  • No half-close. When your client shuts down its sending side, the connection closes as a whole.
  • Writers can be used up. A chain takes at most 4096 writers per epoch and never gives a place back within it, so whoever can write to a chain can fill it until the next epoch.
  • Lost entries. An entry your node missed is not fetched again; the connection it belonged to breaks once the missing entry is too old.
  • UDP with port 0. A client that names port 0 in UDP ASSOCIATE is identified by the first datagram from its IP address, so another program on that address that sends first is taken for the client.
  • Ports and the exit's own network. The rules for destinations have none for ports, and do not know the addresses of the exit's own interfaces.

Peers and protocol versions

A node of release 0.0.7 can read neither a communication spork, which also throws it off the sporks that follow one, nor chain traffic. A node on this branch therefore offers the protocol identifier hedgehog/0.0.5 first, followed by hedgehog/0.0.2 and gridspork/0.0.2. Only a peer that agrees on hedgehog/0.0.5 is sent the communication spork and carries chain traffic, on a second QUIC stream, stream 4. A node of release 0.0.7 offers the other two and connects without proxy traffic.

The branch forked shortly after release 0.0.7 and carries the version 0.0.8-SNAPSHOT. Release 0.0.8 offers hedgehog/0.0.4 and gridspork/0.0.4, none of which this branch offers, so the two cannot connect, see Peer-to-peer network protocol. The branch also lacks the spork co-signing and the signature log of master.

More

Page For
SOCKS proxy implementation Developers: the modules, the SOCKS5 front end, shard groups and exits, sessions and their keys, the exit side and the destination policy
SOCKS proxy chains Developers: chains, entries and their bytes, admission, the chain packets, joins, reconcile and stream budgets

Clone this wiki locally