-
Notifications
You must be signed in to change notification settings - Fork 9
/
socksclient.py
146 lines (127 loc) · 4.98 KB
/
socksclient.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# Copyright (c) 2011-2013, The Tor Project
# See LICENSE for the license.
import inspect
import socket
import struct
from zope.interface import implements
from twisted.internet import defer
from twisted.internet.interfaces import IStreamClientEndpoint, IReactorTime
from twisted.internet.protocol import Protocol, ClientFactory
from twisted.internet.endpoints import _WrappingFactory
class SOCKSError(Exception):
def __init__(self, val):
self.val = val
def __str__(self):
return repr(self.val)
class SOCKSv4ClientProtocol(Protocol):
buf = ''
def noteTime(self, event):
if self._timer:
self._timestamps[event] = self._timer.seconds()
def SOCKSConnect(self, host, port):
# only socksv4a for now
ver = 4
cmd = 1 # stream connection
user = '\x00'
dnsname = ''
try:
addr = socket.inet_aton(host)
except socket.error:
addr = '\x00\x00\x00\x01'
dnsname = '%s\x00' % host
msg = struct.pack('!BBH', ver, cmd, port) + addr + user + dnsname
self.transport.write(msg)
self.noteTime('REQUEST')
def verifySocksReply(self, data):
"""
Return True on success, False on need-more-data.
Raise SOCKSError on request rejected or failed.
"""
if len(data) < 8:
return False
if ord(data[0]) != 0:
self.transport.loseConnection()
raise SOCKSError((1, "bad data"))
status = ord(data[1])
if status != 0x5a:
self.transport.loseConnection()
raise SOCKSError((status, "request not granted: %d" % status))
return True
def isSuccess(self, data):
self.buf += data
return self.verifySocksReply(self.buf)
def connectionMade(self):
self.noteTime('CONNECT')
self.noteTime('NEGOTIATE')
self.SOCKSConnect(self.postHandshakeEndpoint._host,
self.postHandshakeEndpoint._port)
def dataReceived(self, data):
if self.isSuccess(data):
self.noteTime('RESPONSE')
# Build protocol from provided factory and transfer control to it.
self.transport.protocol = self.postHandshakeFactory.buildProtocol(
self.transport.getHost())
self.transport.protocol.transport = self.transport
self.transport.protocol.connectionMade()
self.handshakeDone.callback(self.transport.getPeer())
class SOCKSv4ClientFactory(ClientFactory):
protocol = SOCKSv4ClientProtocol
def buildProtocol(self, addr):
r=ClientFactory.buildProtocol(self, addr)
r.postHandshakeEndpoint = self.postHandshakeEndpoint
r.postHandshakeFactory = self.postHandshakeFactory
r.handshakeDone = self.handshakeDone
r._timestamps = self._timestamps
r._timer = self._timer
return r
class SOCKSWrapper(object):
implements(IStreamClientEndpoint)
factory = SOCKSv4ClientFactory
def __init__(self, reactor, host, port, endpoint, timestamps=None):
self._host = host
self._port = port
self._reactor = reactor
self._endpoint = endpoint
self._timestamps = None
self._timer = None
if timestamps is not None:
self._timestamps = timestamps
self._timer = IReactorTime(reactor)
def noteTime(self, event):
if self._timer:
self._timestamps[event] = self._timer.seconds()
def connect(self, protocolFactory):
"""
Return a deferred firing when the SOCKS connection is established.
"""
def createWrappingFactory(f):
"""
Wrap creation of _WrappingFactory since __init__() doesn't
take a canceller as of Twisted 12.1 or something.
"""
if len(inspect.getargspec(_WrappingFactory.__init__)[0]) == 3:
def _canceller(deferred):
connector.stopConnecting()
deferred.errback(
error.ConnectingCancelledError(
connector.getDestination()))
return _WrappingFactory(f, _canceller)
else: # Twisted >= 12.1.
return _WrappingFactory(f)
self.noteTime('START')
try:
# Connect with an intermediate SOCKS factory/protocol,
# which then hands control to the provided protocolFactory
# once a SOCKS connection has been established.
f = self.factory()
f.postHandshakeEndpoint = self._endpoint
f.postHandshakeFactory = protocolFactory
f.handshakeDone = defer.Deferred()
f._timestamps = self._timestamps
f._timer = self._timer
wf = createWrappingFactory(f)
self._reactor.connectTCP(self._host, self._port, wf)
self.noteTime('SOCKET')
return f.handshakeDone
except:
return defer.fail()