diff --git a/README.md b/README.md index fda8fee..4c7ef0d 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,8 @@ to google.com via a local SOCKS proxy server: ```php $loop = React\EventLoop\Factory::create(); -$client = new Client('127.0.0.1:1080', new Connector($loop)); +$connector = new React\Socket\Connector($loop); +$client = new Clue\React\Socks\Client('127.0.0.1:1080', $connector); $client->connect('tcp://www.google.com:80')->then(function (ConnectionInterface $stream) { $stream->write("GET / HTTP/1.0\r\n\r\n"); @@ -59,11 +60,12 @@ proxy server listening for connections on `localhost:1080`: ```php $loop = React\EventLoop\Factory::create(); -// listen on localhost:1080 -$socket = new Socket('127.0.0.1:1080', $loop); +// start a new SOCKS proxy server +$server = new Clue\React\Socks\Server($loop); -// start a new server listening for incoming connection on the given socket -$server = new Server($loop, $socket); +// listen on localhost:1080 +$socket = new React\Socket\Server('127.0.0.1:1080', $loop); +$server->listen($socket); $loop->run(); ``` @@ -93,20 +95,17 @@ You can omit the port if you're using the default SOCKS port 1080: $client = new Client('127.0.0.1', $connector); ``` -If you need custom connector settings (DNS resolution, timeouts etc.), you can explicitly pass a -custom instance of the [`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface): +If you need custom connector settings (DNS resolution, TLS parameters, timeouts, +proxy servers etc.), you can explicitly pass a custom instance of the +[`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface): ```php -// use local DNS server -$dnsResolverFactory = new DnsFactory(); -$resolver = $dnsResolverFactory->createCached('127.0.0.1', $loop); - -// outgoing connections to SOCKS server via interface 192.168.10.1 -// this is not to be confused with local DNS resolution (see further below) -$connector = new DnsConnector( - new TcpConnector($loop, array('bindto' => '192.168.10.1:0')), - $resolver -); +$connector = new React\Socket\Connector($loop, array( + 'dns' => '127.0.0.1', + 'tcp' => array( + 'bindto' => '192.168.10.1:0' + ) +)); $client = new Client('my-socks-server.local:1080', $connector); ``` @@ -622,12 +621,15 @@ It also registers everything with the main [`EventLoop`](https://github.com/reac and an underlying TCP/IP socket server like this: ```php -$loop = \React\EventLoop\Factory::create(); +$loop = React\EventLoop\Factory::create(); + +$server = new Clue\React\Socks\Server($loop); // listen on localhost:$port -$socket = new Socket($port, $loop); +$socket = new React\Socket\Server($port, $loop); +$server->listen($socket); -$server = new Server($loop, $socket); +$loop->run(); ``` #### Server connector @@ -636,21 +638,19 @@ The `Server` uses an instance of ReactPHP's [`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface) to establish outgoing connections for each incoming connection request. -If you need custom connector settings (DNS resolution, timeouts etc.), you can explicitly pass a -custom instance of the [`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface): +If you need custom connector settings (DNS resolution, TLS parameters, timeouts, +proxy servers etc.), you can explicitly pass a custom instance of the +[`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface): ```php -// use local DNS server -$dnsResolverFactory = new DnsFactory(); -$resolver = $dnsResolverFactory->createCached('127.0.0.1', $loop); - -// outgoing connections to target host via interface 192.168.10.1 -$connector = new DnsConnector( - new TcpConnector($loop, array('bindto' => '192.168.10.1:0')), - $resolver -); +$connector = new React\Socket\Connector($loop, array( + 'dns' => '127.0.0.1', + 'tcp' => array( + 'bindto' => '192.168.10.1:0' + ) +)); -$server = new Server($loop, $socket, $connector); +$server = new Clue\React\Socks\Server($loop, $connector); ``` If you want to forward the outgoing connection through another SOCKS proxy, you @@ -758,15 +758,20 @@ In order to connect through another SOCKS server, you can simply use the You can create a SOCKS `Client` instance like this: ```php +$loop = React\EventLoop\Factory::create(); + // set next SOCKS server example.com:1080 as target $connector = new React\Socket\Connector($loop); -$client = new Client('user:pass@example.com:1080', $connector); +$client = new Clue\React\Socks\Client('user:pass@example.com:1080', $connector); + +// start a new server which forwards all connections to the other SOCKS server +$server = new Clue\React\Socks\Server($loop, $client); // listen on localhost:1080 -$socket = new Socket('127.0.0.1:1080', $loop); +$socket = new React\Socket\Server('127.0.0.1:1080', $loop); +$server->listen($socket); -// start a new server which forwards all connections to the other SOCKS server -$server = new Server($loop, $socket, $client); +$loop->run(); ``` See also [example #21](examples). @@ -807,7 +812,9 @@ details. You can simply start your listening socket on the `tls://` URI scheme like this: ```php -$loop = \React\EventLoop\Factory::create(); +$loop = React\EventLoop\Factory::create(); + +$server = new Clue\React\Socks\Server($loop); // listen on tls://127.0.0.1:1080 with the given server certificate $socket = new React\Socket\Server('tls://127.0.0.1:1080', $loop, array( @@ -815,7 +822,9 @@ $socket = new React\Socket\Server('tls://127.0.0.1:1080', $loop, array( 'local_cert' => __DIR__ . '/localhost.pem', ) )); -$server = new Server($loop, $socket); +$server->listen($socket); + +$loop->run(); ``` See also [example 31](examples). @@ -842,11 +851,15 @@ having to rely on explicit [authentication](#server-authentication). You can simply start your listening socket on the `unix://` URI scheme like this: ```php -$loop = \React\EventLoop\Factory::create(); +$loop = React\EventLoop\Factory::create(); + +$server = new Clue\React\Socks\Server($loop); // listen on /tmp/proxy.sock $socket = new React\Socket\Server('unix:///tmp/proxy.sock', $loop); -$server = new Server($loop, $socket); +$server->listen($socket); + +$loop->run(); ``` > Note that Unix domain sockets (UDS) are considered advanced usage and that diff --git a/examples/11-server.php b/examples/11-server.php index da0a1a1..e60e202 100644 --- a/examples/11-server.php +++ b/examples/11-server.php @@ -7,12 +7,12 @@ $loop = React\EventLoop\Factory::create(); -// listen on 127.0.0.1:1080 or first argument -$listen = isset($argv[1]) ? $argv[1] : '127.0.0.1:1080'; -$socket = new Socket($listen, $loop); +// start a new SOCKS proxy server +$server = new Server($loop); -// start a new server listening for incoming connection on the given socket -$server = new Server($loop, $socket); +// listen on 127.0.0.1:1080 or first argument +$socket = new Socket(isset($argv[1]) ? $argv[1] : '127.0.0.1:1080', $loop); +$server->listen($socket); echo 'SOCKS server listening on ' . $socket->getAddress() . PHP_EOL; diff --git a/examples/12-server-with-password.php b/examples/12-server-with-password.php index 55cc30b..d7af2e4 100644 --- a/examples/12-server-with-password.php +++ b/examples/12-server-with-password.php @@ -7,18 +7,18 @@ $loop = React\EventLoop\Factory::create(); -// listen on 127.0.0.1:1080 or first argument -$listen = isset($argv[1]) ? $argv[1] : '127.0.0.1:1080'; -$socket = new Socket($listen, $loop); - -// start a new server listening for incoming connection on the given socket +// start a new SOCKS proxy server // require authentication and hence make this a SOCKS5-only server -$server = new Server($loop, $socket); +$server = new Server($loop); $server->setAuthArray(array( 'tom' => 'god', 'user' => 'p@ssw0rd' )); +// listen on 127.0.0.1:1080 or first argument +$socket = new Socket(isset($argv[1]) ? $argv[1] : '127.0.0.1:1080', $loop); +$server->listen($socket); + echo 'SOCKS5 server requiring authentication listening on ' . $socket->getAddress() . PHP_EOL; $loop->run(); diff --git a/examples/13-server-blacklist.php b/examples/13-server-blacklist.php index c153049..12b475e 100644 --- a/examples/13-server-blacklist.php +++ b/examples/13-server-blacklist.php @@ -28,12 +28,12 @@ '*' => $permit )); -// listen on 127.0.0.1:1080 or first argument -$listen = isset($argv[1]) ? $argv[1] : '127.0.0.1:1080'; -$socket = new Socket($listen, $loop); +// start a new SOCKS proxy server using our connection manager for outgoing connections +$server = new Server($loop, $connector); -// start the actual socks server on the given server socket and using our connection manager for outgoing connections -$server = new Server($loop, $socket, $connector); +// listen on 127.0.0.1:1080 or first argument +$socket = new Socket(isset($argv[1]) ? $argv[1] : '127.0.0.1:1080', $loop); +$server->listen($socket); echo 'SOCKS server listening on ' . $socket->getAddress() . PHP_EOL; diff --git a/examples/21-server-proxy-chaining.php b/examples/21-server-proxy-chaining.php index 0d0dee2..7be27ab 100644 --- a/examples/21-server-proxy-chaining.php +++ b/examples/21-server-proxy-chaining.php @@ -30,11 +30,12 @@ $connector = new Client($proxy, $connector); } +// start a new SOCKS proxy server which forwards all connections to the other SOCKS server +$server = new Server($loop, $connector); + // listen on 127.0.0.1:1080 or first argument $socket = new Socket($listen, $loop); - -// start a new server which forwards all connections to the other SOCKS server -$server = new Server($loop, $socket, $connector); +$server->listen($socket); echo 'SOCKS server listening on ' . $socket->getAddress() . PHP_EOL; echo 'Forwarding via: ' . implode(' -> ', $path) . PHP_EOL; diff --git a/examples/22-server-proxy-chaining-from-random-pool.php b/examples/22-server-proxy-chaining-from-random-pool.php index 39245c9..72016db 100644 --- a/examples/22-server-proxy-chaining-from-random-pool.php +++ b/examples/22-server-proxy-chaining-from-random-pool.php @@ -35,11 +35,13 @@ } $connector = new ConnectionManagerRandom($clients); -$socket = new Socket($listen, $loop); - -// start the actual socks server on the given server socket and using our connection manager for outgoing connections +// start the SOCKS proxy server using our connection manager for outgoing connections $server = new Server($loop, $socket, $connector); +// listen on 127.0.0.1:1080 or first argument +$socket = new Socket($listen, $loop); +$server->listen($socket); + echo 'SOCKS server listening on ' . $socket->getAddress() . PHP_EOL; echo 'Randomly picking from: ' . implode(', ', $pool) . PHP_EOL; diff --git a/examples/31-server-secure.php b/examples/31-server-secure.php index b4b2109..27653ff 100644 --- a/examples/31-server-secure.php +++ b/examples/31-server-secure.php @@ -7,15 +7,15 @@ $loop = React\EventLoop\Factory::create(); +// start a new SOCKS proxy server +$server = new Server($loop); + // listen on tls://127.0.0.1:1080 or first argument $listen = isset($argv[1]) ? $argv[1] : '127.0.0.1:1080'; $socket = new Socket('tls://' . $listen, $loop, array('tls' => array( 'local_cert' => __DIR__ . '/localhost.pem', ))); -// start a new server listening for incoming connection on the given socket -$server = new Server($loop, $socket); - echo 'SOCKS over TLS server listening on ' . str_replace('tls:', 'sockss:', $socket->getAddress()) . PHP_EOL; $loop->run(); diff --git a/src/Server.php b/src/Server.php index cc41f1f..080994b 100644 --- a/src/Server.php +++ b/src/Server.php @@ -43,7 +43,7 @@ final class Server private $protocolVersion = null; - public function __construct(LoopInterface $loop, ServerInterface $serverInterface, ConnectorInterface $connector = null) + public function __construct(LoopInterface $loop, ConnectorInterface $connector = null) { if ($connector === null) { $connector = new Connector($loop); @@ -51,9 +51,16 @@ public function __construct(LoopInterface $loop, ServerInterface $serverInterfac $this->loop = $loop; $this->connector = $connector; + } + /** + * @param ServerInterface $socket + * @return void + */ + public function listen(ServerInterface $socket) + { $that = $this; - $serverInterface->on('connection', function ($connection) use ($that) { + $socket->on('connection', function ($connection) use ($that) { $that->onConnection($connection); }); } diff --git a/tests/FunctionalTest.php b/tests/FunctionalTest.php index 63315b4..ec74e6b 100644 --- a/tests/FunctionalTest.php +++ b/tests/FunctionalTest.php @@ -30,7 +30,8 @@ public function setUp() $this->port = parse_url($address, PHP_URL_PORT); $this->assertNotEquals(0, $this->port); - $this->server = new Server($this->loop, $socket); + $this->server = new Server($this->loop); + $this->server->listen($socket); $this->connector = new TcpConnector($this->loop); $this->client = new Client('127.0.0.1:' . $this->port, $this->connector); } @@ -113,7 +114,8 @@ public function testConnectionSocksOverTls() $socket = new \React\Socket\Server('tls://127.0.0.1:0', $this->loop, array('tls' => array( 'local_cert' => __DIR__ . '/../examples/localhost.pem', ))); - $this->server = new Server($this->loop, $socket); + $this->server = new Server($this->loop); + $this->server->listen($socket); $this->connector = new Connector($this->loop, array('tls' => array( 'verify_peer' => false, @@ -137,7 +139,8 @@ public function testConnectionSocksOverTlsUsesPeerNameFromSocksUri() $socket = new \React\Socket\Server('tls://127.0.0.1:0', $this->loop, array('tls' => array( 'local_cert' => __DIR__ . '/../examples/localhost.pem', ))); - $this->server = new Server($this->loop, $socket); + $this->server = new Server($this->loop); + $this->server->listen($socket); $this->connector = new Connector($this->loop, array('tls' => array( 'verify_peer' => false, @@ -157,7 +160,8 @@ public function testConnectionSocksOverUnix() $path = sys_get_temp_dir() . '/test' . mt_rand(1000, 9999) . '.sock'; $socket = new UnixServer($path, $this->loop); - $this->server = new Server($this->loop, $socket); + $this->server = new Server($this->loop); + $this->server->listen($socket); $this->connector = new Connector($this->loop); $this->client = new Client('socks+unix://' . $path, $this->connector); @@ -176,7 +180,8 @@ public function testConnectionSocks5OverUnix() $path = sys_get_temp_dir() . '/test' . mt_rand(1000, 9999) . '.sock'; $socket = new UnixServer($path, $this->loop); - $this->server = new Server($this->loop, $socket); + $this->server = new Server($this->loop); + $this->server->listen($socket); $this->server->setProtocolVersion(5); $this->connector = new Connector($this->loop); @@ -196,7 +201,8 @@ public function testConnectionSocksWithAuthenticationOverUnix() $path = sys_get_temp_dir() . '/test' . mt_rand(1000, 9999) . '.sock'; $socket = new UnixServer($path, $this->loop); - $this->server = new Server($this->loop, $socket); + $this->server = new Server($this->loop); + $this->server->listen($socket); $this->server->setAuthArray(array('name' => 'pass')); $this->connector = new Connector($this->loop); diff --git a/tests/ServerTest.php b/tests/ServerTest.php index 5c73845..965bccc 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -12,16 +12,23 @@ class ServerTest extends TestCase public function setUp() { - $socket = $this->getMockBuilder('React\Socket\ServerInterface') - ->getMock(); - $loop = $this->getMockBuilder('React\EventLoop\LoopInterface') ->getMock(); $this->connector = $this->getMockBuilder('React\Socket\ConnectorInterface') ->getMock(); - $this->server = new Server($loop, $socket, $this->connector); + $this->server = new Server($loop, $this->connector); + } + + /** + * @doesNotPerformAssertions + */ + public function testListen() + { + $socket = $this->getMockBuilder('React\Socket\ServerInterface')->getMock(); + + $this->server->listen($socket); } public function testSetProtocolVersion()