[tor-commits] [ooni-probe/master] Finish reafactoring and porting daphn3.
art at torproject.org
art at torproject.org
Mon Nov 12 19:14:03 UTC 2012
commit 03a8462714d0609d0548d24fb5f8762b8d12d358
Author: Arturo Filastò <art at fuffa.org>
Date: Mon Nov 12 20:12:18 2012 +0100
Finish reafactoring and porting daphn3.
* XXX not fully tested
---
nettests/core/daphn3.py | 71 +++++++++++++++-------
ooni/kit/daphn3.py | 125 ++++++++++++++++++++++---------------
oonib/config.py | 4 +-
oonib/testhelpers/tcp_helpers.py | 46 ++++++++++++--
4 files changed, 164 insertions(+), 82 deletions(-)
diff --git a/nettests/core/daphn3.py b/nettests/core/daphn3.py
index cc4803c..c277c56 100644
--- a/nettests/core/daphn3.py
+++ b/nettests/core/daphn3.py
@@ -6,18 +6,42 @@ from ooni import nettest
from ooni.kit import daphn3
from ooni.utils import log
+class Daphn3ClientProtocol(daphn3.Daphn3Protocol):
+ def nextStep(self):
+ log.debug("Moving on to next step in the state walk")
+ self.current_data_received = 0
+ if self.current_step >= (len(self.steps) - 1):
+ log.msg("Reached the end of the state machine")
+ log.msg("Censorship fingerpint bisected!")
+ step_idx, mutation_idx = self.factory.mutation
+ log.msg("step_idx: %s | mutation_id: %s" % (step_idx, mutation_idx))
+ #self.transport.loseConnection()
+ if self.report:
+ self.report['mutation_idx'] = mutation_idx
+ self.report['step_idx'] = step_idx
+ self.d.callback(None)
+ return
+ else:
+ self.current_step += 1
+ if self._current_step_role() == self.role:
+ # We need to send more data because we are again responsible for
+ # doing so.
+ self.sendPayload()
+
+
class Daphn3ClientFactory(protocol.ClientFactory):
protocol = daphn3.Daphn3Protocol
- def __init__(self, steps):
- self.steps = steps
+ mutation = [0,0]
+ steps = None
def buildProtocol(self, addr):
- p = self.protocol(steps=self.steps)
+ p = self.protocol()
+ p.steps = self.steps
p.factory = self
return p
def startedConnecting(self, connector):
- print "Started connecting %s" % connector
+ log.msg("Started connecting %s" % connector)
def clientConnectionFailed(self, reason, connector):
log.err("We failed connecting the the OONIB")
@@ -31,8 +55,8 @@ class Daphn3ClientFactory(protocol.ClientFactory):
class daphn3Args(usage.Options):
optParameters = [
- ['host', 'h', None, 'Target Hostname'],
- ['port', 'p', None, 'Target port number']]
+ ['host', 'h', '127.0.0.1', 'Target Hostname'],
+ ['port', 'p', 57003, 'Target port number']]
optFlags = [['pcap', 'c', 'Specify that the input file is a pcap file'],
['yaml', 'y', 'Specify that the input file is a YAML file (default)']]
@@ -68,21 +92,16 @@ class daphn3Test(nettest.NetTestCase):
else:
daphn3Steps = [{'client': 'testing'}, {'server': 'antani'}]
- for idx, step in enumerate(daphn3Steps):
- current_packet = step.values()[0]
- for mutation_idx in range(len(current_packet)):
- if step.keys()[0] == "client":
- mutated_step = daphn3.daphn3Mutate(daphn3Steps,
- idx, mutation_idx)
- yield mutated_step
- else:
- yield daphn3Steps
-
- def setUp(self):
- self.factory = Daphn3ClientFactory(self.input)
- self.factory.report = self.report
- print "Just set the factory to %s with %s" % (self.factory,
- self.input)
+ #for idx, step in enumerate(daphn3Steps):
+ # current_packet = step.values()[0]
+ # for mutation_idx in range(len(current_packet)):
+ # if step.keys()[0] == "client":
+ # mutated_step = daphn3.daphn3Mutate(daphn3Steps,
+ # idx, mutation_idx)
+ # yield mutated_step
+ # else:
+ # yield daphn3Steps
+ yield daphn3Steps
def test_daphn3(self):
host = self.localOptions['host']
@@ -95,11 +114,17 @@ class daphn3Test(nettest.NetTestCase):
def success(protocol):
log.msg("Successfully connected")
- protocol.sendMutation()
+ protocol.sendPayload()
+ return protocol.d
log.msg("Connecting to %s:%s" % (host, port))
endpoint = endpoints.TCP4ClientEndpoint(reactor, host, port)
- d = endpoint.connect(self.factory)
+ daphn3_factory = Daphn3ClientFactory()
+ #daphn3_factory.steps = self.input
+ daphn3_factory.steps = [{'client': 'client_packet'},
+ {'server': 'server_packet'}]
+ daphn3_factory.report = self.report
+ d = endpoint.connect(daphn3_factory)
d.addErrback(failure)
d.addCallback(success)
return d
diff --git a/ooni/kit/daphn3.py b/ooni/kit/daphn3.py
index 1c340b4..8d655c3 100644
--- a/ooni/kit/daphn3.py
+++ b/ooni/kit/daphn3.py
@@ -76,7 +76,7 @@ def read_yaml(filename):
class NoInputSpecified(Exception):
pass
-class StateError(Exception):
+class StepError(Exception):
pass
def daphn3MutateString(string, i):
@@ -88,7 +88,7 @@ def daphn3MutateString(string, i):
if y == i:
mutated += chr(ord(string[i]) + 1)
else:
- mutated += string[i]
+ mutated += string[y]
return mutated
def daphn3Mutate(steps, step_idx, mutation_idx):
@@ -109,77 +109,100 @@ def daphn3Mutate(steps, step_idx, mutation_idx):
return mutated_steps
class Daphn3Protocol(protocol.Protocol):
- def __init__(self, steps=None,
- yaml_file=None, pcap_file=None,
- role="client"):
- if yaml_file:
- self.steps = read_yaml(yaml_file)
- elif pcap_file:
- self.steps = read_pcap(pcap_file)
- elif steps:
- self.steps = steps
- else:
- raise NoInputSpecified
-
- # XXX remove me
- #self.steps = [{'client': 'antani'}, {'server': 'sblinda'}]
- self.role = role
- # We use this index to keep track of where we are in the state machine
- self.current_step = 0
-
- # 0 indicates we are waiting to receive data, while 1 indicates we are
- # sending data
- self.current_state = 0
- self.current_data_received = 0
-
- def sendMutation(self):
- self.debug("Sending mutation")
- current_step_role = self.steps[self.current_step].keys()[0]
- current_step_data = self.steps[self.current_step].values()[0]
+ steps = None
+ role = "client"
+ report = None
+ # We use this index to keep track of where we are in the state machine
+ current_step = 0
+ current_data_received = 0
+
+ # We use this to keep track of the mutated steps
+ mutated_steps = None
+ d = defer.Deferred()
+
+ def _current_step_role(self):
+ return self.steps[self.current_step].keys()[0]
+
+ def _current_step_data(self):
+ step_idx, mutation_idx = self.factory.mutation
+ log.debug("Mutating %s %s" % (step_idx, mutation_idx))
+ mutated_step = daphn3Mutate(self.steps,
+ step_idx, mutation_idx)
+ log.debug("Mutated packet into %s" % mutated_step)
+ return mutated_step[self.current_step].values()[0]
+
+ def sendPayload(self):
+ self.debug("Sending payload")
+ current_step_role = self._current_step_role()
+ current_step_data = self._current_step_data()
if current_step_role == self.role:
print "In a state to do shit %s" % current_step_data
self.transport.write(current_step_data)
- self.nextState()
+ self.nextStep()
else:
print "Not in a state to do anything"
def connectionMade(self):
print "Got connection"
- self.sendMutation()
def debug(self, msg):
- print "Current step %s" % self.current_step
- print "Current data received %s" % self.current_data_received
- print "Current role %s" % self.role
- print "Current steps %s" % self.steps
- print "Current state %s" % self.current_state
-
- def nextState(self):
- print "Moving on to next state"
- self.current_data_received = 0
- self.current_step += 1
- if self.current_step >= len(self.steps):
- print "Going to loose this connection"
- self.transport.loseConnection()
- return
- self.sendMutation()
+ log.debug("Current step %s" % self.current_step)
+ log.debug("Current data received %s" % self.current_data_received)
+ log.debug("Current role %s" % self.role)
+ log.debug("Current steps %s" % self.steps)
+ log.debug("Current step data %s" % self._current_step_data())
+
+ def nextStep(self):
+ """
+ XXX this method is overwritten individually by client and server transport.
+ There is probably a smarter way to do this and refactor the common
+ code into one place, but for the moment like this is good.
+ """
+ pass
def dataReceived(self, data):
current_step_role = self.steps[self.current_step].keys()[0]
log.debug("Current step role %s" % current_step_role)
if current_step_role == self.role:
log.debug("Got a state error!")
- raise StateError("I should not have gotten data, while I did, \
- perhaps there is a wrong state machine?")
+ raise StepError("I should not have gotten data, while I did, \
+ perhaps there is something wrong with the state machine?")
self.current_data_received += len(data)
expected_data_in_this_state = len(self.steps[self.current_step].values()[0])
log.debug("Current data received %s" % self.current_data_received)
if self.current_data_received >= expected_data_in_this_state:
- self.nextState()
+ self.nextStep()
+
+ def nextMutation(self):
+ log.debug("Moving onto next mutation")
+ # [step_idx, mutation_idx]
+ c_step_idx, c_mutation_idx = self.factory.mutation
+ log.debug("[%s]: c_step_idx: %s | c_mutation_idx: %s" % (self.role,
+ c_step_idx, c_mutation_idx))
+
+ if c_step_idx >= (len(self.steps) - 1):
+ log.err("No censorship fingerprint bisected.")
+ log.err("Givinig up.")
+ self.transport.loseConnection()
+ return
+
+ # This means we have mutated all bytes in the step
+ # we should proceed to mutating the next step.
+ log.debug("steps: %s | %s" % (self.steps, self.steps[c_step_idx]))
+ if c_mutation_idx >= (len(self.steps[c_step_idx].values()[0]) - 1):
+ log.debug("Finished mutating step")
+ # increase step
+ self.factory.mutation[0] += 1
+ # reset mutation idx
+ self.factory.mutation[1] = 0
+ else:
+ log.debug("Mutating next byte in step")
+ # increase mutation index
+ self.factory.mutation[1] += 1
def connectionLost(self, reason):
- self.debug("Lost the connection")
- print reason
+ self.debug("--- Lost the connection ---")
+ self.nextMutation()
diff --git a/oonib/config.py b/oonib/config.py
index cf2e362..1a70b85 100644
--- a/oonib/config.py
+++ b/oonib/config.py
@@ -27,8 +27,8 @@ helpers.tcp_echo = Storage()
helpers.tcp_echo.port = 57002
helpers.daphn3 = Storage()
-helpers.daphn3.yaml_file = "/path/to/data/oonib/daphn3.yaml"
-helpers.daphn3.pcap_file = "/path/to/data/server.pcap"
+#helpers.daphn3.yaml_file = "/path/to/data/oonib/daphn3.yaml"
+#helpers.daphn3.pcap_file = "/path/to/data/server.pcap"
helpers.daphn3.port = 57003
helpers.dns = Storage()
diff --git a/oonib/testhelpers/tcp_helpers.py b/oonib/testhelpers/tcp_helpers.py
index 4287a59..4d32ae0 100644
--- a/oonib/testhelpers/tcp_helpers.py
+++ b/oonib/testhelpers/tcp_helpers.py
@@ -3,7 +3,7 @@ from twisted.internet.protocol import Protocol, Factory, ServerFactory
from twisted.internet.error import ConnectionDone
from oonib import config
-
+from ooni.utils import log
from ooni.kit.daphn3 import Daphn3Protocol
from ooni.kit.daphn3 import read_pcap, read_yaml
@@ -17,8 +17,37 @@ class TCPEchoHelper(Factory):
"""
protocol = TCPEchoProtocol
-daphn3Steps = [{'client': '\x00\x00\x00'},
- {'server': '\x00\x00\x00'}]
+if config.helpers.daphn3.yaml_file:
+ daphn3Steps = read_pcap(config.helpers.daphn3.yaml_file)
+
+elif config.helpers.daphn3.pcap_file:
+ daphn3Steps = read_yaml(config.helpers.daphn3.pcap_file)
+
+else:
+ daphn3Steps = [{'client': 'client_packet'},
+ {'server': 'server_packet'}]
+
+class Daphn3ServerProtocol(Daphn3Protocol):
+ def nextStep(self):
+ log.debug("Moving on to next step in the state walk")
+ self.current_data_received = 0
+ # Python why?
+ if self.current_step >= (len(self.steps) - 1):
+ log.msg("Reached the end of the state machine")
+ log.msg("Censorship fingerpint bisected!")
+ step_idx, mutation_idx = self.factory.mutation
+ log.msg("step_idx: %s | mutation_id: %s" % (step_idx, mutation_idx))
+ #self.transport.loseConnection()
+ if self.report:
+ self.report['mutation_idx'] = mutation_idx
+ self.report['step_idx'] = step_idx
+ return
+ else:
+ self.current_step += 1
+ if self._current_step_role() == self.role:
+ # We need to send more data because we are again responsible for
+ # doing so.
+ self.sendPayload()
class Daphn3Server(ServerFactory):
"""
@@ -29,10 +58,15 @@ class Daphn3Server(ServerFactory):
two different clients are sharing the same IP, but hopefully the
probability of such thing is not that likely.
"""
- protocol = Daphn3Protocol
+ protocol = Daphn3ServerProtocol
+ # step_idx, mutation_idx
+ mutation = [0, 0]
def buildProtocol(self, addr):
- p = self.protocol(steps=daphn3Steps,
- role="server")
+ p = self.protocol()
+ p.steps = daphn3Steps
+ p.role = "server"
p.factory = self
return p
+
+
More information about the tor-commits
mailing list