[Pkg-privacy-commits] [obfsproxy] 72/353: Start passing buffers to transports.
Ximin Luo
infinity0 at moszumanska.debian.org
Sat Aug 22 13:01:41 UTC 2015
This is an automated email from the git hooks/post-receive script.
infinity0 pushed a commit to branch master
in repository obfsproxy.
commit fd9bb0b6f1092a29dccfcc1f7a38191419fa9610
Author: George Kadianakis <desnacked at riseup.net>
Date: Wed Oct 3 17:00:59 2012 +0300
Start passing buffers to transports.
---
obfsproxy.py | 4 +-
obfsproxy/network/buffer.py | 75 ++++++++++++++++++++++++++++++++++++++
obfsproxy/network/network.py | 60 ++++++++++++++----------------
obfsproxy/test/buffer_unittest.py | 43 ++++++++++++++++++++++
obfsproxy/transports/base.py | 4 ++
obfsproxy/transports/dummy.py | 17 +++------
obfsproxy/transports/transports.py | 6 +--
7 files changed, 160 insertions(+), 49 deletions(-)
diff --git a/obfsproxy.py b/obfsproxy.py
index fbace9e..10c2233 100755
--- a/obfsproxy.py
+++ b/obfsproxy.py
@@ -81,9 +81,9 @@ def do_external_mode(args):
from twisted.internet import reactor, error, address, tcp
if (args.mode == 'client') or (args.mode == 'server'):
- factory = network.StaticDestinationServerFactory(args.dest, args.mode, transportClass())
+ factory = network.StaticDestinationServerFactory(args.dest, args.mode, transportClass)
elif args.mode == 'socks':
- factory = socks.SOCKSv4Factory(transportClass())
+ factory = socks.SOCKSv4Factory(transportClass)
reactor.listenTCP(int(args.listen_addr[1]), factory)
reactor.run()
diff --git a/obfsproxy/network/buffer.py b/obfsproxy/network/buffer.py
new file mode 100644
index 0000000..36defb7
--- /dev/null
+++ b/obfsproxy/network/buffer.py
@@ -0,0 +1,75 @@
+class Buffer(object):
+ """
+ A Buffer is a simple FIFO buffer. You write() stuff to it, and you
+ read() them back. You can also peek() or drain() data.
+ """
+
+ def __init__(self, data=''):
+ """
+ Initialize a buffer with 'data'.
+ """
+ self.buffer = bytes(data)
+
+ def read(self, n=-1):
+ """
+ Read and return 'n' bytes from the buffer.
+
+ If 'n' is negative, read and return the whole buffer.
+ If 'n' is larger than the size of the buffer, read and return
+ the whole buffer.
+ """
+
+ if (n < 0) or (n > len(self.buffer)):
+ the_whole_buffer = self.buffer
+ self.buffer = bytes('')
+ return the_whole_buffer
+
+ data = self.buffer[:n]
+ self.buffer = self.buffer[n:]
+ return data
+
+ def write(self, data):
+ """
+ Append 'data' to the buffer.
+ """
+ self.buffer = self.buffer + data
+
+ def peek(self, n=-1):
+ """
+ Return 'n' bytes from the buffer, without draining them.
+
+ If 'n' is negative, return the whole buffer.
+ If 'n' is larger than the size of the buffer, return the whole
+ buffer.
+ """
+
+ if (n < 0) or (n > len(self.buffer)):
+ return self.buffer
+
+ return self.buffer[:n]
+
+ def drain(self, n=-1):
+ """
+ Drain 'n' bytes from the buffer.
+
+ If 'n' is negative, drain the whole buffer.
+ If 'n' is larger than the size of the buffer, drain the whole
+ buffer.
+ """
+ if (n < 0) or (n > len(self.buffer)):
+ self.buffer = bytes('')
+ return
+
+ self.buffer = self.buffer[n:]
+ return
+
+ def __len__(self):
+ """Returns length of buffer. Used in len()."""
+ return len(self.buffer)
+
+ def __nonzero__(self):
+ """
+ Returns True if the buffer is non-empty.
+ Used in truth-value testing.
+ """
+ return True if len(self.buffer) else False
diff --git a/obfsproxy/network/network.py b/obfsproxy/network/network.py
index e267301..e760913 100644
--- a/obfsproxy/network/network.py
+++ b/obfsproxy/network/network.py
@@ -4,6 +4,8 @@ from twisted.internet import reactor, error, address, tcp
from twisted.internet.protocol import Protocol, Factory, ClientFactory
import obfsproxy.common.log as log
+import obfsproxy.network.buffer as buffer
+import obfsproxy.transports.base as base
"""
Networking subsystem:
@@ -132,23 +134,23 @@ class Circuit(Protocol):
def dataReceived(self, data, conn):
"""
We received 'data' on 'conn'. Pass the data to our transport,
- and then proxy it to the other side.
+ and then proxy it to the other side. # XXX 'data' is a buffer.
Requires both downstream and upstream connections to be set.
-
- Returns the bytes that were not used by the transport.
"""
log.debug("%s: Received %d bytes." % (self.name, len(data)))
assert(self.downstream and self.upstream)
assert((conn is self.downstream) or (conn is self.upstream))
- if conn is self.downstream:
- leftovers = self.transport.receivedDownstream(data, self)
- else:
- leftovers = self.transport.receivedUpstream(data, self)
-
- return leftovers
+ try:
+ if conn is self.downstream:
+ self.transport.receivedDownstream(data, self)
+ else:
+ self.transport.receivedUpstream(data, self)
+ except base.PluggableTransportError, err: # Our transport didn't like that data.
+ log.info("%s: %s: Closing circuit." % (self.name, str(err)))
+ self.close()
def close(self):
"""
@@ -172,7 +174,6 @@ class StaticDestinationProtocol(Protocol):
Attributes:
mode: 'server' or 'client'
circuit: The circuit this connection belongs to.
- direction: 'downstream' or 'upstream'
buffer: Buffer that holds data that can't be proxied right
away. This can happen because the circuit is not yet
@@ -183,7 +184,7 @@ class StaticDestinationProtocol(Protocol):
def __init__(self, circuit, mode):
self.mode = mode
self.circuit = circuit
- self.direction = None # XXX currently unused
+ self.buffer = buffer.Buffer()
self.closed = False # True if connection is closed.
@@ -197,41 +198,34 @@ class StaticDestinationProtocol(Protocol):
it in our circuit.
"""
- # Initialize the buffer for this connection:
- self.buffer = ''
-
# Find the connection's direction and register it in the circuit.
if self.mode == 'client' and not self.circuit.upstream:
log.info("%s: connectionMade (client): " \
"Setting it as upstream on our circuit." % self.name)
self.circuit.setUpstreamConnection(self)
- self.direction = 'upstream'
elif self.mode == 'client':
log.info("%s: connectionMade (client): " \
"Setting it as downstream on our circuit." % self.name)
self.circuit.setDownstreamConnection(self)
- self.direction = 'downstream'
elif self.mode == 'server' and not self.circuit.downstream:
log.info("%s: connectionMade (server): " \
"Setting it as downstream on our circuit." % self.name)
self.circuit.setDownstreamConnection(self)
- self.direction = 'downstream'
elif self.mode == 'server':
log.info("%s: connectionMade (server): " \
"Setting it as upstream on our circuit." % self.name)
self.circuit.setUpstreamConnection(self)
- self.direction = 'upstream'
def connectionLost(self, reason):
- log.info("%s: Connection was lost (%s)." % (self.name, reason.getErrorMessage()))
+ log.debug("%s: Connection was lost (%s)." % (self.name, reason.getErrorMessage()))
self.circuit.close()
def connectionFailed(self, reason):
- log.info("%s: Connection failed to connect (%s)." % (self.name, reason.getErrorMessage()))
+ log.debug("%s: Connection failed to connect (%s)." % (self.name, reason.getErrorMessage()))
self.circuit.close()
def dataReceived(self, data):
@@ -243,21 +237,21 @@ class StaticDestinationProtocol(Protocol):
Circuit.setDownstreamConnection(). Document or split function.
"""
if (not self.buffer) and (not data):
- log.info("%s: dataReceived called without a reason.", self.name)
+ log.debug("%s: dataReceived called without a reason.", self.name)
return
log.debug("%s: Received %d bytes (and %d cached):\n%s" \
- % (self.name, len(data), len(self.buffer), str(data)))
+ % (self.name, len(data), len(self.buffer), repr(data)))
- # Circuit is not fully connected yet, cache what we got.
+ # Add the received data to the buffer.
+ self.buffer.write(data)
+
+ # Circuit is not fully connected yet, nothing to do here.
if not self.circuit.circuitIsReady():
- log.debug("%s: Caching them %d bytes." % (self.name, len(data)))
- self.buffer += data
+ log.debug("%s: Incomplete circuit; cached %d bytes." % (self.name, len(data)))
return
- # Send received and buffered data to the circuit. Buffer the
- # data that the transport could not use.
- self.buffer = self.circuit.dataReceived(self.buffer + data, self)
+ self.circuit.dataReceived(self.buffer, self)
def write(self, buf):
"""
@@ -300,7 +294,8 @@ class StaticDestinationClientFactory(Factory):
pass # connectionLost event is handled on the Protocol.
def clientConnectionFailed(self, connector, reason):
- pass # connectionFailed event is handled on the Protocol.
+ log.info("%s: Connection failed (%s)." % (self.name, reason.getErrorMessage()))
+ self.circuit.close()
class StaticDestinationServerFactory(Factory):
"""
@@ -317,12 +312,11 @@ class StaticDestinationServerFactory(Factory):
transport: the pluggable transport we should use to
obfuscate traffic on this connection.
"""
-
- def __init__(self, remote_addrport, mode, transport):
+ def __init__(self, remote_addrport, mode, transport_class):
self.remote_host = remote_addrport[0]
self.remote_port = int(remote_addrport[1])
self.mode = mode
- self.transport = transport
+ self.transport_class = transport_class
self.name = "fact_s_%s" % hex(id(self))
@@ -334,7 +328,7 @@ class StaticDestinationServerFactory(Factory):
def buildProtocol(self, addr):
log.info("%s: New connection." % self.name)
- circuit = Circuit(self.transport)
+ circuit = Circuit(self.transport_class())
# XXX instantiates a new factory for each client
clientFactory = StaticDestinationClientFactory(circuit, self.mode)
diff --git a/obfsproxy/test/buffer_unittest.py b/obfsproxy/test/buffer_unittest.py
new file mode 100644
index 0000000..4deefea
--- /dev/null
+++ b/obfsproxy/test/buffer_unittest.py
@@ -0,0 +1,43 @@
+import unittest
+
+import obfsproxy.network.buffer as buffer
+
+class testBuffer(unittest.TestCase):
+ def setUp(self):
+ self.test_string = "No pop no style, I strictly roots."
+ self.buf = buffer.Buffer(self.test_string)
+
+ def test_totalread(self):
+ tmp = self.buf.read(-1)
+ self.assertEqual(tmp, self.test_string)
+
+ def test_byte_by_byte(self):
+ """Read one byte at a time."""
+ for i in xrange(len(self.test_string)):
+ self.assertEqual(self.buf.read(1), self.test_string[i])
+
+ def test_bigread(self):
+ self.assertEqual(self.buf.read(666), self.test_string)
+
+ def test_peek(self):
+ tmp = self.buf.peek(-1)
+ self.assertEqual(tmp, self.test_string)
+ self.assertEqual(self.buf.read(-1), self.test_string)
+
+ def test_drain(self):
+ tmp = self.buf.drain(-1) # drain everything
+ self.assertIsNone(tmp) # check non-existent retval
+ self.assertEqual(self.buf.read(-1), '') # it should be empty.
+ self.assertEqual(len(self.buf), 0)
+
+ def test_drain2(self):
+ tmp = self.buf.drain(len(self.test_string)-1) # drain everything but a byte
+ self.assertIsNone(tmp) # check non-existent retval
+ self.assertEqual(self.buf.peek(-1), '.') # peek at last character
+ self.assertEqual(len(self.buf), 1) # length must be 1
+
+
+if __name__ == '__main__':
+ unittest.main()
+
+
diff --git a/obfsproxy/transports/base.py b/obfsproxy/transports/base.py
index f395b9b..bea8a5e 100644
--- a/obfsproxy/transports/base.py
+++ b/obfsproxy/transports/base.py
@@ -48,12 +48,14 @@ class BaseDaemon:
def receivedDownstream(self, data, circuit):
"""
Received 'data' in the downstream side of 'circuit'.
+ 'data' is an obfsproxy.network.buffer.Buffer.
"""
pass
def receivedUpstream(self, data, circuit):
"""
Received 'data' in the upstream side of 'circuit'.
+ 'data' is an obfsproxy.network.buffer.Buffer.
"""
pass
@@ -88,3 +90,5 @@ class BaseDaemon:
return False
return True
+
+class PluggableTransportError(Exception): pass
diff --git a/obfsproxy/transports/dummy.py b/obfsproxy/transports/dummy.py
index 706a358..02e321e 100644
--- a/obfsproxy/transports/dummy.py
+++ b/obfsproxy/transports/dummy.py
@@ -8,28 +8,23 @@ from obfsproxy.transports.base import BaseDaemon
class DummyDaemon(BaseDaemon):
"""
- DummyDaemon is the base class for DummyClient and DummyServer.
- Since the protocol is so simple, DummyDaemon provides all of the
- functionality for the dummy protocol implementation.
+ Implements the dummy protocol. A protocol that simply proxies data
+ without obfuscating them.
"""
def receivedDownstream(self, data, circuit):
"""
- receivedDownstream is the event which is called when bytes are received from the downstream socket.
- The dummy protocol just writes these to the upstream socket.
+ Got data from downstream; relay them upstream.
"""
- circuit.upstream.write(data)
- return ''
+ circuit.upstream.write(data.read())
def receivedUpstream(self, data, circuit):
"""
- receivedUpstream is the event which is called when bytes are received from the upstream socket.
- The dummy protocol just writes these to the downstream socket.
+ Got data from upstream; relay them downstream.
"""
- circuit.downstream.write(data)
- return ''
+ circuit.downstream.write(data.read())
class DummyClient(DummyDaemon):
diff --git a/obfsproxy/transports/transports.py b/obfsproxy/transports/transports.py
index 09db92d..c74c54c 100644
--- a/obfsproxy/transports/transports.py
+++ b/obfsproxy/transports/transports.py
@@ -3,13 +3,13 @@ import obfsproxy.transports.dummy as dummy
import obfsproxy.transports.b64 as b64
# XXX broken transports
#import obfsproxy.transports.dust_transport as dust
-#import obfsproxy.transports.obfs2 as obfs2
+import obfsproxy.transports.obfs2 as obfs2
#import obfsproxy.transports.obfs3 as obfs3
transports = { 'dummy' : {'client' : dummy.DummyClient, 'socks' : dummy.DummyClient, 'server' : dummy.DummyServer },
- 'b64' : {'client' : b64.B64Client, 'socks' : b64.B64Client, 'server' : b64.B64Server } }
+ 'b64' : {'client' : b64.B64Client, 'socks' : b64.B64Client, 'server' : b64.B64Server },
# 'dust' : {'client' : dust.DustClient, 'socks' : dust.DustClient, 'server' : dust.DustServer } }
-# 'obfs2' : {'client' : obfs2.Obfs2Client, 'socks' : obfs2.Obfs2Client, 'server' : obfs2.Obfs2Server },
+ 'obfs2' : {'client' : obfs2.Obfs2Client, 'socks' : obfs2.Obfs2Client, 'server' : obfs2.Obfs2Server } }
# 'obfs3' : {'client' : obfs3.Obfs3Client, 'socks' : obfs3.Obfs3Client, 'server' : obfs3.Obfs3Server }
def get_transport_class_from_name_and_mode(name, mode):
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-privacy/packages/obfsproxy.git
More information about the Pkg-privacy-commits
mailing list