| @@ -7,7 +7,7 @@ __version__ = '0.1.1' | |||
| __all__ = ('Socks4Protocol', 'Socks5Protocol', 'Socks4Auth', | |||
| 'Socks5Auth', 'Socks4Addr', 'Socks5Addr', 'SocksError', | |||
| 'NoAcceptableAuthMethods', 'LoginAuthenticationFailed', | |||
| 'NoAcceptableAuthMethods', 'LoginAuthenticationFailed', 'SocksConnectionError', | |||
| '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, | |||
| 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') | |||
| @@ -1,4 +1,9 @@ | |||
| import socket | |||
| import aiohttp | |||
| import ipaddress | |||
| from aiohttp.errors import ProxyConnectionError | |||
| from .errors import SocksError, SocksConnectionError | |||
| from . import create_connection | |||
| __all__ = ('SocksConnector',) | |||
| @@ -46,9 +51,14 @@ class SocksConnector(aiohttp.TCPConnector): | |||
| proto=hinfo['proto'], flags=hinfo['flags'], local_addr=self._local_addr) | |||
| return transp, proto | |||
| except OSError as e: | |||
| except (OSError, SocksError, SocksConnectionError) as e: | |||
| exc = e | |||
| 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): | |||
| pass | |||
| class SocksConnectionError(OSError): | |||
| pass | |||
| @@ -106,7 +106,7 @@ class Socks4Protocol(SocksProtocol): | |||
| raise InvalidServerReply('SOCKS4 proxy server sent invalid data') | |||
| if resp[1] != c.SOCKS4_GRANTED: | |||
| 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] | |||
| return (host, port), binded | |||
| @@ -138,7 +138,7 @@ class Socks5Protocol(SocksProtocol): | |||
| chosen_auth = await self.read_response(2) | |||
| 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: | |||
| req = [0x01, chr(len(self._auth.login)).encode(), self._auth.login, | |||
| @@ -149,11 +149,11 @@ class Socks5Protocol(SocksProtocol): | |||
| if auth_status[0] != 0x01: | |||
| raise InvalidServerReply('SOCKS5 proxy server sent invalid data') | |||
| if auth_status[1] != c.SOCKS5_GRANTED: | |||
| raise LoginAuthenticationFailed | |||
| raise LoginAuthenticationFailed('SOCKS5 authentication failed') | |||
| # offered auth methods rejected | |||
| elif chosen_auth[1] != c.SOCKS5_AUTH_ANONYMOUS: | |||
| if chosen_auth[1] == c.SOCKS5_AUTH_NO_ACCEPTABLE_METHODS: | |||
| raise NoAcceptableAuthMethods | |||
| raise NoAcceptableAuthMethods('All offered SOCKS5 authentication methods were rejected') | |||
| else: | |||
| raise InvalidServerReply('SOCKS5 proxy server sent invalid data') | |||
| @@ -165,10 +165,10 @@ class Socks5Protocol(SocksProtocol): | |||
| resp = await self.read_response(3) | |||
| if resp[0] != c.SOCKS_VER5: | |||
| raise InvalidServerVersion | |||
| raise InvalidServerVersion('SOCKS5 proxy server sent invalid version') | |||
| if resp[1] != c.SOCKS5_GRANTED: | |||
| 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() | |||