Skip to content

Commit

Permalink
Add socket and SSL/TLS context options to connectors
Browse files Browse the repository at this point in the history
  • Loading branch information
clue committed Nov 21, 2015
1 parent 0460210 commit a1b8f8b
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 8 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ $tcpConnector->create('127.0.0.1', 80)->then(function (React\Stream\Stream $stre
$loop->run();
```

You can optionally pass additional
[socket context options](http://php.net/manual/en/context.socket.php)
to the constructor like this:

```php
$tcpConnector = new React\SocketClient\TcpConnector($loop, array(
'bindto' => '192.168.0.1:0'
));
```

Note that this class only allows you to connect to IP/port combinations.
If you want to connect to hostname/port combinations, see also the following chapter.

Expand Down Expand Up @@ -102,6 +112,17 @@ $secureConnector->create('www.google.com', 443)->then(function (React\Stream\Str
$loop->run();
```

You can optionally pass additional
[SSL context options](http://php.net/manual/en/context.ssl.php)
to the constructor like this:

```php
$secureConnector = new React\SocketClient\SecureConnector($dnsConnector, $loop, array(
'verify_peer' => false,
'verify_peer_name' => false
));
```

### Unix domain sockets

Similarly, the `UnixConnector` class can be used to connect to Unix domain socket (UDS)
Expand Down
3 changes: 3 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,8 @@
"branch-alias": {
"dev-master": "0.4-dev"
}
},
"require-dev": {
"clue/block-react": "~1.0"
}
}
18 changes: 12 additions & 6 deletions src/SecureConnector.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,29 @@ class SecureConnector implements ConnectorInterface
{
private $connector;
private $streamEncryption;
private $context;

public function __construct(ConnectorInterface $connector, LoopInterface $loop)
public function __construct(ConnectorInterface $connector, LoopInterface $loop, array $context = array())
{
$this->connector = $connector;
$this->streamEncryption = new StreamEncryption($loop);
$this->context = $context;
}

public function create($host, $port)
{
return $this->connector->create($host, $port)->then(function (Stream $stream) use ($host) {
$context = $this->context + array(
'SNI_enabled' => true,
'SNI_server_name' => $host,
'CN_match' => $host,
'peer_name' => $host
);

return $this->connector->create($host, $port)->then(function (Stream $stream) use ($context) {
// (unencrypted) TCP/IP connection succeeded

// set required SSL/TLS context options
$resource = $stream->stream;
stream_context_set_option($resource, 'ssl', 'SNI_enabled', true);
stream_context_set_option($resource, 'ssl', 'SNI_server_name', $host);
stream_context_set_option($resource, 'ssl', 'peer_name', $host);
stream_context_set_option($stream->stream, array('ssl' => $context));

// try to enable encryption
return $this->streamEncryption->enable($stream)->then(null, function ($error) use ($stream) {
Expand Down
13 changes: 11 additions & 2 deletions src/TcpConnector.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
class TcpConnector implements ConnectorInterface
{
private $loop;
private $context;

public function __construct(LoopInterface $loop)
public function __construct(LoopInterface $loop, array $context = array())
{
$this->loop = $loop;
$this->context = $context;
}

public function create($ip, $port)
Expand All @@ -25,7 +27,14 @@ public function create($ip, $port)

$url = $this->getSocketUrl($ip, $port);

$socket = stream_socket_client($url, $errno, $errstr, 0, STREAM_CLIENT_CONNECT | STREAM_CLIENT_ASYNC_CONNECT);
$socket = stream_socket_client(
$url,
$errno,
$errstr,
0,
STREAM_CLIENT_CONNECT | STREAM_CLIENT_ASYNC_CONNECT,
stream_context_create(array('socket' => $this->context))
);

if (!$socket) {
return Promise\reject(new \RuntimeException(
Expand Down
42 changes: 42 additions & 0 deletions tests/IntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use React\SocketClient\Connector;
use React\SocketClient\SecureConnector;
use React\Stream\BufferedSink;
use Clue\React\Block;

class IntegrationTest extends TestCase
{
Expand Down Expand Up @@ -69,4 +70,45 @@ public function gettingEncryptedStuffFromGoogleShouldWork()
$this->assertTrue($connected);
$this->assertRegExp('#^HTTP/1\.0#', $response);
}

/** @test */
public function testSelfSignedRejectsIfVerificationIsEnabled()
{
$loop = new StreamSelectLoop();

$factory = new Factory();
$dns = $factory->create('8.8.8.8', $loop);


$secureConnector = new SecureConnector(
new Connector($loop, $dns),
$loop,
array(
'verify_peer' => true
)
);

$this->setExpectedException('RuntimeException');
Block\await($secureConnector->create('self-signed.badssl.com', 443), $loop);
}

/** @test */
public function testSelfSignedResolvesIfVerificationIsDisabled()
{
$loop = new StreamSelectLoop();

$factory = new Factory();
$dns = $factory->create('8.8.8.8', $loop);

$secureConnector = new SecureConnector(
new Connector($loop, $dns),
$loop,
array(
'verify_peer' => false
)
);

$conn = Block\await($secureConnector->create('self-signed.badssl.com', 443), $loop);
$conn->close();
}
}

0 comments on commit a1b8f8b

Please sign in to comment.