diff options
author | Nick Mathewson <nickm@torproject.org> | 2008-11-16 20:15:34 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2008-11-16 20:15:34 +0000 |
commit | c5749895ab4f6893bdf1d398691d1dd33e81574c (patch) | |
tree | 4ee47c3c6c56e313c3074f04c77a3637cf0fe31d /lib/thandy/socksurls.py | |
parent | 02a2e5807f23ad0cad9a49b5febe08ec25fcc74c (diff) |
have some more thandy. This update includes a working downloader with tor support, a package system framework, and more. Most of what's left is glue code.
git-svn-id: file:///home/or/svnrepo/updater/trunk@17288 55e972cd-5a19-0410-ae62-a4d7a52db4cd
Diffstat (limited to 'lib/thandy/socksurls.py')
-rw-r--r-- | lib/thandy/socksurls.py | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/lib/thandy/socksurls.py b/lib/thandy/socksurls.py new file mode 100644 index 0000000..d035a6c --- /dev/null +++ b/lib/thandy/socksurls.py @@ -0,0 +1,93 @@ +# Copyright 2008 The Tor Project, Inc. See LICENSE for licensing information. + +"""Implements URL types for socks-mediated connections.""" + +import socket +import httplib +import logging +import struct +import urllib2 + +# XXXX This isn't really threadsafe, but for now we don't change this after +# startup. +SOCKS_HOST = None +SOCKS_PORT = None + +def setSocksProxy(host, port): + """Set the global SOCKS proxy to host:port.""" + global SOCKS_HOST, SOCKS_PORT + SOCKS_HOST = host + SOCKS_PORT = port + +def _recvall(sock, n): + """Helper: fetch N bytes from the socket sock.""" + result = "" + while 1: + s = sock.recv(n) + if not s: + return result + result += s + n -= len(s) + if n <= 0: + return result + +def socks_connect(host, port): + """Helper: use the SOCKS proxy to open a connection to host:port. + Uses the simple and Tor-friendly SOCKS4a protocol.""" + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + logging.debug("Connecting to SOCKS proxy") + sock.connect((SOCKS_HOST, SOCKS_PORT)) + + # Now, the handshake! We just do socks4a, since that's the simplest. + version = 4 # socks 4 + command = 1 # connect + addr = 1 # 0.0.0.1, signals socks4a. + userid = "" + + messageheader = struct.pack("!BBHL", version, command, port, addr) + message = "%s%s\x00%s\x00" % (messageheader, userid, host) + + sock.sendall(message) + + logging.debug("Waiting for reply from SOCKS proxy") + reply = _recvall(sock, 8) + code = ord(reply[1]) + if code == 0x5a: + logging.debug("SOCKS proxy is connected.") + return sock + else: + raise socket.error("Bad SOCKS response code from proxy: %d", code) + except: + sock.close() + raise + +# Copies of HTTPConnection and HTTPSConnection that use socks instead of +# direct connections. +class SocksHTTPConnection(httplib.HTTPConnection): + def connect(self): + self.sock = socks_connect(self.host, self.port) +class SocksHTTPSConnection(httplib.HTTPSConnection): + def connect(self): + socket = socks_connect(self.host, self.port) + ssl = socket.ssl(sock, None, None) + self.sock = socket.FakeSocket(socket, ssl) + +# URL handlers for HTTP and HTTPS urls that use socks instead of direct +# connections. +class SocksHTTPHandler(urllib2.AbstractHTTPHandler): + def http_open(self, req): + return self.do_open(SocksHTTPConnection, req) + http_request = urllib2.AbstractHTTPHandler.do_request_ +class SocksHTTPSHandler(urllib2.AbstractHTTPHandler): + def https_open(self, req): + return self.do_open(SocksHTTPSConnection, req) + https_request = urllib2.AbstractHTTPHandler.do_request_ + +def build_socks_opener(): + """Return an urllib2.OpenerDirector object to open HTTP and HTTPS + urls using SOCKS connections.""" + opener = urllib2.OpenerDirector() + opener.add_handler(SocksHTTPSHandler()) + opener.add_handler(SocksHTTPHandler()) + return opener |