Skip to content

Commit 5953103

Browse files
authored
Merge pull request #71 from clue-labs/sockss
Report socks5s:// remote URI scheme for SOCKS over TLS during auth
2 parents a56cafe + 90acc5e commit 5953103

3 files changed

Lines changed: 33 additions & 2 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,7 @@ $server->setAuth(function ($username, $password, $remote) {
738738
// or use promises for delayed authentication
739739

740740
// $remote is a full URI à la socks5://user:pass@192.168.1.1:1234
741+
// or socks5s://user:pass@192.168.1.1:1234 for SOCKS over TLS
741742
// useful for logging or extracting parts, such as the remote IP
742743
$ip = parse_url($remote, PHP_URL_HOST);
743744

src/Server.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,10 +194,11 @@ public function handleSocks4(ConnectionInterface $stream, $protocolVersion, Stre
194194
$remote = $stream->getRemoteAddress();
195195
if ($remote !== null) {
196196
// remove transport scheme and prefix socks4:// instead
197+
$secure = strpos($remote, 'tls://') === 0;
197198
if (($pos = strpos($remote, '://')) !== false) {
198199
$remote = substr($remote, $pos + 3);
199200
}
200-
$remote = 'socks4://' . $remote;
201+
$remote = 'socks4' . ($secure ? 's' : '') . '://' . $remote;
201202
}
202203

203204
$that = $this;
@@ -246,10 +247,11 @@ public function handleSocks5(ConnectionInterface $stream, $auth=null, StreamRead
246247
$remote = $stream->getRemoteAddress();
247248
if ($remote !== null) {
248249
// remove transport scheme and prefix socks5:// instead
250+
$secure = strpos($remote, 'tls://') === 0;
249251
if (($pos = strpos($remote, '://')) !== false) {
250252
$remote = substr($remote, $pos + 3);
251253
}
252-
$remote = 'socks5://' . $remote;
254+
$remote = 'socks5' . ($secure ? 's' : '') . '://' . $remote;
253255
}
254256

255257
$that = $this;

tests/ServerTest.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,20 @@ public function testHandleSocks4aConnectionWithHostnameAndSourceAddressWillEstab
271271
$connection->emit('data', array("\x04\x01" . "\x00\x50" . "\x00\x00\x00\x01" . "\x00" . "example.com" . "\x00"));
272272
}
273273

274+
public function testHandleSocks4aConnectionWithSecureTlsSourceAddressWillEstablishOutgoingConnection()
275+
{
276+
$connection = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('pause', 'end', 'getRemoteAddress'))->getMock();
277+
$connection->expects($this->once())->method('getRemoteAddress')->willReturn('tls://10.20.30.40:5060');
278+
279+
$promise = new Promise(function () { });
280+
281+
$this->connector->expects($this->once())->method('connect')->with('example.com:80?source=socks4s%3A%2F%2F10.20.30.40%3A5060')->willReturn($promise);
282+
283+
$this->server->onConnection($connection);
284+
285+
$connection->emit('data', array("\x04\x01" . "\x00\x50" . "\x00\x00\x00\x01" . "\x00" . "example.com" . "\x00"));
286+
}
287+
274288
public function testHandleSocks4aConnectionWithInvalidHostnameWillNotEstablishOutgoingConnection()
275289
{
276290
$connection = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('pause', 'end'))->getMock();
@@ -309,6 +323,20 @@ public function testHandleSocks5ConnectionWithIpv4AndSourceAddressWillEstablishO
309323
$connection->emit('data', array("\x05\x01\x00" . "\x05\x01\x00\x01" . pack('N', ip2long('127.0.0.1')) . "\x00\x50"));
310324
}
311325

326+
public function testHandleSocks5ConnectionWithSecureTlsIpv4AndSourceAddressWillEstablishOutgoingConnection()
327+
{
328+
$connection = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('pause', 'end', 'write', 'getRemoteAddress'))->getMock();
329+
$connection->expects($this->once())->method('getRemoteAddress')->willReturn('tls://10.20.30.40:5060');
330+
331+
$promise = new Promise(function () { });
332+
333+
$this->connector->expects($this->once())->method('connect')->with('127.0.0.1:80?source=socks5s%3A%2F%2F10.20.30.40%3A5060')->willReturn($promise);
334+
335+
$this->server->onConnection($connection);
336+
337+
$connection->emit('data', array("\x05\x01\x00" . "\x05\x01\x00\x01" . pack('N', ip2long('127.0.0.1')) . "\x00\x50"));
338+
}
339+
312340
public function testHandleSocks5ConnectionWithIpv6WillEstablishOutgoingConnection()
313341
{
314342
$connection = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('pause', 'end', 'write'))->getMock();

0 commit comments

Comments
 (0)