• Stars
    star
    116
  • Rank 303,894 (Top 6 %)
  • Language
    PHP
  • License
    MIT License
  • Created over 10 years ago
  • Updated almost 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Async SOCKS proxy connector client and server implementation, tunnel any TCP/IP-based protocol through a SOCKS5 or SOCKS4(a) proxy server, built on top of ReactPHP.

clue/reactphp-socks

CI status installs on Packagist

Async SOCKS proxy connector client and server implementation, tunnel any TCP/IP-based protocol through a SOCKS5 or SOCKS4(a) proxy server, built on top of ReactPHP.

The SOCKS proxy protocol family (SOCKS5, SOCKS4 and SOCKS4a) is commonly used to tunnel HTTP(S) traffic through an intermediary ("proxy"), to conceal the origin address (anonymity) or to circumvent address blocking (geoblocking). While many (public) SOCKS proxy servers often limit this to HTTP(S) port 80 and 443 only, this can technically be used to tunnel any TCP/IP-based protocol (HTTP, SMTP, IMAP etc.). This library provides a simple API to create these tunneled connections for you. Because it implements ReactPHP's standard ConnectorInterface, it can simply be used in place of a normal connector. This makes it fairly simple to add SOCKS proxy support to pretty much any existing higher-level protocol implementation. Besides the client side, it also provides a simple SOCKS server implementation which allows you to build your own SOCKS proxy servers with custom business logic.

  • Async execution of connections - Send any number of SOCKS requests in parallel and process their responses as soon as results come in. The Promise-based design provides a sane interface to working with out of order responses and possible connection errors.
  • Standard interfaces - Allows easy integration with existing higher-level components by implementing ReactPHP's standard ConnectorInterface.
  • Lightweight, SOLID design - Provides a thin abstraction that is just good enough and does not get in your way. Builds on top of well-tested components and well-established concepts instead of reinventing the wheel.
  • Good test coverage - Comes with an automated tests suite and is regularly tested against actual proxy servers in the wild.

Table of contents

Support us

We invest a lot of time developing, maintaining and updating our awesome open-source projects. You can help us sustain this high-quality of our work by becoming a sponsor on GitHub. Sponsors get numerous benefits in return, see our sponsoring page for details.

Let's take these projects to the next level together! 🚀

Quickstart example

Once installed, you can use the following code to send a secure HTTPS request to google.com through a local SOCKS proxy server:

<?php

require __DIR__ . '/vendor/autoload.php';

$proxy = new Clue\React\Socks\Client('127.0.0.1:1080');

$connector = new React\Socket\Connector(array(
    'tcp' => $proxy,
    'dns' => false
));

$browser = new React\Http\Browser($connector);

$browser->get('https://google.com/')->then(function (Psr\Http\Message\ResponseInterface $response) {
    var_dump($response->getHeaders(), (string) $response->getBody());
}, function (Exception $e) {
    echo 'Error: ' . $e->getMessage() . PHP_EOL;
});

If you're not already running any other SOCKS proxy server, you can use the following code to create a SOCKS proxy server listening for connections on 127.0.0.1:1080:

<?php

require __DIR__ . '/vendor/autoload.php';

// start a new SOCKS proxy server
$socks = new Clue\React\Socks\Server();

// listen on 127.0.0.1:1080
$socket = new React\Socket\SocketServer('127.0.0.1:1080');
$socks->listen($socket);

See also the examples.

Usage

Client

The Client is responsible for communication with your SOCKS server instance.

Its constructor simply accepts a SOCKS proxy URI with the SOCKS proxy server address:

$proxy = new Clue\React\Socks\Client('127.0.0.1:1080');

You can omit the port if you're using the default SOCKS port 1080:

$proxy = new Clue\React\Socks\Client('127.0.0.1');

If you need custom connector settings (DNS resolution, TLS parameters, timeouts, proxy servers etc.), you can explicitly pass a custom instance of the ConnectorInterface:

$connector = new React\Socket\Connector(array(
    'dns' => '127.0.0.1',
    'tcp' => array(
        'bindto' => '192.168.10.1:0'
    )
));

$proxy = new Clue\React\Socks\Client('my-socks-server.local:1080', $connector);

This is one of the two main classes in this package. Because it implements ReactPHP's standard ConnectorInterface, it can simply be used in place of a normal connector. Accordingly, it provides only a single public method, the connect() method. The connect(string $uri): PromiseInterface<ConnectionInterface, Exception> method can be used to establish a streaming connection. It returns a Promise which either fulfills with a ConnectionInterface on success or rejects with an Exception on error.

This makes it fairly simple to add SOCKS proxy support to pretty much any higher-level component:

- $acme = new AcmeApi($connector);
+ $proxy = new Clue\React\Socks\Client('127.0.0.1:1080', $connector);
+ $acme = new AcmeApi($proxy);

Plain TCP connections

SOCKS proxies are most frequently used to issue HTTP(S) requests to your destination. However, this is actually performed on a higher protocol layer and this connector is actually inherently a general-purpose plain TCP/IP connector. As documented above, you can simply invoke its connect() method to establish a streaming plain TCP/IP connection and use any higher level protocol like so:

$proxy = new Clue\React\Socks\Client('127.0.0.1:1080');

$proxy->connect('tcp://www.google.com:80')->then(function (React\Socket\ConnectionInterface $connection) {
    echo 'connected to www.google.com:80';
    $connection->write("GET / HTTP/1.0\r\n\r\n");

    $connection->on('data', function ($chunk) {
        echo $chunk;
    });
});

You can either use the Client directly or you may want to wrap this connector in ReactPHP's Connector:

$proxy = new Clue\React\Socks\Client('127.0.0.1:1080');

$connector = new React\Socket\Connector(array(
    'tcp' => $proxy,
    'dns' => false
));

$connector->connect('tcp://www.google.com:80')->then(function (React\Socket\ConnectionInterface $connection) {
    echo 'connected to www.google.com:80';
    $connection->write("GET / HTTP/1.0\r\n\r\n");

    $connection->on('data', function ($chunk) {
        echo $chunk;
    });
});

See also the first example.

The tcp:// scheme can also be omitted. Passing any other scheme will reject the promise.

Pending connection attempts can be cancelled by cancelling its pending promise like so:

$promise = $connector->connect($uri);

$promise->cancel();

Calling cancel() on a pending promise will cancel the underlying TCP/IP connection to the SOCKS server and/or the SOCKS protocol negotiation and reject the resulting promise.

Secure TLS connections

This class can also be used if you want to establish a secure TLS connection (formerly known as SSL) between you and your destination, such as when using secure HTTPS to your destination site. You can simply wrap this connector in ReactPHP's Connector:

$proxy = new Clue\React\Socks\Client('127.0.0.1:1080');

$connector = new React\Socket\Connector(array(
    'tcp' => $proxy,
    'dns' => false
));

$connector->connect('tls://www.google.com:443')->then(function (React\Socket\ConnectionInterface $connection) {
    // proceed with just the plain text data
    // everything is encrypted/decrypted automatically
    echo 'connected to SSL encrypted www.google.com';
    $connection->write("GET / HTTP/1.0\r\n\r\n");

    $connection->on('data', function ($chunk) {
        echo $chunk;
    });
});

See also the second example.

Pending connection attempts can be cancelled by canceling its pending promise as usual.

Note how secure TLS connections are in fact entirely handled outside of this SOCKS client implementation.

You can optionally pass additional SSL context options to the constructor like this:

$connector = new React\Socket\Connector(array(
    'tcp' => $proxy,
    'tls' => array(
        'verify_peer' => false,
        'verify_peer_name' => false
    ),
    'dns' => false
));

HTTP requests

This library also allows you to send HTTP requests through a SOCKS proxy server.

In order to send HTTP requests, you first have to add a dependency for ReactPHP's async HTTP client. This allows you to send both plain HTTP and TLS-encrypted HTTPS requests like this:

$proxy = new Clue\React\Socks\Client('127.0.0.1:1080');

$connector = new React\Socket\Connector(array(
    'tcp' => $proxy,
    'dns' => false
));

$browser = new React\Http\Browser($connector);

$browser->get('https://example.com/')->then(function (Psr\Http\Message\ResponseInterface $response) {
    var_dump($response->getHeaders(), (string) $response->getBody());
}, function (Exception $e) {
    echo 'Error: ' . $e->getMessage() . PHP_EOL;
});

See also ReactPHP's HTTP client and any of the examples for more details.

Protocol version

This library supports the SOCKS5 and SOCKS4(a) protocol versions. It focuses on the most commonly used core feature of connecting to a destination host through the SOCKS proxy server. In this mode, a SOCKS proxy server acts as a generic proxy allowing higher level application protocols to work through it.

SOCKS5 SOCKS4(a)
Protocol specification RFC 1928 SOCKS4.protocol / SOCKS4A.protocol
Tunnel outgoing TCP/IP connections ✓ ✓
Remote DNS resolution ✓ ✗ / ✓
IPv6 addresses ✓ ✗
Username/Password authentication ✓ (as per RFC 1929) ✗
Handshake # roundtrips 2 (3 with authentication) 1
Handshake traffic
+ remote DNS
variable (+ auth + IPv6)
+ hostname - 3
17 bytes
+ hostname + 1
Incoming BIND requests not implemented not implemented
UDP datagrams not implemented ✗
GSSAPI authentication not implemented ✗

By default, the Client communicates via SOCKS5 with the SOCKS server. This is done because SOCKS5 is the latest version from the SOCKS protocol family and generally has best support across other vendors. You can also omit the default socks:// URI scheme. Similarly, the socks5:// URI scheme acts as an alias for the default socks:// URI scheme.

// all three forms are equivalent
$proxy = new Clue\React\Socks\Client('127.0.0.1:1080');
$proxy = new Clue\React\Socks\Client('socks://127.0.0.1:1080');
$proxy = new Clue\React\Socks\Client('socks5://127.0.0.1:1080');

If want to explicitly set the protocol version to SOCKS4(a), you can use the URI scheme socks4:// as part of the SOCKS URI:

$proxy = new Clue\React\Socks\Client('socks4://127.0.0.1:1080');

DNS resolution

By default, the Client does not perform any DNS resolution at all and simply forwards any hostname you're trying to connect to to the SOCKS server. The remote SOCKS server is thus responsible for looking up any hostnames via DNS (this default mode is thus called remote DNS resolution). As seen above, this mode is supported by the SOCKS5 and SOCKS4a protocols, but not the original SOCKS4 protocol, as the protocol lacks a way to communicate hostnames.

On the other hand, all SOCKS protocol versions support sending destination IP addresses to the SOCKS server. In this mode you either have to stick to using IPs only (which is ofen unfeasable) or perform any DNS lookups locally and only transmit the resolved destination IPs (this mode is thus called local DNS resolution).

The default remote DNS resolution is useful if your local Client either can not resolve target hostnames because it has no direct access to the internet or if it should not resolve target hostnames because its outgoing DNS traffic might be intercepted (in particular when using the Tor network).

As noted above, the Client defaults to using remote DNS resolution. However, wrapping the Client in ReactPHP's Connector actually performs local DNS resolution unless explicitly defined otherwise. Given that remote DNS resolution is assumed to be the preferred mode, all other examples explicitly disable DNS resolution like this:

$proxy = new Clue\React\Socks\Client('127.0.0.1:1080');

$connector = new React\Socket\Connector(array(
    'tcp' => $proxy,
    'dns' => false
));

If you want to explicitly use local DNS resolution (such as when explicitly using SOCKS4), you can use the following code:

$proxy = new Clue\React\Socks\Client('127.0.0.1:1080');

// set up Connector which uses Google's public DNS (8.8.8.8)
$connector = new React\Socket\Connector(array(
    'tcp' => $proxy,
    'dns' => '8.8.8.8'
));

See also the fourth example.

Pending connection attempts can be cancelled by cancelling its pending promise as usual.

Note how local DNS resolution is in fact entirely handled outside of this SOCKS client implementation.

Authentication

This library supports username/password authentication for SOCKS5 servers as defined in RFC 1929.

On the client side, simply pass your username and password to use for authentication (see below). For each further connection the client will merely send a flag to the server indicating authentication information is available. Only if the server requests authentication during the initial handshake, the actual authentication credentials will be transmitted to the server.

Note that the password is transmitted in cleartext to the SOCKS proxy server, so this methods should not be used on a network where you have to worry about eavesdropping.

You can simply pass the authentication information as part of the SOCKS URI:

$proxy = new Clue\React\Socks\Client('alice:[email protected]:1080');

Note that both the username and password must be percent-encoded if they contain special characters:

$user = 'he:llo';
$pass = 'p@ss';
$url = rawurlencode($user) . ':' . rawurlencode($pass) . '@127.0.0.1:1080';

$proxy = new Clue\React\Socks\Client($url);

The authentication details will be transmitted in cleartext to the SOCKS proxy server only if it requires username/password authentication. If the authentication details are missing or not accepted by the remote SOCKS proxy server, it is expected to reject each connection attempt with an exception error code of SOCKET_EACCES (13).

Authentication is only supported by protocol version 5 (SOCKS5), so passing authentication to the Client enforces communication with protocol version 5 and complains if you have explicitly set anything else:

// throws InvalidArgumentException
new Clue\React\Socks\Client('socks4://alice:[email protected]:1080');

Proxy chaining

The Client is responsible for creating connections to the SOCKS server which then connects to the target host.

Client -> SocksServer -> TargetHost

Sometimes it may be required to establish outgoing connections via another SOCKS server. For example, this can be useful if you want to conceal your origin address.

Client -> MiddlemanSocksServer -> TargetSocksServer -> TargetHost

The Client uses any instance of the ConnectorInterface to establish outgoing connections. In order to connect through another SOCKS server, you can simply use another SOCKS connector from another SOCKS client like this:

// https via the proxy chain  "MiddlemanSocksServer -> TargetSocksServer -> TargetHost"
// please note how the client uses TargetSocksServer (not MiddlemanSocksServer!),
// which in turn then uses MiddlemanSocksServer.
// this creates a TCP/IP connection to MiddlemanSocksServer, which then connects
// to TargetSocksServer, which then connects to the TargetHost
$middle = new Clue\React\Socks\Client('127.0.0.1:1080');
$target = new Clue\React\Socks\Client('example.com:1080', $middle);

$connector = new React\Socket\Connector(array(
    'tcp' => $target,
    'dns' => false
));

$connector->connect('tls://www.google.com:443')->then(function (React\Socket\ConnectionInterface $connection) {
    // …
});

See also the third example.

Pending connection attempts can be canceled by canceling its pending promise as usual.

Proxy chaining can happen on the server side and/or the client side:

  • If you ask your client to chain through multiple proxies, then each proxy server does not really know anything about chaining at all. This means that this is a client-only property.

  • If you ask your server to chain through another proxy, then your client does not really know anything about chaining at all. This means that this is a server-only property and not part of this class. For example, you can find this in the below Server class or somewhat similar when you're using the Tor network.

Connection timeout

By default, the Client does not implement any timeouts for establishing remote connections. Your underlying operating system may impose limits on pending and/or idle TCP/IP connections, anywhere in a range of a few minutes to several hours.

Many use cases require more control over the timeout and likely values much smaller, usually in the range of a few seconds only.

You can use ReactPHP's Connector to decorate any given ConnectorInterface instance. It provides the same connect() method, but will automatically reject the underlying connection attempt if it takes too long:

$proxy = new Clue\React\Socks\Client('127.0.0.1:1080');

$connector = new React\Socket\Connector(array(
    'tcp' => $proxy,
    'dns' => false,
    'timeout' => 3.0
));

$connector->connect('tcp://google.com:80')->then(function (React\Socket\ConnectionInterface $connection) {
    // connection succeeded within 3.0 seconds
});

See also any of the examples.

Pending connection attempts can be cancelled by cancelling its pending promise as usual.

Note how connection timeout is in fact entirely handled outside of this SOCKS client implementation.

SOCKS over TLS

All SOCKS protocol versions support forwarding TCP/IP based connections and higher level protocols. This implies that you can also use secure TLS connections to transfer sensitive data across SOCKS proxy servers. This means that no eavesdropper nor the proxy server will be able to decrypt your data.

However, the initial SOCKS communication between the client and the proxy is usually via an unencrypted, plain TCP/IP connection. This means that an eavesdropper may be able to see where you connect to and may also be able to see your SOCKS authentication details in cleartext.

As an alternative, you may establish a secure TLS connection to your SOCKS proxy before starting the initial SOCKS communication. This means that no eavesdroppper will be able to see the destination address you want to connect to or your SOCKS authentication details.

You can use the sockss:// URI scheme or use an explicit SOCKS protocol version like this:

$proxy = new Clue\React\Socks\Client('sockss://127.0.0.1:1080');

$proxy = new Clue\React\Socks\Client('socks4s://127.0.0.1:1080');

See also example 32.

Similarly, you can also combine this with authentication like this:

$proxy = new Clue\React\Socks\Client('sockss://alice:[email protected]:1080');

Note that for most use cases, secure TLS connections should be used instead. SOCKS over TLS is considered advanced usage and is used very rarely in practice. In particular, the SOCKS server has to accept secure TLS connections, see also Server SOCKS over TLS for more details. Also, PHP does not support "double encryption" over a single connection. This means that enabling secure TLS connections over a communication channel that has been opened with SOCKS over TLS may not be supported.

Note that the SOCKS protocol does not support the notion of TLS. The above works reasonably well because TLS is only used for the connection between client and proxy server and the SOCKS protocol data is otherwise identical. This implies that this may also have only limited support for proxy chaining over multiple TLS paths.

Unix domain sockets

All SOCKS protocol versions support forwarding TCP/IP based connections and higher level protocols. In some advanced cases, it may be useful to let your SOCKS server listen on a Unix domain socket (UDS) path instead of a IP:port combination. For example, this allows you to rely on file system permissions instead of having to rely on explicit authentication.

You can use the socks+unix:// URI scheme or use an explicit SOCKS protocol version like this:

$proxy = new Clue\React\Socks\Client('socks+unix:///tmp/proxy.sock');

$proxy = new Clue\React\Socks\Client('socks4+unix:///tmp/proxy.sock');

Similarly, you can also combine this with authentication like this:

$proxy = new Clue\React\Socks\Client('socks+unix://alice:password@/tmp/proxy.sock');

Note that Unix domain sockets (UDS) are considered advanced usage and PHP only has limited support for this. In particular, enabling secure TLS may not be supported.

Note that the SOCKS protocol does not support the notion of UDS paths. The above works reasonably well because UDS is only used for the connection between client and proxy server and the path will not actually passed over the protocol. This implies that this does also not support proxy chaining over multiple UDS paths.

Server

The Server is responsible for accepting incoming communication from SOCKS clients and forwarding the requested connection to the target host. It supports the SOCKS5 and SOCKS4(a) protocol versions by default. You can start listening on an underlying TCP/IP socket server like this:

$socks = new Clue\React\Socks\Server();

// listen on 127.0.0.1:1080
$socket = new React\Socket\SocketServer('127.0.0.1:1080');
$socks->listen($socket);

This class takes an optional LoopInterface|null $loop parameter that can be used to pass the event loop instance to use for this object. You can use a null value here in order to use the default loop. This value SHOULD NOT be given unless you're sure you want to explicitly use a given event loop instance.

Additionally, the Server constructor accepts optional parameters to explicitly configure the connector to use and to require authentication. For more details, read on...

Server connector

The Server uses an instance of ReactPHP's ConnectorInterface to establish outgoing connections for each incoming connection request.

If you need custom connector settings (DNS resolution, TLS parameters, timeouts, proxy servers etc.), you can explicitly pass a custom instance of the ConnectorInterface:

$connector = new React\Socket\Connector(array(
    'dns' => '127.0.0.1',
    'tcp' => array(
        'bindto' => '192.168.10.1:0'
    )
));

$socks = new Clue\React\Socks\Server(null, $connector);

If you want to forward the outgoing connection through another SOCKS proxy, you may also pass a Client instance as a connector, see also server proxy chaining for more details.

Internally, the Server uses ReactPHP's normal connect() method, but it also passes the original client IP as the ?source={remote} parameter. The source parameter contains the full remote URI, including the protocol and any authentication details, for example socks://alice:[email protected]:5678 or socks4://1.2.3.4:5678 for legacy SOCKS4(a). You can use this parameter for logging purposes or to restrict connection requests for certain clients by providing a custom implementation of the ConnectorInterface.

Server authentication

By default, the Server does not require any authentication from the clients. You can enable authentication support so that clients need to pass a valid username and password before forwarding any connections.

Setting authentication on the Server enforces each further connected client to use protocol version 5 (SOCKS5). If a client tries to use any other protocol version, does not send along authentication details or if authentication details can not be verified, the connection will be rejected.

If you only want to accept static authentication details, you can simply pass an additional assoc array with your authentication details to the Server like this:

$socks = new Clue\React\Socks\Server(null, null, array(
    'alice' => 'password',
    'bob' => 's3cret!1'
));

See also example #12.

If you want more control over authentication, you can pass an authenticator function that should return a bool value like this synchronous example:

$socks = new Clue\React\Socks\Server(null, null, function ($username, $password, $remote) {
    // $remote is a full URI à la socks://alice:[email protected]:1234
    // or sockss://alice:[email protected]:1234 for SOCKS over TLS
    // or may be null when remote is unknown (SOCKS over Unix Domain Sockets)
    // useful for logging or extracting parts, such as the remote IP
    $ip = parse_url($remote, PHP_URL_HOST);

    return ($username === 'root' && $password === 'secret' && $ip === '127.0.0.1');
});

Because your authentication mechanism might take some time to actually check the provided authentication credentials (like querying a remote database or webservice), the server also supports a Promise-based interface. While this might seem more complex at first, it actually provides a very powerful way of handling a large number of connections concurrently without ever blocking any connections. You can return a Promise from the authenticator function that will fulfill with a bool value like this async example:

$socks = new Clue\React\Socks\Server(null, null, function ($username, $password) use ($db) {
    // pseudo-code: query database for given authentication details
    return $db->query(
        'SELECT 1 FROM users WHERE name = ? AND password = ?',
        array($username, $password)
    )->then(function (QueryResult $result) {
        // ensure we find exactly one match in the database
        return count($result->resultRows) === 1;
    });
});

Server proxy chaining

The Server is responsible for creating connections to the target host.

Client -> SocksServer -> TargetHost

Sometimes it may be required to establish outgoing connections via another SOCKS server. For example, this can be useful if your target SOCKS server requires authentication, but your client does not support sending authentication information (e.g. like most webbrowser).

Client -> MiddlemanSocksServer -> TargetSocksServer -> TargetHost

The Server uses any instance of the ConnectorInterface to establish outgoing connections. In order to connect through another SOCKS server, you can simply use the Client SOCKS connector from above. You can create a SOCKS Client instance like this:

// set next SOCKS server example.com:1080 as target
$proxy = new Clue\React\Socks\Client('alice:[email protected]:1080');

// start a new server which forwards all connections to the other SOCKS server
$socks = new Clue\React\Socks\Server(null, $proxy);

// listen on 127.0.0.1:1080
$socket = new React\Socket\SocketServer('127.0.0.1:1080');
$socks->listen($socket);

See also example #21.

Proxy chaining can happen on the server side and/or the client side:

  • If you ask your client to chain through multiple proxies, then each proxy server does not really know anything about chaining at all. This means that this is a client-only property and not part of this class. For example, you can find this in the above Client class.

  • If you ask your server to chain through another proxy, then your client does not really know anything about chaining at all. This means that this is a server-only property and can be implemented as above.

Server SOCKS over TLS

Both SOCKS5 and SOCKS4(a) protocol versions support forwarding TCP/IP based connections and higher level protocols. This implies that you can also use secure TLS connections to transfer sensitive data across SOCKS proxy servers. This means that no eavesdropper nor the proxy server will be able to decrypt your data.

However, the initial SOCKS communication between the client and the proxy is usually via an unencrypted, plain TCP/IP connection. This means that an eavesdropper may be able to see where the client connects to and may also be able to see the SOCKS authentication details in cleartext.

As an alternative, you may listen for SOCKS over TLS connections so that the client has to establish a secure TLS connection to your SOCKS proxy before starting the initial SOCKS communication. This means that no eavesdroppper will be able to see the destination address the client wants to connect to or their SOCKS authentication details.

You can simply start your listening socket on the tls:// URI scheme like this:

$socks = new Clue\React\Socks\Server();

// listen on tls://127.0.0.1:1080 with the given server certificate
$socket = new React\Socket\SocketServer('tls://127.0.0.1:1080', array(
    'tls' => array(
        'local_cert' => __DIR__ . '/localhost.pem',
    )
));
$socks->listen($socket);

See also example 31.

Note that for most use cases, secure TLS connections should be used instead. SOCKS over TLS is considered advanced usage and is used very rarely in practice.

Note that the SOCKS protocol does not support the notion of TLS. The above works reasonably well because TLS is only used for the connection between client and proxy server and the SOCKS protocol data is otherwise identical. This implies that this does also not support proxy chaining over multiple TLS paths.

Server Unix domain sockets

Both SOCKS5 and SOCKS4(a) protocol versions support forwarding TCP/IP based connections and higher level protocols. In some advanced cases, it may be useful to let your SOCKS server listen on a Unix domain socket (UDS) path instead of a IP:port combination. For example, this allows you to rely on file system permissions instead of having to rely on explicit authentication.

You can simply start your listening socket on the unix:// URI scheme like this:

$socks = new Clue\React\Socks\Server();

// listen on /tmp/proxy.sock
$socket = new React\Socket\SocketServer('unix:///tmp/proxy.sock');
$socks->listen($socket);

Note that Unix domain sockets (UDS) are considered advanced usage and that the SOCKS protocol does not support the notion of UDS paths. The above works reasonably well because UDS is only used for the connection between client and proxy server and the path will not actually passed over the protocol. This implies that this does also not support proxy chaining over multiple UDS paths.

Servers

Using a PHP SOCKS server

  • If you're looking for an end-user SOCKS server daemon, you may want to use LeProxy or clue/psocksd.
  • If you're looking for a SOCKS server implementation, consider using the above Server class.

Using SSH as a SOCKS server

If you already have an SSH server set up, you can easily use it as a SOCKS tunnel end point. On your client, simply start your SSH client and use the -D <port> option to start a local SOCKS server (quoting the man page: a local "dynamic" application-level port forwarding).

You can start a local SOCKS server by creating a loopback connection to your local system if you already run an SSH daemon:

ssh -D 1080 localhost

Alternatively, you can start a local SOCKS server tunneling through a given remote host that runs an SSH daemon:

ssh -D 1080 example.com

Now you can simply use this SSH SOCKS server like this:

$proxy = new Clue\React\Socks\Client('127.0.0.1:1080');

$proxy->connect('tcp://www.google.com:80')->then(function (React\Socket\ConnectionInterface $connection) {
    $connection->write("GET / HTTP/1.0\r\n\r\n");

    $connection->on('data', function ($chunk) {
        echo $chunk;
    });
});

Note that the above will allow all users on the local system to connect over your SOCKS server without authentication which may or may not be what you need. As an alternative, recent OpenSSH client versions also support Unix domain sockets (UDS) paths so that you can rely on Unix file system permissions instead:

ssh -D/tmp/proxy.sock example.com

Now you can simply use this SSH SOCKS server like this:

$proxy = new Clue\React\Socks\Client('socks+unix:///tmp/proxy.sock');

$proxy->connect('tcp://www.google.com:80')->then(function (React\Socket\ConnectionInterface $connection) {
    $connection->write("GET / HTTP/1.0\r\n\r\n");

    $connection->on('data', function ($chunk) {
        echo $chunk;
    });
});

As an alternative to requiring this manual setup, you may also want to look into using clue/reactphp-ssh-proxy which automatically creates this SSH tunnel for you. It provides an implementation of the same ConnectorInterface so that supporting either proxy protocol should be fairly trivial.

Using the Tor (anonymity network) to tunnel SOCKS connections

The Tor anonymity network client software is designed to encrypt your traffic and route it over a network of several nodes to conceal its origin. It presents a SOCKS5 and SOCKS4(a) interface on TCP port 9050 by default which allows you to tunnel any traffic through the anonymity network:

$proxy = new Clue\React\Socks\Client('127.0.0.1:9050');

$proxy->connect('tcp://www.google.com:80')->then(function (React\Socket\ConnectionInterface $connection) {
    $connection->write("GET / HTTP/1.0\r\n\r\n");

    $connection->on('data', function ($chunk) {
        echo $chunk;
    });
});

In most common scenarios you probably want to stick to default remote DNS resolution and don't want your client to resolve the target hostnames, because you would leak DNS information to anybody observing your local traffic. Also, Tor provides hidden services through an .onion pseudo top-level domain which have to be resolved by Tor.

Install

The recommended way to install this library is through Composer. New to Composer?

This project follows SemVer. This will install the latest supported version:

composer require clue/socks-react:^1.4

See also the CHANGELOG for details about version upgrades.

This project aims to run on any platform and thus does not require any PHP extensions and supports running on legacy PHP 5.3 through current PHP 8+ and HHVM. It's highly recommended to use the latest supported PHP version for this project.

Tests

To run the test suite, you first need to clone this repo and then install all dependencies through Composer:

composer install

To run the test suite, go to the project root and run:

vendor/bin/phpunit

The test suite contains a number of tests that rely on a working internet connection, alternatively you can also run it like this:

vendor/bin/phpunit --exclude-group internet

License

This project is released under the permissive MIT license.

Did you know that I offer custom development services and issuing invoices for sponsorships of releases and for contributions? Contact me (@clue) for details.

More

  • If you want to learn more about how the ConnectorInterface and its usual implementations look like, refer to the documentation of the underlying react/socket component.
  • If you want to learn more about processing streams of data, refer to the documentation of the underlying react/stream component.
  • As an alternative to a SOCKS5 / SOCKS4(a) proxy, you may also want to look into using an HTTP CONNECT proxy instead. You may want to use clue/reactphp-http-proxy which also provides an implementation of the same ConnectorInterface so that supporting either proxy protocol should be fairly trivial.
  • As an alternative to a SOCKS5 / SOCKS4(a) proxy, you may also want to look into using an SSH proxy (SSH tunnel) instead. You may want to use clue/reactphp-ssh-proxy which also provides an implementation of the same ConnectorInterface so that supporting either proxy protocol should be fairly trivial.
  • If you're dealing with public proxies, you'll likely have to work with mixed quality and unreliable proxies. You may want to look into using clue/reactphp-connection-manager-extra which allows retrying unreliable ones, implying connection timeouts, concurrently working with multiple connectors and more.
  • If you're looking for an end-user SOCKS server daemon, you may want to use LeProxy or clue/psocksd.

More Repositories

1

stream-filter

A simple and modern approach to stream filtering in PHP
PHP
1,608
star
2

phar-composer

Simple phar creation for every PHP project managed via Composer
PHP
858
star
3

graph-composer

Dependency graph visualization for composer.json (PHP + Composer)
PHP
852
star
4

framework-x

Framework X – the simple and fast micro framework for building reactive web applications that run anywhere.
PHP
718
star
5

reactphp-buzz

[Deprecated] Simple, async PSR-7 HTTP client for concurrently processing any number of HTTP requests, built on top of ReactPHP.
PHP
356
star
6

socket-raw

Simple and lightweight OOP wrapper for PHP's low-level sockets extension (ext-sockets)
PHP
325
star
7

docker-json-server

JSON Server docker image, REST API mocking based on plain JSON
Shell
297
star
8

reactphp-redis

Async Redis client implementation, built on top of ReactPHP.
PHP
245
star
9

docker-ttrss

Tiny Tiny RSS feed reader as a docker image.
PHP
200
star
10

reactphp-stdio

Async, event-driven and UTF-8 aware console input & output (STDIN, STDOUT) for truly interactive CLI applications, built on top of ReactPHP.
PHP
193
star
11

php-redis-server

A Redis server implementation in pure PHP
PHP
181
star
12

commander

Finally a sane way to register available commands and arguments and match your command line in PHP
PHP
171
star
13

reactphp-block

Lightweight library that eases using components built for ReactPHP in a traditional, blocking environment.
PHP
152
star
14

reactphp-mq

Mini Queue, the lightweight in-memory message queue to concurrently do many (but not too many) things at once, built on top of ReactPHP.
PHP
127
star
15

reactphp-zenity

Zenity allows you to build graphical desktop (GUI) applications in PHP, built on top of ReactPHP.
PHP
120
star
16

reactphp-term

Streaming terminal emulator, built on top of ReactPHP
PHP
103
star
17

reactphp-docker

Async, event-driven access to the Docker Engine API, built on top of ReactPHP.
PHP
100
star
18

reactphp-ami

Streaming, event-driven access to the Asterisk Manager Interface (AMI), built on top of ReactPHP.
PHP
71
star
19

framework-x-placeholder

Framework X – the simple and fast micro framework for building reactive web applications that run anywhere.
67
star
20

docker-adminer

Adminer docker image, a full-featured database management tool for the web
66
star
21

reactphp-utf8

Streaming UTF-8 parser, built on top of ReactPHP
PHP
66
star
22

reactphp-soap

Simple, async SOAP webservice client, built on top of ReactPHP.
PHP
62
star
23

php-socks

[maintenance] look at clue/socks-react instead
PHP
62
star
24

reactphp-ndjson

Streaming newline-delimited JSON (NDJSON) parser and encoder for ReactPHP.
PHP
62
star
25

reactphp-flux

Flux, the lightweight stream processor to concurrently do many (but not too many) things at once, built on top of ReactPHP.
PHP
58
star
26

php-sse-react

Streaming, async HTML5 Server-Sent Events server (aka. SSE or EventSource), built on top of ReactPHP
PHP
54
star
27

psocksd

The SOCKS tunnel / proxy server daemon written in PHP
PHP
53
star
28

reactphp-csv

Streaming CSV (Comma-Separated Values or Character-Separated Values) parser and encoder for ReactPHP.
PHP
51
star
29

reactphp-eventsource

Instant real-time updates. Lightweight EventSource client receiving live messages via HTML5 Server-Sent Events (SSE). Fast stream processing built on top of ReactPHP's event-driven architecture.
PHP
48
star
30

reactphp-sqlite

Async SQLite database, lightweight non-blocking process wrapper around file-based database extension (ext-sqlite3), built on top of ReactPHP.
PHP
46
star
31

reactphp-http-proxy

Async HTTP proxy connector, tunnel any TCP/IP-based protocol through an HTTP CONNECT proxy server, built on top of ReactPHP.
PHP
45
star
32

docker-phpvirtualbox

phpVirtualBox docker image, a modern webinterface mirroring the VirtualBox GUI to administer VirtualBox VMs in a headless environment
PHP
42
star
33

php-redis-protocol

A Redis protocol parser / serializer written in PHP
PHP
38
star
34

docker-h5ai

h5ai docker image, the modern web server index
34
star
35

reactphp-shell

Run async commands within any interactive shell command, built on top of ReactPHP.
PHP
32
star
36

arguments

The simple way to split your command line string into an array of command arguments in PHP.
PHP
31
star
37

php-json-query

The JSON query language implemented in PHP
PHP
30
star
38

reactphp-zlib

Streaming zlib compressor and decompressor for ReactPHP, supporting compression and decompression of GZIP, ZLIB and raw DEFLATE formats.
PHP
28
star
39

json-stream

Simple, lightweight, incremental parser for JSON streaming (concatenated JSON and newline-delimited JSON), in PHP
PHP
24
star
40

json-query-language

A structured query language for querying / filtering JSON documents, expressed in JSON
24
star
41

graph-uml

UML class diagrams in PHP
PHP
24
star
42

reactphp-ssh-proxy

Async SSH proxy connector and forwarder, tunnel any TCP/IP-based protocol through an SSH server, built on top of ReactPHP.
PHP
23
star
43

docker-streamripper

Streamripper docker image, an application that lets you record streaming mp3 to your hard drive
Shell
22
star
44

reactphp-multicast

Simple, event-driven multicast UDP message client and server for ReactPHP.
PHP
21
star
45

reactphp-pq

PQ ("peak"), automatically wrap blocking functions in an async child process and turn blocking functions into non-blocking promises, built on top of ReactPHP
20
star
46

php-socket-react

Binding for raw sockets (ext-sockets) in React PHP
PHP
20
star
47

reactphp-connection-manager-extra

Provides extra (in terms of "additional", "extraordinary", "special" and "unusual") decorators, built on top of ReactPHP's Socket
PHP
20
star
48

docker-frontroute

A docker image to automatically set up a front router (reverse proxy) for linked web containers
PHP
19
star
49

reactphp-ssdp

Async Simple Service Discovery Protocol (SSDP), built on top of ReactPHP.
PHP
19
star
50

reactphp-quassel

Streaming, event-driven access to your Quassel IRC core, built on top of ReactPHP
PHP
18
star
51

docker-webgrind

Webgrind docker image, a Xdebug profiling web frontend
Shell
18
star
52

php-wake-on-lan-react

Turn on your PC with Wake-On-LAN (WOL) requests via React PHP
PHP
18
star
53

docker-httpie

HTTpie docker image, a cURL-like tool for humans
Shell
17
star
54

make.php

A GNU Make clone written in pure PHP. Run your Makefiles no matter whether GNU make is available.
17
star
55

reactphp-packagist-api

Simple async access to packagist.org's API, like listing project details, number of downloads etc., built on top of ReactPHP.
PHP
16
star
56

reactphp-mdns

Simple, async multicast DNS (mDNS) resolver for zeroconf networking, built on top of ReactPHP.
PHP
14
star
57

reactphp-memoize

Automatically memoize async function calls by caching function results, built on top of ReactPHP.
13
star
58

docker-polipo

Docker image for Polipo, a caching web/http proxy
13
star
59

php-icmp-react

Simple async lowlevel ICMP (ping) messaging library built on top of React PHP
PHP
13
star
60

docker-apt-cacher

Dockerized apt-cacher container
Shell
13
star
61

php-hexdump

View any (binary) string as a hexdump in php
PHP
12
star
62

reactphp-tar

Streaming parser to extract tarballs with ReactPHP.
PHP
12
star
63

reactphp-s3

Async S3 filesystem API (supporting Amazon S3, Ceph, MiniIO, DigitalOcean Spaces and others), built on top of ReactPHP.
11
star
64

confgen

Configuration file generator (confgen) – an easy way to generate structured (configuration) files on the fly by processing a Twig template and an arbitrary input data structure.
PHP
10
star
65

reactphp-mailer

Async mailer using SMTP to send large number of emails concurrently, built on top of ReactPHP.
9
star
66

reactphp-clickhouse

Blazing fast access to your ClickHouse database, built on top of @ReactPHP.
8
star
67

docker-vboxwebsrv

Tunneled VirtualBox SOAP webserver docker image
Shell
8
star
68

php-solusvm-api-react

Simple async access to your VPS box through the SolusVM API, built on top of React PHP
PHP
7
star
69

php-readline-react

Experimental reactive binding for ext-readline, built on top of React PHP
PHP
6
star
70

php-json-merge-patch

JSON merge patch (RFC 7396) is a simple alternative to JSON patch (RFC 6902) – dead-simple PHP library
PHP
6
star
71

qdatastream

Lightweight PHP library that allows exchanging binary data with Qt programs (QDataStream)
PHP
5
star
72

reactphp-tsv

Streaming TSV (Tab-Separated Values) parser and encoder for ReactPHP.
5
star
73

docker-textract

textract docker image, allows you to extract text from any document. no muss. no fuss.
Shell
5
star
74

quasselio

Quassel I/O, the lightweight web interface for Quassel IRC in a single PHP file
5
star
75

fd

Access to low-level file desciptors (FDs) with PHP, provides close(), dup(), open() and family
5
star
76

docker-quassel-core

Quassel Core docker image, a modern, cross-platform, distributed IRC program
4
star
77

reactphp-ltsv

Streaming LTSV (Labeled Tab-Separated Values) parser and encoder for ReactPHP.
4
star
78

docker-archeologit

ArcheoloGit docker image, visualize the age and dev activity for git repositories
Shell
4
star
79

reactphp-dns-sd

Async DNS Service Discovery (DNS-SD) implementation for ReactPHP
4
star
80

clue.engineering

Source code for the https://clue.engineering/ website.
HTML
4
star
81

quassel-cli

A CLI Quassel client
4
star
82

reactphp-ftp

Streaming client for FTP servers (File Transfer Protocol), built on top of ReactPHP.
4
star
83

reactphp-rediscovered

A Redis server framework written in pure PHP. Create your own Redis server and your own custom commands without hassle.
3
star
84

docker-redis-benchmark

A minimal docker image to ease running the redis-benchmark
Shell
3
star
85

docker-sculpin

Sculpin Docker image, a static site generator
3
star
86

docker-php-redis-server

A docker image to easily test-drive the php-redis-server
Shell
2
star
87

phpmdoc

PHP + MarkDown + phpdoc = phpmdoc, because writing documentation for PHP projects shouldn't be hard. Parses your class files to create a simple and fully automated markdown document (such as a README.md).
2
star
88

framework-x-website

Source code for the Framework X website.
HTML
2
star
89

docker-kpcli

Minimal kpcli docker image, a command line interface for KeePass
Shell
2
star
90

clue

2
star
91

bitbake-react

Programatically control your bitbake build shell, built on top of React PHP
PHP
2
star
92

php-viewvc-api-react

Simple, async access to your ViewVC web interface, built on top of React PHP
PHP
2
star
93

reactphp-ping

Async, event-driven ping requests to check network connectivity, built on top of ReactPHP.
2
star
94

php-caret-notation

^B A dead-simple PHP library to add caret notation in order to safely show strings that contain ASCII control characters (unprintable characters)
PHP
2
star
95

reactphp-bencode

Streaming Bencode (B-encode) protocol parser and encoder for ReactPHP
1
star
96

docker-psocksd

A docker image for psocksd, the fast, extensible SOCKS tunnel / proxy server daemon written in PHP
Shell
1
star
97

docker-disco

Disco Docker image, a simple visual GitHub browser with pull request support
Shell
1
star
98

mdtoc

Automatic table of contents (TOC) for your markdown documents, with opinionated defaults to keep your README.md up to date without the fuss.
1
star
99

reactphp-netstring

Streaming netstring protocol parser and encoder for ReactPHP
1
star
100

reactphp-imap

Streaming client for IMAP mail servers using IMAP IDLE for instant email notifications, built on top of ReactPHP.
1
star