Example #1
0
    def create(self, **kwargs):
        # Create WireGuard Interface
        self.ifname = kwargs.get('ifname')
        self.ip = kwargs.get('ip')

        with IPDB() as ip:
            dev = ip.create(kind='wireguard', ifname=self.ifname)
            dev.add_ip(self.ip)
            dev.up()
            dev.commit()

        wg = WireGuard()
        wg.set(self.ifname,
               private_key=kwargs.get('privatekey'),
               listen_port=kwargs.get('listenport'))
Example #2
0
def wg_set(**kwargs):
    wg = WireGuard()

    interface_kwargs = ['private_key', 'fwmark', 'listen_port']
    peer_kwargs = [
        'public_key', 'remove', 'preshared_key', 'endpoint_addr',
        'endpoint_port', 'persistent_keepalive', 'allowed_ips'
    ]
    interface = {}
    peer = {}
    for arg, value in kwargs.items():
        if arg in interface_kwargs:
            interface[arg] = value
        elif arg in peer_kwargs:
            peer[arg] = value

    if 'endpoint_addr' in peer and 'endpoint_port' not in peer:
        peer['endpoint_port'] = 51820

    if peer:
        wg.set(config.IFNAME, **interface, peer=peer)
    else:
        wg.set(config.IFNAME, **interface)
Example #3
0
    def addpeer(self, **kwargs):
        # Create WireGuard object
        wg = WireGuard()

        # build peer dict
        peer = {}
        for key in kwargs.keys():
            if key == 'publickey':
                peer = {**peer, **{'public_key': kwargs.get('publickey')}}
            if key == 'endpointaddr':
                peer = {
                    **peer,
                    **{
                        'endpoint_addr': kwargs.get('endpointaddr')
                    }
                }
            if key == 'endpointport':
                peer = {
                    **peer,
                    **{
                        'endpoint_port': kwargs.get('endpointport')
                    }
                }
            if key == 'keepalive':
                peer = {
                    **peer,
                    **{
                        'persistent_keepalive': kwargs.get('keepalive')
                    }
                }
            if key == 'allowedips':
                peer = {**peer, **{'allowed_ips': kwargs.get('allowedips')}}

        print(f"peer: {peer}")

        # add peer
        wg.set(self.ifname, peer=peer)
Example #4
0
class TestBasic(object):
    @skip_if_not_supported
    def setup(self):
        require_user('root')
        self.ipnets = []
        self.wg = WireGuard()
        self.log_id = uifname()
        self.ndb = NDB(log='../ndb-%s-%s.log' % (os.getpid(), self.log_id),
                       rtnl_debug=True)
        self.netif = uifname()
        self.wg0if = uifname()
        self.wg1if = uifname()
        self.ifnames = [self.netif, self.wg0if, self.wg1if]
        self.ipnets.append(allocate_network())
        self.ipnets.append(allocate_network())
        self.ipranges = [[str(x) for x in net] for net in self.ipnets]
        # create the "network" interface
        (self.ndb.interfaces.create(ifname=self.netif, kind='dummy').set(
            'state', 'up').add_ip('%s/24' % (self.ipranges[0][1])).commit())
        # create one peer
        (self.ndb.interfaces.create(ifname=self.wg0if, kind='wireguard').set(
            'state', 'up').add_ip('%s/24' % (self.ipranges[1][1])).commit())
        # create another peer
        (self.ndb.interfaces.create(ifname=self.wg1if, kind='wireguard').set(
            'state', 'up').add_ip('%s/24' % (self.ipranges[1][2])).commit())

    def teardown(self):
        with NDB() as ndb:
            for i in self.ifnames:
                (ndb.interfaces[i].remove().commit())
        for net in self.ipnets:
            free_network(net)

    def test_set_peer(self):
        # host A
        #
        # private key aPrZzfjeiNuy/oolBFkX4ClU3UjYzVemhK49TfZvMmU=
        # public key orXRcGaN/vxYm0fupIq/Q0ePQyDviyDRtAxAPNJMrA0=
        peerB = {
            'public_key':
            'waDwFcRFnPzGJqgaYoV3P7V3NOji5QNPNjUGuBrwwTI=',
            'endpoint_addr':
            self.ipranges[1][1],
            'endpoint_port':
            12453,
            'persistent_keepalive':
            15,
            'allowed_ips':
            ['%s/24' % self.ipranges[0][0],
             '%s/24' % self.ipranges[1][0]]
        }

        self.wg.set(self.wg0if,
                    private_key='aPrZzfjeiNuy/oolBFkX4ClU3UjYzVemhK49TfZvMmU=',
                    listen_port=12452,
                    peer=peerB)
        # host B
        #
        # private key eHqiUofUM6A41mDVSTbBwFyfkDsVW7uEhv9A8romH2A=
        # public key waDwFcRFnPzGJqgaYoV3P7V3NOji5QNPNjUGuBrwwTI=
        peerA = {
            'public_key':
            'orXRcGaN/vxYm0fupIq/Q0ePQyDviyDRtAxAPNJMrA0=',
            'endpoint_addr':
            self.ipranges[1][1],
            'endpoint_port':
            12452,
            'persistent_keepalive':
            15,
            'allowed_ips':
            ['%s/24' % self.ipranges[0][0],
             '%s/24' % self.ipranges[1][0]]
        }

        self.wg.set(self.wg1if,
                    private_key='eHqiUofUM6A41mDVSTbBwFyfkDsVW7uEhv9A8romH2A=',
                    listen_port=12453,
                    peer=peerA)

        assert grep('wg show %s' % self.wg0if,
                    pattern='peer: %s' % peerB['public_key'])
        assert grep('wg show %s' % self.wg0if,
                    pattern='endpoint: %s:%s' %
                    (peerB['endpoint_addr'], peerB['endpoint_port']))
        assert grep('wg show %s' % self.wg0if, pattern='transfer:')
Example #5
0
class WgConf():
    def __init__(self, client=None):

        self.wg_kernel = module_loaded('wireguard')
        self.wg = WireGuard() if self.wg_kernel else WireguardGo()
        self.ipdb = IPDB()
        self.routes = Routes()
        self.client = client

    def create_syntropy_interfaces(self, ifaces):
        result = []
        for ifname in ifaces.keys():
            int_data = self.create_interface(ifname, ifaces[ifname].get('ip'))
            if int_data.get('public_key') != ifaces[ifname].get('public_key'):
                result.append({"fn": "create_interface", "data": int_data})

    @staticmethod
    def get_wg_interfaces():
        with IPDB() as ipdb:
            current_interfaces = [
                k for k, v in ipdb.by_name.items()
                if re.match(WG_NAME_PATTERN, k)
            ]
        return current_interfaces

    def clear_interfaces(self, dump):
        remote_interfaces = [
            d['args']['ifname'] for d in dump if d['fn'] == 'create_interface'
        ]
        current_interfaces = self.get_wg_interfaces()
        remove_interfaces = set(current_interfaces) - set(remote_interfaces)
        logger.debug(
            f"Clearing interfaces REMOTE - {remote_interfaces}, CURRENT - {current_interfaces} REMOVE={remove_interfaces}"
        )
        for interface in remove_interfaces:
            self.remove_interface(interface)

    def clear_unused_routes(self, dump):
        remote_peers = [d['args'] for d in dump if d['fn'] == 'add_peer']
        remote_interfaces = [
            d['args']['ifname'] for d in dump if d['fn'] == 'create_interface'
        ]
        for ifname in remote_interfaces:
            allowed_ips = []
            remote_peers = [
                allowed_ips.extend(peer['allowed_ips'])
                for peer in remote_peers if peer and peer['ifname'] == ifname
            ]
            self.routes.clear_unused_routes(ifname, allowed_ips)

    def clear_peers(self, dump):
        remote_peers = [
            d['args']['public_key'] for d in dump if d['fn'] == 'add_peer'
        ]
        current_interfaces = self.get_wg_interfaces()
        for iface in current_interfaces:
            peers = get_peer_info(iface, self.wg)
            for peer in peers:
                if peer not in remote_peers:
                    self.remove_peer(iface, peer)

    def get_wg_keys(self, ifname):
        private_key_path = f"/etc/syntropy-agent/privatekey-{ifname}"
        public_key_path = f"/etc/syntropy-agent/publickey-{ifname}"
        private_key = Path(private_key_path)
        public_key = Path(public_key_path)
        if not private_key.is_file() or not public_key.is_file():
            privKey = PrivateKey.generate()
            pubKey = base64.b64encode(bytes(privKey.public_key))
            privKey = base64.b64encode(bytes(privKey))
            base64_privKey = privKey.decode('ascii')
            base64_pubKey = pubKey.decode('ascii')
            private_key.write_text(base64_privKey)
            public_key.write_text(base64_pubKey)
            private_key.chmod(0o600)
            public_key.chmod(0o600)

        if self.wg_kernel:
            return public_key.read_text().strip(), private_key.read_text(
            ).strip()
        else:
            return public_key.read_text().strip(), private_key_path

    def next_free_port(self, port=1024, max_port=65535):
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        while port <= max_port:
            try:
                sock.bind(('', port))
                sock.close()
                return port
            except OSError:
                port += 1
        raise IOError('no free ports')

    def create_interface(self,
                         ifname,
                         internal_ip,
                         listen_port=None,
                         **kwargs):
        public_key, private_key = self.get_wg_keys(ifname)
        peer_metadata = {'metadata': get_peer_metadata(public_key=public_key)}
        logger.info(
            f"[WG_CONF] - Creating interface {ifname}, {internal_ip} - wg_kernel={self.wg_kernel}",
            extra={'metadata': peer_metadata})

        if self.wg_kernel:
            create_interface(ifname)
        else:
            self.wg.create_interface(ifname)
        set_interface_up(ifname)
        set_interface_ip(ifname, internal_ip)
        self.routes.clear_unused_iface_addrs(ifname, internal_ip.split('/')[0])

        try:
            self.wg.set(ifname,
                        private_key=private_key,
                        listen_port=listen_port)
        except NetlinkError as error:
            if error.code != 98:
                raise
            else:
                # if port was taken before creating.
                self.wg.set(
                    ifname,
                    private_key=private_key,
                )
        listen_port = self.get_listening_port(ifname)
        if not listen_port:
            listen_port = find_free_port()
            self.wg.set(ifname,
                        private_key=private_key,
                        listen_port=listen_port)

        result = {
            "public_key": public_key,
            "listen_port": int(listen_port),
            "ifname": ifname
        }
        logger.debug(f"[WG_CONF] - interface_created {result}",
                     extra={'metadata': peer_metadata})
        return result

    def add_peer(self,
                 ifname,
                 public_key,
                 allowed_ips,
                 gw_ipv4,
                 endpoint_ipv4=None,
                 endpoint_port=None):
        peer_metadata = get_peer_metadata(public_key=public_key)
        if self.wg_kernel:
            try:
                peer_info = get_peer_info(ifname=ifname, wg=self.wg)
            except ValueError as e:
                raise WgConfException(str(e))
            old_ips = set(peer_info.get(public_key, [])) - set(allowed_ips)
            self.routes.ip_route_del(ifname, old_ips)
        peer = {
            'public_key': public_key,
            'endpoint_addr': endpoint_ipv4,
            'endpoint_port': endpoint_port,
            'persistent_keepalive': 15,
            'allowed_ips': allowed_ips
        }
        self.wg.set(ifname, peer=peer)
        statuses = self.routes.ip_route_add(ifname, allowed_ips, gw_ipv4)
        add_iptable_rules(allowed_ips)
        self.client.send_log(
            json.dumps({
                'id': "ID." + str(now()),
                'executed_at': now(),
                "type": "WG_ROUTE_STATUS",
                "data": {
                    "connection_id": peer_metadata.get('connection_id'),
                    "public_key": public_key,
                    "statuses": statuses,
                }
            }))

    def remove_peer(self, ifname, public_key, allowed_ips=None):

        if ifname not in self.get_wg_interfaces():
            logger.debug(f'[WG_CONF] Remove peer - [{ifname}] does not exist')
            return

        peer = {'public_key': public_key, 'remove': True}
        try:
            self.wg.set(ifname, peer=peer)
            if allowed_ips:
                self.routes.ip_route_del(ifname, allowed_ips)
                delete_iptable_rule(allowed_ips)
        except pyroute2.netlink.exceptions.NetlinkError as error:
            if error.code != 19:
                raise
        return

    def remove_interface(self, ifname):
        logger.debug(f'[WG_CONF] Removing interfcae - [{ifname}]')
        delete_interface(ifname)
        logger.debug(f'[WG_CONF] Removed interfcae - [{ifname}]')
        return

    def get_listening_port(self, ifname):
        if self.wg_kernel:
            wg_info = dict(self.wg.info(ifname)[0]['attrs'])
            return wg_info['WGDEVICE_A_LISTEN_PORT']

        else:
            wg_info = self.wg.info(ifname)
            return wg_info['listen_port']