mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2025-07-13 09:32:27 +03:00
Always use python-socks when available
Relying on Python 3.6 or above to be installed to unconditionally use this library would break user's code, because this is a new optional dependency that users may not have installed. Instead, always use the new library when available, which should work better than pysocks because it natively supports asyncio.
This commit is contained in:
parent
ab3c5acf9a
commit
f2f43336c6
|
@ -8,6 +8,11 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
ssl_mod = None
|
ssl_mod = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
import python_socks
|
||||||
|
except ImportError:
|
||||||
|
python_socks = None
|
||||||
|
|
||||||
from ...errors import InvalidChecksumError
|
from ...errors import InvalidChecksumError
|
||||||
from ... import helpers
|
from ... import helpers
|
||||||
|
|
||||||
|
@ -47,7 +52,6 @@ class Connection(abc.ABC):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _wrap_socket_ssl(sock):
|
def _wrap_socket_ssl(sock):
|
||||||
|
|
||||||
if ssl_mod is None:
|
if ssl_mod is None:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
'Cannot use proxy that requires SSL '
|
'Cannot use proxy that requires SSL '
|
||||||
|
@ -61,19 +65,17 @@ class Connection(abc.ABC):
|
||||||
ciphers='ADH-AES256-SHA')
|
ciphers='ADH-AES256-SHA')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parse_proxy(library, proxy_type, addr, port, rdns=True, username=None, password=None):
|
def _parse_proxy(proxy_type, addr, port, rdns=True, username=None, password=None):
|
||||||
|
|
||||||
if isinstance(proxy_type, str):
|
if isinstance(proxy_type, str):
|
||||||
proxy_type = proxy_type.lower()
|
proxy_type = proxy_type.lower()
|
||||||
|
|
||||||
if library == "python-socks":
|
# Always prefer `python_socks` when available
|
||||||
|
if python_socks:
|
||||||
from python_socks import ProxyType
|
from python_socks import ProxyType
|
||||||
|
|
||||||
# We do the check for numerical values here
|
# We do the check for numerical values here
|
||||||
# to be backwards compatible with PySocks proxy format,
|
# to be backwards compatible with PySocks proxy format,
|
||||||
# (since socks.SOCKS5 == 2, socks.SOCKS4 == 1, socks.HTTP == 3)
|
# (since socks.SOCKS5 == 2, socks.SOCKS4 == 1, socks.HTTP == 3)
|
||||||
|
|
||||||
if proxy_type == ProxyType.SOCKS5 or proxy_type == 2 or proxy_type == "socks5":
|
if proxy_type == ProxyType.SOCKS5 or proxy_type == 2 or proxy_type == "socks5":
|
||||||
protocol = ProxyType.SOCKS5
|
protocol = ProxyType.SOCKS5
|
||||||
elif proxy_type == ProxyType.SOCKS4 or proxy_type == 1 or proxy_type == "socks4":
|
elif proxy_type == ProxyType.SOCKS4 or proxy_type == 1 or proxy_type == "socks4":
|
||||||
|
@ -83,14 +85,10 @@ class Connection(abc.ABC):
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unknown proxy protocol type: {}".format(proxy_type))
|
raise ValueError("Unknown proxy protocol type: {}".format(proxy_type))
|
||||||
|
|
||||||
# NOTE: We return a tuple compatible with the
|
# This tuple must be compatible with `python_socks`' `Proxy.create()` signature
|
||||||
# signature (order) of python_socks `Proxy.create()`
|
|
||||||
# I.E.: (proxy_type, host, port, username, password, rdns)
|
|
||||||
|
|
||||||
return protocol, addr, port, username, password, rdns
|
return protocol, addr, port, username, password, rdns
|
||||||
|
|
||||||
elif library == "pysocks":
|
else:
|
||||||
|
|
||||||
from socks import SOCKS5, SOCKS4, HTTP
|
from socks import SOCKS5, SOCKS4, HTTP
|
||||||
|
|
||||||
if proxy_type == 2 or proxy_type == "socks5":
|
if proxy_type == 2 or proxy_type == "socks5":
|
||||||
|
@ -102,23 +100,19 @@ class Connection(abc.ABC):
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unknown proxy protocol type: {}".format(proxy_type))
|
raise ValueError("Unknown proxy protocol type: {}".format(proxy_type))
|
||||||
|
|
||||||
# NOTE: We return a tuple compatible with the
|
# This tuple must be compatible with `PySocks`' `socksocket.set_proxy()` signature
|
||||||
# signature of `PySocks` `socksocket.set_proxy()`
|
|
||||||
# I.E.: (proxy_type, addr, port, rdns, username, password)
|
|
||||||
|
|
||||||
return protocol, addr, port, rdns, username, password
|
return protocol, addr, port, rdns, username, password
|
||||||
|
|
||||||
else:
|
|
||||||
raise ValueError("Unknown proxy library: {}".format(library))
|
|
||||||
|
|
||||||
async def _proxy_connect(self, timeout=None, local_addr=None):
|
async def _proxy_connect(self, timeout=None, local_addr=None):
|
||||||
|
if isinstance(self._proxy, (tuple, list)):
|
||||||
|
parsed = self._parse_proxy(*self._proxy)
|
||||||
|
elif isinstance(self._proxy, dict):
|
||||||
|
parsed = self._parse_proxy(**self._proxy)
|
||||||
|
else:
|
||||||
|
raise TypeError("Proxy of unknown format: {}".format(type(self._proxy)))
|
||||||
|
|
||||||
# Use `python-socks` library for newer Python >= 3.6
|
# Always prefer `python_socks` when available
|
||||||
# Use `PySocks` library for older Python <= 3.5
|
if python_socks:
|
||||||
if sys.version_info >= (3, 6):
|
|
||||||
|
|
||||||
import python_socks
|
|
||||||
|
|
||||||
# python_socks internal errors are not inherited from
|
# python_socks internal errors are not inherited from
|
||||||
# builtin IOError (just from Exception). Instead of adding those
|
# builtin IOError (just from Exception). Instead of adding those
|
||||||
# in exceptions clauses everywhere through the code, we
|
# in exceptions clauses everywhere through the code, we
|
||||||
|
@ -130,16 +124,6 @@ class Connection(abc.ABC):
|
||||||
|
|
||||||
from python_socks.async_.asyncio import Proxy
|
from python_socks.async_.asyncio import Proxy
|
||||||
|
|
||||||
# We expect a dict/tuple in the format of `PySocks` (for compatibility)
|
|
||||||
# I.E.: (proxy_type, addr, port, rdns, username, password).
|
|
||||||
|
|
||||||
if isinstance(self._proxy, (tuple, list)):
|
|
||||||
parsed = self._parse_proxy("python-socks", *self._proxy)
|
|
||||||
elif isinstance(self._proxy, dict):
|
|
||||||
parsed = self._parse_proxy("python-socks", **self._proxy)
|
|
||||||
else:
|
|
||||||
raise TypeError("Proxy of unknown format!", type(self._proxy))
|
|
||||||
|
|
||||||
proxy = Proxy.create(*parsed)
|
proxy = Proxy.create(*parsed)
|
||||||
|
|
||||||
# WARNING: If `local_addr` is set we use manual socket creation, because,
|
# WARNING: If `local_addr` is set we use manual socket creation, because,
|
||||||
|
@ -154,13 +138,11 @@ class Connection(abc.ABC):
|
||||||
timeout=timeout
|
timeout=timeout
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|
||||||
# Here we start manual setup of the socket.
|
# Here we start manual setup of the socket.
|
||||||
# The `address` represents the proxy ip and proxy port,
|
# The `address` represents the proxy ip and proxy port,
|
||||||
# not the destination one (!), because the socket
|
# not the destination one (!), because the socket
|
||||||
# connects to the proxy server, not destination server.
|
# connects to the proxy server, not destination server.
|
||||||
# IPv family is also checked on proxy address.
|
# IPv family is also checked on proxy address.
|
||||||
|
|
||||||
if ':' in proxy.proxy_host:
|
if ':' in proxy.proxy_host:
|
||||||
mode, address = socket.AF_INET6, (proxy.proxy_host, proxy.proxy_port, 0, 0)
|
mode, address = socket.AF_INET6, (proxy.proxy_host, proxy.proxy_port, 0, 0)
|
||||||
else:
|
else:
|
||||||
|
@ -180,7 +162,6 @@ class Connection(abc.ABC):
|
||||||
# As our socket is already created and connected,
|
# As our socket is already created and connected,
|
||||||
# this call sets the destination host/port and
|
# this call sets the destination host/port and
|
||||||
# starts protocol negotiations with the proxy server.
|
# starts protocol negotiations with the proxy server.
|
||||||
|
|
||||||
sock = await proxy.connect(
|
sock = await proxy.connect(
|
||||||
dest_host=self._ip,
|
dest_host=self._ip,
|
||||||
dest_port=self._port,
|
dest_port=self._port,
|
||||||
|
@ -189,23 +170,11 @@ class Connection(abc.ABC):
|
||||||
)
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
import socks
|
import socks
|
||||||
|
|
||||||
# We expect a dict/tuple in the format of `PySocks`.
|
|
||||||
# I.E.: (proxy_type, addr, port, rdns, username, password).
|
|
||||||
|
|
||||||
if isinstance(self._proxy, (tuple, list)):
|
|
||||||
parsed = self._parse_proxy("pysocks", *self._proxy)
|
|
||||||
elif isinstance(self._proxy, dict):
|
|
||||||
parsed = self._parse_proxy("pysocks", **self._proxy)
|
|
||||||
else:
|
|
||||||
raise TypeError("Proxy of unknown format!", type(self._proxy))
|
|
||||||
|
|
||||||
# Here `address` represents destination address (not proxy), because of
|
# Here `address` represents destination address (not proxy), because of
|
||||||
# the `PySocks` implementation of the connection routine.
|
# the `PySocks` implementation of the connection routine.
|
||||||
# IPv family is checked on proxy address, not destination address.
|
# IPv family is checked on proxy address, not destination address.
|
||||||
|
|
||||||
if ':' in parsed[1]:
|
if ':' in parsed[1]:
|
||||||
mode, address = socket.AF_INET6, (self._ip, self._port, 0, 0)
|
mode, address = socket.AF_INET6, (self._ip, self._port, 0, 0)
|
||||||
else:
|
else:
|
||||||
|
@ -230,13 +199,10 @@ class Connection(abc.ABC):
|
||||||
return sock
|
return sock
|
||||||
|
|
||||||
async def _connect(self, timeout=None, ssl=None):
|
async def _connect(self, timeout=None, ssl=None):
|
||||||
|
|
||||||
if self._local_addr is not None:
|
if self._local_addr is not None:
|
||||||
|
|
||||||
# NOTE: If port is not specified, we use 0 port
|
# NOTE: If port is not specified, we use 0 port
|
||||||
# to notify the OS that port should be chosen randomly
|
# to notify the OS that port should be chosen randomly
|
||||||
# from the available ones.
|
# from the available ones.
|
||||||
|
|
||||||
if isinstance(self._local_addr, tuple) and len(self._local_addr) == 2:
|
if isinstance(self._local_addr, tuple) and len(self._local_addr) == 2:
|
||||||
local_addr = self._local_addr
|
local_addr = self._local_addr
|
||||||
elif isinstance(self._local_addr, str):
|
elif isinstance(self._local_addr, str):
|
||||||
|
@ -255,7 +221,6 @@ class Connection(abc.ABC):
|
||||||
local_addr=local_addr
|
local_addr=local_addr
|
||||||
), timeout=timeout)
|
), timeout=timeout)
|
||||||
else:
|
else:
|
||||||
|
|
||||||
# Proxy setup, connection and negotiation is performed here.
|
# Proxy setup, connection and negotiation is performed here.
|
||||||
sock = await self._proxy_connect(
|
sock = await self._proxy_connect(
|
||||||
timeout=timeout,
|
timeout=timeout,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user