1 import os
2 import struct
3 import socket
4 from twisted.web import client
5 from twisted.internet import reactor
6 from twisted.internet.protocol import ClientFactory, Protocol
7 from twisted.python import log
8
9
10 socks = os.getenv('SOCKS')
11 if socks:
12 socks_addr, socks_port = socks.split(':')
13 socks_port = int(socks_port)
14
16 """Implementation of subset of SOCKS4.
17
18 Information taken from http://en.wikipedia.org/wiki/SOCKS
19
20 Once the communication is established, this class behaves as a
21 transport for the client that instanciated it.
22 """
24 self.established = False
25 self.buf = ""
26 log.msg("SOCKS connection to %s" % self.factory.addr)
27 data = struct.pack('!BBH',
28 0x04,
29 0x01,
30 self.factory.port)
31 data += socket.inet_aton(self.factory.addr)
32
33 data += 'pyblio\0'
34 self.transport.write(data)
35
37 if not self.established:
38 self.buf += data
39 if self.buf < 8:
40 return
41 try:
42 _, status, port = struct.unpack('!BBH', self.buf[:4])
43 except struct.error:
44 raise RuntimeError("invalid reply")
45 addr = socket.inet_ntoa(self.buf[4:])
46 if status == 0x5a:
47 self.established = True
48
49 self.disconnecting = False
50
51 self.p = self.factory.client.buildProtocol(addr)
52 self.p.transport = self
53 self.p.connectionMade()
54 else:
55 raise RuntimeError("SOCKS connection refused: %x" % status)
56
57 if self.buf > 8:
58 self.p.dataReceived(self.buf[8:])
59 return
60 self.p.dataReceived(data)
61
65
67 assert self.established
68 self.transport.write(data)
69
72
74 """ A SOCKS4 connection to a server."""
75 protocol = SOCKS4Protocol
76
78 self.addr = addr
79 self.port = port
80 self.client = client
81
84
87
89 """ Cancellable HTTP client.
90
91 This HTTP getter keeps track of the running protocol
92 instances, so that their transport can be closed in the middle of
93 an operation."""
94
95 - def __init__(self, url, *args, **kargs):
96 client.HTTPClientFactory.__init__(self, url, *args, **kargs)
97
98 self.running = []
99
100 scheme, host, port, path = client._parse(url)
101 if socks:
102 from twisted.names.client import getHostByName
103 def connectToIP(ip):
104 self.socks = SOCKS4Client(ip, port, self)
105 reactor.connectTCP(socks_addr, socks_port, self.socks)
106 def failed(failure):
107 self.deferred.errback(failure)
108 getHostByName(host).addCallback(connectToIP).addErrback(failed)
109 else:
110 reactor.connectTCP(host, port, self)
111 return
112
114 p = client.HTTPClientFactory.buildProtocol(self, addr)
115 self.running.append(p)
116 return p
117
121