diff --git a/sjrpc/core/protocols/__init__.py b/sjrpc/core/protocols/__init__.py index 72bc168373c8c13818cc77536d9c0e4286ead94b..27d9f30c9ce6bf516bb2194cbda71f48b60c690e 100644 --- a/sjrpc/core/protocols/__init__.py +++ b/sjrpc/core/protocols/__init__.py @@ -82,5 +82,6 @@ class Protocol(object): from sjrpc.core.protocols.rpc import RpcProtocol from sjrpc.core.protocols.tunnel import TunnelProtocol +from sjrpc.core.protocols.vpn import VpnProtocol -__all__ = ['Protocol', 'RpcProtocol', 'TunnelProtocol'] +__all__ = ['Protocol', 'RpcProtocol', 'TunnelProtocol', 'VpnProtocol'] diff --git a/sjrpc/core/protocols/vpn.py b/sjrpc/core/protocols/vpn.py new file mode 100644 index 0000000000000000000000000000000000000000..5f95764c1e70937702481bdebeeb98e830319d25 --- /dev/null +++ b/sjrpc/core/protocols/vpn.py @@ -0,0 +1,78 @@ +from __future__ import absolute_import + +import os +import struct +import fcntl + +from sjrpc.core.protocols import TunnelProtocol + +__all__ = ['VpnProtocol'] + +class _FileSocket(object): + + ''' + A fake Socket interface for files. + ''' + + def __init__(self, file_): + self.file = file_ + + def recv(self, size): + self.file.read(size) + + def send(self, data): + self.file.write(data) + return len(data) + + def fileno(self): + return self.file.fileno() + + def setblocking(self, blocking): + if not blocking: + # Disable blocking mode on devzero: + current_flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFL) + fcntl.fcntl(self.fileno(), fcntl.F_SETFL, current_flags | os.O_NONBLOCK) + else: + raise NotImplementedError('Not implemented') + + +class VpnProtocol(TunnelProtocol): + + ''' + A VPN protocol which spawn a network interface and tunnel all its traffic + through the sjRpc tunnel. + + :param inherited: All options (except endpoint) are inherited from + :class:`TunnelProtocol`. + :param tun_prefix: the prefix name of the spawned interface + :param tun_mode: which can be VpnProtocol.IFF_TUN or VpnProtocol.IFF_TAP + + The user starting the sjRpc process must have the CAP_NET_ADMIN capability, + by default, only root have this capability. + + .. warning:: + This protocol is a proof of concept and should not be used in production + software. + ''' + + # Taken from linux/if_tun.h: + TUNSETIFF = 0x400454ca + IFF_TUN = 0x0001 + IFF_TAP = 0x0002 + + # Default values: + DEFAULT_TUN_PREFIX = 'tun' + DEFAULT_TUN_MODE = IFF_TAP + + def __init__(self, *args, **kwargs): + tun_prefix = kwargs.pop('tun_prefix', VpnProtocol.DEFAULT_TUN_PREFIX) + tun_mode = kwargs.pop('tun_mode', VpnProtocol.DEFAULT_TUN_MODE) + + ftun = open('/dev/net/tun', 'r+b') + # Create the tunnel and get its final name: + create_tun_arg = struct.pack('16sH', tun_prefix + '%d', tun_mode) + tun = fcntl.ioctl(ftun, VpnProtocol.TUNSETIFF, create_tun_arg) + self.tun_name = tun[:16].rstrip('\0') + + kwargs['endpoint'] = _FileSocket(ftun) + super(VpnProtocol, self).__init__(*args, **kwargs)