| @@ -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() | ||||