4
4
[ ![ Packagist Downloads] ( https://img.shields.io/packagist/dt/clue/reactphp-ssh-proxy?color=blue )] ( https://packagist.org/packages/clue/reactphp-ssh-proxy )
5
5
6
6
Async 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/ ) .
8
8
9
9
[ Secure Shell (SSH)] ( https://en.wikipedia.org/wiki/Secure_Shell ) is a secure
10
10
network 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
75
75
plaintext HTTP request to google.com through a remote SSH server:
76
76
77
77
``` php
78
- $proxy = new Clue\React\SshProxy\SshProcessConnector('
[email protected] ');
78
+ <?php
79
+
80
+ require __DIR__ . '/vendor/autoload.php';
81
+
82
+ $proxy = new Clue\React\SshProxy\SshProcessConnector('
[email protected] ');
79
83
80
84
$connector = new React\Socket\Connector(array(
81
85
'tcp' => $proxy,
82
86
'dns' => false
83
87
));
84
88
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
+ });
94
96
```
95
97
96
98
See also the [ examples] ( examples ) .
@@ -109,7 +111,7 @@ any destination by using an intermediary SSH server as a proxy server.
109
111
This class is implemented as a lightweight process wrapper around the ` ssh `
110
112
client binary, so it will spawn one ` ssh ` process for each connection. For
111
113
example, 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 `
113
115
and forward data from its standard I/O streams. For this to work, you'll have to
114
116
make sure that you have a suitable SSH client installed. On Debian/Ubuntu-based
115
117
systems, you may simply install it like this:
@@ -121,7 +123,7 @@ $ sudo apt install openssh-client
121
123
Its constructor simply accepts an SSH proxy server URL:
122
124
123
125
``` php
124
- $proxy = new Clue\React\SshProxy\SshProcessConnector('user @example.com');
126
+ $proxy = new Clue\React\SshProxy\SshProcessConnector('alice @example.com');
125
127
```
126
128
127
129
The proxy URL may or may not contain a scheme and port definition. The default
@@ -162,7 +164,7 @@ higher-level component:
162
164
163
165
``` diff
164
166
- $acme = new AcmeApi($connector);
165
- + $proxy = new Clue\React\SshProxy\SshProcessConnector('user @example.com');
167
+ + $proxy = new Clue\React\SshProxy\SshProcessConnector('alice @example.com');
166
168
+ $acme = new AcmeApi($proxy);
167
169
```
168
170
@@ -179,7 +181,7 @@ This class is implemented as a lightweight process wrapper around the `ssh`
179
181
client binary and it will spawn one ` ssh ` process on demand for multiple
180
182
connections. For example, once you [ open a connection] ( #plain-tcp-connections )
181
183
to ` 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
183
185
mode and will then create a SOCKS client connection to this server process. You
184
186
can create any number of connections over this one process and it will keep this
185
187
process running while there are any open connections and will automatically
@@ -194,7 +196,7 @@ $ sudo apt install openssh-client
194
196
Its constructor simply accepts an SSH proxy server URL:
195
197
196
198
``` php
197
- $proxy = new Clue\React\SshProxy\SshSocksConnector('user @example.com');
199
+ $proxy = new Clue\React\SshProxy\SshSocksConnector('alice @example.com');
198
200
```
199
201
200
202
The 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
223
225
servers, you may optionally pass a unique bind address like this:
224
226
225
227
``` 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');
227
229
```
228
230
229
231
> * Security note for multi-user systems* : This class will spawn the SSH client
@@ -251,7 +253,7 @@ higher-level component:
251
253
252
254
``` diff
253
255
- $acme = new AcmeApi($connector);
254
- + $proxy = new Clue\React\SshProxy\SshSocksConnector('user @example.com');
256
+ + $proxy = new Clue\React\SshProxy\SshSocksConnector('alice @example.com');
255
257
+ $acme = new AcmeApi($proxy);
256
258
```
257
259
@@ -267,9 +269,9 @@ a streaming plain TCP/IP connection on the `SshProcessConnector` or `SshSocksCon
267
269
and use any higher level protocol like so:
268
270
269
271
``` php
270
- $proxy = new Clue\React\SshProxy\SshProcessConnector('user @example.com');
272
+ $proxy = new Clue\React\SshProxy\SshProcessConnector('alice @example.com');
271
273
// or
272
- $proxy = new Clue\React\SshProxy\SshSocksConnector('user @example.com');
274
+ $proxy = new Clue\React\SshProxy\SshSocksConnector('alice @example.com');
273
275
274
276
$proxy->connect('tcp://smtp.googlemail.com:587')->then(function (React\Socket\ConnectionInterface $connection) {
275
277
$connection->write("EHLO local\r\n");
@@ -283,9 +285,9 @@ You can either use the `SshProcessConnector` or `SshSocksConnector` directly or
283
285
may want to wrap this connector in ReactPHP's [ ` Connector ` ] ( https://github.com/reactphp/socket#connector ) :
284
286
285
287
``` php
286
- $proxy = new Clue\React\SshProxy\SshProcessConnector('user @example.com');
288
+ $proxy = new Clue\React\SshProxy\SshProcessConnector('alice @example.com');
287
289
// or
288
- $proxy = new Clue\React\SshProxy\SshSocksConnector('user @example.com');
290
+ $proxy = new Clue\React\SshProxy\SshSocksConnector('alice @example.com');
289
291
290
292
$connector = new React\Socket\Connector(array(
291
293
'tcp' => $proxy,
@@ -312,11 +314,10 @@ details.
312
314
The ` SshSocksConnector ` can also be used if you want to establish a secure TLS connection
313
315
(formerly known as SSL) between you and your destination, such as when using
314
316
secure 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 ) :
317
318
318
319
``` php
319
- $proxy = new Clue\React\SshProxy\SshSocksConnector('user @example.com');
320
+ $proxy = new Clue\React\SshProxy\SshSocksConnector('alice @example.com');
320
321
321
322
$connector = new React\Socket\Connector(array(
322
323
'tcp' => $proxy,
@@ -348,7 +349,7 @@ In order to send HTTP requests, you first have to add a dependency for
348
349
This allows you to send both plain HTTP and TLS-encrypted HTTPS requests like this:
349
350
350
351
``` php
351
- $proxy = new Clue\React\SshProxy\SshSocksConnector('user @example.com');
352
+ $proxy = new Clue\React\SshProxy\SshSocksConnector('alice @example.com');
352
353
353
354
$connector = new React\Socket\Connector(array(
354
355
'tcp' => $proxy,
@@ -357,7 +358,7 @@ $connector = new React\Socket\Connector(array(
357
358
358
359
$browser = new React\Http\Browser($connector);
359
360
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) {
361
362
var_dump($response->getHeaders(), (string) $response->getBody());
362
363
}, function (Exception $e) {
363
364
echo 'Error: ' . $e->getMessage() . PHP_EOL;
@@ -385,7 +386,7 @@ the above SSH proxy server setup, so we can access a firewalled MySQL database
385
386
server through an SSH tunnel. Here's the gist:
386
387
387
388
``` php
388
- $proxy = new Clue\React\SshProxy\SshProcessConnector('user @example.com');
389
+ $proxy = new Clue\React\SshProxy\SshProcessConnector('alice @example.com');
389
390
390
391
$uri = 'test:test@localhost/test';
391
392
$factory = new React\MySQL\Factory(null, $proxy);
@@ -424,16 +425,14 @@ Many use cases require more control over the timeout and likely values much
424
425
smaller, usually in the range of a few seconds only.
425
426
426
427
You can use ReactPHP's [ ` Connector ` ] ( https://github.com/reactphp/socket#connector )
427
- or the low-level
428
- [ ` TimeoutConnector ` ] ( https://github.com/reactphp/socket#timeoutconnector )
429
428
to decorate any given ` ConnectorInterface ` instance.
430
429
It provides the same ` connect() ` method, but will automatically reject the
431
430
underlying connection attempt if it takes too long:
432
431
433
432
``` php
434
- $proxy = new Clue\React\SshProxy\SshProcessConnector('user @example.com');
433
+ $proxy = new Clue\React\SshProxy\SshProcessConnector('alice @example.com');
435
434
// or
436
- $proxy = new Clue\React\SshProxy\SshSocksConnector('user @example.com');
435
+ $proxy = new Clue\React\SshProxy\SshSocksConnector('alice @example.com');
437
436
438
437
$connector = new React\Socket\Connector(array(
439
438
'tcp' => $proxy,
@@ -477,9 +476,9 @@ Given that remote DNS resolution is assumed to be the preferred mode, all
477
476
other examples explicitly disable DNS resolution like this:
478
477
479
478
``` php
480
- $proxy = new Clue\React\SshProxy\SshProcessConnector('user @example.com');
479
+ $proxy = new Clue\React\SshProxy\SshProcessConnector('alice @example.com');
481
480
// or
482
- $proxy = new Clue\React\SshProxy\SshSocksConnector('user @example.com');
481
+ $proxy = new Clue\React\SshProxy\SshSocksConnector('alice @example.com');
483
482
484
483
$connector = new React\Socket\Connector(array(
485
484
'tcp' => $proxy,
@@ -490,9 +489,9 @@ $connector = new React\Socket\Connector(array(
490
489
If you want to explicitly use * local DNS resolution* , you can use the following code:
491
490
492
491
``` php
493
- $proxy = new Clue\React\SshProxy\SshProcessConnector('user @example.com');
492
+ $proxy = new Clue\React\SshProxy\SshProcessConnector('alice @example.com');
494
493
// or
495
- $proxy = new Clue\React\SshProxy\SshSocksConnector('user @example.com');
494
+ $proxy = new Clue\React\SshProxy\SshSocksConnector('alice @example.com');
496
495
497
496
// set up Connector which uses Google's public DNS (8.8.8.8)
498
497
$connector = new React\Socket\Connector(array(
@@ -512,7 +511,7 @@ can access your SSH proxy server on the command line like this:
512
511
513
512
``` bash
514
513
# test SSH access
515
- $ ssh user @example.com echo hello
514
+ $ ssh alice @example.com echo hello
516
515
```
517
516
518
517
Because 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
529
528
username and password as part of the SSH proxy server URL like this:
530
529
531
530
``` php
532
- $proxy = new Clue\React\SshProxy\SshProcessConnector('user:pass @example.com');
531
+ $proxy = new Clue\React\SshProxy\SshProcessConnector('alice:password @example.com');
533
532
// or
534
- $proxy = new Clue\React\SshProxy\SshSocksConnector('user:pass @example.com');
533
+ $proxy = new Clue\React\SshProxy\SshSocksConnector('alice:password @example.com');
535
534
```
536
535
537
536
For this to work, you will have to have the ` sshpass ` binary installed. On
@@ -547,15 +546,14 @@ special characters:
547
546
``` php
548
547
$user = 'he:llo';
549
548
$pass = 'p@ss';
549
+ $url = rawurlencode($user) . ':' . rawurlencode($pass) . '@example.com';
550
550
551
- $proxy = new Clue\React\SshProxy\SshProcessConnector(
552
- rawurlencode($user) . ':' . rawurlencode($pass) . '@example.com:2222'
553
- );
551
+ $proxy = new Clue\React\SshProxy\SshProcessConnector($url);
554
552
```
555
553
556
554
## Install
557
555
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/ ) .
559
557
[ New to Composer?] ( https://getcomposer.org/doc/00-intro.md )
560
558
561
559
This project follows [ SemVer] ( https://semver.org/ ) .
@@ -593,7 +591,7 @@ $ sudo apt install sshpass
593
591
## Tests
594
592
595
593
To 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/ ) :
597
595
598
596
``` bash
599
597
$ composer install
@@ -602,7 +600,7 @@ $ composer install
602
600
To run the test suite, go to the project root and run:
603
601
604
602
``` bash
605
- $ php vendor/bin/phpunit
603
+ $ vendor/bin/phpunit
606
604
```
607
605
608
606
The 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
612
610
not stored in your bash history like this:
613
611
614
612
``` 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
617
615
```
618
616
619
617
## License
0 commit comments