Path: blob/master/venv/Lib/site-packages/urllib3/contrib/socks.py
811 views
# -*- coding: utf-8 -*-1"""2This module contains provisional support for SOCKS proxies from within3urllib3. This module supports SOCKS4, SOCKS4A (an extension of SOCKS4), and4SOCKS5. To enable its functionality, either install PySocks or install this5module with the ``socks`` extra.67The SOCKS implementation supports the full range of urllib3 features. It also8supports the following SOCKS features:910- SOCKS4A (``proxy_url='socks4a://...``)11- SOCKS4 (``proxy_url='socks4://...``)12- SOCKS5 with remote DNS (``proxy_url='socks5h://...``)13- SOCKS5 with local DNS (``proxy_url='socks5://...``)14- Usernames and passwords for the SOCKS proxy1516.. note::17It is recommended to use ``socks5h://`` or ``socks4a://`` schemes in18your ``proxy_url`` to ensure that DNS resolution is done from the remote19server instead of client-side when connecting to a domain name.2021SOCKS4 supports IPv4 and domain names with the SOCKS4A extension. SOCKS522supports IPv4, IPv6, and domain names.2324When connecting to a SOCKS4 proxy the ``username`` portion of the ``proxy_url``25will be sent as the ``userid`` section of the SOCKS request::2627proxy_url="socks4a://<userid>@proxy-host"2829When connecting to a SOCKS5 proxy the ``username`` and ``password`` portion30of the ``proxy_url`` will be sent as the username/password to authenticate31with the proxy::3233proxy_url="socks5h://<username>:<password>@proxy-host"3435"""36from __future__ import absolute_import3738try:39import socks40except ImportError:41import warnings42from ..exceptions import DependencyWarning4344warnings.warn(45(46"SOCKS support in urllib3 requires the installation of optional "47"dependencies: specifically, PySocks. For more information, see "48"https://urllib3.readthedocs.io/en/latest/contrib.html#socks-proxies"49),50DependencyWarning,51)52raise5354from socket import error as SocketError, timeout as SocketTimeout5556from ..connection import HTTPConnection, HTTPSConnection57from ..connectionpool import HTTPConnectionPool, HTTPSConnectionPool58from ..exceptions import ConnectTimeoutError, NewConnectionError59from ..poolmanager import PoolManager60from ..util.url import parse_url6162try:63import ssl64except ImportError:65ssl = None666768class SOCKSConnection(HTTPConnection):69"""70A plain-text HTTP connection that connects via a SOCKS proxy.71"""7273def __init__(self, *args, **kwargs):74self._socks_options = kwargs.pop("_socks_options")75super(SOCKSConnection, self).__init__(*args, **kwargs)7677def _new_conn(self):78"""79Establish a new connection via the SOCKS proxy.80"""81extra_kw = {}82if self.source_address:83extra_kw["source_address"] = self.source_address8485if self.socket_options:86extra_kw["socket_options"] = self.socket_options8788try:89conn = socks.create_connection(90(self.host, self.port),91proxy_type=self._socks_options["socks_version"],92proxy_addr=self._socks_options["proxy_host"],93proxy_port=self._socks_options["proxy_port"],94proxy_username=self._socks_options["username"],95proxy_password=self._socks_options["password"],96proxy_rdns=self._socks_options["rdns"],97timeout=self.timeout,98**extra_kw99)100101except SocketTimeout:102raise ConnectTimeoutError(103self,104"Connection to %s timed out. (connect timeout=%s)"105% (self.host, self.timeout),106)107108except socks.ProxyError as e:109# This is fragile as hell, but it seems to be the only way to raise110# useful errors here.111if e.socket_err:112error = e.socket_err113if isinstance(error, SocketTimeout):114raise ConnectTimeoutError(115self,116"Connection to %s timed out. (connect timeout=%s)"117% (self.host, self.timeout),118)119else:120raise NewConnectionError(121self, "Failed to establish a new connection: %s" % error122)123else:124raise NewConnectionError(125self, "Failed to establish a new connection: %s" % e126)127128except SocketError as e: # Defensive: PySocks should catch all these.129raise NewConnectionError(130self, "Failed to establish a new connection: %s" % e131)132133return conn134135136# We don't need to duplicate the Verified/Unverified distinction from137# urllib3/connection.py here because the HTTPSConnection will already have been138# correctly set to either the Verified or Unverified form by that module. This139# means the SOCKSHTTPSConnection will automatically be the correct type.140class SOCKSHTTPSConnection(SOCKSConnection, HTTPSConnection):141pass142143144class SOCKSHTTPConnectionPool(HTTPConnectionPool):145ConnectionCls = SOCKSConnection146147148class SOCKSHTTPSConnectionPool(HTTPSConnectionPool):149ConnectionCls = SOCKSHTTPSConnection150151152class SOCKSProxyManager(PoolManager):153"""154A version of the urllib3 ProxyManager that routes connections via the155defined SOCKS proxy.156"""157158pool_classes_by_scheme = {159"http": SOCKSHTTPConnectionPool,160"https": SOCKSHTTPSConnectionPool,161}162163def __init__(164self,165proxy_url,166username=None,167password=None,168num_pools=10,169headers=None,170**connection_pool_kw171):172parsed = parse_url(proxy_url)173174if username is None and password is None and parsed.auth is not None:175split = parsed.auth.split(":")176if len(split) == 2:177username, password = split178if parsed.scheme == "socks5":179socks_version = socks.PROXY_TYPE_SOCKS5180rdns = False181elif parsed.scheme == "socks5h":182socks_version = socks.PROXY_TYPE_SOCKS5183rdns = True184elif parsed.scheme == "socks4":185socks_version = socks.PROXY_TYPE_SOCKS4186rdns = False187elif parsed.scheme == "socks4a":188socks_version = socks.PROXY_TYPE_SOCKS4189rdns = True190else:191raise ValueError("Unable to determine SOCKS version from %s" % proxy_url)192193self.proxy_url = proxy_url194195socks_options = {196"socks_version": socks_version,197"proxy_host": parsed.host,198"proxy_port": parsed.port,199"username": username,200"password": password,201"rdns": rdns,202}203connection_pool_kw["_socks_options"] = socks_options204205super(SOCKSProxyManager, self).__init__(206num_pools, headers, **connection_pool_kw207)208209self.pool_classes_by_scheme = SOCKSProxyManager.pool_classes_by_scheme210211212