[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