[Pkg-privacy-commits] [obfsproxy] 34/353: Documentation update and terminology normalization
Ximin Luo
infinity0 at moszumanska.debian.org
Sat Aug 22 13:01:35 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 783d1418581d97a03acfd6b1e840ce2affa715af
Author: Brandon Wiley <brandon at blanu.net>
Date: Mon Aug 20 16:51:01 2012 -0500
Documentation update and terminology normalization
---
bin/py-obfsproxy | 5 +-
src/cli.py | 20 ++---
src/obfsproxy/crypto/aes.py | 8 +-
src/obfsproxy/framework/circuit.py | 75 ++++++++++++++++++
src/obfsproxy/framework/proxy.py | 12 ++-
src/obfsproxy/framework/pump.py | 49 +++++++-----
src/obfsproxy/framework/socks.py | 18 ++++-
src/obfsproxy/framework/tunnel.py | 59 ---------------
src/obfsproxy/manager/clientManager.py | 21 ++++-
src/obfsproxy/manager/manager.py | 16 ++++
src/obfsproxy/manager/serverManager.py | 23 ++++--
src/obfsproxy/transports/base.py | 51 +++++++++++--
src/obfsproxy/transports/dummy.py | 37 +++++++--
src/obfsproxy/transports/dust_transport.py | 70 ++++++++++++-----
src/obfsproxy/transports/obfs2.py | 118 +++++++++++++++++++----------
src/obfsproxy/transports/obfs3.py | 71 ++++++++++++-----
src/obfsproxy/transports/rot13.py | 65 ++++++++++------
17 files changed, 490 insertions(+), 228 deletions(-)
diff --git a/bin/py-obfsproxy b/bin/py-obfsproxy
index 3dbbf50..25696cc 100755
--- a/bin/py-obfsproxy
+++ b/bin/py-obfsproxy
@@ -1,2 +1,5 @@
-python -u src/cli.py $*
+#!/bin/sh
+
+# Launched the py-obfsproxy command line interface. The -u option is required to get python to use unbuffered I/O.
+python -u src/cli.py $*
diff --git a/src/cli.py b/src/cli.py
index 25d1edf..d887e7d 100644
--- a/src/cli.py
+++ b/src/cli.py
@@ -1,6 +1,12 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+"""
+This is the command line interface to py-obfsproxy.
+It is designed to be a drop-in replacement for the obfsproxy executable.
+Currently, not all of the obfsproxy command line options have been implemented.
+"""
+
import os
import sys
import logging
@@ -48,16 +54,6 @@ if __name__ == '__main__':
help='enabled managed mode, for use when called by tor'
)
-# parser.add_argument('--dest', nargs=1,
-# help='set destination, enable client mode instead of server mode'
-# )
-
-# parser.add_argument('obfsproxy_args')
-# parser.add_argument('protocol_name')
-# parser.add_argument('protocol_args')
-# parser.add_argument('protocol_options')
-# parser.add_argument('protocol_name')
-
try:
args = parser.parse_args()
except Exception, e:
@@ -82,7 +78,3 @@ if __name__ == '__main__':
logging.error('Unsupported mode. Only managed mode is available at the moment.'
)
-# if dest:
-# daemon = ExternalClient()
-# else:
-# daemon = ExternalServer()
diff --git a/src/obfsproxy/crypto/aes.py b/src/obfsproxy/crypto/aes.py
index ff73130..fa4e572 100644
--- a/src/obfsproxy/crypto/aes.py
+++ b/src/obfsproxy/crypto/aes.py
@@ -1,5 +1,8 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+
+""" This module is a convenience wrapper for the AES cipher in CTR mode. """
+
from Crypto.Cipher import AES
from Crypto.Util import Counter
import base64
@@ -21,8 +24,9 @@ pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING
class AESCoder(object):
-
+ """ This class a convenience wrapper for the AES cipher in CTR mode. """
def __init__(self, key):
+ """ Initialize AES with the given key and two counters, one for encryption and one for decryption. """
counterIn = Counter.new(128)
self.cipherIn = AES.new(key, mode=AES.MODE_CTR,
counter=counterIn)
@@ -32,9 +36,11 @@ class AESCoder(object):
counter=counterOut)
def encrypt(self, data):
+ """ Encrypt the given data using AES in CTR mode and the key specified in __init__. """
return self.cipherOut.encrypt(pad(data))
def decrypt(self, data):
+ """ Decrypt the given data using AES in CTR mode and the key specified in __init__. """
return self.cipherIn.decrypt(data).rstrip(PADDING)
diff --git a/src/obfsproxy/framework/circuit.py b/src/obfsproxy/framework/circuit.py
new file mode 100644
index 0000000..cc66842
--- /dev/null
+++ b/src/obfsproxy/framework/circuit.py
@@ -0,0 +1,75 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+""" The circuit module contains the Buffer, Connection, and Circuit classes, which are used for managing connections. """
+
+class Buffer(object):
+ """ The Buffer class manages an internal byte buffer, allowing for reading and writing. """
+ def __init__(self):
+ """ Initialize the Buffer with an empty byte buffer. """
+ self.buffer=bytes('')
+
+ def read(self, x):
+ """ Read exactly x bytes from the buffer. If x bytes are not available, return None. """
+ if len(self.buffer)<x:
+ return None
+ else:
+ data=self.buffer[:x]
+ self.buffer=self.buffer[x:]
+ return data
+
+ def read_some(self):
+ """ Read all of the bytes from the buffer. """
+ return self.read(len(self.buffer))
+
+ def write(self, bs):
+ """ Write the bytes bs to the buffer. """
+ self.buffer=self.buffer+bs
+
+class Connection(object):
+ """ The Connection class contains two buffers, incoming and outgoing. It allows for reading from the incoming buffer and writing to the outgoing buffer. A Connection can be inverted to flip the incoming and outgoing buffers. """
+ def __init__(self, incoming=None, outgoing=None):
+ """ Initialize the Connection's incoming and outgoing buffers. If either buffer is supplied as an optional parameters, reuse that Buffer, otherwise create a new empty Buffer. """
+ if incoming:
+ self.incomingBuffer=incoming
+ else:
+ self.incomingBuffer=Buffer()
+
+ if outgoing:
+ self.outgoingBuffer=outgoing
+ else:
+ self.outgoingBuffer=Buffer()
+
+ def invert(self):
+ """ Returns a Connection with the incoming and outgoing buffers switched. """
+ return Connection(self.outgoingBuffer, self.incomingBuffer)
+
+ def read(self, x):
+ """ Read exactly x bytes from the incoming buffer. If x bytes are not available, return None. """
+ return self.incomingBuffer.read(x)
+
+ def read_some(self):
+ """ Read all of the bytes from the incoming buffer. """
+ return self.incomingBuffer.read_some()
+
+ def write(self, bs):
+ """ Write the bytes bs to the outgoing buffer. """
+ self.outgoingBuffer.write(bs)
+
+class Circuit(object):
+ """ The Circuit class contains two connections, one upstream and one downstream. """
+ def __init__(self, downstream=None, upstream=None):
+ """ Initialize the Circuit's upstream and downstream conections. If either connection is supplied as an optional parameters, reuse that Connection, otherwise create a new Connection. """
+ if downstream:
+ self.downstream=downstream
+ else:
+ self.downstream=Connection()
+ if remove:
+ self.upstream=upstream
+ else:
+ self.upstream=Connection()
+
+ def invert(self):
+ """ Returns a Circuit with the incoming and outgoing buffers switched on the Connections. """
+ return Circuit(self.downstream.invert(), self.upstream.invert())
+
diff --git a/src/obfsproxy/framework/proxy.py b/src/obfsproxy/framework/proxy.py
index 23f23cf..03f7914 100644
--- a/src/obfsproxy/framework/proxy.py
+++ b/src/obfsproxy/framework/proxy.py
@@ -1,6 +1,10 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+"""
+The proxy module contains the ProxyHandler class, which implements the server-side handling of pluggable transports.
+"""
+
from struct import unpack
from socket import inet_ntoa
@@ -16,17 +20,21 @@ from obfsproxy.framework.pump import Pump
class ProxyHandler:
-
+ """
+ The ProxyHandler class implements the server-side handling of pluggable transports.
+ """
transport = None
def setTransport(self, transport):
+ """ setTransport sets the pluggable transport for this proxy server """
self.transport = transport
@_o
def handle(self, conn):
+ """ handle is called by the framework to establish a new proxy connection to the Tor server and start processing when an incoming client connection is established. """
print 'connection'
client = Client()
- yield client.connect('blanu.net', 80)
+ yield client.connect('blanu.net', 80) # FIXME - remove hardcoded destination
self.pump=Pump(conn, client, self.transport)
self.pump.run()
diff --git a/src/obfsproxy/framework/pump.py b/src/obfsproxy/framework/pump.py
index 1b93c54..f840c74 100644
--- a/src/obfsproxy/framework/pump.py
+++ b/src/obfsproxy/framework/pump.py
@@ -1,35 +1,41 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+""" The pump module contains the Pump class, which takes care of moving bytes between the upstream and downstream connections. """
+
import monocle
from monocle import _o, Return
from monocle.stack.network import ConnectionLost
from obfsproxy.util import encode
-from obfsproxy.framework.tunnel import Tunnel
+from obfsproxy.framework.circuit import Circuit
class Pump(object):
- def __init__(self, local, remote, transportClass):
- self.local=local
- self.remote=remote
+ """ The Pump class takes care of moving bytes between the upstream and downstream connections. """
+ def __init__(self, downstream, upstream, transportClass):
+ """ Initializes the downstream and upstream instance variables, instantiates the transportClass, and sets up a circuit. """
+ self.downstream=downstream
+ self.upstream=upstream
- tunnel=Tunnel()
- self.transport=transportClass(tunnel)
- self.tunnel=tunnel.invert()
+ circuit=Circuit()
+ self.transport=transportClass(circuit)
+ self.circuit=circuit.invert()
def run(self):
+ """ Calls the start event on the transport and initiates pumping between upstream and downstream connections in both directions. """
self.transport.start()
- monocle.launch(self.pumpLocal)
- yield self.pumpRemote()
+ monocle.launch(self.pumpDownstream)
+ yield self.pumpUpstream()
@_o
- def pumpLocal(self):
+ def pumpDownstream(self):
+ """ Handle the downstream connection. """
while True:
- data=self.tunnel.local.read_some()
+ data=self.circuit.downstream.read_some()
if data:
try:
- yield self.local.write(data)
+ yield self.downstream.write(data)
except ConnectionLost:
print 'Connection lost'
return
@@ -42,10 +48,10 @@ class Pump(object):
return
try:
- data = yield self.local.read_some()
+ data = yield self.downstream.read_some()
if data:
- self.tunnel.local.write(data)
- self.transport.decodedReceived()
+ self.circuit.downstream.write(data)
+ self.transport.receivedDownstream()
except ConnectionLost:
print 'Client connection closed'
return
@@ -53,12 +59,13 @@ class Pump(object):
return
@_o
- def pumpRemote(self):
+ def pumpUpstream(self):
+ """ Handle the upstream connection. """
while True:
- data=self.tunnel.remote.read_some()
+ data=self.circuit.upstream.read_some()
if data:
try:
- yield self.remote.write(data)
+ yield self.upstream.write(data)
except ConnectionLost:
print 'Connection lost'
return
@@ -71,10 +78,10 @@ class Pump(object):
return
try:
- data = yield self.remote.read_some()
+ data = yield self.upstream.read_some()
if data:
- self.tunnel.remote.write(data)
- self.transport.encodedReceived()
+ self.circuit.upstream.write(data)
+ self.transport.receivedUpstream()
except ConnectionLost:
print 'Client connection closed'
return
diff --git a/src/obfsproxy/framework/socks.py b/src/obfsproxy/framework/socks.py
index f615796..1a4015d 100644
--- a/src/obfsproxy/framework/socks.py
+++ b/src/obfsproxy/framework/socks.py
@@ -1,6 +1,10 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+"""
+The socks module contains the SocksHandler class, which implements the client-side handling of pluggable transports.
+"""
+
import logging
from struct import unpack
from socket import inet_ntoa
@@ -16,12 +20,14 @@ from obfsproxy.util import encode
from obfsproxy.framework.pump import Pump
def uncompact(x):
+ """ uncompact is a convenience method for unpacking an IPv4 address from its byte representation. """
(ip, port) = unpack('!4sH', x)
return (inet_ntoa(ip), port)
@_o
def readHandshake(input):
+ """ readHandshake reads the SOCKS handshake information to the SOCKS client. """
version = (yield input.read(1))
logging.info('version: %s' % (encode(str(version))))
nauth = (yield input.read(1))
@@ -35,11 +41,13 @@ def readHandshake(input):
@_o
def sendHandshake(output):
+ """ sendHandshake sends the SOCKS handshake information to the SOCKS client. """
yield output.write('\x05\x00')
@_o
def readRequest(input):
+ """ readRequest reads the SOCKS request information from the client and returns the bytes represneting the IPv4 destination. """
version = (yield input.read(1))
command = (yield input.read(1))
reserved = (yield input.read(1))
@@ -51,18 +59,23 @@ def readRequest(input):
@_o
def sendResponse(dest, output):
+ """ sendResponse sends the SOCKS response to the request. """
yield output.write('\x05\x00\x00\x01' + dest)
class SocksHandler:
-
+ """
+ The SocksHandler class implements the client-side handling of pluggable transports.
+ """
transport = None
def setTransport(self, transport):
+ """ setTransport sets the pluggable transport for this proxy server """
self.transport = transport
@_o
def handle(self, conn):
+ """ handle is called by the framework to establish a new connection to the proxy server and start processing when an incoming SOCKS client connection is established. """
logging.info('handle_socks')
yield readHandshake(conn)
logging.info('read handshake')
@@ -75,9 +88,6 @@ class SocksHandler:
(addr, port) = uncompact(dest)
-# addr='127.0.0.1'
-# port=8183
-
logging.info(addr)
logging.info(port)
diff --git a/src/obfsproxy/framework/tunnel.py b/src/obfsproxy/framework/tunnel.py
deleted file mode 100644
index 28ec8bc..0000000
--- a/src/obfsproxy/framework/tunnel.py
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-class Buffer(object):
- def __init__(self):
- self.buffer=bytes('')
-
- def read(self, x):
- if len(self.buffer)<x:
- return None
- else:
- data=self.buffer[:x]
- self.buffer=self.buffer[x:]
- return data
-
- def read_some(self):
- return self.read(len(self.buffer))
-
- def write(self, bs):
- self.buffer=self.buffer+bs
-
-class Channel(object):
- def __init__(self, incoming=None, outgoing=None):
- if incoming:
- self.incomingBuffer=incoming
- else:
- self.incomingBuffer=Buffer()
-
- if outgoing:
- self.outgoingBuffer=outgoing
- else:
- self.outgoingBuffer=Buffer()
-
- def invert(self):
- return Channel(self.outgoingBuffer, self.incomingBuffer)
-
- def read(self, x):
- return self.incomingBuffer.read(x)
-
- def read_some(self):
- return self.incomingBuffer.read_some()
-
- def write(self, bs):
- self.outgoingBuffer.write(bs)
-
-class Tunnel(object):
- def __init__(self, local=None, remote=None):
- if local:
- self.local=local
- else:
- self.local=Channel()
- if remove:
- self.remote=remote
- else:
- self.remote=Channel()
-
- def invert(self):
- return Tunnel(self.local.invert(), self.remote.invert())
-
diff --git a/src/obfsproxy/manager/clientManager.py b/src/obfsproxy/manager/clientManager.py
index 95b46f1..c8d3ec9 100644
--- a/src/obfsproxy/manager/clientManager.py
+++ b/src/obfsproxy/manager/clientManager.py
@@ -1,19 +1,32 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+"""
+This module contains the ClientManager class, which implemnts a client manager.
+Managers are command line tools used for testing transports. They simulate Tor by launching transports and providing similar environment variables as would be provided by Tor.
+Managers are only necessary for testing. In actual deployment, Tor can be used.
+"""
+
import os
+import sys
from obfsproxy.manager.manager import Manager
class ClientManager(Manager):
-
- def __init__(self):
+ """ The ClientManager class implemnts a client manager. """
+ def __init__(self, transport):
+ """
+ Call superclass initializer to initialize the environment variables which are used by both clients and servers.
+ Then initialize the environment variable which is used bo just clients.
+ This is TOR_PT_CLIENT_TRANSPORTS.
+ """
Manager.__init__(self)
- os.environ['TOR_PT_CLIENT_TRANSPORTS'] = 'dummy'
+ os.environ['TOR_PT_CLIENT_TRANSPORTS'] = transport
if __name__ == '__main__':
- manager = ClientManager()
+ transport=sys.argv[1]
+ manager = ClientManager(transport)
manager.launch()
diff --git a/src/obfsproxy/manager/manager.py b/src/obfsproxy/manager/manager.py
index 9f5e26f..ffd888e 100644
--- a/src/obfsproxy/manager/manager.py
+++ b/src/obfsproxy/manager/manager.py
@@ -1,18 +1,34 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+"""
+This module contains the Manager class, the base class for client and server managers.
+Managers are command line tools used for testing transports. They simulate Tor by launching transports and providing similar environment variables as would be provided by Tor.
+Managers are only necessary for testing. In actual deployment, Tor can be used.
+"""
+
import os
import sys
import subprocess
class Manager:
+ """ The Manager class is the base class for client and server managers. """
def __init__(self):
+ """
+ Initialize the environment variables which are used by both clients and servers.
+ These are TOR_PT_STATE_LOCATION and TOR_PT_MANAGED_TRANSPORT_VER
+ """
os.environ['TOR_PT_STATE_LOCATION'] = '/'
os.environ['TOR_PT_MANAGED_TRANSPORT_VER'] = '1'
def launch(self):
+ """
+ Launch the client or server process and wait for it to exit, in the meantime printing any output it generates.
+ Launching of the client and server is identical.
+ The client/server behavior is determined by which environment variables have been set by the ClientManager and ServerManager subclasses.
+ """
p = subprocess.Popen(['python', '-u', 'src/cli.py', '--managed'
], stdout=subprocess.PIPE)
line = p.stdout.readline().strip()
diff --git a/src/obfsproxy/manager/serverManager.py b/src/obfsproxy/manager/serverManager.py
index 1c56dc7..39a95dc 100644
--- a/src/obfsproxy/manager/serverManager.py
+++ b/src/obfsproxy/manager/serverManager.py
@@ -1,22 +1,35 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+"""
+This module contains the ServerManager class, which implemnts a server manager.
+Managers are command line tools used for testing transports. They simulate Tor by launching transports and providing similar environment variables as would be provided by Tor.
+Managers are only necessary for testing. In actual deployment, Tor can be used.
+"""
+
import os
+import sys
from obfsproxy.manager.manager import Manager
class ServerManager(Manager):
-
- def __init__(self):
+ """ The ServerManager class implemnts a client manager. """
+ def __init__(self, transport):
+ """
+ Call superclass initializer to initialize the environment variables which are used by both clients and servers.
+ Then initialize the environment variables which are used bo just servers.
+ These are TOR_PT_EXTENDED_SERVER_PORT, TOR_PT_ORPORT, TOR_PT_SERVER_BINDADDR, and TOR_PT_SERVER_TRANSPORTS.
+ """
Manager.__init__(self)
os.environ['TOR_PT_EXTENDED_SERVER_PORT'] = '127.0.0.1:22211'
os.environ['TOR_PT_ORPORT'] = '127.0.0.1:43210'
- os.environ['TOR_PT_SERVER_BINDADDR'] = 'dummy-127.0.0.1:46466'
- os.environ['TOR_PT_SERVER_TRANSPORTS'] = 'dummy'
+ os.environ['TOR_PT_SERVER_BINDADDR'] = transport+'-127.0.0.1:46466'
+ os.environ['TOR_PT_SERVER_TRANSPORTS'] = transport
if __name__ == '__main__':
- manager = ServerManager()
+ transport=sys.argv[1]
+ manager = ServerManager(transport)
manager.launch()
diff --git a/src/obfsproxy/transports/base.py b/src/obfsproxy/transports/base.py
index bb011d5..7c7fadc 100644
--- a/src/obfsproxy/transports/base.py
+++ b/src/obfsproxy/transports/base.py
@@ -1,12 +1,20 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+"""
+This module contains BaseDaemon, a base class for implementing pluggable transport clients and server.
+It is not necessary to subclass BaseDaemon in order to implement pluggable transports.
+However, BaseDaemon provides utility methods that are useful for a variety of common transports.
+"""
class BaseDaemon:
-
- def __init__(self, decodedSocket, encodedSocket):
- self.decodedSocket = decodedSocket
- self.encodedSocket = encodedSocket
+ """
+ The BaseDaemon class is a base class for implementing pluggable transport clients and server.
+ """
+ def __init__(self, downstreamConnection, upstreamConnection):
+ """ Store the upstream and downstream sockets for use in other methods. """
+ self.downstreamConnection = downstreamConnection
+ self.upstreamConnection = upstreamConnection
def read(
self,
@@ -14,6 +22,11 @@ class BaseDaemon:
data,
maxlen,
):
+ """
+ This read method is a convience method which takes a socket to read from, some existing data, and a maxlength.
+ It reads bytes from socket and appends them to data until data is equal to maxlen, or the socket has no more bytes ready.
+ It returns a new data object which is a combination of data and the bytes read from socket and which is <= maxlen.
+ """
remaining = maxlen - len(data)
return data + socket.read(remaining)
@@ -23,6 +36,12 @@ class BaseDaemon:
maxlen,
newState,
):
+ """
+ This is a convience method for state-based protocols which need to read fixed length data from the socket before they can change states.
+ The checkTransition method takes some data, a max length, and state identifier.
+ If len(data) == maxlen then the state is set to the state is set to newState and True is returned.
+ Otherwise, the state stays the same and False is returned.
+ """
if len(data) == maxlen:
state = newState
return True
@@ -30,15 +49,35 @@ class BaseDaemon:
return False
def start(self):
+ """
+ This is the callback method which is called by the framework when a new connection has been made.
+ In BaseDaemon it does nothing.
+ It is overridden by subclasses.
+ """
pass
- def receivedDecoded(self):
+ def receivedDownstream(self):
+ """
+ This is the callback method which is called by the framework when bytes have been received on the downstream socket.
+ In BaseDaemon it does nothing.
+ It is overridden by subclasses.
+ """
pass
- def receivedEncoded(self):
+ def receivedUpstream(self):
+ """
+ This is the callback method which is called by the framework when bytes have been received on the upstream socket.
+ In BaseDaemon it does nothing.
+ It is overridden by subclasses.
+ """
pass
def end(self):
+ """
+ This is the callback method which is called by the framework when the connection is closed.
+ In BaseDaemon it does nothing.
+ It is overridden by subclasses.
+ """
pass
diff --git a/src/obfsproxy/transports/dummy.py b/src/obfsproxy/transports/dummy.py
index 7f1e69c..eccc918 100644
--- a/src/obfsproxy/transports/dummy.py
+++ b/src/obfsproxy/transports/dummy.py
@@ -1,26 +1,47 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+""" This module contains an implementation of the 'dummy' transport. """
+
from obfsproxy.transports.base import BaseDaemon
class DummyDaemon(BaseDaemon):
-
- def receivedDecoded(self):
- data = self.decodedSocket.readAll()
- self.encodedSocket.write(data)
-
- def receivedEncoded(self):
- data = self.encodedSocket.readAll()
- self.decodedSocket.write(data)
+ """
+ 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.
+ """
+ def receivedDownstream(self):
+ """
+ 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.
+ """
+ data = self.downstreamConnection.readAll()
+ self.upstreamConnection.write(data)
+
+ def receivedUpstream(self):
+ """
+ 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.
+ """
+ data = self.upstreamConnection.readAll()
+ self.downstreamConnection.write(data)
class DummyClient(DummyDaemon):
+ """
+ DummyClient is a client for the 'dummy' protocol.
+ Since this protocol is so simple, the client and the server are identical and both just trivially subclass DummyDaemon.
+ """
pass
class DummyServer(DummyDaemon):
+ """
+ DummyServer is a server for the 'dummy' protocol.
+ Since this protocol is so simple, the client and the server are identical and both just trivially subclass DummyDaemon.
+ """
pass
diff --git a/src/obfsproxy/transports/dust_transport.py b/src/obfsproxy/transports/dust_transport.py
index f9d9a39..fd7ad86 100644
--- a/src/obfsproxy/transports/dust_transport.py
+++ b/src/obfsproxy/transports/dust_transport.py
@@ -1,6 +1,10 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+"""
+The dust_transport module contains the DustDaemon, DustClient, and DustServer classes which implement the Dust transport.
+"""
+
from dust.extensions.lite.lite_socket2 import lite_socket, makeSession, \
makeEphemeralSession, createEphemeralKeypair
from dust.core.dust_packet import IV_SIZE, KEY_SIZE
@@ -14,60 +18,88 @@ HANDSHAKE_SIZE = IV_SIZE + KEY_SIZE
class DustDaemon(BaseDaemon):
-
- def __init__(self, decodedSocket, encodedSocket):
- BaseDaemon.__init__(self, decodedSocket, encodedSocket)
+ """
+ DustDaemon is the base class for DustClient and DustServer.
+ It implements the functionality which is common across both the client and server implementations.
+ """
+ def __init__(self, downstreamConnection, upstreamConnection):
+ """
+ Initializes the daemon with a downstream and upstream socket.
+ This also sets the protocol state to HANDSHAKE_WRITE and generates an ephemeral keypair.
+ """
+ BaseDaemon.__init__(self, downstreamConnection, upstreamConnection)
self.state = HANDSHAKE_WRITE
self.ekeypair = createEphemeralKeypair()
self.epub = bytes('')
def start(self):
- self.encodedSocket.write(self.ekeypair.public.bytes)
-
- def receivedDecoded(self):
-
+ """
+ This is the callback method which is called by the framework when a new connection has been made.
+ In the Dust protocol, on start the public part of the ephemeral keypair is written upstream.
+ """
+ self.upstreamConnection.write(self.ekeypair.public.bytes)
+
+ def receivedDownstream(self):
+ """
+ This is the callback method which is called by the framework when bytes have been received on the downstream socket.
+ In the Dust protocol, downstream bytes are buffered until the handshake is complete and the protocol is in STREAM mode, at which point all bytes received from downstream are encrypted and sent upstream.
+ """
# If we're in streaming mode, encode and write the incoming data
if self.state == STREAM:
- data = self.decodedSocket.readAll()
+ data = self.downstreamConnection.readAll()
if data:
- self.encodedSocket.write(self.coder.encode(data))
+ self.upstreamConnection.write(self.coder.encode(data))
# Else do nothing, data will buffer until we've done the handshake
- def receivedEncoded(self, data):
+ def receivedUpstream(self, data):
+ """
+ This is the callback method which is called by the framework when bytes have been received on the upstream socket.
+ In the Dust protocol, the upstream handshake is read, and then the protocol is switched to STREAM mode, at which point all bytes received from upstream are encrypted and sent downstream.
+ """
if self.state == HANDSHAKE:
- self.epub = self.read(self.encodedSocket, self.epub,
+ self.epub = self.read(self.upstreamConnection, self.epub,
HANDSHAKE_SIZE)
if self.checkTransition(self.epub, HANDSHAKE_SIZE, STREAM):
esession = makeEphemeralSession(self.ekeypair,
self.epub)
self.coder = lite_socket(esession)
- data = self.decodedSocket.readAll()
+ data = self.downstreamConnection.readAll()
if data:
- self.encodedSocket.write(self.coder.encode(data))
+ self.upstreamConnection.write(self.coder.encode(data))
- data = self.encodedSocket.readAll()
+ data = self.upstreamConnection.readAll()
if data:
- self.decodedSocket.write(self.coder.decode(data))
+ self.downstreamConnection.write(self.coder.decode(data))
else:
- data = self.encodedSocket.readAll()
+ data = self.upstreamConnection.readAll()
if data:
- self.decodedSocket.write(self.coder.decode(data))
+ self.downstreamConnection.write(self.coder.decode(data))
def end(self):
+ """
+ This is the callback method which is called by the framework when the connection is closed.
+ In DustDaemon it does nothing.
+ """
pass
class DustClient(DustDaemon):
-
+ """
+ DustClient is a client for the Dust protocol.
+ In this simplified implementation of the protocol, the client and the server are identical and both just trivially subclass DustDaemon.
+ """
pass
class DustServer(DustDaemon):
-
+ """
+ DustServer is a server for the Dust protocol.
+ In this simplified implementation of the protocol, the client and the server are identical and both just trivially subclass DustDaemon.
+ """
pass
diff --git a/src/obfsproxy/transports/obfs2.py b/src/obfsproxy/transports/obfs2.py
index 203adb6..e18c3e4 100644
--- a/src/obfsproxy/transports/obfs2.py
+++ b/src/obfsproxy/transports/obfs2.py
@@ -1,6 +1,10 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+"""
+The obfs2 module implements the obfs2 protocol.
+"""
+
import os
import random
@@ -29,76 +33,82 @@ READ_PADDING = 3
STREAM = 4
-# H(x) is SHA256 of x.
-
def h(x):
+ """ H(x) is SHA256 of x. """
hasher = hashlib.sha256()
hasher.update(x)
return hasher.digest()
-# H^n(x) is H(x) called iteratively n times.
-
def hn(x, n):
+ """ H^n(x) is H(x) called iteratively n times. """
data = x
for x in range(n):
data = h(data)
return data
-# E(k,s) is the AES-CTR-128 encryption of s using K as key.
-
def e(k, s):
+ """ E(k,s) is the AES-CTR-128 encryption of s using K as key. """
cipher = AESCoder(k)
return cipher.encode(s)
-# D(k, s) is the AES-CTR-128 decryption of s using K as key.
-
def d(k, s):
+ """ D(k, s) is the AES-CTR-128 decryption of s using K as key. """
cipher = AESCoder(k)
return cipher.decode(s)
-# UINT32(n) is the 4 byte value of n in big-endian (network) order.
-
def uint32(n):
+ """ UINT32(n) is the 4 byte value of n in big-endian (network) order. """
return struct.pack('!I', n)
def decodeUint32(bs):
+ """
+ decodeUint32(bs) is the reverse of uint32(n).
+ It returns the int value represneted by the 4 byte big-endian (network) order encoding represented by bs.
+ """
return struct.unpack('!I', bs)[0]
-# SR(n) is n bytes of strong random data.
-
def sr(n):
+ """ SR(n) is n bytes of strong random data. """
return os.urandom(n)
-# WR(n) is n bytes of weaker random data.
-
def wr(n):
+ """ WR(n) is n bytes of weaker random data. """
return ''.join(chr(random.randint(0, 255)) for _ in range(n))
-# MAC(s, x) = H(s | x | s)
-
def mac(s, x):
+ """ # MAC(s, x) = H(s | x | s) """
return h(s + x + s)
class Obfs2Daemon(BaseDaemon):
-
- def __init__(self, decodedSocket, encodedSocket):
- self.decodedSocket = decodedSocket
- self.encodedSocket = encodedSocket
+ """
+ Obfs2Daemon implements the obfs2 protocol.
+ It is subclassed by Obfs2Client and Obfs2Server.
+ """
+ def __init__(self, downstreamConnection, upstreamConnection):
+ """
+ Initializes the Obfs2Daemon instance with the upstream and downstream connections.
+ Also initializes the seed, padkey, and padlen buffers to be empty byte strings.
+ """
+ self.downstreamConnection = downstreamConnection
+ self.upstreamConnection = upstreamConnection
self.otherSeed = bytes('')
self.otherPadKeyEncrypted = bytes('')
self.otherPadLenBytes = bytes('')
def start(self):
-
+ """
+ This is the callback method which is called by the framework when a new connection has been made.
+ In the obfs2 protocol, on start the seed, encrypted magic value, padding length, and padding are written upstream.
+ """
# The initiator generates:
# INIT_SEED = SR(SEED_LENGTH)
@@ -118,39 +128,52 @@ class Obfs2Daemon(BaseDaemon):
self.state = READ_SEED
- def receivedDecoded(self):
+ def receivedDownstream(self):
+ """
+ This is the callback method which is called by the framework when bytes have been received on the downstream socket.
+ In the obfs2 protocol, downstream bytes are buffered until the handshake is complete and the protocol is in STREAM mode, at which point all bytes received from downstream are encrypted and sent upstream.
+ """
if state == STREAM:
- data = self.decodedSocket.readAll()
+ data = self.downstreamConnection.readAll()
encodedData = encode(data)
- self.encodedSocket.write(encodedData)
-
- def receivedEncoded(self):
+ self.upstreamConnection.write(encodedData)
+
+ def receivedUpstream(self):
+ """
+ This is the callback method which is called by the framework when bytes have been received on the upstream socket.
+ In the obfs2 protocol, the upstream data stream is read to find the following values:
+ - seed
+ - padding key
+ - padding length
+ - padding
+ The protocol is then switched to STREAM mode, at which point all bytes received from upstream are encrypted and sent downstream.
+ """
if state == READ_SEED:
- self.otherSeed = self.read(self.encodedSocket,
+ self.otherSeed = self.read(self.upstreamConnection,
self.otherSeed, SEED_LENGTH)
if self.checkTransition(self.otherSeed, SEED_LENGTH,
READ_PADKEY):
self.otherPadKeyDerived = \
self.derivePadKey(self.otherSeed, not self.server)
elif state == READ_PADKEY:
- self.otherPadKeyEncrypted = self.read(self.encodedSocket,
+ self.otherPadKeyEncrypted = self.read(self.upstreamConnection,
self.otherPadKeyEncrypted, KEYLEN)
if self.checkTransition(self.otherPadKeyEncrypted, KEYLEN,
READ_PADLEN):
if self.otherPadKeyEncrypted != self.otherPadKeyDerived:
- self.encodedSocket.disconnect()
- self.decodedSocket.disconnect()
+ self.upstreamConnection.disconnect()
+ self.downstreamConnection.disconnect()
elif state == READ_PADLEN:
- self.otherPadLenBytes = self.read(self.encodedSocket,
+ self.otherPadLenBytes = self.read(self.upstreamConnection,
self.otherPadLenBytes, 4)
if self.checkTransition(self.otherPadLenBytes, 4,
READ_PADDING):
self.otherPadLen = decodeUint32(self.otherPadLenBytes)
if self.otherPadLen > MAX_PADDING:
- self.encodedSocket.disconnect()
- self.decodedSocket.disconnect()
+ self.upstreamConnection.disconnect()
+ self.downstreamConnection.disconnect()
elif state == READ_PADDING:
- self.otherPadding = self.read(self.encodedSocket,
+ self.otherPadding = self.read(self.upstreamConnection,
self.otherPadding, self.otherPadLen)
if self.checkTransition(self.otherPadding,
self.otherPadLen, READ_PADDING):
@@ -175,11 +198,12 @@ class Obfs2Daemon(BaseDaemon):
self.otherCipher = initCipher(self.otheriv,
self.otherKey)
elif state == STREAM:
- data = self.encodedSocket.readAll()
+ data = self.upstreamConnection.readAll()
decodedData = decode(data)
- self.decodedSocket.write(decodedData)
+ self.downstreamConnection.write(decodedData)
def derivePadKey(self, seed, padString):
+ """ derivePadKey returns the MAC of the padString and seed. """
return mac(padString, seed)[:KEYLEN]
def deriveSecret(
@@ -188,6 +212,7 @@ class Obfs2Daemon(BaseDaemon):
otherSeed,
server,
):
+ """ deriveSecret returns the MAC of the stored padString, the seed, and the otherSeed. """
if server:
# RESP_SECRET = MAC("Responder obfuscated data", INIT_SEED|RESP_SEED)
@@ -200,25 +225,34 @@ class Obfs2Daemon(BaseDaemon):
return mac(self.padString, seed + otherSeed)
def initCipher(self, iv, key):
+ """ initCipher initializes the AES cipher using the given key and IV. """
coder = AESCoder(key)
coder.encode(iv)
return coder
def end(self):
+ """
+ This is the callback method which is called by the framework when the connection is closed.
+ In Obfs2Daemon it does nothing.
+ """
pass
class Obfs2Client(Obfs2Daemon):
-
- def __init__(self, decodedSocket, encodedSocket):
+ """
+ Obfs2Client is a client for the obfs2 protocol.
+ The client and server differ in terms of their padding strings.
+ """
+ def __init__(self, downstreamConnection, upstreamConnection):
self.padString = 'Initiator obfuscation padding'
self.otherPadString = 'Responder obfuscation padding'
class Obfs2Server(Obfs2Daemon):
-
- def __init__(self, decodedSocket, encodedSocket):
+ """
+ Obfs2Server is a server for the obfs2 protocol.
+ The client and server differ in terms of their padding strings.
+ """
+ def __init__(self, downstreamConnection, upstreamConnection):
self.padString = 'Responder obfuscation padding'
self.otherPadString = 'Initiator obfuscation padding'
-
-
diff --git a/src/obfsproxy/transports/obfs3.py b/src/obfsproxy/transports/obfs3.py
index a4c10b4..0b9ec6a 100644
--- a/src/obfsproxy/transports/obfs3.py
+++ b/src/obfsproxy/transports/obfs3.py
@@ -1,6 +1,10 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+"""
+The obfs3 module implements the obfs3 protocol.
+"""
+
from dust.extensions.lite.lite_socket2 import makeSession, \
makeEphemeralSession, createEphemeralKeypair
from dust.core.dust_packet import IV_SIZE, KEY_SIZE
@@ -15,60 +19,87 @@ HANDSHAKE_SIZE = IV_SIZE + KEY_SIZE
class Obfs3Daemon(BaseDaemon):
-
- def __init__(self, decodedSocket, encodedSocket):
- BaseDaemon.__init__(self, decodedSocket, encodedSocket)
+ """
+ Obfs2Daemon implements the obfs2 protocol.
+ It is subclassed by Obfs2Client and Obfs2Server.
+ """
+ def __init__(self, downstreamConnection, upstreamConnection):
+ """
+ Initializes the daemon with a downstream and upstream socket.
+ This also sets the protocol state to HANDSHAKE_WRITE and generates an ephemeral keypair.
+ """
+ BaseDaemon.__init__(self, downstreamConnection, upstreamConnection)
self.state = HANDSHAKE_WRITE
self.ekeypair = createEphemeralKeypair()
self.epub = bytes('')
def start(self):
- self.encodedSocket.write(self.ekeypair.public.bytes)
-
- def receivedDecoded(self):
+ """
+ This is the callback method which is called by the framework when a new connection has been made.
+ In the obfs3 protocol, on start the public part of the ephemeral keypair is written upstream.
+ """
+ self.upstreamConnection.write(self.ekeypair.public.bytes)
+
+ def receivedDownstream(self):
+ """
+ This is the callback method which is called by the framework when bytes have been received on the downstream socket.
+ In the obfs3 protocol, downstream bytes are buffered until the handshake is complete and the protocol is in STREAM mode, at which point all bytes received from downstream are encrypted and sent upstream.
+ """
# If we're in streaming mode, encode and write the incoming data
if self.state == STREAM:
- data = self.decodedSocket.readAll()
+ data = self.downstreamConnection.readAll()
if data:
- self.encodedSocket.write(self.coder.encode(data))
+ self.upstreamConnection.write(self.coder.encode(data))
# Else do nothing, data will buffer until we've done the handshake
- def receivedEncoded(self, data):
+ def receivedUpstream(self, data):
+ """
+ This is the callback method which is called by the framework when bytes have been received on the upstream socket.
+ In the obfs3 protocol, the upstream handshake is read, and then the protocol is switched to STREAM mode, at which point all bytes received from upstream are encrypted and sent downstream.
+ """
if self.state == HANDSHAKE:
- self.epub = self.read(self.encodedSocket, self.epub,
+ self.epub = self.read(self.upstreamConnection, self.epub,
HANDSHAKE_SIZE)
if self.checkTransition(self.epub, HANDSHAKE_SIZE, STREAM):
esession = makeEphemeralSession(self.ekeypair,
self.epub)
self.coder = AESCoder(esession)
- data = self.decodedSocket.readAll()
+ data = self.downstreamConnection.readAll()
if data:
- self.encodedSocket.write(self.coder.encode(data))
+ self.upstreamConnection.write(self.coder.encode(data))
- data = self.encodedSocket.readAll()
+ data = self.upstreamConnection.readAll()
if data:
- self.decodedSocket.write(self.coder.decode(data))
+ self.downstreamConnection.write(self.coder.decode(data))
else:
- data = self.encodedSocket.readAll()
+ data = self.upstreamConnection.readAll()
if data:
- self.decodedSocket.write(self.coder.decode(data))
+ self.downstreamConnection.write(self.coder.decode(data))
def end(self):
+ """
+ This is the callback method which is called by the framework when the connection is closed.
+ In Obfs3Daemon it does nothing.
+ """
pass
class Obfs3Client(Obfs3Daemon):
-
+ """
+ Obfs3Client is a client for the obfs3 protocol.
+ In this simplified implementation of the protocol, the client and the server are identical and both just trivially subclass DustDaemon.
+ """
pass
class Obfs3Server(Obfs3Daemon):
-
+ """
+ Obfs3Server is a server for the obfs3 protocol.
+ In this simplified implementation of the protocol, the client and the server are identical and both just trivially subclass DustDaemon.
+ """
pass
-
-
diff --git a/src/obfsproxy/transports/rot13.py b/src/obfsproxy/transports/rot13.py
index 113de18..79029cf 100644
--- a/src/obfsproxy/transports/rot13.py
+++ b/src/obfsproxy/transports/rot13.py
@@ -1,38 +1,59 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
-
-def rot13(data):
- for x in range(len(data)):
- ascii = ord(data[x])
- if ascii >= 97 and ascii <= 122: # a-z
- data[x] = (ascii - 97 + 13) % 26 + 97
- elif ascii >= 65 and ascii <= 90:
-
- # A-Z
-
- data[x] = (ascii - 65 + 13) % 26 + 65
- return data
-
+""" This module contains an implementation of the 'rot13' transport. """
class Rot13Daemon:
-
- def __init__(self, client, server):
- pass
-
- def encode(self, data):
- return rot13(data)
-
- def decode(self, data):
- return rot13(data)
+ """
+ Rot13Daemon is the base class for Rot13Client and Rot13Server.
+ Since the protocol is so simple, Rot13Daemon provides all of the functionality for the rot13 protocol implementation.
+ """
+
+ def rot13(self, data):
+ """
+ The rot13 method performs a rot13 transformation on just the alphabetical characters in the data.
+ """
+ for x in range(len(data)):
+ ascii = ord(data[x])
+ if ascii >= 97 and ascii <= 122: # a-z
+ data[x] = (ascii - 97 + 13) % 26 + 97
+ elif ascii >= 65 and ascii <= 90:
+
+ # A-Z
+
+ data[x] = (ascii - 65 + 13) % 26 + 65
+
+ return data
+
+ def receivedDownstream(self, data):
+ """
+ receivedDownstream is the event which is called when bytes are received from the downstream socket.
+ The rot13 protocol encodes them with the rot13 function and then writes the result to the upstream socket.
+ """
+ return self.rot13(data)
+
+ def receivedUpstream(self, data):
+ """
+ receivedUpstream is the event which is called when bytes are received from the upstream socket.
+ The rot13 protocol encodes them with the rot13 function and then writes the result to the downstream socket.
+ """
+ return self.rot13(data)
class Rot13Client(Rot13Daemon):
+ """
+ Rot13Client is a client for the 'rot13' protocol.
+ Since this protocol is so simple, the client and the server are identical and both just trivially subclass Rot13Daemon.
+ """
pass
class Rot13Server:
+ """
+ Rot13Server is a server for the 'rot13' protocol.
+ Since this protocol is so simple, the client and the server are identical and both just trivially subclass Rot13Daemon.
+ """
pass
--
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