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)