Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 51 additions & 40 deletions wg-gen.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/usr/bin/env python3
import ipaddress
import json
import os.path
import random
Expand All @@ -13,15 +14,18 @@ def get_public_ip(self) -> str:
"""Returns a string of a public ip address"""
return json.loads(subprocess.check_output('curl -s https://ipinfo.io', shell=True).decode('utf-8'))['ip']

def generate_private_ip(self):
"""Returns random ip address in 10.0.0.0/8 range"""
return f'10.{random.randrange(0, 255)}.{random.randrange(0, 255)}.'
def generate_private_ip(self, subnet: int = 22):
"""Returns random subnet in 10.0.0.0/8 range, defaults to 22 bit subnet"""
generated_ip_interface = ipaddress.IPv4Interface(
f'10.{random.randrange(0, 255)}.{random.randrange(0, 255)}.{random.randrange(0, 255)}/{subnet}'
)
return (list(generated_ip_interface.network.hosts())[-1], generated_ip_interface.netmask)

def get_current_time(self) -> str:
"""Returns current time w/o milliseconds"""
return datetime.now().isoformat(' ', 'seconds')

def get_default_interface_name(self):
def get_default_interface_name(self):
return subprocess.check_output("ip route show 0.0.0.0/0 | awk '{print $5}' | head -n 1", shell=True).decode('UTF-8').strip()

def read_json(self) -> json:
Expand Down Expand Up @@ -50,43 +54,51 @@ def generate_guest_configs(self, name: str, data: Dict) -> Dict:
"Generates peer config and adds it to wghub.conf. Takes config json file and spits it back with changed seqno"
peer_keys = self.generate_wg_keys()
preshared_key = self.generate_preshared_key()
if int(data['seqno']) > 254:
return print("Maximum amount of IPs in /24 subnet exceeded.")
else:
with open('wghub.conf', 'a') as file:
file.write(
f'\n\n'
f'#{data["seqno"]} Generated at {self.get_current_time()} for {name}\n'
f'[Peer]\n'
f'PublicKey = {peer_keys[1]}\n'
f'PresharedKey = {preshared_key}\n'
f'AllowedIPs = {data["private_ip"]}{data["seqno"]}/32'
)
with open('wgclient_' + data['seqno'] + '.conf', 'w') as file:
file.write(
f'#{data["seqno"]} generated at {self.get_current_time()} for {name}\n'
f'[Interface]\n'
f'PrivateKey = {peer_keys[0]}\n'
f'Address = {data["private_ip"]}{data["seqno"]}{data["cidr"]}\n'
f'MTU = 1280\n'
f'DNS = {data["DNS"]}\n\n'
f'[Peer]\n'
f'PublicKey = {data["hub_public_key"]}\n'
f'PresharedKey = {preshared_key}\n'
f'AllowedIPs = {data["client_allowed_ips"]}\n'
f'Endpoint = {data["public_ip"]}:{data["port"]}\n'
f'PersistentKeepalive = 25\n'
)
data['seqno'] = str(int(data['seqno']) + 1)
return data
gw_address = ipaddress.IPv4Interface(f'{data["private_ip"]}/{data["private_ip_netmask"]}')
client_ip = list(gw_address.network.hosts())[int(data["seqno"])]
client_interface = ipaddress.IPv4Interface(f'{client_ip}/{data["private_ip_netmask"]}')

if gw_address == client_interface:
raise Exception('You reached last IP address in your wireguard network. No more clients can be generated.')

with open('wghub.conf', 'a') as file:
file.write(
f'\n\n'
f'# {data["seqno"]} Generated at {self.get_current_time()} for {name}\n'
f'[Peer]\n'
f'PublicKey = {peer_keys[1]}\n'
f'PresharedKey = {preshared_key}\n'
f'AllowedIPs = {data["private_ip"]}{data["seqno"]}/32'
)
with open('wgclient_' + str(int(data['seqno']) + 1) + '.conf', 'w') as file:
file.write(
f'#{data["seqno"]} generated at {self.get_current_time()} for {name}\n'
f'[Interface]\n'
f'PrivateKey = {peer_keys[0]}\n'
f'Address = {client_interface.with_prefixlen}\n'
f'MTU = 1280\n'
f'DNS = {data["DNS"]}\n\n'
f'[Peer]\n'
f'PublicKey = {data["hub_public_key"]}\n'
f'PresharedKey = {preshared_key}\n'
f'AllowedIPs = {data["client_allowed_ips"]}\n'
f'Endpoint = {data["public_ip"]}:{data["port"]}\n'
f'PersistentKeepalive = 25\n'
)
self.gen_qr_code(data)

data['seqno'] = str(int(data['seqno']) + 1)
return data

def generate_hub(self, data: Dict[str, str]) -> None:
"""Generates wghub.conf configuration file from dictionary"""
gw_address = ipaddress.IPv4Interface(f'{data["private_ip"]}/{data["private_ip_netmask"]}')

with open('wghub.conf', 'w') as file:
file.write(
f'# hub generated at {self.get_current_time()}\n'
f'[Interface]\n'
f'Address = {data["private_ip"]}1{data["cidr"]}\n'
f'Address = {gw_address.with_prefixlen}\n'
f'ListenPort = {data["port"]}\n'
f'PrivateKey = {data["hub_private_key"]}\n'
f'SaveConfig = False\n'
Expand All @@ -100,7 +112,7 @@ def generate_hub(self, data: Dict[str, str]) -> None:

def gen_qr_code(self, data: dict) -> None:
"""Generates qr code from a configuration file"""
subprocess.run(f'qrencode -t ansiutf8 < wgclient_{int(data["seqno"]) - 1}.conf', shell=True)
subprocess.run(f'qrencode -t ansiutf8 < wgclient_{int(data["seqno"]) + 1}.conf', shell=True)


def main():
Expand All @@ -114,17 +126,17 @@ def main():
wireguard_data = wireguard.generate_guest_configs('client', wireguard_data)

wireguard.save_json(wireguard_data)
wireguard.gen_qr_code(wireguard_data)
else:
hub_keys = wireguard.generate_wg_keys()
hub_ips = wireguard.generate_private_ip()
wireguard_data = {
'private_ip': wireguard.generate_private_ip(),
'private_ip': str(hub_ips[0]),
'private_ip_netmask': str(hub_ips[1]),
'public_ip': wireguard.get_public_ip(),
'hub_private_key': hub_keys[0],
'hub_public_key': hub_keys[1],
'seqno': '2',
'seqno': '0',
'port': str(random.randrange(10000, 60000)),
'cidr': '/24',
'DNS': '1.1.1.1',
'oiface': wireguard.get_default_interface_name(),
'client_allowed_ips': '0.0.0.0/0'
Expand All @@ -137,7 +149,6 @@ def main():
except IndexError:
wireguard_data = wireguard.generate_guest_configs('client', wireguard_data)

wireguard.gen_qr_code(wireguard_data)
wireguard.save_json(wireguard_data)


Expand Down