Anonymous avatar Anonymous committed f28974e

Sync to latest version of socks.py

Comments (0)

Files changed (1)

python2/httplib2/socks.py

 
 Copyright 2006 Dan-Haim. All rights reserved.
 
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
 1. Redistributions of source code must retain the above copyright notice, this
    list of conditions and the following disclaimer.
 2. Redistributions in binary form must reproduce the above copyright notice,
 3. Neither the name of Dan Haim nor the names of his contributors may be used
    to endorse or promote products derived from this software without specific
    prior written permission.
-
+   
 THIS SOFTWARE IS PROVIDED BY DAN HAIM "AS IS" AND ANY EXPRESS OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA
 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMANGE.
 
 
 This module provides a standard socket-like interface for Python
 """
 
 import socket
+import struct
+import sys
 
 if getattr(socket, 'socket', None) is None:
     raise ImportError('socket.socket missing, proxy support unusable')
 
-import struct
-import sys
-
 PROXY_TYPE_SOCKS4 = 1
 PROXY_TYPE_SOCKS5 = 2
 PROXY_TYPE_HTTP = 3
 
 _defaultproxy = None
+_orgsocket = socket.socket
 
-# Small hack for Python 2.x
-if sys.version_info[0] <= 2:
-    def bytes(obj, enc=None):
-        return obj
-
-class ProxyError(Exception):
-    def __init__(self, value):
-        self.value = value
-    def __str__(self):
-        return repr(self.value)
-
-class GeneralProxyError(ProxyError):
-    def __init__(self, value):
-        self.value = value
-    def __str__(self):
-        return repr(self.value)
-
-class Socks5AuthError(ProxyError):
-    def __init__(self, value):
-        self.value = value
-    def __str__(self):
-        return repr(self.value)
-
-class Socks5Error(ProxyError):
-    def __init__(self, value):
-        self.value = value
-    def __str__(self):
-        return repr(self.value)
-
-class Socks4Error(ProxyError):
-    def __init__(self, value):
-        self.value = value
-    def __str__(self):
-        return repr(self.value)
-
-class HTTPError(ProxyError):
-    def __init__(self, value):
-        self.value = value
-    def __str__(self):
-        return repr(self.value)
+class ProxyError(Exception): pass
+class GeneralProxyError(ProxyError): pass
+class Socks5AuthError(ProxyError): pass
+class Socks5Error(ProxyError): pass
+class Socks4Error(ProxyError): pass
+class HTTPError(ProxyError): pass
 
 _generalerrors = ("success",
-                  "invalid data",
-                  "not connected",
-                  "not available",
-                  "bad proxy type",
-                  "bad input")
+    "invalid data",
+    "not connected",
+    "not available",
+    "bad proxy type",
+    "bad input")
 
 _socks5errors = ("succeeded",
-                 "general SOCKS server failure",
-                 "connection not allowed by ruleset",
-                 "Network unreachable",
-                 "Host unreachable",
-                 "Connection refused",
-                 "TTL expired",
-                 "Command not supported",
-                 "Address type not supported",
-                 "Unknown error")
+    "general SOCKS server failure",
+    "connection not allowed by ruleset",
+    "Network unreachable",
+    "Host unreachable",
+    "Connection refused",
+    "TTL expired",
+    "Command not supported",
+    "Address type not supported",
+    "Unknown error")
 
 _socks5autherrors = ("succeeded",
-                     "authentication is required",
-                     "all offered authentication methods were rejected",
-                     "unknown username or invalid password",
-                     "unknown error")
+    "authentication is required",
+    "all offered authentication methods were rejected",
+    "unknown username or invalid password",
+    "unknown error")
 
 _socks4errors = ("request granted",
-                 "request rejected or failed",
-                 ("request rejected because SOCKS server cannot connect to "
-                  "identd on the client"),
-                 ("request rejected because the client program and identd"
-                  " report different user-ids"),
-                 "unknown error")
+    "request rejected or failed",
+    "request rejected because SOCKS server cannot connect to identd on the client",
+    "request rejected because the client program and identd report different user-ids",
+    "unknown error")
 
-
-def setdefaultproxy(proxytype=None, addr=None, port=None, rdns=True,
-                    username=None, password=None):
+def setdefaultproxy(proxytype=None, addr=None, port=None, rdns=True, username=None, password=None):
     """setdefaultproxy(proxytype, addr[, port[, rdns[, username[, password]]]])
     Sets a default proxy which all further socksocket objects will use,
     unless explicitly changed.
     global _defaultproxy
     _defaultproxy = (proxytype, addr, port, rdns, username, password)
 
+def wrapmodule(module):
+    """wrapmodule(module)
+    Attempts to replace a module's socket library with a SOCKS socket. Must set
+    a default proxy using setdefaultproxy(...) first.
+    This will only work on modules that import socket directly into the namespace;
+    most of the Python Standard Library falls into this category.
+    """
+    if _defaultproxy != None:
+        module.socket.socket = socksocket
+    else:
+        raise GeneralProxyError((4, "no proxy specified"))
 
 class socksocket(socket.socket):
     """socksocket([family[, type[, proto]]]) -> socket object
-
     Open a SOCKS enabled socket. The parameters are the same as
     those of the standard socket init. In order for SOCKS to work,
     you must specify family=AF_INET, type=SOCK_STREAM and proto=0.
     """
 
-    def __init__(self, family=socket.AF_INET, type=socket.SOCK_STREAM,
-                 proto=0, _sock=None):
-        socket.socket.__init__(self, family, type, proto, _sock)
+    def __init__(self, family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, _sock=None):
+        _orgsocket.__init__(self, family, type, proto, _sock)
         if _defaultproxy != None:
             self.__proxy = _defaultproxy
         else:
         self.__proxysockname = None
         self.__proxypeername = None
 
-    def __decode(self, bytes):
-        if getattr(bytes, 'decode', False):
-            try:
-                bytes = bytes.decode()
-            except Exception:
-                pass
-        return bytes
-
-    def __encode(self, bytes):
-        if getattr(bytes, 'encode', False):
-            try:
-                bytes = bytes.encode()
-            except Exception:
-                pass
-        return bytes
-
     def __recvall(self, count):
         """__recvall(count) -> data
         Receive EXACTLY the number of bytes requested from the socket.
         Blocks until the required number of bytes have been received.
         """
-        data = bytes("")
+        data = self.recv(count)
         while len(data) < count:
-            d = self.recv(count - len(data))
-            if not d:
-                raise GeneralProxyError(
-                    (0, "connection closed unexpectedly"))
-            data = data + self.__decode(d)
+            d = self.recv(count-len(data))
+            if not d: raise GeneralProxyError((0, "connection closed unexpectedly"))
+            data = data + d
         return data
 
-    def sendall(self, bytes):
-        socket.socket.sendall(self, self.__encode(bytes))
-
-    def setproxy(self, proxytype=None, addr=None, port=None, rdns=True,
-                 username=None, password=None):
+    def setproxy(self, proxytype=None, addr=None, port=None, rdns=True, username=None, password=None):
         """setproxy(proxytype, addr[, port[, rdns[, username[, password]]]])
         Sets the proxy to be used.
         proxytype -    The type of the proxy to be used. Three types
         Negotiates a connection through a SOCKS5 server.
         """
         # First we'll send the authentication packages we support.
-        if (self.__proxy[4] != None) and (self.__proxy[5] != None):
+        if (self.__proxy[4]!=None) and (self.__proxy[5]!=None):
             # The username/password details were supplied to the
             # setproxy method so we support the USERNAME/PASSWORD
             # authentication (in addition to the standard none).
-            self.sendall("\x05\x02\x00\x02")
+            self.sendall(struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02))
         else:
             # No username/password were entered, therefore we
             # only support connections with no authentication.
-            self.sendall("\x05\x01\x00")
+            self.sendall(struct.pack('BBB', 0x05, 0x01, 0x00))
         # We'll receive the server's response to determine which
         # method was selected
         chosenauth = self.__recvall(2)
-        if chosenauth[0] != "\x05":
+        if chosenauth[0:1] != chr(0x05).encode():
             self.close()
             raise GeneralProxyError((1, _generalerrors[1]))
         # Check the chosen authentication method
-        if chosenauth[1] == "\x00":
+        if chosenauth[1:2] == chr(0x00).encode():
             # No authentication is required
             pass
-        elif chosenauth[1] == "\x02":
+        elif chosenauth[1:2] == chr(0x02).encode():
             # Okay, we need to perform a basic username/password
             # authentication.
-            self.sendall("\x01" + chr(len(self.__proxy[4])) + self.__proxy[4] +
-                         chr(len(self.__proxy[5])) + self.__proxy[5])
+            self.sendall(chr(0x01).encode() + chr(len(self.__proxy[4])) + self.__proxy[4] + chr(len(self.__proxy[5])) + self.__proxy[5])
             authstat = self.__recvall(2)
-            if authstat[0] != "\x01":
+            if authstat[0:1] != chr(0x01).encode():
                 # Bad response
                 self.close()
                 raise GeneralProxyError((1, _generalerrors[1]))
-            if authstat[1] != "\x00":
+            if authstat[1:2] != chr(0x00).encode():
                 # Authentication failed
                 self.close()
                 raise Socks5AuthError((3, _socks5autherrors[3]))
         else:
             # Reaching here is always bad
             self.close()
-            if chosenauth[1] == "\xFF":
+            if chosenauth[1] == chr(0xFF).encode():
                 raise Socks5AuthError((2, _socks5autherrors[2]))
             else:
                 raise GeneralProxyError((1, _generalerrors[1]))
         # Now we can request the actual connection
-        req = "\x05\x01\x00"
+        req = struct.pack('BBB', 0x05, 0x01, 0x00)
         # If the given destination address is an IP address, we'll
         # use the IPv4 address request even if remote resolving was specified.
         try:
             ipaddr = socket.inet_aton(destaddr)
-            req = req + "\x01" + ipaddr
+            req = req + chr(0x01).encode() + ipaddr
         except socket.error:
             # Well it's not an IP number,  so it's probably a DNS name.
-            if self.__proxy[3] == True:
+            if self.__proxy[3]:
                 # Resolve remotely
                 ipaddr = None
-                req = req + "\x03" + chr(len(destaddr)) + destaddr
+                req = req + chr(0x03).encode() + chr(len(destaddr)).encode() + destaddr
             else:
                 # Resolve locally
                 ipaddr = socket.inet_aton(socket.gethostbyname(destaddr))
-                req = req + "\x01" + ipaddr
-        req = req + self.__decode(struct.pack(">H", destport))
+                req = req + chr(0x01).encode() + ipaddr
+        req = req + struct.pack(">H", destport)
         self.sendall(req)
         # Get the response
         resp = self.__recvall(4)
-        if resp[0] != "\x05":
+        if resp[0:1] != chr(0x05).encode():
             self.close()
             raise GeneralProxyError((1, _generalerrors[1]))
-        elif resp[1] != "\x00":
+        elif resp[1:2] != chr(0x00).encode():
             # Connection failed
             self.close()
-            if ord(resp[1]) <= 8:
-                raise Socks5Error((ord(resp[1]), _socks5errors[ord(resp[1])]))
+            if ord(resp[1:2])<=8:
+                raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])]))
             else:
                 raise Socks5Error((9, _socks5errors[9]))
         # Get the bound address/port
-        elif resp[3] == "\x01":
+        elif resp[3:4] == chr(0x01).encode():
             boundaddr = self.__recvall(4)
-        elif resp[3] == "\x03":
+        elif resp[3:4] == chr(0x03).encode():
             resp = resp + self.recv(1)
-            boundaddr = self.__recvall(ord(resp[4]))
+            boundaddr = self.__recvall(ord(resp[4:5]))
         else:
             self.close()
-            raise GeneralProxyError((1, _generalerrors[1]))
-        boundport = struct.unpack(">H", bytes(self.__recvall(2), 'utf8'))[0]
-        self.__proxysockname = boundaddr, boundport
+            raise GeneralProxyError((1,_generalerrors[1]))
+        boundport = struct.unpack(">H", self.__recvall(2))[0]
+        self.__proxysockname = (boundaddr, boundport)
         if ipaddr != None:
             self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
         else:
         """getproxypeername() -> address info
         Returns the IP and port number of the proxy.
         """
-        return socket.socket.getpeername(self)
+        return _orgsocket.getpeername(self)
 
     def getpeername(self):
         """getpeername() -> address info
         """
         return self.__proxypeername
 
-    def __negotiatesocks4(self, destaddr, destport):
+    def __negotiatesocks4(self,destaddr,destport):
         """__negotiatesocks4(self,destaddr,destport)
         Negotiates a connection through a SOCKS4 server.
         """
             ipaddr = socket.inet_aton(destaddr)
         except socket.error:
             # It's a DNS name. Check where it should be resolved.
-            if self.__proxy[3] == True:
-                ipaddr = "\x00\x00\x00\x01"
+            if self.__proxy[3]:
+                ipaddr = struct.pack("BBBB", 0x00, 0x00, 0x00, 0x01)
                 rmtrslv = True
             else:
                 ipaddr = socket.inet_aton(socket.gethostbyname(destaddr))
         # Construct the request packet
-        req = "\x04\x01" + self.__decode(struct.pack(">H", destport)) + ipaddr
+        req = struct.pack(">BBH", 0x04, 0x01, destport) + ipaddr
         # The username parameter is considered userid for SOCKS4
         if self.__proxy[4] != None:
             req = req + self.__proxy[4]
-        req = req + "\x00"
+        req = req + chr(0x00).encode()
         # DNS name if remote resolving is required
         # NOTE: This is actually an extension to the SOCKS4 protocol
         # called SOCKS4A and may not be supported in all cases.
-        if rmtrslv==True:
-            req = req + destaddr + "\x00"
+        if rmtrslv:
+            req = req + destaddr + chr(0x00).encode()
         self.sendall(req)
         # Get the response from the server
         resp = self.__recvall(8)
-        if resp[0] != "\x00":
+        if resp[0:1] != chr(0x00).encode():
             # Bad data
             self.close()
-            raise GeneralProxyError((1, _generalerrors[1]))
-        if resp[1] != "\x5A":
+            raise GeneralProxyError((1,_generalerrors[1]))
+        if resp[1:2] != chr(0x5A).encode():
             # Server returned an error
             self.close()
-            if ord(resp[1]) in (91,92,93):
+            if ord(resp[1:2]) in (91, 92, 93):
                 self.close()
-                raise Socks4Error((ord(resp[1]), _socks4errors[ord(resp[1])-90]))
+                raise Socks4Error((ord(resp[1:2]), _socks4errors[ord(resp[1:2]) - 90]))
             else:
-                raise Socks4Error((94,_socks4errors[4]))
+                raise Socks4Error((94, _socks4errors[4]))
         # Get the bound address/port
-        self.__proxysockname = (socket.inet_ntoa(resp[4:]),struct.unpack(">H",bytes(resp[2:4],'utf8'))[0])
+        self.__proxysockname = (socket.inet_ntoa(resp[4:]), struct.unpack(">H", resp[2:4])[0])
         if rmtrslv != None:
-            self.__proxypeername = (socket.inet_ntoa(ipaddr),destport)
+            self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
         else:
             self.__proxypeername = (destaddr, destport)
 
         Negotiates a connection through an HTTP server.
         """
         # If we need to resolve locally, we do this now
-        if self.__proxy[3] == False:
+        if not self.__proxy[3]:
             addr = socket.gethostbyname(destaddr)
         else:
             addr = destaddr
-        self.sendall(("CONNECT %s:%s HTTP/1.1\r\n"
-                      "Host: %s\r\n\r\n") % (addr, destport, destaddr))
+        self.sendall(("CONNECT " + addr + ":" + str(destport) + " HTTP/1.1\r\n" + "Host: " + destaddr + "\r\n\r\n").encode())
         # We read the response until we get the string "\r\n\r\n"
         resp = self.recv(1)
-        while resp.find("\r\n\r\n") == -1:
+        while resp.find("\r\n\r\n".encode()) == -1:
             resp = resp + self.recv(1)
         # We just need the first line to check if the connection
         # was successful
-        statusline = resp.splitlines()[0].split(" ", 2)
-        if statusline[0] not in ("HTTP/1.0", "HTTP/1.1"):
+        statusline = resp.splitlines()[0].split(" ".encode(), 2)
+        if statusline[0] not in ("HTTP/1.0".encode(), "HTTP/1.1".encode()):
             self.close()
             raise GeneralProxyError((1, _generalerrors[1]))
         try:
         self.__proxypeername = (addr, destport)
 
     def connect(self, destpair):
-        """connect(self,despair)
+        """connect(self, despair)
         Connects to the specified destination through a proxy.
         destpar - A tuple of the IP/DNS address and the port number.
         (identical to socket's connect).
         To select the proxy server use setproxy().
         """
         # Do a minimal input check first
-        # TODO(durin42): seriously? type checking? do we care?
-        if ((not isinstance(destpair, (list, tuple))) or len(destpair) < 2
-            or not isinstance(destpair[0], str) or not isinstance(destpair[1], int)):
+        if (not type(destpair) in (list,tuple)) or (len(destpair) < 2) or (type(destpair[0]) != type('')) or (type(destpair[1]) != int):
             raise GeneralProxyError((5, _generalerrors[5]))
         if self.__proxy[0] == PROXY_TYPE_SOCKS5:
             if self.__proxy[2] != None:
                 portnum = self.__proxy[2]
             else:
                 portnum = 1080
-            socket.socket.connect(self,(self.__proxy[1], portnum))
+            _orgsocket.connect(self, (self.__proxy[1], portnum))
             self.__negotiatesocks5(destpair[0], destpair[1])
         elif self.__proxy[0] == PROXY_TYPE_SOCKS4:
             if self.__proxy[2] != None:
                 portnum = self.__proxy[2]
             else:
                 portnum = 1080
-            socket.socket.connect(self, (self.__proxy[1], portnum))
+            _orgsocket.connect(self,(self.__proxy[1], portnum))
             self.__negotiatesocks4(destpair[0], destpair[1])
         elif self.__proxy[0] == PROXY_TYPE_HTTP:
             if self.__proxy[2] != None:
                 portnum = self.__proxy[2]
             else:
                 portnum = 8080
-            socket.socket.connect(self, (self.__proxy[1], portnum))
+            _orgsocket.connect(self,(self.__proxy[1], portnum))
             self.__negotiatehttp(destpair[0], destpair[1])
         elif self.__proxy[0] == None:
-            socket.socket.connect(self, (destpair[0], destpair[1]))
+            _orgsocket.connect(self, (destpair[0], destpair[1]))
         else:
             raise GeneralProxyError((4, _generalerrors[4]))
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.