from django.db import transaction from .models import * @transaction.atomic def create_vpn(*, public_key: str, network_size: int ) -> VPNNetwork: # Select suitable pool pools = VPNPool.objects.filter(subnetwork_size=network_size) # FIXME: exception - which? if not pools: return None # Find all pools with the correct size # For each pool see if it has still space: # num network reversations < 2**(subnetwork_size-network_size) def next_free_network(self): if self.num_free_networks == 0: # FIXME: use right exception raise Exception("No free networks") if len(self.free_networks) > 0: return self.free_networks[0].address if len(self.used_networks) > 0: """ sample: pool = 2a0a:e5c1:200::/40 last_used = 2a0a:e5c1:204::/48 next: """ last_net = ipaddress.ip_network(self.used_networks.last().address) last_net_ip = last_net[0] if last_net_ip.version == 6: offset_to_next = 2**(128 - self.subnetwork_size) elif last_net_ip.version == 4: offset_to_next = 2**(32 - self.subnetwork_size) next_net_ip = last_net_ip + offset_to_next return str(next_net_ip) else: # first network to be created return self.network @property def wireguard_config_filename(self): return '/etc/wireguard/{}.conf'.format(self.network) @property def wireguard_config(self): wireguard_config = [ """ [Interface] ListenPort = 51820 PrivateKey = {privatekey} """.format(privatekey=self.wireguard_private_key) ] peers = [] for reservation in self.vpnnetworkreservation_set.filter(status='used'): public_key = reservation.vpnnetwork_set.first().wireguard_public_key peer_network = "{}/{}".format(reservation.address, self.subnetwork_size) owner = reservation.vpnnetwork_set.first().owner peers.append(""" # Owner: {owner} [Peer] PublicKey = {public_key} AllowedIPs = {peer_network} """.format( owner=owner, public_key=public_key, peer_network=peer_network)) wireguard_config.extend(peers) return "\n".join(wireguard_config) def configure_wireguard_vpnserver(self): """ This method is designed to run as a celery task and should not be called directly from the web """ # subprocess, ssh pass def num_maximum_networks(self): """ sample: network_size = 40 subnetwork_size = 48 maximum_networks = 2^(48-40) 2nd sample: network_size = 8 subnetwork_size = 24 maximum_networks = 2^(24-8) """ return 2**(self.subnetwork_mask - self.network_mask)