Skip to content
Permalink
Browse files
Finish implementation of SOCKS5 proxy client with example usage.
  • Loading branch information
hellais committed Dec 5, 2012
1 parent 9fb250f commit f542f4d9b28f6690c0359a2d9a6b10d179d1872e
Showing with 66 additions and 10 deletions.
  1. +39 −0 example.py
  2. +25 −8 txsocksx/client.py
  3. +2 −2 txsocksx/parser.py
@@ -0,0 +1,39 @@
from twisted.internet import reactor
from twisted.internet.protocol import Protocol, Factory
from twisted.internet.endpoints import TCP4ClientEndpoint

from txsocksx.client import SOCKS5ClientEndpoint

class GETSlash(Protocol):
def connectionMade(self):
self.transport.write("GET / HTTP/1.1\n\r\n\r")

def buildProtocol(self):
return self

def dataReceived(self, data):
print "Got this as a response"
print data

class GETSlashFactory(Factory):
def buildProtocol(self, addr):
print "Building protocol towards"
return GETSlash()

socks_addr = '127.0.0.1'
socks_port = 9050
TCPPoint = TCP4ClientEndpoint(reactor, socks_addr, socks_port)

dst_addr = 'checkip.dyndns.com'
dst_port = 80
SOCKSPoint = SOCKS5ClientEndpoint(dst_addr,
dst_port, TCPPoint)

d = SOCKSPoint.connect(GETSlashFactory())
@d.addErrback
def _gotError(error):
print "Error in connection"
reactor.stop()

reactor.run()

@@ -26,6 +26,8 @@ class SOCKS5Client(protocol.Protocol):
implements(interfaces.ITransport)

otherProtocol = None
debug = True

def __init__(self):
self._state = 'ServerVersionMethod'

@@ -35,7 +37,7 @@ def connectionMade(self):
def writeVersionMethod(self):
"""
This creates:
ver octet:nmethods octet{1, 255}:methods
ver octet:nmethods octet{2, 255}:methods
"""
supported_methods = [m.method for m in self.factory.authMethods]

@@ -59,9 +61,11 @@ def writeRequest(self, result, cmd=c.CMD_CONNECT):
message.hostToSOCKSAddress() + \
shortToBytes(self.factory.port)
)
self.log("writeRequest %s" % (repr(req)))
self._state = 'ServerReply'

def readServerVersionMethod(self, message):
self.log("readServerVersionMethod")
ver, method = message.serverVersionMethod()
if method not in self.factory.authMethods:
raise e.MethodsNotAcceptedError(
@@ -74,35 +78,47 @@ def readServerVersionMethod(self, message):

def readServerReply(self, message):
status, address, port = message.serverReply()
self.log("readServerReply %s %s %s" % (status, address, port))
if status != 0:
raise status

self._state = 'ProxyData'
self.factory.proxyConnectionEstablished(self)

def readProxyData(self, data):
# There really is no reason for this to get called; we shouldn't be in
# raw mode until after SOCKS negotiation finishes.
assert self.otherProtocol is not None
self.otherProtocol.dataReceived(data)

def dataReceived(self, data):
self.log("Got some data %s" % repr(data))
if self._state == 'ProxyData':
self.readProxyData(data)
return

# XXX-Security audit makeGrammar
message = SOCKSGrammar(data)

current_state_method = getattr(self, 'read' + self._state)
d = defer.maybeDeferred(current_state_method,
message)
d.addErrback(self.factory.proxyConnectionFailed)

def proxyEstablished(self, other):
self.otherProtocol = other
other.makeConnection(SOCKS5ClientTransport(self))

def rawDataReceived(self, data):
# There really is no reason for this to get called; we shouldn't be in
# raw mode until after SOCKS negotiation finishes.
assert self.otherProtocol is not None
self.otherProtocol.dataReceived(data)

def connectionLost(self, reason):
if self.otherProtocol:
self.log("Connection Lost with other protocol")
self.otherProtocol.connectionLost(reason)
else:
self.log("Connection Lost with no protocol")
self.factory.proxyConnectionFailed(
failure.Failure(e.ConnectionLostEarly()))
def log(self, msg):
if self.debug:
print msg

class SOCKS5ClientFactory(protocol.ClientFactory):
protocol = SOCKS5Client
@@ -118,6 +134,7 @@ def proxyConnectionFailed(self, reason):
self.deferred.errback(reason)

def clientConnectionFailed(self, connector, reason):
print "Failed because of %s" % reason
self.proxyConnectionFailed(reason)

def proxyConnectionEstablished(self, proxyProtocol):
@@ -107,6 +107,6 @@

# XXX how do I do the equivalent of the above and generate the grammar to a
# file?
#parsley.moduleFromGrammar(socks_grammar, 'SOCKSGrammar',
# object, {"e": error, "a": auth})
# parsley.moduleFromGrammar(socks_grammar, 'SOCKSGrammar',
# object, {"e": error, "a": auth})

0 comments on commit f542f4d

Please sign in to comment.