[tor-dev] Obfsproxy Address Translation

Alfredo Palhares masterkorp at masterkorp.net
Fri Jan 23 12:36:57 UTC 2015


Hello,

Sorry for the delay, I finnally set on the quest to understand obfsproxy.
So with the help of pdb and a few questions here and there I got to some
places, and with a lot of more questions to ask.

## Studying the client

The client launches a connection on obfsproxy/pyofsproxypy do_external_mode() the
launch_transport.launch_transport_listener method is where the socks listeners is set.
Right after that the Twisted library reactor module is initiated with reactor.run() on
line 107 of the file obfsproxy/pyobfsproxy.py

After that the Twisted event loop is started and it will listen to events that
are set on methods like listenTCP() the wiki page about servers[1]

I've set a pdb.set_trace() on the buildProtocol() method in the file 
obfsproxy/network/socks.py and the backtrace looks like.

(Pdb) bt
  /usr/lib/python2.7/runpy.py(162)_run_module_as_main()
-> "__main__", fname, loader, pkg_name)
  /usr/lib/python2.7/runpy.py(72)_run_code()
-> exec code in run_globals
  /usr/lib/python2.7/pdb.py(1338)<module>()
-> pdb.main()
  /usr/lib/python2.7/pdb.py(1314)main()
-> pdb._runscript(mainpyfile)
  /usr/lib/python2.7/pdb.py(1233)_runscript()
-> self.run(statement)
  /usr/lib/python2.7/bdb.py(400)run()
-> exec cmd in globals, locals
  <string>(1)<module>()
  /home/masterkorp/Public/obfsproxy/bin/obfsproxy(16)<module>()
-> run()
  /home/masterkorp/Public/obfsproxy/obfsproxy/pyobfsproxy.py(207)run()
-> pyobfsproxy()
  /home/masterkorp/Public/obfsproxy/obfsproxy/pyobfsproxy.py(189)pyobfsproxy()
-> do_external_mode(args)
  /home/masterkorp/Public/obfsproxy/obfsproxy/pyobfsproxy.py(108)do_external_mode()
-> reactor.run()
  /usr/lib/python2.7/site-packages/twisted/internet/base.py(1192)run()
-> self.mainLoop()
  /usr/lib/python2.7/site-packages/twisted/internet/base.py(1204)mainLoop()
-> self.doIteration(t)
  /usr/lib/python2.7/site-packages/twisted/internet/epollreactor.py(396)doPoll()
-> log.callWithLogger(selectable, _drdw, selectable, fd, event)
  /usr/lib/python2.7/site-packages/twisted/python/log.py(88)callWithLogger()
-> return callWithContext({"system": lp}, func, *args, **kw)
  /usr/lib/python2.7/site-packages/twisted/python/log.py(73)callWithContext()
-> return context.call({ILogContext: newCtx}, func, *args, **kw)
  /usr/lib/python2.7/site-packages/twisted/python/context.py(118)callWithContext()
-> return self.currentContext().callWithContext(ctx, func, *args, **kw)
  /usr/lib/python2.7/site-packages/twisted/python/context.py(81)callWithContext()
-> return func(*args,**kw)
  /usr/lib/python2.7/site-packages/twisted/internet/posixbase.py(614)_doReadOrWrite()
-> why = selectable.doRead()
  /usr/lib/python2.7/site-packages/twisted/internet/tcp.py(1062)doRead()
-> protocol = self.factory.buildProtocol(self._buildAddr(addr))
  /home/masterkorp/Public/obfsproxy/obfsproxy/network/socks.py(183)buildProtocol()
-> circuit = network.Circuit(self.transport_class())

It goes directly to this method from Twistedm, which  confirms that all the SOCKS
is set. This creates a new Circuit. And the like the documentation says a Circuit
is a pair of connections between and the obfsproxy client and openvpn client (in
this case) or obfsproxy server and OpenVPN server.

Then I set a pdb.set_trace() dataReceived() on obfsproxy/network/network.py well
because of the name. And a backtrace looks like:

(Pdb) bt
  /usr/lib/python2.7/runpy.py(162)_run_module_as_main()
-> "__main__", fname, loader, pkg_name)
  /usr/lib/python2.7/runpy.py(72)_run_code()
-> exec code in run_globals
  /usr/lib/python2.7/pdb.py(1338)<module>()
-> pdb.main()
  /usr/lib/python2.7/pdb.py(1314)main()
-> pdb._runscript(mainpyfile)
  /usr/lib/python2.7/pdb.py(1233)_runscript()
-> self.run(statement)
  /usr/lib/python2.7/bdb.py(400)run()
-> exec cmd in globals, locals
  <string>(1)<module>()
  /home/masterkorp/Public/obfsproxy/bin/obfsproxy(3)<module>()
-> import sys, os
  /home/masterkorp/Public/obfsproxy/obfsproxy/pyobfsproxy.py(205)run()
-> pyobfsproxy()
  /home/masterkorp/Public/obfsproxy/obfsproxy/pyobfsproxy.py(187)pyobfsproxy()
-> do_external_mode(args)
  /home/masterkorp/Public/obfsproxy/obfsproxy/pyobfsproxy.py(106)do_external_mode()
-> reactor.run()
  /usr/lib/python2.7/site-packages/twisted/internet/base.py(1192)run()
-> self.mainLoop()
  /usr/lib/python2.7/site-packages/twisted/internet/base.py(1204)mainLoop()
-> self.doIteration(t)
  /usr/lib/python2.7/site-packages/twisted/internet/epollreactor.py(396)doPoll()
-> log.callWithLogger(selectable, _drdw, selectable,fd, event)
  /usr/lib/python2.7/site-packages/twisted/python/log.py(88)callWithLogger()
-> return callWithContext({"system": lp}, func,*args, **kw)
/usr/lib/python2.7/site-packages/twisted/python/log.py(73)callWithContext()
-> return context.call({ILogContext: newCtx},func, *args, **kw)
  /usr/lib/python2.7/site-packages/twisted/python/context.py(118)callWithContext()
-> return self.currentContext().callWithContext(ctx,func, *args, **kw)
  /usr/lib/python2.7/site-packages/twisted/python/context.py(81)callWithContext()
-> return func(*args,**kw)
 /usr/lib/python2.7/site-packages/twisted/internet/posixbase.py(614)_doReadOrWrite()
-> why = selectable.doRead()
  /usr/lib/python2.7/site-packages/twisted/internet/tcp.py(214)doRead()
-> return self._dataReceived(data)
  /usr/lib/python2.7/site-packages/twisted/internet/tcp.py(220)_dataReceived()
-> rval = self.protocol.dataReceived(data)
  /home/masterkorp/Public/obfsproxy/obfsproxy/network/socks5.py(163)dataReceived()
-> self.processEstablishedData(data)
  /home/masterkorp/Public/obfsproxy/obfsproxy/network/socks.py(107)processEstablishedData()
-> self.circuit.dataReceived(self.buffer, self)
  /home/masterkorp/Public/obfsproxy/obfsproxy/network/network.py(152)dataReceived()
-> if self.closed:

Its not too far away for the previous backtrace

Inside the method I try to see what the heck is going on.
(Pdb) print self
<obfsproxy.network.network.Circuit instance at 0x7fbbec1c3758>

This is the circuit itself, passing self seems a into the methods seems a
print self common thing to do. I verihave no idea why.

(Pdb) print conn
<obfsproxy.network.socks.OBFSSOCKSv5Protocol object at 0x7fbbec1b75d0>

Conn is a socks connections. I wonder how can I extract the source IP from it.

(Pdb) print data
<obfsproxy.network.buffer.Buffer object at 0x7fbbec1b7510>

data is butter object. Apparently is a First In First Out data container. Not
sure where this object was initially created.

I've tried to use the peek method, whiting pdb.
(Pdb) print data.peek(n=100)
8£öä¢ÂZ

Passing n=<whatever> always shows that same string. Maybe that is just it, kinda
like an initial hanshake ?

Just a few steps foward here. there is a log.debug
2015-01-22 17:25:35,162 [DEBUG] circ_0x7fbbec1c3758: upstream: Received 16bytes.

Ok I think I am on the right path.

Then the receivedUpstream() on obfsproxy/network/transports/scramblesuit/scramblesuit.py

A few steps forward in:
 if self.protoState == const.ST_CONNECTED:

Where the const.ST_CONNECTED comes from ? printing shows an value of "2" which
on this case its equal to self.protoState, that I think it means that obfsproxy
client is connected to obfsproxy Server correct me if I am wrong

Then the data send to sendRemote. which obfsucates the data itself and reads
from the Buffer object.

In here I could not get info about the SOCKS client Ip address. Wich is weird.

Can you shed some light ?

Thanks in advance?

[1] https://twistedmatrix.com/documents/current/core/howto/servers.html

--
Regards,
Alfredo Palhares


More information about the tor-dev mailing list