@@ -7,7 +7,7 @@ __version__ = '0.1.1' | |||||
__all__ = ('Socks4Protocol', 'Socks5Protocol', 'Socks4Auth', | __all__ = ('Socks4Protocol', 'Socks5Protocol', 'Socks4Auth', | ||||
'Socks5Auth', 'Socks4Addr', 'Socks5Addr', 'SocksError', | 'Socks5Auth', 'Socks4Addr', 'Socks5Addr', 'SocksError', | ||||
'NoAcceptableAuthMethods', 'LoginAuthenticationFailed', | |||||
'NoAcceptableAuthMethods', 'LoginAuthenticationFailed', 'SocksConnectionError', | |||||
'InvalidServerVersion', 'InvalidServerReply', 'create_connection') | 'InvalidServerVersion', 'InvalidServerReply', 'create_connection') | ||||
@@ -46,11 +46,19 @@ async def create_connection(protocol_factory, proxy, proxy_auth, dst, *, remote_ | |||||
proxy=proxy, proxy_auth=proxy_auth, dst=dst, | proxy=proxy, proxy_auth=proxy_auth, dst=dst, | ||||
remote_resolve=remote_resolve, loop=loop) | remote_resolve=remote_resolve, loop=loop) | ||||
transport, protocol = await loop.create_connection( | |||||
socks_factory, proxy.host, proxy.port, ssl=ssl, family=family, proto=proto, | |||||
flags=flags, sock=sock, local_addr=local_addr, server_hostname=server_hostname) | |||||
try: | |||||
transport, protocol = await loop.create_connection( | |||||
socks_factory, proxy.host, proxy.port, ssl=ssl, family=family, proto=proto, | |||||
flags=flags, sock=sock, local_addr=local_addr, server_hostname=server_hostname) | |||||
except OSError as exc: | |||||
raise SocksConnectionError('[Errno %s] Can not connect to proxy %s:%d [%s]' % | |||||
(exc.errno, proxy.host, proxy.port, exc.strerror)) from exc | |||||
await protocol.negotiate_done() | |||||
try: | |||||
await protocol.negotiate_done() | |||||
except SocksError as exc: | |||||
raise SocksError('Can not connect to %s:%s [%s]' % | |||||
(dst[0], dst[1], exc)) | |||||
sock = transport.get_extra_info('socket') | sock = transport.get_extra_info('socket') | ||||
@@ -1,4 +1,9 @@ | |||||
import socket | |||||
import aiohttp | import aiohttp | ||||
import ipaddress | |||||
from aiohttp.errors import ProxyConnectionError | |||||
from .errors import SocksError, SocksConnectionError | |||||
from . import create_connection | from . import create_connection | ||||
__all__ = ('SocksConnector',) | __all__ = ('SocksConnector',) | ||||
@@ -46,9 +51,14 @@ class SocksConnector(aiohttp.TCPConnector): | |||||
proto=hinfo['proto'], flags=hinfo['flags'], local_addr=self._local_addr) | proto=hinfo['proto'], flags=hinfo['flags'], local_addr=self._local_addr) | ||||
return transp, proto | return transp, proto | ||||
except OSError as e: | |||||
except (OSError, SocksError, SocksConnectionError) as e: | |||||
exc = e | exc = e | ||||
else: | else: | ||||
raise aiohttp.ClientOSError(exc.errno, | |||||
'Can not connect to %s:%s [%s]' % | |||||
(req.host, req.port, exc.strerror)) from exc | |||||
if isinstance(exc, SocksConnectionError): | |||||
raise ProxyConnectionError(*exc.args) | |||||
if isinstance(exc, SocksError): | |||||
raise exc | |||||
else: | |||||
raise aiohttp.ClientOSError(exc.errno, | |||||
'Can not connect to %s:%s [%s]' % | |||||
(req.host, req.port, exc.strerror)) from exc |
@@ -16,3 +16,7 @@ class InvalidServerVersion(SocksError): | |||||
class InvalidServerReply(SocksError): | class InvalidServerReply(SocksError): | ||||
pass | pass | ||||
class SocksConnectionError(OSError): | |||||
pass |
@@ -106,7 +106,7 @@ class Socks4Protocol(SocksProtocol): | |||||
raise InvalidServerReply('SOCKS4 proxy server sent invalid data') | raise InvalidServerReply('SOCKS4 proxy server sent invalid data') | ||||
if resp[1] != c.SOCKS4_GRANTED: | if resp[1] != c.SOCKS4_GRANTED: | ||||
error = c.SOCKS4_ERRORS.get(resp[1], 'Unknown error') | error = c.SOCKS4_ERRORS.get(resp[1], 'Unknown error') | ||||
raise SocksError('{0:#04x}: {1}'.format(resp[1], error)) | |||||
raise SocksError('[Errno {0:#04x}]: {1}'.format(resp[1], error)) | |||||
binded = socket.inet_ntoa(resp[4:]), struct.unpack('>H', resp[2:4])[0] | binded = socket.inet_ntoa(resp[4:]), struct.unpack('>H', resp[2:4])[0] | ||||
return (host, port), binded | return (host, port), binded | ||||
@@ -138,7 +138,7 @@ class Socks5Protocol(SocksProtocol): | |||||
chosen_auth = await self.read_response(2) | chosen_auth = await self.read_response(2) | ||||
if chosen_auth[0] != c.SOCKS_VER5: | if chosen_auth[0] != c.SOCKS_VER5: | ||||
raise InvalidServerVersion | |||||
raise InvalidServerVersion('SOCKS5 proxy server sent invalid version') | |||||
if chosen_auth[1] == c.SOCKS5_AUTH_UNAME_PWD: | if chosen_auth[1] == c.SOCKS5_AUTH_UNAME_PWD: | ||||
req = [0x01, chr(len(self._auth.login)).encode(), self._auth.login, | req = [0x01, chr(len(self._auth.login)).encode(), self._auth.login, | ||||
@@ -149,11 +149,11 @@ class Socks5Protocol(SocksProtocol): | |||||
if auth_status[0] != 0x01: | if auth_status[0] != 0x01: | ||||
raise InvalidServerReply('SOCKS5 proxy server sent invalid data') | raise InvalidServerReply('SOCKS5 proxy server sent invalid data') | ||||
if auth_status[1] != c.SOCKS5_GRANTED: | if auth_status[1] != c.SOCKS5_GRANTED: | ||||
raise LoginAuthenticationFailed | |||||
raise LoginAuthenticationFailed('SOCKS5 authentication failed') | |||||
# offered auth methods rejected | # offered auth methods rejected | ||||
elif chosen_auth[1] != c.SOCKS5_AUTH_ANONYMOUS: | elif chosen_auth[1] != c.SOCKS5_AUTH_ANONYMOUS: | ||||
if chosen_auth[1] == c.SOCKS5_AUTH_NO_ACCEPTABLE_METHODS: | if chosen_auth[1] == c.SOCKS5_AUTH_NO_ACCEPTABLE_METHODS: | ||||
raise NoAcceptableAuthMethods | |||||
raise NoAcceptableAuthMethods('All offered SOCKS5 authentication methods were rejected') | |||||
else: | else: | ||||
raise InvalidServerReply('SOCKS5 proxy server sent invalid data') | raise InvalidServerReply('SOCKS5 proxy server sent invalid data') | ||||
@@ -165,10 +165,10 @@ class Socks5Protocol(SocksProtocol): | |||||
resp = await self.read_response(3) | resp = await self.read_response(3) | ||||
if resp[0] != c.SOCKS_VER5: | if resp[0] != c.SOCKS_VER5: | ||||
raise InvalidServerVersion | |||||
raise InvalidServerVersion('SOCKS5 proxy server sent invalid version') | |||||
if resp[1] != c.SOCKS5_GRANTED: | if resp[1] != c.SOCKS5_GRANTED: | ||||
error = c.SOCKS5_ERRORS.get(resp[1], 'Unknown error') | error = c.SOCKS5_ERRORS.get(resp[1], 'Unknown error') | ||||
raise SocksError('{0:#04x}: {1}'.format(resp[1], error)) | |||||
raise SocksError('[Errno {0:#04x}]: {1}'.format(resp[1], error)) | |||||
binded = await self.read_address() | binded = await self.read_address() | ||||