1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
|
import socket
from ._types import ProxyType
from ._errors import ProxyConnectionError, ProxyTimeoutError
from ._helpers import parse_proxy_url
from ._stream_sync import SyncSocketStream
from ._proto_socks5_sync import Socks5Proto
from ._proto_http_sync import HttpProto
from ._proto_socks4_sync import Socks4Proto
DEFAULT_TIMEOUT = 60
class SyncProxy:
def connect(self, dest_host, dest_port, timeout=None, _socket=None):
raise NotImplementedError() # pragma: no cover
@property
def proxy_host(self):
raise NotImplementedError() # pragma: no cover
@property
def proxy_port(self):
raise NotImplementedError() # pragma: no cover
class Proxy:
@classmethod
def create(cls, proxy_type: ProxyType, host: str, port: int,
username: str = None, password: str = None,
rdns: bool = None) -> SyncProxy:
if proxy_type == ProxyType.SOCKS4:
return Socks4Proxy(
proxy_host=host,
proxy_port=port,
user_id=username,
rdns=rdns
)
if proxy_type == ProxyType.SOCKS5:
return Socks5Proxy(
proxy_host=host,
proxy_port=port,
username=username,
password=password,
rdns=rdns
)
if proxy_type == ProxyType.HTTP:
return HttpProxy(
proxy_host=host,
proxy_port=port,
username=username,
password=password
)
raise ValueError('Invalid proxy type: ' # pragma: no cover
'{}'.format(proxy_type))
@classmethod
def from_url(cls, url: str, **kwargs) -> SyncProxy:
proxy_type, host, port, username, password = parse_proxy_url(url)
return cls.create(
proxy_type=proxy_type,
host=host,
port=port,
username=username,
password=password,
**kwargs
)
class SyncProxyConnection(SyncProxy):
def __init__(self, proxy_host, proxy_port):
self._proxy_host = proxy_host
self._proxy_port = proxy_port
self._dest_host = None
self._dest_port = None
self._timeout = None
self._stream = SyncSocketStream()
def connect(self, dest_host, dest_port, timeout=None, _socket=None):
if timeout is None:
timeout = DEFAULT_TIMEOUT
self._dest_host = dest_host
self._dest_port = dest_port
self._timeout = timeout
try:
self._stream.open_connection(
host=self._proxy_host,
port=self._proxy_port,
timeout=timeout,
_socket=_socket
)
self.negotiate()
except socket.timeout as e:
self._stream.close()
raise ProxyTimeoutError('Proxy connection timed out: %s'
% self._timeout) from e
except OSError as e:
self._stream.close()
msg = ('Can not connect to proxy %s:%s [%s]' %
(self._proxy_host, self._proxy_port, e.strerror))
raise ProxyConnectionError(e.errno, msg) from e
except Exception:
self._stream.close()
raise
return self._stream.socket
def negotiate(self):
raise NotImplementedError
@property
def proxy_host(self):
return self._proxy_host
@property
def proxy_port(self):
return self._proxy_port
class Socks5Proxy(SyncProxyConnection):
def __init__(self, proxy_host, proxy_port,
username=None, password=None, rdns=None):
super().__init__(
proxy_host=proxy_host,
proxy_port=proxy_port
)
self._username = username
self._password = password
self._rdns = rdns
def negotiate(self):
proto = Socks5Proto(
stream=self._stream,
dest_host=self._dest_host,
dest_port=self._dest_port,
username=self._username,
password=self._password,
rdns=self._rdns
)
proto.negotiate()
class Socks4Proxy(SyncProxyConnection):
def __init__(self, proxy_host, proxy_port,
user_id=None, rdns=None):
super().__init__(
proxy_host=proxy_host,
proxy_port=proxy_port
)
self._user_id = user_id
self._rdns = rdns
def negotiate(self):
proto = Socks4Proto(
stream=self._stream,
dest_host=self._dest_host,
dest_port=self._dest_port,
user_id=self._user_id,
rdns=self._rdns
)
proto.negotiate()
class HttpProxy(SyncProxyConnection):
def __init__(self, proxy_host, proxy_port, username=None, password=None):
super().__init__(
proxy_host=proxy_host,
proxy_port=proxy_port
)
self._username = username
self._password = password
def negotiate(self):
proto = HttpProto(
stream=self._stream,
dest_host=self._dest_host,
dest_port=self._dest_port,
username=self._username,
password=self._password
)
proto.negotiate()
|