diff options
Diffstat (limited to 'src/leap/bitmask/backend')
-rw-r--r-- | src/leap/bitmask/backend/backend.py | 43 | ||||
-rw-r--r-- | src/leap/bitmask/backend/backend_proxy.py | 25 | ||||
-rw-r--r-- | src/leap/bitmask/backend/signaler.py | 25 | ||||
-rw-r--r-- | src/leap/bitmask/backend/signaler_qt.py | 39 | ||||
-rw-r--r-- | src/leap/bitmask/backend/utils.py | 54 |
5 files changed, 135 insertions, 51 deletions
diff --git a/src/leap/bitmask/backend/backend.py b/src/leap/bitmask/backend/backend.py index 75eff8a9..cff731ba 100644 --- a/src/leap/bitmask/backend/backend.py +++ b/src/leap/bitmask/backend/backend.py @@ -20,6 +20,7 @@ # TODO use txzmq bindings instead. import json +import os import threading import time @@ -28,10 +29,14 @@ import psutil from twisted.internet import defer, reactor, threads import zmq -from zmq.auth.thread import ThreadAuthenticator +try: + from zmq.auth.thread import ThreadAuthenticator +except ImportError: + pass from leap.bitmask.backend.api import API, PING_REQUEST from leap.bitmask.backend.utils import get_backend_certificates +from leap.bitmask.config import flags from leap.bitmask.backend.signaler import Signaler import logging @@ -43,12 +48,15 @@ class Backend(object): Backend server. Receives signals from backend_proxy and emit signals if needed. """ - # XXX this should not be hardcoded. Make it configurable. - PORT = '5556' - # XXX we might want to make this configurable per-platform, # and use the most performant socket type on each one. - BIND_ADDR = "tcp://127.0.0.1:%s" % PORT + if flags.ZMQ_HAS_CURVE: + # XXX this should not be hardcoded. Make it configurable. + PORT = '5556' + BIND_ADDR = "tcp://127.0.0.1:%s" % PORT + else: + SOCKET_FILE = "/tmp/bitmask.socket.0" + BIND_ADDR = "ipc://%s" % SOCKET_FILE PING_INTERVAL = 2 # secs @@ -73,20 +81,23 @@ class Backend(object): context = zmq.Context() socket = context.socket(zmq.REP) - # Start an authenticator for this context. - auth = ThreadAuthenticator(context) - auth.start() - # XXX do not hardcode this here. - auth.allow('127.0.0.1') + if flags.ZMQ_HAS_CURVE: + # Start an authenticator for this context. + auth = ThreadAuthenticator(context) + auth.start() + # XXX do not hardcode this here. + auth.allow('127.0.0.1') - # Tell authenticator to use the certificate in a directory - auth.configure_curve(domain='*', location=zmq.auth.CURVE_ALLOW_ANY) - public, secret = get_backend_certificates() - socket.curve_publickey = public - socket.curve_secretkey = secret - socket.curve_server = True # must come before bind + # Tell authenticator to use the certificate in a directory + auth.configure_curve(domain='*', location=zmq.auth.CURVE_ALLOW_ANY) + public, secret = get_backend_certificates() + socket.curve_publickey = public + socket.curve_secretkey = secret + socket.curve_server = True # must come before bind socket.bind(self.BIND_ADDR) + if not flags.ZMQ_HAS_CURVE: + os.chmod(self.SOCKET_FILE, 0600) self._zmq_socket = socket diff --git a/src/leap/bitmask/backend/backend_proxy.py b/src/leap/bitmask/backend/backend_proxy.py index 3e79289f..b2f79a70 100644 --- a/src/leap/bitmask/backend/backend_proxy.py +++ b/src/leap/bitmask/backend/backend_proxy.py @@ -30,6 +30,7 @@ import zmq from leap.bitmask.backend.api import API, STOP_REQUEST, PING_REQUEST from leap.bitmask.backend.utils import generate_zmq_certificates_if_needed from leap.bitmask.backend.utils import get_backend_certificates +from leap.bitmask.config import flags import logging logger = logging.getLogger(__name__) @@ -41,8 +42,11 @@ class BackendProxy(object): to the backend. """ - PORT = '5556' - SERVER = "tcp://localhost:%s" % PORT + if flags.ZMQ_HAS_CURVE: + PORT = '5556' + SERVER = "tcp://localhost:%s" % PORT + else: + SERVER = "ipc:///tmp/bitmask.socket.0" POLL_TIMEOUT = 4000 # ms POLL_TRIES = 3 @@ -59,15 +63,16 @@ class BackendProxy(object): logger.debug("Connecting to server...") socket = context.socket(zmq.REQ) - # public, secret = zmq.curve_keypair() - client_keys = zmq.curve_keypair() - socket.curve_publickey = client_keys[0] - socket.curve_secretkey = client_keys[1] + if flags.ZMQ_HAS_CURVE: + # public, secret = zmq.curve_keypair() + client_keys = zmq.curve_keypair() + socket.curve_publickey = client_keys[0] + socket.curve_secretkey = client_keys[1] - # The client must know the server's public key to make a CURVE - # connection. - public, _ = get_backend_certificates() - socket.curve_serverkey = public + # The client must know the server's public key to make a CURVE + # connection. + public, _ = get_backend_certificates() + socket.curve_serverkey = public socket.setsockopt(zmq.RCVTIMEO, 1000) socket.setsockopt(zmq.LINGER, 0) # Terminate early diff --git a/src/leap/bitmask/backend/signaler.py b/src/leap/bitmask/backend/signaler.py index 43cba994..aec2f606 100644 --- a/src/leap/bitmask/backend/signaler.py +++ b/src/leap/bitmask/backend/signaler.py @@ -26,6 +26,7 @@ import zmq from leap.bitmask.backend.api import SIGNALS from leap.bitmask.backend.utils import get_frontend_certificates +from leap.bitmask.config import flags import logging logger = logging.getLogger(__name__) @@ -36,8 +37,11 @@ class Signaler(object): Signaler client. Receives signals from the backend and sends to the signaling server. """ - PORT = "5667" - SERVER = "tcp://localhost:%s" % PORT + if flags.ZMQ_HAS_CURVE: + PORT = "5667" + SERVER = "tcp://localhost:%s" % PORT + else: + SERVER = "ipc:///tmp/bitmask.socket.1" POLL_TIMEOUT = 2000 # ms POLL_TRIES = 500 @@ -49,15 +53,16 @@ class Signaler(object): logger.debug("Connecting to signaling server...") socket = context.socket(zmq.REQ) - # public, secret = zmq.curve_keypair() - client_keys = zmq.curve_keypair() - socket.curve_publickey = client_keys[0] - socket.curve_secretkey = client_keys[1] + if flags.ZMQ_HAS_CURVE: + # public, secret = zmq.curve_keypair() + client_keys = zmq.curve_keypair() + socket.curve_publickey = client_keys[0] + socket.curve_secretkey = client_keys[1] - # The client must know the server's public key to make a CURVE - # connection. - public, _ = get_frontend_certificates() - socket.curve_serverkey = public + # The client must know the server's public key to make a CURVE + # connection. + public, _ = get_frontend_certificates() + socket.curve_serverkey = public socket.setsockopt(zmq.RCVTIMEO, 1000) socket.setsockopt(zmq.LINGER, 0) # Terminate early diff --git a/src/leap/bitmask/backend/signaler_qt.py b/src/leap/bitmask/backend/signaler_qt.py index 433f18ed..b7f48d21 100644 --- a/src/leap/bitmask/backend/signaler_qt.py +++ b/src/leap/bitmask/backend/signaler_qt.py @@ -18,16 +18,21 @@ Signaling server. Receives signals from the signaling client and emit Qt signals for the GUI. """ +import os import threading import time from PySide import QtCore import zmq -from zmq.auth.thread import ThreadAuthenticator +try: + from zmq.auth.thread import ThreadAuthenticator +except ImportError: + pass from leap.bitmask.backend.api import SIGNALS from leap.bitmask.backend.utils import get_frontend_certificates +from leap.bitmask.config import flags import logging logger = logging.getLogger(__name__) @@ -38,8 +43,12 @@ class SignalerQt(QtCore.QObject): Signaling server. Receives signals from the signaling client and emit Qt signals for the GUI. """ - PORT = "5667" - BIND_ADDR = "tcp://127.0.0.1:%s" % PORT + if flags.ZMQ_HAS_CURVE: + PORT = "5667" + BIND_ADDR = "tcp://127.0.0.1:%s" % PORT + else: + SOCKET_FILE = "/tmp/bitmask.socket.1" + BIND_ADDR = "ipc://%s" % SOCKET_FILE def __init__(self): QtCore.QObject.__init__(self) @@ -67,20 +76,24 @@ class SignalerQt(QtCore.QObject): context = zmq.Context() socket = context.socket(zmq.REP) - # Start an authenticator for this context. - auth = ThreadAuthenticator(context) - auth.start() - auth.allow('127.0.0.1') + if flags.ZMQ_HAS_CURVE: + # Start an authenticator for this context. + auth = ThreadAuthenticator(context) + auth.start() + auth.allow('127.0.0.1') - # Tell authenticator to use the certificate in a directory - auth.configure_curve(domain='*', location=zmq.auth.CURVE_ALLOW_ANY) - public, secret = get_frontend_certificates() - socket.curve_publickey = public - socket.curve_secretkey = secret - socket.curve_server = True # must come before bind + # Tell authenticator to use the certificate in a directory + auth.configure_curve(domain='*', location=zmq.auth.CURVE_ALLOW_ANY) + public, secret = get_frontend_certificates() + socket.curve_publickey = public + socket.curve_secretkey = secret + socket.curve_server = True # must come before bind socket.bind(self.BIND_ADDR) + if not flags.ZMQ_HAS_CURVE: + os.chmod(self.SOCKET_FILE, 0600) + while self._do_work.is_set(): # Wait for next request from client try: diff --git a/src/leap/bitmask/backend/utils.py b/src/leap/bitmask/backend/utils.py index 18e70743..b2674330 100644 --- a/src/leap/bitmask/backend/utils.py +++ b/src/leap/bitmask/backend/utils.py @@ -22,20 +22,63 @@ import os import shutil import stat -import zmq.auth +import zmq +try: + import zmq.auth +except ImportError: + pass + +from leap.bitmask.config import flags from leap.bitmask.util import get_path_prefix from leap.common.files import mkdir_p +from leap.common.check import leap_assert logger = logging.getLogger(__name__) KEYS_DIR = os.path.join(get_path_prefix(), 'leap', 'zmq_certificates') +def _zmq_has_curve(): + """ + Return whether the current ZMQ has support for auth and CurveZMQ security. + + :rtype: bool + + Version notes: + `zmq.curve_keypair()` is new in version 14.0, new in version libzmq-4.0. + Requires libzmq (>= 4.0) to have been linked with libsodium. + `zmq.auth` module is new in version 14.1 + `zmq.has()` is new in version 14.1, new in version libzmq-4.1. + """ + zmq_version = zmq.zmq_version_info() + pyzmq_version = zmq.pyzmq_version_info() + + if pyzmq_version >= (14, 1, 0) and zmq_version >= (4, 1): + return zmq.has('curve') + + if pyzmq_version < (14, 1, 0): + return False + + if zmq_version < (4, 0): + # security is new in libzmq 4.0 + return False + + try: + zmq.curve_keypair() + except zmq.error.ZMQError: + # security requires libzmq to be linked against libsodium + return False + + return True + + def generate_zmq_certificates(): """ Generate client and server CURVE certificate files. """ + leap_assert(flags.ZMQ_HAS_CURVE, "CurveZMQ not supported!") + # Create directory for certificates, remove old content if necessary if os.path.exists(KEYS_DIR): shutil.rmtree(KEYS_DIR) @@ -53,6 +96,8 @@ def get_frontend_certificates(): """ Return the frontend's public and secret certificates. """ + leap_assert(flags.ZMQ_HAS_CURVE, "CurveZMQ not supported!") + frontend_secret_file = os.path.join(KEYS_DIR, "frontend.key_secret") public, secret = zmq.auth.load_certificate(frontend_secret_file) return public, secret @@ -62,6 +107,8 @@ def get_backend_certificates(base_dir='.'): """ Return the backend's public and secret certificates. """ + leap_assert(flags.ZMQ_HAS_CURVE, "CurveZMQ not supported!") + backend_secret_file = os.path.join(KEYS_DIR, "backend.key_secret") public, secret = zmq.auth.load_certificate(backend_secret_file) return public, secret @@ -84,5 +131,8 @@ def generate_zmq_certificates_if_needed(): Generate the needed ZMQ certificates for backend/frontend communication if needed. """ - if not _certificates_exist(): + if flags.ZMQ_HAS_CURVE and not _certificates_exist(): generate_zmq_certificates() + + +flags.ZMQ_HAS_CURVE = _zmq_has_curve() |