Skip to content

Commit f42f2db

Browse files
authored
Merge pull request #58 from clue-labs/auth-remote
Pass full remote URI as parameter to authentication callback
2 parents 7365861 + 5a0e3b2 commit f42f2db

3 files changed

Lines changed: 54 additions & 6 deletions

File tree

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -615,9 +615,15 @@ While this might seem complex at first, it actually provides a very simple way
615615
to handle simultanous connections in a non-blocking fashion and increases overall performance.
616616

617617
```PHP
618-
$server->setAuth(function ($username, $password) {
618+
$server->setAuth(function ($username, $password, $remote) {
619619
// either return a boolean success value right away
620620
// or use promises for delayed authentication
621+
622+
// $remote is a full URI à la socks5://user:pass@192.168.1.1:1234
623+
// useful for logging or extracting parts, such as the remote IP
624+
$ip = parse_url($remote, PHP_URL_HOST);
625+
626+
return ($username === 'root' && $ip === '127.0.0.1');
621627
});
622628
```
623629

src/Server.php

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ public function setAuth($auth)
6666
throw new UnexpectedValueException('Authentication requires SOCKS5. Consider using protocol version 5 or waive authentication');
6767
}
6868
// wrap authentication callback in order to cast its return value to a promise
69-
$this->auth = function($username, $password) use ($auth) {
70-
$ret = call_user_func($auth, $username, $password);
69+
$this->auth = function($username, $password, $remote) use ($auth) {
70+
$ret = call_user_func($auth, $username, $password, $remote);
7171
if ($ret instanceof PromiseInterface) {
7272
return $ret;
7373
}
@@ -237,9 +237,17 @@ public function handleSocks5(ConnectionInterface $stream, $auth=null, StreamRead
237237
return $reader->readByte()->then(function ($length) use ($reader) {
238238
return $reader->readLength($length);
239239
})->then(function ($password) use ($username, $auth, $stream) {
240-
// username and password known => authenticate
241-
// echo 'auth: ' . $username.' : ' . $password . PHP_EOL;
242-
return $auth($username, $password)->then(function () use ($stream, $username) {
240+
// username and password given => authenticate
241+
$remote = $stream->getRemoteAddress();
242+
if ($remote !== null) {
243+
// remove transport scheme and prefix socks5:// instead
244+
if (($pos = strpos($remote, '://')) !== false) {
245+
$remote = substr($remote, $pos + 3);
246+
}
247+
$remote = 'socks5://' . rawurlencode($username) . ':' . rawurlencode($password) . '@' . $remote;
248+
}
249+
250+
return $auth($username, $password, $remote)->then(function () use ($stream, $username) {
243251
// accept
244252
$stream->emit('auth', array($username));
245253
$stream->write(pack('C2', 0x01, 0x00));

tests/FunctionalTest.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,40 @@ public function testConnectionAuthenticationFromUri()
9797
$this->assertResolveStream($this->client->connect('www.google.com:80'));
9898
}
9999

100+
public function testConnectionAuthenticationCallback()
101+
{
102+
$called = 0;
103+
$that = $this;
104+
$this->server->setAuth(function ($name, $pass, $remote) use ($that, &$called) {
105+
++$called;
106+
$that->assertEquals('name', $name);
107+
$that->assertEquals('pass', $pass);
108+
$that->assertStringStartsWith('socks5://name:pass@127.0.0.1:', $remote);
109+
110+
return true;
111+
});
112+
113+
$this->client = new Client('name:pass@127.0.0.1:' . $this->port, $this->connector);
114+
115+
$this->assertResolveStream($this->client->connect('www.google.com:80'));
116+
$this->assertEquals(1, $called);
117+
}
118+
119+
public function testConnectionAuthenticationCallbackWillNotBeInvokedIfClientsSendsNoAuth()
120+
{
121+
$called = 0;
122+
$this->server->setAuth(function () use (&$called) {
123+
++$called;
124+
125+
return true;
126+
});
127+
128+
$this->client = new Client('127.0.0.1:' . $this->port, $this->connector);
129+
130+
$this->assertRejectPromise($this->client->connect('www.google.com:80'));
131+
$this->assertEquals(0, $called);
132+
}
133+
100134
public function testConnectionAuthenticationFromUriEncoded()
101135
{
102136
$this->server->setAuthArray(array('name' => 'p@ss:w0rd'));

0 commit comments

Comments
 (0)