[tor-commits] [oonib/master] Refactor oonib's usage of twisted application API
art at torproject.org
art at torproject.org
Wed Sep 3 13:56:01 UTC 2014
commit 4d76c781a67b77d0c4115b011ee6257cf933c4ce
Author: aagbsn <aagbsn at extc.org>
Date: Wed Aug 27 14:13:48 2014 +0000
Refactor oonib's usage of twisted application API
---
bin/oonib | 16 +++---
oonib/onion.py | 96 ++++++++++++++++++++++++++++++++++
oonib/oonibackend.py | 73 +++++++++++++++++++++-----
oonib/runner.py | 140 --------------------------------------------------
4 files changed, 166 insertions(+), 159 deletions(-)
diff --git a/bin/oonib b/bin/oonib
index 7fb1c35..fcb0c72 100755
--- a/bin/oonib
+++ b/bin/oonib
@@ -12,6 +12,7 @@ sys.path.insert(0, os.path.abspath(os.getcwd()))
from oonib import errors as e
from oonib.config import config
+from oonib.log import LoggerFactory
try:
config.load()
@@ -36,9 +37,6 @@ except e.InvalidDeckDirectory, path:
print "Invalid deck directory: %s" % path
sys.exit(6)
-from oonib import runner
-from oonib.oonibackend import application
-
if config.main.chroot:
sys.argv.append('--chroot')
sys.argv.append(config.chroot)
@@ -46,6 +44,12 @@ if config.main.chroot:
if not config.main.nodaemon:
sys.argv.append('-y')
-def runApp(config):
- runner.OBaseRunner(config).run()
-runApp(config.main)
+from oonib.oonibackend import application
+
+from twisted.scripts._twistd_unix import UnixApplicationRunner
+class OBaseRunner(UnixApplicationRunner):
+ temporary_data_dir = None
+ def createOrGetApplication(self):
+ return application
+OBaseRunner.loggerFactory = LoggerFactory
+OBaseRunner(config.main).run()
diff --git a/oonib/onion.py b/oonib/onion.py
new file mode 100644
index 0000000..1950a41
--- /dev/null
+++ b/oonib/onion.py
@@ -0,0 +1,96 @@
+import tempfile
+from oonib import log
+from oonib.config import config
+from twisted.internet import reactor, endpoints
+import os
+
+from random import randint
+import socket
+
+from txtorcon import TCPHiddenServiceEndpoint, TorConfig
+from txtorcon import launch_tor
+
+from txtorcon import __version__ as txtorcon_version
+if tuple(map(int, txtorcon_version.split('.'))) < (0, 9, 0):
+ """
+ Fix for bug in txtorcon versions < 0.9.0 where TCPHiddenServiceEndpoint
+ listens on all interfaces by default.
+ """
+ def create_listener(self, proto):
+ self._update_onion(self.hiddenservice.dir)
+ self.tcp_endpoint = endpoints.TCP4ServerEndpoint(self.reactor,
+ self.listen_port,
+ interface='127.0.0.1')
+ d = self.tcp_endpoint.listen(self.protocolfactory)
+ d.addCallback(self._add_attributes).addErrback(self._retry_local_port)
+ return d
+ TCPHiddenServiceEndpoint._create_listener = create_listener
+
+def randomFreePort(addr="127.0.0.1"):
+ """
+ Args:
+
+ addr (str): the IP address to attempt to bind to.
+
+ Returns an int representing the free port number at the moment of calling
+
+ Note: there is no guarantee that some other application will attempt to
+ bind to this port once this function has been called.
+ """
+ free = False
+ while not free:
+ port = randint(1024, 65535)
+ s = socket.socket()
+ try:
+ s.bind((addr, port))
+ free = True
+ except:
+ pass
+ s.close()
+ return port
+
+def txSetupFailed(failure):
+ log.err("Setup failed")
+ log.exception(failure)
+
+def startTor(torconfig):
+ def updates(prog, tag, summary):
+ print("%d%%: %s" % (prog, summary))
+
+ if config.main.socks_port:
+ torconfig.SocksPort = config.main.socks_port
+ if config.main.control_port:
+ torconfig.ControlPort = config.main.control_port
+ if config.main.tor2webmode:
+ torconfig.Tor2webMode = 1
+ torconfig.CircuitBuildTimeout = 60
+ if config.main.tor_datadir is None:
+ temporary_data_dir = tempfile.mkdtemp()
+ log.warn("Option 'tor_datadir' in oonib.conf is unspecified!")
+ log.warn("Using %s" % temporary_data_dir)
+ torconfig.DataDirectory = temporary_data_dir
+ else:
+ if os.path.exists(config.main.tor_datadir):
+ torconfig.DataDirectory = os.path.abspath(config.main.tor_datadir)
+ else:
+ raise Exception
+ torconfig.save()
+ if not hasattr(torconfig, 'ControlPort'):
+ control_port = int(randomFreePort())
+ torconfig.ControlPort = control_port
+ config.main.control_port = control_port
+
+ if not hasattr(torconfig, 'SocksPort'):
+ socks_port = int(randomFreePort())
+ torconfig.SocksPort = socks_port
+ config.main.socks_port = socks_port
+
+ torconfig.save()
+
+ if config.main.tor_binary is not None:
+ d = launch_tor(torconfig, reactor,
+ tor_binary=config.main.tor_binary,
+ progress_updates=updates)
+ else:
+ d = launch_tor(torconfig, reactor, progress_updates=updates)
+ return d
diff --git a/oonib/oonibackend.py b/oonib/oonibackend.py
index 2a9fa7d..ca51f45 100644
--- a/oonib/oonibackend.py
+++ b/oonib/oonibackend.py
@@ -7,13 +7,19 @@
# In here we start all the test helpers that are required by ooniprobe and
# start the report collector
-from twisted.application import internet, service
-from twisted.names import dns
-
+from oonib.api import ooniBackend, ooniBouncer
+from oonib.config import config
+from oonib.onion import startTor
from oonib.testhelpers import dns_helpers, ssl_helpers
from oonib.testhelpers import http_helpers, tcp_helpers
-from oonib.config import config
+import os
+
+from twisted.application import internet, service
+from twisted.internet import reactor
+from twisted.names import dns
+
+from txtorcon import TCPHiddenServiceEndpoint, TorConfig
if config.main.uid and config.main.gid:
application = service.Application('oonibackend', uid=config.main.uid,
@@ -21,28 +27,28 @@ if config.main.uid and config.main.gid:
else:
application = service.Application('oonibackend')
-serviceCollection = service.IServiceCollection(application)
+multiService = service.MultiService()
if config.helpers['ssl'].port:
print "Starting SSL helper on %s" % config.helpers['ssl'].port
ssl_helper = internet.SSLServer(int(config.helpers['ssl'].port),
http_helpers.HTTPReturnJSONHeadersHelper(),
ssl_helpers.SSLContext(config))
- ssl_helper.setServiceParent(serviceCollection)
+ multiService.addService(ssl_helper)
# Start the DNS Server related services
if config.helpers['dns'].tcp_port:
print "Starting TCP DNS Helper on %s" % config.helpers['dns'].tcp_port
tcp_dns_helper = internet.TCPServer(int(config.helpers['dns'].tcp_port),
dns_helpers.DNSTestHelper())
- tcp_dns_helper.setServiceParent(serviceCollection)
+ multiService.addService(tcp_dns_helper)
if config.helpers['dns'].udp_port:
print "Starting UDP DNS Helper on %s" % config.helpers['dns'].udp_port
udp_dns_factory = dns.DNSDatagramProtocol(dns_helpers.DNSTestHelper())
udp_dns_helper = internet.UDPServer(int(config.helpers['dns'].udp_port),
udp_dns_factory)
- udp_dns_helper.setServiceParent(serviceCollection)
+ multiService.addService(udp_dns_helper)
if config.helpers['dns_discovery'].udp_port:
print ("Starting UDP DNS Discovery Helper on %s" %
@@ -51,14 +57,14 @@ if config.helpers['dns_discovery'].udp_port:
dns.DNSDatagramProtocol(
dns_helpers.DNSResolverDiscovery()
))
- udp_dns_discovery.setServiceParent(serviceCollection)
+ multiService.addService(udp_dns_discovery)
if config.helpers['dns_discovery'].tcp_port:
print ("Starting TCP DNS Discovery Helper on %s" %
config.helpers['dns_discovery'].tcp_port)
tcp_dns_discovery = internet.TCPServer(int(config.helpers['dns_discovery'].tcp_port),
dns_helpers.DNSResolverDiscovery())
- tcp_dns_discovery.setServiceParent(serviceCollection)
+ multiService.addService(tcp_dns_discovery)
# XXX this needs to be ported
@@ -67,18 +73,59 @@ if config.helpers['daphn3'].port:
print "Starting Daphn3 helper on %s" % config.helpers['daphn3'].port
daphn3_helper = internet.TCPServer(int(config.helpers['daphn3'].port),
tcp_helpers.Daphn3Server())
- daphn3_helper.setServiceParent(serviceCollection)
+ multiService.addService(daphn3_helper)
if config.helpers['tcp-echo'].port:
print "Starting TCP echo helper on %s" % config.helpers['tcp-echo'].port
tcp_echo_helper = internet.TCPServer(int(config.helpers['tcp-echo'].port),
tcp_helpers.TCPEchoHelper())
- tcp_echo_helper.setServiceParent(serviceCollection)
+ multiService.addService(tcp_echo_helper)
if config.helpers['http-return-json-headers'].port:
print "Starting HTTP return request helper on %s" % config.helpers['http-return-json-headers'].port
http_return_request_helper = internet.TCPServer(
int(config.helpers['http-return-json-headers'].port),
http_helpers.HTTPReturnJSONHeadersHelper())
- http_return_request_helper.setServiceParent(serviceCollection)
+multiService.addService(http_return_request_helper)
+
+# add the tor collector service here
+if config.main.tor_hidden_service:
+ torconfig = TorConfig()
+ d = startTor(torconfig)
+
+ def addCollector(torControlProtocol):
+ data_dir = os.path.join(torconfig.DataDirectory, 'collector')
+ collector_service = internet.StreamServerEndpointService(
+ TCPHiddenServiceEndpoint(reactor,
+ torconfig, 80,
+ hidden_service_dir=data_dir),
+ ooniBackend)
+ multiService.addService(collector_service)
+ collector_service.startService()
+ return torControlProtocol
+
+ d.addCallback(addCollector)
+
+ if ooniBouncer:
+ def addBouncer(torControlProtocol):
+ data_dir = os.path.join(torconfig.DataDirectory, 'bouncer')
+
+ bouncer_service = internet.StreamServerEndpointService(
+ TCPHiddenServiceEndpoint(reactor,
+ torconfig, 80,
+ hidden_service_dir=data_dir),
+ ooniBouncer)
+ multiService.addService(bouncer_service)
+ bouncer_service.startService()
+ return torControlProtocol
+
+ d.addCallback(addBouncer)
+else:
+ if ooniBouncer:
+ bouncer_service = internet.TCPServer(8888, ooniBouncer, interface="127.0.0.1")
+ multiService.addService(bouncer_service)
+ bouncer_service.startService()
+ collector_service = internet.TCPServer(8889, ooniBackend, interface="127.0.0.1")
+ multiService.addService(collector_service)
+ collector_service.startService()
diff --git a/oonib/runner.py b/oonib/runner.py
deleted file mode 100644
index 47ddc35..0000000
--- a/oonib/runner.py
+++ /dev/null
@@ -1,140 +0,0 @@
-"""
-In here we define a runner for the oonib backend system.
-"""
-
-from __future__ import print_function
-
-from distutils.version import LooseVersion
-import tempfile
-import os
-
-from shutil import rmtree
-
-from twisted.internet import reactor, endpoints
-from twisted.python.runtime import platformType
-
-from txtorcon import TCPHiddenServiceEndpoint, TorConfig
-from txtorcon import launch_tor
-
-from oonib.api import ooniBackend, ooniBouncer
-from oonib.config import config
-
-from oonib import oonibackend
-from oonib import log
-
-from txtorcon import __version__ as txtorcon_version
-if tuple(map(int, txtorcon_version.split('.'))) < (0, 9, 0):
- """
- Fix for bug in txtorcon versions < 0.9.0 where TCPHiddenServiceEndpoint
- listens on all interfaces by default.
- """
- def create_listener(self, proto):
- self._update_onion(self.hiddenservice.dir)
- self.tcp_endpoint = endpoints.TCP4ServerEndpoint(self.reactor,
- self.listen_port,
- interface='127.0.0.1')
- d = self.tcp_endpoint.listen(self.protocolfactory)
- d.addCallback(self._add_attributes).addErrback(self._retry_local_port)
- return d
- TCPHiddenServiceEndpoint._create_listener = create_listener
-
-class OBaseRunner(object):
- pass
-
-if platformType == "win32":
- from twisted.scripts._twistw import WindowsApplicationRunner
-
- OBaseRunner = WindowsApplicationRunner
- # XXX Currently we don't support windows for starting a Tor Hidden Service
- log.warn(
- "Apologies! We don't support starting a Tor Hidden Service on Windows.")
-
-else:
- from twisted.scripts._twistd_unix import UnixApplicationRunner
- class OBaseRunner(UnixApplicationRunner):
- temporary_data_dir = None
-
- def txSetupFailed(self, failure):
- log.err("Setup failed")
- log.exception(failure)
-
- def setupHSEndpoint(self, tor_process_protocol, torconfig, endpoint):
- endpointName = endpoint.settings['name']
-
- def setup_complete(port):
- if LooseVersion(txtorcon_version) >= LooseVersion('0.10.0'):
- onion_uri = port.address.onion_uri
- else:
- onion_uri = port.onion_uri
- print("Exposed %s Tor hidden service "
- "on httpo://%s" % (endpointName, onion_uri))
-
- public_port = 80
- data_dir = os.path.join(torconfig.DataDirectory, endpointName)
- if LooseVersion(txtorcon_version) >= LooseVersion('0.10.0'):
- hs_endpoint = TCPHiddenServiceEndpoint(reactor,
- torconfig,
- public_port,
- hidden_service_dir=data_dir)
- else:
- hs_endpoint = TCPHiddenServiceEndpoint(reactor,
- torconfig,
- public_port,
- data_dir=data_dir)
- d = hs_endpoint.listen(endpoint)
- d.addCallback(setup_complete)
- d.addErrback(self.txSetupFailed)
- return d
-
- def startTor(self, torconfig):
- def updates(prog, tag, summary):
- print("%d%%: %s" % (prog, summary))
-
- torconfig.SocksPort = config.main.socks_port
- if config.main.tor2webmode:
- torconfig.Tor2webMode = 1
- torconfig.CircuitBuildTimeout = 60
- if config.main.tor_datadir is None:
- self.temporary_data_dir = tempfile.mkdtemp()
- log.warn("Option 'tor_datadir' in oonib.conf is unspecified!")
- log.warn("Using %s" % self.temporary_data_dir)
- torconfig.DataDirectory = self.temporary_data_dir
- else:
- torconfig.DataDirectory = config.main.tor_datadir
- torconfig.save()
- if config.main.tor_binary is not None:
- d = launch_tor(torconfig, reactor,
- tor_binary=config.main.tor_binary,
- progress_updates=updates)
- else:
- d = launch_tor(torconfig, reactor, progress_updates=updates)
- return d
-
- def postApplication(self):
- """After the application is created, start the application and run
- the reactor. After the reactor stops, clean up PID files and such.
- """
- self.startApplication(self.application)
- # This is our addition. The rest is taken from
- # twisted/scripts/_twistd_unix.py 12.2.0
- if config.main.tor_hidden_service:
- torconfig = TorConfig()
- d = self.startTor(torconfig)
- d.addCallback(self.setupHSEndpoint, torconfig, ooniBackend)
- if ooniBouncer:
- d.addCallback(self.setupHSEndpoint, torconfig, ooniBouncer)
- else:
- if ooniBouncer:
- reactor.listenTCP(8888, ooniBouncer, interface="127.0.0.1")
- reactor.listenTCP(8889, ooniBackend, interface="127.0.0.1")
- self.startReactor(None, self.oldstdout, self.oldstderr)
- self.removePID(self.config['pidfile'])
- if self.temporary_data_dir:
- log.msg("Removing temporary directory: %s"
- % self.temporary_data_dir)
- rmtree(self.temporary_data_dir, onerror=log.err)
-
- def createOrGetApplication(self):
- return oonibackend.application
-
-OBaseRunner.loggerFactory = log.LoggerFactory
More information about the tor-commits
mailing list