Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
socks.py848 linesDownload Raw Back to site-packages
1from base64 import b64encode2try:3    from collections.abc import Callable4except ImportError:5    from collections import Callable6from errno import EOPNOTSUPP, EINVAL, EAGAIN7import functools8from io import BytesIO9import logging10import os11from os import SEEK_CUR12import socket13import struct14import sys15 16__version__ = "1.7.1"17 18 19if os.name == "nt" and sys.version_info < (3, 0):20    try:21        import win_inet_pton22    except ImportError:23        raise ImportError(24            "To run PySocks on Windows you must install win_inet_pton")25 26log = logging.getLogger(__name__)27 28PROXY_TYPE_SOCKS4 = SOCKS4 = 129PROXY_TYPE_SOCKS5 = SOCKS5 = 230PROXY_TYPE_HTTP = HTTP = 331 32PROXY_TYPES = {"SOCKS4": SOCKS4, "SOCKS5": SOCKS5, "HTTP": HTTP}33PRINTABLE_PROXY_TYPES = dict(zip(PROXY_TYPES.values(), PROXY_TYPES.keys()))34 35_orgsocket = _orig_socket = socket.socket36 37 38def set_self_blocking(function):39 40    @functools.wraps(function)41    def wrapper(*args, **kwargs):42        self = args[0]43        try:44            _is_blocking = self.gettimeout()45            if _is_blocking == 0:46                self.setblocking(True)47            return function(*args, **kwargs)48        except Exception as e:49            raise50        finally:51            # set orgin blocking52            if _is_blocking == 0:53                self.setblocking(False)54    return wrapper55 56 57class ProxyError(IOError):58    """Socket_err contains original socket.error exception."""59    def __init__(self, msg, socket_err=None):60        self.msg = msg61        self.socket_err = socket_err62 63        if socket_err:64            self.msg += ": {}".format(socket_err)65 66    def __str__(self):67        return self.msg68 69 70class GeneralProxyError(ProxyError):71    pass72 73 74class ProxyConnectionError(ProxyError):75    pass76 77 78class SOCKS5AuthError(ProxyError):79    pass80 81 82class SOCKS5Error(ProxyError):83    pass84 85 86class SOCKS4Error(ProxyError):87    pass88 89 90class HTTPError(ProxyError):91    pass92 93SOCKS4_ERRORS = {94    0x5B: "Request rejected or failed",95    0x5C: ("Request rejected because SOCKS server cannot connect to identd on"96           " the client"),97    0x5D: ("Request rejected because the client program and identd report"98           " different user-ids")99}100 101SOCKS5_ERRORS = {102    0x01: "General SOCKS server failure",103    0x02: "Connection not allowed by ruleset",104    0x03: "Network unreachable",105    0x04: "Host unreachable",106    0x05: "Connection refused",107    0x06: "TTL expired",108    0x07: "Command not supported, or protocol error",109    0x08: "Address type not supported"110}111 112DEFAULT_PORTS = {SOCKS4: 1080, SOCKS5: 1080, HTTP: 8080}113 114 115def set_default_proxy(proxy_type=None, addr=None, port=None, rdns=True,116                      username=None, password=None):117    """Sets a default proxy.118 119    All further socksocket objects will use the default unless explicitly120    changed. All parameters are as for socket.set_proxy()."""121    socksocket.default_proxy = (proxy_type, addr, port, rdns,122                                username.encode() if username else None,123                                password.encode() if password else None)124 125 126def setdefaultproxy(*args, **kwargs):127    if "proxytype" in kwargs:128        kwargs["proxy_type"] = kwargs.pop("proxytype")129    return set_default_proxy(*args, **kwargs)130 131 132def get_default_proxy():133    """Returns the default proxy, set by set_default_proxy."""134    return socksocket.default_proxy135 136getdefaultproxy = get_default_proxy137 138 139def wrap_module(module):140    """Attempts to replace a module's socket library with a SOCKS socket.141 142    Must set a default proxy using set_default_proxy(...) first. This will143    only work on modules that import socket directly into the namespace;144    most of the Python Standard Library falls into this category."""145    if socksocket.default_proxy:146        module.socket.socket = socksocket147    else:148        raise GeneralProxyError("No default proxy specified")149 150wrapmodule = wrap_module151 152 153def create_connection(dest_pair,154                      timeout=None, source_address=None,155                      proxy_type=None, proxy_addr=None,156                      proxy_port=None, proxy_rdns=True,157                      proxy_username=None, proxy_password=None,158                      socket_options=None):159    """create_connection(dest_pair, *[, timeout], **proxy_args) -> socket object160 161    Like socket.create_connection(), but connects to proxy162    before returning the socket object.163 164    dest_pair - 2-tuple of (IP/hostname, port).165    **proxy_args - Same args passed to socksocket.set_proxy() if present.166    timeout - Optional socket timeout value, in seconds.167    source_address - tuple (host, port) for the socket to bind to as its source168    address before connecting (only for compatibility)169    """170    # Remove IPv6 brackets on the remote address and proxy address.171    remote_host, remote_port = dest_pair172    if remote_host.startswith("["):173        remote_host = remote_host.strip("[]")174    if proxy_addr and proxy_addr.startswith("["):175        proxy_addr = proxy_addr.strip("[]")176 177    err = None178 179    # Allow the SOCKS proxy to be on IPv4 or IPv6 addresses.180    for r in socket.getaddrinfo(proxy_addr, proxy_port, 0, socket.SOCK_STREAM):181        family, socket_type, proto, canonname, sa = r182        sock = None183        try:184            sock = socksocket(family, socket_type, proto)185 186            if socket_options:187                for opt in socket_options:188                    sock.setsockopt(*opt)189 190            if isinstance(timeout, (int, float)):191                sock.settimeout(timeout)192 193            if proxy_type:194                sock.set_proxy(proxy_type, proxy_addr, proxy_port, proxy_rdns,195                               proxy_username, proxy_password)196            if source_address:197                sock.bind(source_address)198 199            sock.connect((remote_host, remote_port))200            return sock201 202        except (socket.error, ProxyError) as e:203            err = e204            if sock:205                sock.close()206                sock = None207 208    if err:209        raise err210 211    raise socket.error("gai returned empty list.")212 213 214class _BaseSocket(socket.socket):215    """Allows Python 2 delegated methods such as send() to be overridden."""216    def __init__(self, *pos, **kw):217        _orig_socket.__init__(self, *pos, **kw)218 219        self._savedmethods = dict()220        for name in self._savenames:221            self._savedmethods[name] = getattr(self, name)222            delattr(self, name)  # Allows normal overriding mechanism to work223 224    _savenames = list()225 226 227def _makemethod(name):228    return lambda self, *pos, **kw: self._savedmethods[name](*pos, **kw)229for name in ("sendto", "send", "recvfrom", "recv"):230    method = getattr(_BaseSocket, name, None)231 232    # Determine if the method is not defined the usual way233    # as a function in the class.234    # Python 2 uses __slots__, so there are descriptors for each method,235    # but they are not functions.236    if not isinstance(method, Callable):237        _BaseSocket._savenames.append(name)238        setattr(_BaseSocket, name, _makemethod(name))239 240 241class socksocket(_BaseSocket):242    """socksocket([family[, type[, proto]]]) -> socket object243 244    Open a SOCKS enabled socket. The parameters are the same as245    those of the standard socket init. In order for SOCKS to work,246    you must specify family=AF_INET and proto=0.247    The "type" argument must be either SOCK_STREAM or SOCK_DGRAM.248    """249 250    default_proxy = None251 252    def __init__(self, family=socket.AF_INET, type=socket.SOCK_STREAM,253                 proto=0, *args, **kwargs):254        if type not in (socket.SOCK_STREAM, socket.SOCK_DGRAM):255            msg = "Socket type must be stream or datagram, not {!r}"256            raise ValueError(msg.format(type))257 258        super(socksocket, self).__init__(family, type, proto, *args, **kwargs)259        self._proxyconn = None  # TCP connection to keep UDP relay alive260 261        if self.default_proxy:262            self.proxy = self.default_proxy263        else:264            self.proxy = (None, None, None, None, None, None)265        self.proxy_sockname = None266        self.proxy_peername = None267 268        self._timeout = None269 270    def _readall(self, file, count):271        """Receive EXACTLY the number of bytes requested from the file object.272 273        Blocks until the required number of bytes have been received."""274        data = b""275        while len(data) < count:276            d = file.read(count - len(data))277            if not d:278                raise GeneralProxyError("Connection closed unexpectedly")279            data += d280        return data281 282    def settimeout(self, timeout):283        self._timeout = timeout284        try:285            # test if we're connected, if so apply timeout286            peer = self.get_proxy_peername()287            super(socksocket, self).settimeout(self._timeout)288        except socket.error:289            pass290 291    def gettimeout(self):292        return self._timeout293 294    def setblocking(self, v):295        if v:296            self.settimeout(None)297        else:298            self.settimeout(0.0)299 300    def set_proxy(self, proxy_type=None, addr=None, port=None, rdns=True,301                  username=None, password=None):302        """ Sets the proxy to be used.303 304        proxy_type -  The type of the proxy to be used. Three types305                        are supported: PROXY_TYPE_SOCKS4 (including socks4a),306                        PROXY_TYPE_SOCKS5 and PROXY_TYPE_HTTP307        addr -        The address of the server (IP or DNS).308        port -        The port of the server. Defaults to 1080 for SOCKS309                        servers and 8080 for HTTP proxy servers.310        rdns -        Should DNS queries be performed on the remote side311                       (rather than the local side). The default is True.312                       Note: This has no effect with SOCKS4 servers.313        username -    Username to authenticate with to the server.314                       The default is no authentication.315        password -    Password to authenticate with to the server.316                       Only relevant when username is also provided."""317        self.proxy = (proxy_type, addr, port, rdns,318                      username.encode() if username else None,319                      password.encode() if password else None)320 321    def setproxy(self, *args, **kwargs):322        if "proxytype" in kwargs:323            kwargs["proxy_type"] = kwargs.pop("proxytype")324        return self.set_proxy(*args, **kwargs)325 326    def bind(self, *pos, **kw):327        """Implements proxy connection for UDP sockets.328 329        Happens during the bind() phase."""330        (proxy_type, proxy_addr, proxy_port, rdns, username,331         password) = self.proxy332        if not proxy_type or self.type != socket.SOCK_DGRAM:333            return _orig_socket.bind(self, *pos, **kw)334 335        if self._proxyconn:336            raise socket.error(EINVAL, "Socket already bound to an address")337        if proxy_type != SOCKS5:338            msg = "UDP only supported by SOCKS5 proxy type"339            raise socket.error(EOPNOTSUPP, msg)340        super(socksocket, self).bind(*pos, **kw)341 342        # Need to specify actual local port because343        # some relays drop packets if a port of zero is specified.344        # Avoid specifying host address in case of NAT though.345        _, port = self.getsockname()346        dst = ("0", port)347 348        self._proxyconn = _orig_socket()349        proxy = self._proxy_addr()350        self._proxyconn.connect(proxy)351 352        UDP_ASSOCIATE = b"\x03"353        _, relay = self._SOCKS5_request(self._proxyconn, UDP_ASSOCIATE, dst)354 355        # The relay is most likely on the same host as the SOCKS proxy,356        # but some proxies return a private IP address (10.x.y.z)357        host, _ = proxy358        _, port = relay359        super(socksocket, self).connect((host, port))360        super(socksocket, self).settimeout(self._timeout)361        self.proxy_sockname = ("0.0.0.0", 0)  # Unknown362 363    def sendto(self, bytes, *args, **kwargs):364        if self.type != socket.SOCK_DGRAM:365            return super(socksocket, self).sendto(bytes, *args, **kwargs)366        if not self._proxyconn:367            self.bind(("", 0))368 369        address = args[-1]370        flags = args[:-1]371 372        header = BytesIO()373        RSV = b"\x00\x00"374        header.write(RSV)375        STANDALONE = b"\x00"376        header.write(STANDALONE)377        self._write_SOCKS5_address(address, header)378 379        sent = super(socksocket, self).send(header.getvalue() + bytes, *flags,380                                            **kwargs)381        return sent - header.tell()382 383    def send(self, bytes, flags=0, **kwargs):384        if self.type == socket.SOCK_DGRAM:385            return self.sendto(bytes, flags, self.proxy_peername, **kwargs)386        else:387            return super(socksocket, self).send(bytes, flags, **kwargs)388 389    def recvfrom(self, bufsize, flags=0):390        if self.type != socket.SOCK_DGRAM:391            return super(socksocket, self).recvfrom(bufsize, flags)392        if not self._proxyconn:393            self.bind(("", 0))394 395        buf = BytesIO(super(socksocket, self).recv(bufsize + 1024, flags))396        buf.seek(2, SEEK_CUR)397        frag = buf.read(1)398        if ord(frag):399            raise NotImplementedError("Received UDP packet fragment")400        fromhost, fromport = self._read_SOCKS5_address(buf)401 402        if self.proxy_peername:403            peerhost, peerport = self.proxy_peername404            if fromhost != peerhost or peerport not in (0, fromport):405                raise socket.error(EAGAIN, "Packet filtered")406 407        return (buf.read(bufsize), (fromhost, fromport))408 409    def recv(self, *pos, **kw):410        bytes, _ = self.recvfrom(*pos, **kw)411        return bytes412 413    def close(self):414        if self._proxyconn:415            self._proxyconn.close()416        return super(socksocket, self).close()417 418    def get_proxy_sockname(self):419        """Returns the bound IP address and port number at the proxy."""420        return self.proxy_sockname421 422    getproxysockname = get_proxy_sockname423 424    def get_proxy_peername(self):425        """426        Returns the IP and port number of the proxy.427        """428        return self.getpeername()429 430    getproxypeername = get_proxy_peername431 432    def get_peername(self):433        """Returns the IP address and port number of the destination machine.434 435        Note: get_proxy_peername returns the proxy."""436        return self.proxy_peername437 438    getpeername = get_peername439 440    def _negotiate_SOCKS5(self, *dest_addr):441        """Negotiates a stream connection through a SOCKS5 server."""442        CONNECT = b"\x01"443        self.proxy_peername, self.proxy_sockname = self._SOCKS5_request(444            self, CONNECT, dest_addr)445 446    def _SOCKS5_request(self, conn, cmd, dst):447        """448        Send SOCKS5 request with given command (CMD field) and449        address (DST field). Returns resolved DST address that was used.450        """451        proxy_type, addr, port, rdns, username, password = self.proxy452 453        writer = conn.makefile("wb")454        reader = conn.makefile("rb", 0)  # buffering=0 renamed in Python 3455        try:456            # First we'll send the authentication packages we support.457            if username and password:458                # The username/password details were supplied to the459                # set_proxy method so we support the USERNAME/PASSWORD460                # authentication (in addition to the standard none).461                writer.write(b"\x05\x02\x00\x02")462            else:463                # No username/password were entered, therefore we464                # only support connections with no authentication.465                writer.write(b"\x05\x01\x00")466 467            # We'll receive the server's response to determine which468            # method was selected469            writer.flush()470            chosen_auth = self._readall(reader, 2)471 472            if chosen_auth[0:1] != b"\x05":473                # Note: string[i:i+1] is used because indexing of a bytestring474                # via bytestring[i] yields an integer in Python 3475                raise GeneralProxyError(476                    "SOCKS5 proxy server sent invalid data")477 478            # Check the chosen authentication method479 480            if chosen_auth[1:2] == b"\x02":481                # Okay, we need to perform a basic username/password482                # authentication.483                if not (username and password):484                    # Although we said we don't support authentication, the485                    # server may still request basic username/password486                    # authentication487                    raise SOCKS5AuthError("No username/password supplied. "488                                          "Server requested username/password"489                                          " authentication")490 491                writer.write(b"\x01" + chr(len(username)).encode()492                             + username493                             + chr(len(password)).encode()494                             + password)495                writer.flush()496                auth_status = self._readall(reader, 2)497                if auth_status[0:1] != b"\x01":498                    # Bad response499                    raise GeneralProxyError(500                        "SOCKS5 proxy server sent invalid data")501                if auth_status[1:2] != b"\x00":502                    # Authentication failed503                    raise SOCKS5AuthError("SOCKS5 authentication failed")504 505                # Otherwise, authentication succeeded506 507            # No authentication is required if 0x00508            elif chosen_auth[1:2] != b"\x00":509                # Reaching here is always bad510                if chosen_auth[1:2] == b"\xFF":511                    raise SOCKS5AuthError(512                        "All offered SOCKS5 authentication methods were"513                        " rejected")514                else:515                    raise GeneralProxyError(516                        "SOCKS5 proxy server sent invalid data")517 518            # Now we can request the actual connection519            writer.write(b"\x05" + cmd + b"\x00")520            resolved = self._write_SOCKS5_address(dst, writer)521            writer.flush()522 523            # Get the response524            resp = self._readall(reader, 3)525            if resp[0:1] != b"\x05":526                raise GeneralProxyError(527                    "SOCKS5 proxy server sent invalid data")528 529            status = ord(resp[1:2])530            if status != 0x00:531                # Connection failed: server returned an error532                error = SOCKS5_ERRORS.get(status, "Unknown error")533                raise SOCKS5Error("{:#04x}: {}".format(status, error))534 535            # Get the bound address/port536            bnd = self._read_SOCKS5_address(reader)537 538            super(socksocket, self).settimeout(self._timeout)539            return (resolved, bnd)540        finally:541            reader.close()542            writer.close()543 544    def _write_SOCKS5_address(self, addr, file):545        """546        Return the host and port packed for the SOCKS5 protocol,547        and the resolved address as a tuple object.548        """549        host, port = addr550        proxy_type, _, _, rdns, username, password = self.proxy551        family_to_byte = {socket.AF_INET: b"\x01", socket.AF_INET6: b"\x04"}552 553        # If the given destination address is an IP address, we'll554        # use the IP address request even if remote resolving was specified.555        # Detect whether the address is IPv4/6 directly.556        for family in (socket.AF_INET, socket.AF_INET6):557            try:558                addr_bytes = socket.inet_pton(family, host)559                file.write(family_to_byte[family] + addr_bytes)560                host = socket.inet_ntop(family, addr_bytes)561                file.write(struct.pack(">H", port))562                return host, port563            except socket.error:564                continue565 566        # Well it's not an IP number, so it's probably a DNS name.567        if rdns:568            # Resolve remotely569            host_bytes = host.encode("idna")570            file.write(b"\x03" + chr(len(host_bytes)).encode() + host_bytes)571        else:572            # Resolve locally573            addresses = socket.getaddrinfo(host, port, socket.AF_UNSPEC,574                                           socket.SOCK_STREAM,575                                           socket.IPPROTO_TCP,576                                           socket.AI_ADDRCONFIG)577            # We can't really work out what IP is reachable, so just pick the578            # first.579            target_addr = addresses[0]580            family = target_addr[0]581            host = target_addr[4][0]582 583            addr_bytes = socket.inet_pton(family, host)584            file.write(family_to_byte[family] + addr_bytes)585            host = socket.inet_ntop(family, addr_bytes)586        file.write(struct.pack(">H", port))587        return host, port588 589    def _read_SOCKS5_address(self, file):590        atyp = self._readall(file, 1)591        if atyp == b"\x01":592            addr = socket.inet_ntoa(self._readall(file, 4))593        elif atyp == b"\x03":594            length = self._readall(file, 1)595            addr = self._readall(file, ord(length))596        elif atyp == b"\x04":597            addr = socket.inet_ntop(socket.AF_INET6, self._readall(file, 16))598        else:599            raise GeneralProxyError("SOCKS5 proxy server sent invalid data")600 601        port = struct.unpack(">H", self._readall(file, 2))[0]602        return addr, port603 604    def _negotiate_SOCKS4(self, dest_addr, dest_port):605        """Negotiates a connection through a SOCKS4 server."""606        proxy_type, addr, port, rdns, username, password = self.proxy607 608        writer = self.makefile("wb")609        reader = self.makefile("rb", 0)  # buffering=0 renamed in Python 3610        try:611            # Check if the destination address provided is an IP address612            remote_resolve = False613            try:614                addr_bytes = socket.inet_aton(dest_addr)615            except socket.error:616                # It's a DNS name. Check where it should be resolved.617                if rdns:618                    addr_bytes = b"\x00\x00\x00\x01"619                    remote_resolve = True620                else:621                    addr_bytes = socket.inet_aton(622                        socket.gethostbyname(dest_addr))623 624            # Construct the request packet625            writer.write(struct.pack(">BBH", 0x04, 0x01, dest_port))626            writer.write(addr_bytes)627 628            # The username parameter is considered userid for SOCKS4629            if username:630                writer.write(username)631            writer.write(b"\x00")632 633            # DNS name if remote resolving is required634            # NOTE: This is actually an extension to the SOCKS4 protocol635            # called SOCKS4A and may not be supported in all cases.636            if remote_resolve:637                writer.write(dest_addr.encode("idna") + b"\x00")638            writer.flush()639 640            # Get the response from the server641            resp = self._readall(reader, 8)642            if resp[0:1] != b"\x00":643                # Bad data644                raise GeneralProxyError(645                    "SOCKS4 proxy server sent invalid data")646 647            status = ord(resp[1:2])648            if status != 0x5A:649                # Connection failed: server returned an error650                error = SOCKS4_ERRORS.get(status, "Unknown error")651                raise SOCKS4Error("{:#04x}: {}".format(status, error))652 653            # Get the bound address/port654            self.proxy_sockname = (socket.inet_ntoa(resp[4:]),655                                   struct.unpack(">H", resp[2:4])[0])656            if remote_resolve:657                self.proxy_peername = socket.inet_ntoa(addr_bytes), dest_port658            else:659                self.proxy_peername = dest_addr, dest_port660        finally:661            reader.close()662            writer.close()663 664    def _negotiate_HTTP(self, dest_addr, dest_port):665        """Negotiates a connection through an HTTP server.666 667        NOTE: This currently only supports HTTP CONNECT-style proxies."""668        proxy_type, addr, port, rdns, username, password = self.proxy669 670        # If we need to resolve locally, we do this now671        addr = dest_addr if rdns else socket.gethostbyname(dest_addr)672 673        http_headers = [674            (b"CONNECT " + addr.encode("idna") + b":"675             + str(dest_port).encode() + b" HTTP/1.1"),676            b"Host: " + dest_addr.encode("idna")677        ]678 679        if username and password:680            http_headers.append(b"Proxy-Authorization: basic "681                                + b64encode(username + b":" + password))682 683        http_headers.append(b"\r\n")684 685        self.sendall(b"\r\n".join(http_headers))686 687        # We just need the first line to check if the connection was successful688        fobj = self.makefile()689        status_line = fobj.readline()690        fobj.close()691 692        if not status_line:693            raise GeneralProxyError("Connection closed unexpectedly")694 695        try:696            proto, status_code, status_msg = status_line.split(" ", 2)697        except ValueError:698            raise GeneralProxyError("HTTP proxy server sent invalid response")699 700        if not proto.startswith("HTTP/"):701            raise GeneralProxyError(702                "Proxy server does not appear to be an HTTP proxy")703 704        try:705            status_code = int(status_code)706        except ValueError:707            raise HTTPError(708                "HTTP proxy server did not return a valid HTTP status")709 710        if status_code != 200:711            error = "{}: {}".format(status_code, status_msg)712            if status_code in (400, 403, 405):713                # It's likely that the HTTP proxy server does not support the714                # CONNECT tunneling method715                error += ("\n[*] Note: The HTTP proxy server may not be"716                          " supported by PySocks (must be a CONNECT tunnel"717                          " proxy)")718            raise HTTPError(error)719 720        self.proxy_sockname = (b"0.0.0.0", 0)721        self.proxy_peername = addr, dest_port722 723    _proxy_negotiators = {724                           SOCKS4: _negotiate_SOCKS4,725                           SOCKS5: _negotiate_SOCKS5,726                           HTTP: _negotiate_HTTP727                         }728 729    @set_self_blocking730    def connect(self, dest_pair, catch_errors=None):731        """732        Connects to the specified destination through a proxy.733        Uses the same API as socket's connect().734        To select the proxy server, use set_proxy().735 736        dest_pair - 2-tuple of (IP/hostname, port).737        """738        if len(dest_pair) != 2 or dest_pair[0].startswith("["):739            # Probably IPv6, not supported -- raise an error, and hope740            # Happy Eyeballs (RFC6555) makes sure at least the IPv4741            # connection works...742            raise socket.error("PySocks doesn't support IPv6: %s"743                               % str(dest_pair))744 745        dest_addr, dest_port = dest_pair746 747        if self.type == socket.SOCK_DGRAM:748            if not self._proxyconn:749                self.bind(("", 0))750            dest_addr = socket.gethostbyname(dest_addr)751 752            # If the host address is INADDR_ANY or similar, reset the peer753            # address so that packets are received from any peer754            if dest_addr == "0.0.0.0" and not dest_port:755                self.proxy_peername = None756            else:757                self.proxy_peername = (dest_addr, dest_port)758            return759 760        (proxy_type, proxy_addr, proxy_port, rdns, username,761         password) = self.proxy762 763        # Do a minimal input check first764        if (not isinstance(dest_pair, (list, tuple))765                or len(dest_pair) != 2766                or not dest_addr767                or not isinstance(dest_port, int)):768            # Inputs failed, raise an error769            raise GeneralProxyError(770                "Invalid destination-connection (host, port) pair")771 772        # We set the timeout here so that we don't hang in connection or during773        # negotiation.774        super(socksocket, self).settimeout(self._timeout)775 776        if proxy_type is None:777            # Treat like regular socket object778            self.proxy_peername = dest_pair779            super(socksocket, self).settimeout(self._timeout)780            super(socksocket, self).connect((dest_addr, dest_port))781            return782 783        proxy_addr = self._proxy_addr()784 785        try:786            # Initial connection to proxy server.787            super(socksocket, self).connect(proxy_addr)788 789        except socket.error as error:790            # Error while connecting to proxy791            self.close()792            if not catch_errors:793                proxy_addr, proxy_port = proxy_addr794                proxy_server = "{}:{}".format(proxy_addr, proxy_port)795                printable_type = PRINTABLE_PROXY_TYPES[proxy_type]796 797                msg = "Error connecting to {} proxy {}".format(printable_type,798                                                                    proxy_server)799                log.debug("%s due to: %s", msg, error)800                raise ProxyConnectionError(msg, error)801            else:802                raise error803 804        else:805            # Connected to proxy server, now negotiate806            try:807                # Calls negotiate_{SOCKS4, SOCKS5, HTTP}808                negotiate = self._proxy_negotiators[proxy_type]809                negotiate(self, dest_addr, dest_port)810            except socket.error as error:811                if not catch_errors:812                    # Wrap socket errors813                    self.close()814                    raise GeneralProxyError("Socket error", error)815                else:816                    raise error817            except ProxyError:818                # Protocol error while negotiating with proxy819                self.close()820                raise821                822    @set_self_blocking823    def connect_ex(self, dest_pair):824        """ https://docs.python.org/3/library/socket.html#socket.socket.connect_ex825        Like connect(address), but return an error indicator instead of raising an exception for errors returned by the C-level connect() call (other problems, such as "host not found" can still raise exceptions).826        """827        try:828            self.connect(dest_pair, catch_errors=True)829            return 0830        except OSError as e:831            # If the error is numeric (socket errors are numeric), then return number as 832            # connect_ex expects. Otherwise raise the error again (socket timeout for example)833            if e.errno:834                return e.errno835            else:836                raise837 838    def _proxy_addr(self):839        """840        Return proxy address to connect to as tuple object841        """842        (proxy_type, proxy_addr, proxy_port, rdns, username,843         password) = self.proxy844        proxy_port = proxy_port or DEFAULT_PORTS.get(proxy_type)845        if not proxy_port:846            raise GeneralProxyError("Invalid proxy type")847        return proxy_addr, proxy_port848 
codekingpro/portable-devtools · Team Ai