44[ ![ Packagist Downloads] ( https://img.shields.io/packagist/dt/clue/reactphp-ssh-proxy?color=blue )] ( https://packagist.org/packages/clue/reactphp-ssh-proxy )
55
66Async SSH proxy connector and forwarder, tunnel any TCP/IP-based protocol through an SSH server,
7- built on top of [ ReactPHP] ( https://reactphp.org ) .
7+ built on top of [ ReactPHP] ( https://reactphp.org/ ) .
88
99[ Secure Shell (SSH)] ( https://en.wikipedia.org/wiki/Secure_Shell ) is a secure
1010network protocol that is most commonly used to access a login shell on a remote
@@ -75,22 +75,24 @@ The following example code demonstrates how this library can be used to send a
7575plaintext HTTP request to google.com through a remote SSH server:
7676
7777``` php
78- $proxy = new Clue\React\SshProxy\SshProcessConnector('user@example.com');
78+ <?php
79+
80+ require __DIR__ . '/vendor/autoload.php';
81+
82+ $proxy = new Clue\React\SshProxy\SshProcessConnector('alice@example.com');
7983
8084$connector = new React\Socket\Connector(array(
8185 'tcp' => $proxy,
8286 'dns' => false
8387));
8488
85- $connector->connect('tcp://google.com:80')->then(function (React\Socket\ConnectionInterface $connection) {
86- $connection->write("GET / HTTP/1.1\r\nHost: google.com\r\nConnection: close\r\n\r\n");
87- $connection->on('data', function ($chunk) {
88- echo $chunk;
89- });
90- $connection->on('close', function () {
91- echo '[DONE]';
92- });
93- }, 'printf');
89+ $browser = new React\Http\Browser($connector);
90+
91+ $browser->get('http://example.com/')->then(function (Psr\Http\Message\ResponseInterface $response) {
92+ var_dump($response->getHeaders(), (string) $response->getBody());
93+ }, function (Exception $e) {
94+ echo 'Error: ' . $e->getMessage() . PHP_EOL;
95+ });
9496```
9597
9698See also the [ examples] ( examples ) .
@@ -109,7 +111,7 @@ any destination by using an intermediary SSH server as a proxy server.
109111This class is implemented as a lightweight process wrapper around the ` ssh `
110112client binary, so it will spawn one ` ssh ` process for each connection. For
111113example, if you [ open a connection] ( #plain-tcp-connections ) to
112- ` tcp://reactphp.org:80 ` , it will run the equivalent of ` ssh -W reactphp.org:80 user @example.com `
114+ ` tcp://reactphp.org:80 ` , it will run the equivalent of ` ssh -W reactphp.org:80 alice @example.com `
113115and forward data from its standard I/O streams. For this to work, you'll have to
114116make sure that you have a suitable SSH client installed. On Debian/Ubuntu-based
115117systems, you may simply install it like this:
@@ -121,7 +123,7 @@ $ sudo apt install openssh-client
121123Its constructor simply accepts an SSH proxy server URL:
122124
123125``` php
124- $proxy = new Clue\React\SshProxy\SshProcessConnector('user @example.com');
126+ $proxy = new Clue\React\SshProxy\SshProcessConnector('alice @example.com');
125127```
126128
127129The proxy URL may or may not contain a scheme and port definition. The default
@@ -162,7 +164,7 @@ higher-level component:
162164
163165``` diff
164166- $acme = new AcmeApi($connector);
165- + $proxy = new Clue\React\SshProxy\SshProcessConnector('user @example.com');
167+ + $proxy = new Clue\React\SshProxy\SshProcessConnector('alice @example.com');
166168+ $acme = new AcmeApi($proxy);
167169```
168170
@@ -179,7 +181,7 @@ This class is implemented as a lightweight process wrapper around the `ssh`
179181client binary and it will spawn one ` ssh ` process on demand for multiple
180182connections. For example, once you [ open a connection] ( #plain-tcp-connections )
181183to ` tcp://reactphp.org:80 ` for the first time, it will run the equivalent of
182- ` ssh -D 1080 user @example.com ` to run the SSH client in local SOCKS proxy server
184+ ` ssh -D 1080 alice @example.com ` to run the SSH client in local SOCKS proxy server
183185mode and will then create a SOCKS client connection to this server process. You
184186can create any number of connections over this one process and it will keep this
185187process running while there are any open connections and will automatically
@@ -194,7 +196,7 @@ $ sudo apt install openssh-client
194196Its constructor simply accepts an SSH proxy server URL:
195197
196198``` php
197- $proxy = new Clue\React\SshProxy\SshSocksConnector('user @example.com');
199+ $proxy = new Clue\React\SshProxy\SshSocksConnector('alice @example.com');
198200```
199201
200202The proxy URL may or may not contain a scheme and port definition. The default
@@ -223,7 +225,7 @@ to use multiple instances of this class to connect to different SSH proxy
223225servers, you may optionally pass a unique bind address like this:
224226
225227``` php
226- $proxy = new Clue\React\SshProxy\SshSocksConnector('user @example.com?bind=127.1.1.1:1081', );
228+ $proxy = new Clue\React\SshProxy\SshSocksConnector('alice @example.com?bind=127.1.1.1:1081');
227229```
228230
229231> * Security note for multi-user systems* : This class will spawn the SSH client
@@ -251,7 +253,7 @@ higher-level component:
251253
252254``` diff
253255- $acme = new AcmeApi($connector);
254- + $proxy = new Clue\React\SshProxy\SshSocksConnector('user @example.com');
256+ + $proxy = new Clue\React\SshProxy\SshSocksConnector('alice @example.com');
255257+ $acme = new AcmeApi($proxy);
256258```
257259
@@ -267,9 +269,9 @@ a streaming plain TCP/IP connection on the `SshProcessConnector` or `SshSocksCon
267269and use any higher level protocol like so:
268270
269271``` php
270- $proxy = new Clue\React\SshProxy\SshProcessConnector('user @example.com');
272+ $proxy = new Clue\React\SshProxy\SshProcessConnector('alice @example.com');
271273// or
272- $proxy = new Clue\React\SshProxy\SshSocksConnector('user @example.com');
274+ $proxy = new Clue\React\SshProxy\SshSocksConnector('alice @example.com');
273275
274276$proxy->connect('tcp://smtp.googlemail.com:587')->then(function (React\Socket\ConnectionInterface $connection) {
275277 $connection->write("EHLO local\r\n");
@@ -283,9 +285,9 @@ You can either use the `SshProcessConnector` or `SshSocksConnector` directly or
283285may want to wrap this connector in ReactPHP's [ ` Connector ` ] ( https://github.com/reactphp/socket#connector ) :
284286
285287``` php
286- $proxy = new Clue\React\SshProxy\SshProcessConnector('user @example.com');
288+ $proxy = new Clue\React\SshProxy\SshProcessConnector('alice @example.com');
287289// or
288- $proxy = new Clue\React\SshProxy\SshSocksConnector('user @example.com');
290+ $proxy = new Clue\React\SshProxy\SshSocksConnector('alice @example.com');
289291
290292$connector = new React\Socket\Connector(array(
291293 'tcp' => $proxy,
@@ -312,11 +314,10 @@ details.
312314The ` SshSocksConnector ` can also be used if you want to establish a secure TLS connection
313315(formerly known as SSL) between you and your destination, such as when using
314316secure HTTPS to your destination site. You can simply wrap this connector in
315- ReactPHP's [ ` Connector ` ] ( https://github.com/reactphp/socket#connector ) or the
316- low-level [ ` SecureConnector ` ] ( https://github.com/reactphp/socket#secureconnector ) :
317+ ReactPHP's [ ` Connector ` ] ( https://github.com/reactphp/socket#connector ) :
317318
318319``` php
319- $proxy = new Clue\React\SshProxy\SshSocksConnector('user @example.com');
320+ $proxy = new Clue\React\SshProxy\SshSocksConnector('alice @example.com');
320321
321322$connector = new React\Socket\Connector(array(
322323 'tcp' => $proxy,
@@ -348,7 +349,7 @@ In order to send HTTP requests, you first have to add a dependency for
348349This allows you to send both plain HTTP and TLS-encrypted HTTPS requests like this:
349350
350351``` php
351- $proxy = new Clue\React\SshProxy\SshSocksConnector('user @example.com');
352+ $proxy = new Clue\React\SshProxy\SshSocksConnector('alice @example.com');
352353
353354$connector = new React\Socket\Connector(array(
354355 'tcp' => $proxy,
@@ -357,7 +358,7 @@ $connector = new React\Socket\Connector(array(
357358
358359$browser = new React\Http\Browser($connector);
359360
360- $browser->get('https ://example.com/')->then(function (Psr\Http\Message\ResponseInterface $response) {
361+ $browser->get('http ://example.com/')->then(function (Psr\Http\Message\ResponseInterface $response) {
361362 var_dump($response->getHeaders(), (string) $response->getBody());
362363}, function (Exception $e) {
363364 echo 'Error: ' . $e->getMessage() . PHP_EOL;
@@ -385,7 +386,7 @@ the above SSH proxy server setup, so we can access a firewalled MySQL database
385386server through an SSH tunnel. Here's the gist:
386387
387388``` php
388- $proxy = new Clue\React\SshProxy\SshProcessConnector('user @example.com');
389+ $proxy = new Clue\React\SshProxy\SshProcessConnector('alice @example.com');
389390
390391$uri = 'test:test@localhost/test';
391392$factory = new React\MySQL\Factory(null, $proxy);
@@ -424,16 +425,14 @@ Many use cases require more control over the timeout and likely values much
424425smaller, usually in the range of a few seconds only.
425426
426427You can use ReactPHP's [ ` Connector ` ] ( https://github.com/reactphp/socket#connector )
427- or the low-level
428- [ ` TimeoutConnector ` ] ( https://github.com/reactphp/socket#timeoutconnector )
429428to decorate any given ` ConnectorInterface ` instance.
430429It provides the same ` connect() ` method, but will automatically reject the
431430underlying connection attempt if it takes too long:
432431
433432``` php
434- $proxy = new Clue\React\SshProxy\SshProcessConnector('user @example.com');
433+ $proxy = new Clue\React\SshProxy\SshProcessConnector('alice @example.com');
435434// or
436- $proxy = new Clue\React\SshProxy\SshSocksConnector('user @example.com');
435+ $proxy = new Clue\React\SshProxy\SshSocksConnector('alice @example.com');
437436
438437$connector = new React\Socket\Connector(array(
439438 'tcp' => $proxy,
@@ -477,9 +476,9 @@ Given that remote DNS resolution is assumed to be the preferred mode, all
477476other examples explicitly disable DNS resolution like this:
478477
479478``` php
480- $proxy = new Clue\React\SshProxy\SshProcessConnector('user @example.com');
479+ $proxy = new Clue\React\SshProxy\SshProcessConnector('alice @example.com');
481480// or
482- $proxy = new Clue\React\SshProxy\SshSocksConnector('user @example.com');
481+ $proxy = new Clue\React\SshProxy\SshSocksConnector('alice @example.com');
483482
484483$connector = new React\Socket\Connector(array(
485484 'tcp' => $proxy,
@@ -490,9 +489,9 @@ $connector = new React\Socket\Connector(array(
490489If you want to explicitly use * local DNS resolution* , you can use the following code:
491490
492491``` php
493- $proxy = new Clue\React\SshProxy\SshProcessConnector('user @example.com');
492+ $proxy = new Clue\React\SshProxy\SshProcessConnector('alice @example.com');
494493// or
495- $proxy = new Clue\React\SshProxy\SshSocksConnector('user @example.com');
494+ $proxy = new Clue\React\SshProxy\SshSocksConnector('alice @example.com');
496495
497496// set up Connector which uses Google's public DNS (8.8.8.8)
498497$connector = new React\Socket\Connector(array(
@@ -512,7 +511,7 @@ can access your SSH proxy server on the command line like this:
512511
513512``` bash
514513# test SSH access
515- $ ssh user @example.com echo hello
514+ $ ssh alice @example.com echo hello
516515```
517516
518517Because this class is designed to be used to create any number of connections,
@@ -529,9 +528,9 @@ If your SSH proxy server requires password authentication, you may pass the
529528username and password as part of the SSH proxy server URL like this:
530529
531530``` php
532- $proxy = new Clue\React\SshProxy\SshProcessConnector('user:pass @example.com');
531+ $proxy = new Clue\React\SshProxy\SshProcessConnector('alice:password @example.com');
533532// or
534- $proxy = new Clue\React\SshProxy\SshSocksConnector('user:pass @example.com');
533+ $proxy = new Clue\React\SshProxy\SshSocksConnector('alice:password @example.com');
535534```
536535
537536For this to work, you will have to have the ` sshpass ` binary installed. On
@@ -547,15 +546,14 @@ special characters:
547546``` php
548547$user = 'he:llo';
549548$pass = 'p@ss';
549+ $url = rawurlencode($user) . ':' . rawurlencode($pass) . '@example.com';
550550
551- $proxy = new Clue\React\SshProxy\SshProcessConnector(
552- rawurlencode($user) . ':' . rawurlencode($pass) . '@example.com:2222'
553- );
551+ $proxy = new Clue\React\SshProxy\SshProcessConnector($url);
554552```
555553
556554## Install
557555
558- The recommended way to install this library is [ through Composer] ( https://getcomposer.org ) .
556+ The recommended way to install this library is [ through Composer] ( https://getcomposer.org/ ) .
559557[ New to Composer?] ( https://getcomposer.org/doc/00-intro.md )
560558
561559This project follows [ SemVer] ( https://semver.org/ ) .
@@ -593,7 +591,7 @@ $ sudo apt install sshpass
593591## Tests
594592
595593To run the test suite, you first need to clone this repo and then install all
596- dependencies [ through Composer] ( https://getcomposer.org ) :
594+ dependencies [ through Composer] ( https://getcomposer.org/ ) :
597595
598596``` bash
599597$ composer install
@@ -602,7 +600,7 @@ $ composer install
602600To run the test suite, go to the project root and run:
603601
604602``` bash
605- $ php vendor/bin/phpunit
603+ $ vendor/bin/phpunit
606604```
607605
608606The test suite contains a number of tests that require an actual SSH proxy server.
@@ -612,8 +610,8 @@ environment and prefix this with a space to make sure your login credentials are
612610not stored in your bash history like this:
613611
614612``` bash
615- $ export SSH_PROXY=user:secret @example.com
616- $ php vendor/bin/phpunit --exclude-group internet
613+ $ export SSH_PROXY=alice:password @example.com
614+ $ vendor/bin/phpunit
617615```
618616
619617## License
0 commit comments