Skip to content
vpn.py 2.21 KiB
Newer Older
Antoine Millet's avatar
Antoine Millet committed
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)