Skip to content

Commit f9d7b45

Browse files
committed
Non-issue : Added SSL support to Socket and SocketListener without handshake verification
1 parent ddbf317 commit f9d7b45

File tree

2 files changed

+141
-27
lines changed

2 files changed

+141
-27
lines changed

Socket/Socket.php

Lines changed: 68 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,24 @@ class Socket extends AsyncStream implements SocketInterface
2121
*/
2222
const TYPE_TCP = 'tcp_socket/ssl';
2323

24+
/**
25+
* @var string
26+
*/
27+
const TYPE_UDP = 'udp_socket';
28+
29+
/**
30+
* @var string
31+
*/
32+
const TYPE_UNKNOWN = 'Unknown';
33+
34+
const TRANSPORT_TCP = 'tcp';
35+
36+
const TRANSPORT_UDP = 'udp';
37+
38+
const TRANSPORT_SSL = 'ssl';
39+
40+
const TRANSPORT_TLS = 'tls';
41+
2442
/**
2543
* @var bool[]
2644
*/
@@ -47,11 +65,11 @@ public function __construct($endpointOrResource, LoopInterface $loop, $config =
4765
}
4866
catch (Error $ex)
4967
{
50-
throw new InstantiationException('SocketClient could not be created.');
68+
throw new InstantiationException('SocketClient could not be created.', $ex);
5169
}
5270
catch (Exception $ex)
5371
{
54-
throw new InstantiationException('SocketClient could not be created.');
72+
throw new InstantiationException('SocketClient could not be created.', $ex);
5573
}
5674
}
5775

@@ -115,6 +133,17 @@ public function getLocalPort()
115133
return isset($address[1]) ? $address[1] : '';
116134
}
117135

136+
/**
137+
* @override
138+
* @inheritDoc
139+
*/
140+
public function getLocalTransport()
141+
{
142+
$endpoint = explode('://', $this->getLocalEndpoint(), 2);
143+
144+
return isset($endpoint[0])?$endpoint[0]:'';
145+
}
146+
118147
/**
119148
* @override
120149
* @inheritDoc
@@ -148,6 +177,16 @@ public function getRemotePort()
148177
return isset($address[1]) ? $address[1] : '';
149178
}
150179

180+
/**
181+
* @override
182+
* @inheritDoc
183+
*/
184+
public function getRemoteTransport()
185+
{
186+
$endpoint = explode('://', $this->getRemoteEndpoint(), 2);
187+
188+
return isset($endpoint[0])?$endpoint[0]:'';
189+
}
151190

152191
/**
153192
* Create the client resource.
@@ -159,20 +198,31 @@ public function getRemotePort()
159198
* @return resource
160199
* @throws LogicException
161200
*/
162-
protected function createClient($endpoint, $options = [])
201+
protected function createClient($endpoint, $options = ['ssl'=> false])
163202
{
164-
$context = [];
165203
$context['socket'] = [
166-
'connect' => $endpoint
204+
'connect' => $endpoint
167205
];
168206

207+
$ssl = (bool) (isset($options['ssl']) ? $options['ssl'] : false);
208+
209+
if ($ssl === true)
210+
{
211+
$context['ssl'] = [
212+
'verify_peer' => true,
213+
'verify_peer_name'=>false,
214+
'allow_self_signed' => true,
215+
'cafile'=>$options['cafile'],
216+
];
217+
}
218+
169219
$context = stream_context_create($context);
170220
// Error reporting suppressed since stream_socket_client() emits an E_WARNING on failure.
171221
$socket = @stream_socket_client(
172222
$endpoint,
173223
$errno,
174224
$errstr,
175-
null, // Timeout does not apply for async connect.
225+
0, // Timeout does not apply for async connect.
176226
STREAM_CLIENT_CONNECT | STREAM_CLIENT_ASYNC_CONNECT,
177227
$context
178228
);
@@ -194,7 +244,7 @@ protected function createClient($endpoint, $options = [])
194244
*/
195245
public function handleRead()
196246
{
197-
$data = stream_socket_recvfrom($this->resource, $this->bufferSize);
247+
$data = fread($this->resource, $this->bufferSize);
198248

199249
if ($data !== '' && $data !== false)
200250
{
@@ -238,7 +288,7 @@ private function parseEndpoint($wantPeer = false)
238288
return $this->cachedEndpoint[$wantIndex];
239289
}
240290

241-
if (get_resource_type($this->resource) === 'Unknown')
291+
if (get_resource_type($this->resource) === Socket::TYPE_UNKNOWN)
242292
{
243293
return '';
244294
}
@@ -249,24 +299,31 @@ private function parseEndpoint($wantPeer = false)
249299
switch ($type)
250300
{
251301
case Socket::TYPE_UNIX:
252-
$endpoint = 'unix://' . $name;
302+
$transport = 'unix://';
303+
$endpoint = $transport . $name;
253304
break;
254305

255306
case Socket::TYPE_TCP:
307+
$transport = 'tcp://';
256308
if (substr_count($name, ':') > 1)
257309
{
258310
$parts = explode(':', $name);
259311
$count = count($parts);
260312
$port = $parts[$count - 1];
261313
unset($parts[$count - 1]);
262-
$endpoint = 'tcp://[' . implode(':', $parts) . ']:' . $port;
314+
$endpoint = $transport.'[' . implode(':', $parts) . ']:' . $port;
263315
}
264316
else
265317
{
266-
$endpoint = 'tcp://' . $name;
318+
$endpoint = $transport . $name;
267319
}
268320
break;
269321

322+
case Socket::TYPE_UDP:
323+
$transport = 'udp://';
324+
$endpoint = $transport . $name;
325+
break;
326+
270327
default:
271328
$endpoint = '';
272329
}

Socket/SocketListener.php

Lines changed: 73 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,14 @@ class SocketListener extends BaseEventEmitter implements SocketListenerInterface
5151
* @param mixed[] $config
5252
* @throws InstantiationException
5353
*/
54-
public function __construct($endpointOrResource, LoopInterface $loop, $config = [])
54+
public function __construct($endpointOrResource, LoopInterface $loop, $config = ['ssl'=>false])
5555
{
5656
$this->endpoint = $endpointOrResource;
5757
$this->socket = null;
5858
$this->loop = $loop;
5959
$this->open = false;
6060
$this->paused = true;
61+
$this->config = $config;
6162
}
6263

6364
/**
@@ -97,7 +98,18 @@ public function start()
9798
else
9899
{
99100
$this->socket = &$this->endpoint;
101+
102+
if ($this->config['ssl'] === true)
103+
{
104+
stream_context_set_option($this->socket, 'ssl', 'verify_peer', false);
105+
stream_context_set_option($this->socket, 'ssl', 'allow_self_signed', true);
106+
stream_context_set_option($this->socket,'ssl','verify_peer_name',false);
107+
stream_context_set_option($this->socket, 'ssl', 'local_cert', $this->config['local_cert']);
108+
stream_context_set_option($this->socket, 'ssl', 'local_pk', $this->config['local_pk']);
109+
stream_context_set_option($this->socket, 'ssl', 'passphrase', $this->config['passphrase']);
110+
}
100111
}
112+
101113
$this->resume();
102114
$this->open = true;
103115
}
@@ -111,7 +123,6 @@ public function start()
111123
}
112124
}
113125

114-
115126
/**
116127
* @override
117128
* @inheritDoc
@@ -163,6 +174,17 @@ public function getLocalPort()
163174
return isset($address[1]) ? $address[1] : '';
164175
}
165176

177+
/**
178+
* @override
179+
* @inheritDoc
180+
*/
181+
public function getLocalTransport()
182+
{
183+
$endpoint = explode('://', $this->getLocalEndpoint(), 2);
184+
185+
return isset($endpoint[0])?$endpoint[0]:'';
186+
}
187+
166188
/**
167189
* @override
168190
* @inheritDoc
@@ -234,6 +256,15 @@ public function isPaused()
234256
return $this->paused;
235257
}
236258

259+
/**
260+
* @internal
261+
* @return bool
262+
*/
263+
public function isEncrypt()
264+
{
265+
return $this->encrypt && true;
266+
}
267+
237268
/**
238269
* @override
239270
* @inheritDoc
@@ -316,26 +347,41 @@ protected function createServer($endpoint, $config = [])
316347
}
317348
}
318349

350+
$ssl = (bool) ((isset($config['ssl'])) ? $config['ssl'] : false);
319351
$backlog = (int) (isset($config['backlog']) ? $config['backlog'] : self::DEFAULT_BACKLOG);
320352
$reuseaddr = (bool) (isset($config['reuseaddr']) ? $config['reuseaddr'] : false);
321353
$reuseport = (bool) (isset($config['reuseport']) ? $config['reuseport'] : false);
322354

323-
$context = [];
324355
$context['socket'] = [
325-
'bindto' => $endpoint,
326-
'backlog' => $backlog,
327-
'ipv6_v6only' => true,
328-
'so_reuseaddr' => $reuseaddr,
329-
'so_reuseport' => $reuseport,
356+
'bindto' => $endpoint,
357+
'backlog' => $backlog,
358+
'ipv6_v6only' => true,
359+
'so_reuseaddr' => $reuseaddr,
360+
'so_reuseport' => $reuseport,
330361
];
331362

363+
if($ssl) {
364+
$context['ssl'] = [
365+
'verify_peer'=>false,
366+
'verify_peer_name' => false,
367+
'allow_self_signed'=> true,
368+
'local_cert' => $config['local_cert'],
369+
'local_pk' => $config['local_pk'],
370+
'passphrase' => $config['passphrase'],
371+
];
372+
373+
}
374+
375+
$bitmask = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN;
376+
332377
$context = stream_context_create($context);
378+
333379
// Error reporting suppressed since stream_socket_server() emits an E_WARNING on failure.
334-
$socket = @stream_socket_server(
380+
$socket = stream_socket_server(
335381
$endpoint,
336382
$errno,
337383
$errstr,
338-
STREAM_SERVER_BIND | STREAM_SERVER_LISTEN,
384+
$bitmask,
339385
$context
340386
);
341387

@@ -414,21 +460,32 @@ private function parseEndpoint()
414460
$name = stream_socket_get_name($this->socket, false);
415461
$type = $this->getStreamType();
416462

417-
switch ($type) {
463+
switch ($type)
464+
{
418465
case Socket::TYPE_UNIX:
419-
$endpoint = 'unix://' . $name;
466+
$transport = 'unix://';
467+
$endpoint = $transport . $name;
420468
break;
421469

422470
case Socket::TYPE_TCP:
423-
if (substr_count($name, ':') > 1) {
471+
$transport = 'tcp://';
472+
if (substr_count($name, ':') > 1)
473+
{
424474
$parts = explode(':', $name);
425475
$count = count($parts);
426476
$port = $parts[$count - 1];
427477
unset($parts[$count - 1]);
428-
$endpoint = 'tcp://[' . implode(':', $parts) . ']:' . $port;
429-
} else {
430-
$endpoint = 'tcp://' . $name;
478+
$endpoint = $transport.'[' . implode(':', $parts) . ']:' . $port;
431479
}
480+
else
481+
{
482+
$endpoint = $transport . $name;
483+
}
484+
break;
485+
486+
case Socket::TYPE_UDP:
487+
$transport = 'udp://';
488+
$endpoint = $transport . $name;
432489
break;
433490

434491
default:

0 commit comments

Comments
 (0)