From 90acc5e39e6f2efd152c5e1382e5f7f9cb68a60c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Sat, 16 Dec 2017 17:42:44 +0100 Subject: [PATCH] Report socks5s:// remote URI scheme for SOCKS over TLS during auth --- README.md | 1 + src/Server.php | 6 ++++-- tests/ServerTest.php | 28 ++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b7b9899..f971d7c 100644 --- a/README.md +++ b/README.md @@ -738,6 +738,7 @@ $server->setAuth(function ($username, $password, $remote) { // or use promises for delayed authentication // $remote is a full URI à la socks5://user:pass@192.168.1.1:1234 + // or socks5s://user:pass@192.168.1.1:1234 for SOCKS over TLS // useful for logging or extracting parts, such as the remote IP $ip = parse_url($remote, PHP_URL_HOST); diff --git a/src/Server.php b/src/Server.php index 3605160..0a069e2 100644 --- a/src/Server.php +++ b/src/Server.php @@ -194,10 +194,11 @@ public function handleSocks4(ConnectionInterface $stream, $protocolVersion, Stre $remote = $stream->getRemoteAddress(); if ($remote !== null) { // remove transport scheme and prefix socks4:// instead + $secure = strpos($remote, 'tls://') === 0; if (($pos = strpos($remote, '://')) !== false) { $remote = substr($remote, $pos + 3); } - $remote = 'socks4://' . $remote; + $remote = 'socks4' . ($secure ? 's' : '') . '://' . $remote; } $that = $this; @@ -246,10 +247,11 @@ public function handleSocks5(ConnectionInterface $stream, $auth=null, StreamRead $remote = $stream->getRemoteAddress(); if ($remote !== null) { // remove transport scheme and prefix socks5:// instead + $secure = strpos($remote, 'tls://') === 0; if (($pos = strpos($remote, '://')) !== false) { $remote = substr($remote, $pos + 3); } - $remote = 'socks5://' . $remote; + $remote = 'socks5' . ($secure ? 's' : '') . '://' . $remote; } $that = $this; diff --git a/tests/ServerTest.php b/tests/ServerTest.php index f378c74..5c73845 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -271,6 +271,20 @@ public function testHandleSocks4aConnectionWithHostnameAndSourceAddressWillEstab $connection->emit('data', array("\x04\x01" . "\x00\x50" . "\x00\x00\x00\x01" . "\x00" . "example.com" . "\x00")); } + public function testHandleSocks4aConnectionWithSecureTlsSourceAddressWillEstablishOutgoingConnection() + { + $connection = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('pause', 'end', 'getRemoteAddress'))->getMock(); + $connection->expects($this->once())->method('getRemoteAddress')->willReturn('tls://10.20.30.40:5060'); + + $promise = new Promise(function () { }); + + $this->connector->expects($this->once())->method('connect')->with('example.com:80?source=socks4s%3A%2F%2F10.20.30.40%3A5060')->willReturn($promise); + + $this->server->onConnection($connection); + + $connection->emit('data', array("\x04\x01" . "\x00\x50" . "\x00\x00\x00\x01" . "\x00" . "example.com" . "\x00")); + } + public function testHandleSocks4aConnectionWithInvalidHostnameWillNotEstablishOutgoingConnection() { $connection = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('pause', 'end'))->getMock(); @@ -309,6 +323,20 @@ public function testHandleSocks5ConnectionWithIpv4AndSourceAddressWillEstablishO $connection->emit('data', array("\x05\x01\x00" . "\x05\x01\x00\x01" . pack('N', ip2long('127.0.0.1')) . "\x00\x50")); } + public function testHandleSocks5ConnectionWithSecureTlsIpv4AndSourceAddressWillEstablishOutgoingConnection() + { + $connection = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('pause', 'end', 'write', 'getRemoteAddress'))->getMock(); + $connection->expects($this->once())->method('getRemoteAddress')->willReturn('tls://10.20.30.40:5060'); + + $promise = new Promise(function () { }); + + $this->connector->expects($this->once())->method('connect')->with('127.0.0.1:80?source=socks5s%3A%2F%2F10.20.30.40%3A5060')->willReturn($promise); + + $this->server->onConnection($connection); + + $connection->emit('data', array("\x05\x01\x00" . "\x05\x01\x00\x01" . pack('N', ip2long('127.0.0.1')) . "\x00\x50")); + } + public function testHandleSocks5ConnectionWithIpv6WillEstablishOutgoingConnection() { $connection = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('pause', 'end', 'write'))->getMock();