@@ -200,8 +200,13 @@ public function handleConnectedSocks(ConnectionInterface $stream, $host, $port)
200200 }
201201 $ promise ->then (function () use ($ deferred , $ stream ) {
202202 $ deferred ->resolve ($ stream );
203- }, function ($ error ) use ($ deferred ) {
204- $ deferred ->reject (new Exception ('Unable to communicate... ' , 0 , $ error ));
203+ }, function (Exception $ error ) use ($ deferred ) {
204+ // pass custom RuntimeException through as-is, otherwise wrap in protocol error
205+ if (!$ error instanceof RuntimeException) {
206+ $ error = new RuntimeException ('Invalid response received from proxy (EBADMSG) ' , defined ('SOCKET_EBADMSG ' ) ? SOCKET_EBADMSG : 71 , $ error );
207+ }
208+
209+ $ deferred ->reject ($ error );
205210 });
206211
207212 return $ deferred ->promise ()->then (
@@ -242,9 +247,12 @@ private function handleSocks4(ConnectionInterface $stream, $host, $port, StreamR
242247 'port ' => 'n ' ,
243248 'ip ' => 'N '
244249 ))->then (function ($ data ) {
245- if ($ data ['null ' ] !== 0x00 || $ data [ ' status ' ] !== 0x5a ) {
250+ if ($ data ['null ' ] !== 0x00 ) {
246251 throw new Exception ('Invalid SOCKS response ' );
247252 }
253+ if ($ data ['status ' ] !== 0x5a ) {
254+ throw new RuntimeException ('Proxy refused connection with SOCKS error code ' . sprintf ('0x%02X ' , $ data ['status ' ]) . ' (ECONNREFUSED) ' , defined ('SOCKET_ECONNREFUSED ' ) ? SOCKET_ECONNREFUSED : 111 );
255+ }
248256 });
249257 }
250258
@@ -282,12 +290,12 @@ private function handleSocks5(ConnectionInterface $stream, $host, $port, StreamR
282290 'status ' => 'C '
283291 ))->then (function ($ data ) {
284292 if ($ data ['version ' ] !== 0x01 || $ data ['status ' ] !== 0x00 ) {
285- throw new Exception ('Username/Password authentication failed ' );
293+ throw new RuntimeException ('Username/Password authentication failed (EACCES) ' , defined ( ' SOCKET_EACCES ' ) ? SOCKET_EACCES : 13 );
286294 }
287295 });
288296 } else if ($ data ['method ' ] !== 0x00 ) {
289297 // any other method than "no authentication"
290- throw new Exception ( ' Unacceptable authentication method requested ' );
298+ throw new RuntimeException ( ' No acceptable authentication method found (EACCES) ' , defined ( ' SOCKET_EACCES ' ) ? SOCKET_EACCES : 13 );
291299 }
292300 })->then (function () use ($ stream , $ reader , $ host , $ port ) {
293301 // do not resolve hostname. only try to convert to (binary/packed) IP
@@ -312,9 +320,12 @@ private function handleSocks5(ConnectionInterface $stream, $host, $port, StreamR
312320 'type ' => 'C '
313321 ));
314322 })->then (function ($ data ) use ($ reader ) {
315- if ($ data ['version ' ] !== 0x05 || $ data ['status ' ] !== 0x00 || $ data [ ' null ' ] !== 0x00 ) {
323+ if ($ data ['version ' ] !== 0x05 || $ data ['null ' ] !== 0x00 ) {
316324 throw new Exception ('Invalid SOCKS response ' );
317325 }
326+ if ($ data ['status ' ] !== 0x00 ) {
327+ throw new RuntimeException ('Proxy refused connection with SOCKS error code ' . sprintf ('0x%02X ' , $ data ['status ' ]) . ' (ECONNREFUSED) ' , defined ('SOCKET_ECONNREFUSED ' ) ? SOCKET_ECONNREFUSED : 111 );
328+ }
318329 if ($ data ['type ' ] === 0x01 ) {
319330 // IPv4 address => skip IP and port
320331 return $ reader ->readLength (6 );
0 commit comments