commit c0423382890576b92bb55121bfbc394ad941cf98
Author: Arturo Filastò <hellais(a)torproject.org>
Date: Mon May 28 23:40:13 2012 +0200
Implement parts of OONI Backend.
* Write an HTTP server that replies with the headers sent by the browser
* Write a Proxy DNS server that proxies requests and writes to log
---
backend/dnsbackend.py | 16 ++++++++++
backend/httpbackend.py | 74 ++++++++++++++++++++++++++++++++++++++++++++++++
backend/oonibackend.py | 34 ++++++++++++++++++++++
plugoo/tests.py | 16 ++--------
4 files changed, 128 insertions(+), 12 deletions(-)
diff --git a/backend/__init__.py b/backend/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/backend/dnsbackend.py b/backend/dnsbackend.py
new file mode 100644
index 0000000..689d1a4
--- /dev/null
+++ b/backend/dnsbackend.py
@@ -0,0 +1,16 @@
+from twisted.internet.protocol import Factory, Protocol
+from twisted.internet import reactor
+from twisted.names import dns
+from twisted.names import client, server
+
+class ProxyDNSServer(server.DNSServerFactory):
+ def __init__(self, authorities = None,
+ caches = None, clients = None,
+ verbose = 0):
+ resolver = client.Resolver(servers=[('8.8.8.8', 53)])
+ server.DNSServerFactory.__init__(self, authorities = authorities,
+ caches = caches, clients = [resolver],
+ verbose = verbose)
+ def handleQuery(self, message, protocol, address):
+ print message, protocol, address
+ server.DNSServerFactory.handleQuery(self, message, protocol, address)
diff --git a/backend/httpbackend.py b/backend/httpbackend.py
new file mode 100644
index 0000000..79a487b
--- /dev/null
+++ b/backend/httpbackend.py
@@ -0,0 +1,74 @@
+import json
+import random
+import string
+
+from twisted.application import internet, service
+from twisted.internet import protocol, reactor, defer
+from twisted.protocols import basic
+from twisted.web import resource, server, static
+from twisted.web.microdom import escape
+
+server.version = "Apache"
+
+class HTTPRandomPage(resource.Resource):
+ """
+ This generates a random page of arbitrary length and containing the string
+ selected by the user.
+ The format is the following:
+ /random/<length>/<keyword>
+ """
+ isLeaf = True
+ def _gen_random_string(self, length):
+ return ''.join(random.choice(string.letters) for x in range(length))
+
+ def genRandomPage(self, length=100, keyword=None):
+ data = self._gen_random_string(length/2)
+ if keyword:
+ data += keyword
+ data += self._gen_random_string(length - length/2)
+ data += '\n'
+ return data
+
+ def render(self, request):
+ length = 100
+ keyword = None
+ path_parts = request.path.split('/')
+ if len(path_parts) > 2:
+ length = int(path_parts[2])
+ if length > 100000:
+ length = 100000
+
+ if len(path_parts) > 3:
+ keyword = escape(path_parts[3])
+
+ return self.genRandomPage(length, keyword)
+
+class HTTPReturnHeaders(resource.Resource):
+ """
+ This returns the headers being sent by the client in JSON format.
+ """
+ isLeaf = True
+ def render(self, request):
+ req_headers = request.getAllHeaders()
+ return json.dumps(req_headers)
+
+class HTTPSendHeaders(resource.Resource):
+ """
+ This sends to the client the headers that they send inside of the POST
+ request encoded in json.
+ """
+ isLeaf = True
+ def render_POST(self, request):
+ headers = json.loads(request.content.read())
+ for header, value in headers.items():
+ request.setHeader(str(header), str(value))
+ return ''
+
+class HTTPBackend(resource.Resource):
+ def __init__(self):
+ resource.Resource.__init__(self)
+ self.putChild('random', HTTPRandomPage())
+ self.putChild('returnheaders', HTTPReturnHeaders())
+ self.putChild('sendheaders', HTTPSendHeaders())
+
+
diff --git a/backend/oonibackend.py b/backend/oonibackend.py
new file mode 100644
index 0000000..774a9c5
--- /dev/null
+++ b/backend/oonibackend.py
@@ -0,0 +1,34 @@
+"""
+ ooni backend
+ ************
+
+ This is the backend system responsible for running certain services that
+ are useful for censorship detection.
+"""
+import json
+import random
+import string
+
+from twisted.application import internet, service
+from twisted.internet import protocol, reactor, defer
+from twisted.protocols import basic
+from twisted.web import resource, server, static
+from twisted.web.microdom import escape
+from twisted.names import dns
+
+from backend.httpbackend import HTTPBackend
+from backend.dnsbackend import ProxyDNSServer
+
+# This tells twisted to set the
+server.version = "Apache"
+
+application = service.Application('oonibackend')
+serviceCollection = service.IServiceCollection(application)
+internet.TCPServer(8000, server.Site(HTTPBackend())).setServiceParent(serviceCollection)
+
+# Start the DNS Server related services
+TCPDNSServer = ProxyDNSServer()
+internet.TCPServer(8002, TCPDNSServer).setServiceParent(serviceCollection)
+UDPFactory = dns.DNSDatagramProtocol(TCPDNSServer)
+internet.UDPServer(5353, UDPFactory).setServiceParent(serviceCollection)
+
diff --git a/plugoo/tests.py b/plugoo/tests.py
index 39adfa2..09363a2 100644
--- a/plugoo/tests.py
+++ b/plugoo/tests.py
@@ -186,20 +186,16 @@ class TwistedTest(object):
result['start_time'] = self.start_time
result['end_time'] = self.end_time
result['run_time'] = self.end_time - self.start_time
- return self.d.callback(result)
def _do_experiment(self):
- self.d_experiment = defer.Deferred()
- self.d_experiment.addCallback(self._do_control)
- self.experiment()
+ self.d = defer.maybeDeferred(self.experiment)
+ self.d.addCallback(self.control)
+ self.d.addCallback(self.finished)
return self.d
- def _do_control(self, exp):
- self.control(exp)
- self.finished(dict())
-
def control(self, exp):
print "Doing control..."
+ self.d.callback(result)
def experiment(self):
print "Doing experiment"
@@ -207,10 +203,6 @@ class TwistedTest(object):
def startTest(self):
print "Starting test %s" % repr(self)
- self.d = defer.Deferred()
- result = {}
- #reactor.callLater(2.0, self.finished, result)
- # Start experiment
return self._do_experiment()
class TwistedTestFactory(object):