|
#!/bin/env python3 |
|
|
|
""" |
|
WireGuard Mesh Network builder for systemd-networkd |
|
|
|
10.0.123.1 |
|
alpha --- bravo 10.0.123.2 |
|
|- charlie 10.0.123.3 |
|
|
|
10.1.123.1 |
|
bravo --- alpha 10.1.123.2 |
|
|- charlie 10.1.123.3 |
|
|
|
10.2.123.1 |
|
charlie --- alpha 10.2.123.2 |
|
|- bravo 10.2.123.3 |
|
|
|
How to use? |
|
1. fill your host info. ``HOSTS`` |
|
2. run this script |
|
3. copy generated .netdev, .network files to your hosts (e.g. /etc/systemd/network/) |
|
4. enjoy mesh network |
|
""" |
|
|
|
import subprocess |
|
import os |
|
|
|
HOSTS = [ |
|
{ |
|
'hostname': 'alpha', |
|
'external_ip': '198.51.100.1', |
|
'external_port': '11111', |
|
'private_key': None, # DON'T FILL |
|
'public_key': None, # DON'T FILL |
|
'preshared_key': None # DON'T FILL |
|
}, |
|
{ |
|
'hostname': 'bravo', |
|
'external_ip': '198.51.100.2', |
|
'external_port': '22222', |
|
'private_key': None, # DON'T FILL |
|
'public_key': None, # DON'T FILL |
|
'preshared_key': None # DON'T FILL |
|
}, |
|
{ |
|
'hostname': 'charlie', |
|
'external_ip': '198.51.100.3', |
|
'external_port': '33333', |
|
'private_key': None, # DON'T FILL |
|
'public_key': None, # DON'T FILL |
|
'preshared_key': None # DON'T FILL |
|
} |
|
] |
|
|
|
|
|
def generate_private_key() -> str: |
|
proc = subprocess.run(["wg", "genkey"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
|
return proc.stdout.decode("utf8").strip() |
|
|
|
|
|
def generate_public_key(private_key: str) -> str: |
|
s = subprocess.Popen(['wg', 'pubkey'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
|
output, errs = s.communicate(private_key.encode()) |
|
output = output.decode() |
|
return output.strip() |
|
|
|
|
|
def generate_preshared_key() -> str: |
|
proc = subprocess.run(["wg", "genpsk"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
|
return proc.stdout.decode("utf8").strip() |
|
|
|
|
|
def generate_config(index, router_hostname, peers): |
|
root_peer = [x for x in peers if x['hostname'] == router_hostname][0] |
|
non_router_peers = [x for x in peers if x['hostname'] != router_hostname] |
|
|
|
router_netdev = f"""[NetDev] |
|
Name = wg{index} |
|
Description = WireGuard mesh .netdev "{router_hostname}" [router] |
|
Kind = wireguard |
|
|
|
[WireGuard] |
|
ListenPort = {root_peer['external_port']} |
|
PrivateKey = {root_peer['private_key']} |
|
# PublicKey = {root_peer['public_key']} |
|
""" |
|
|
|
for peer_index, peer in enumerate(non_router_peers): |
|
router_netdev += f""" |
|
# {peer['hostname']} |
|
[WireGuardPeer] |
|
PublicKey = {peer['public_key']} |
|
PresharedKey = {peer['preshared_key']} |
|
AllowedIPs = 10.{index}.123.{peer_index + 2}/32 |
|
""" |
|
|
|
router_network = f"""[Match] |
|
Name = wg{index} |
|
|
|
[Network] |
|
Description = WireGuard mesh .network "{router_hostname}" [router] |
|
Address = 10.{index}.123.1/32 |
|
|
|
[Route] |
|
Gateway = 10.{index}.123.1 |
|
Destination = 10.{index}.123.0/24 |
|
""" |
|
|
|
os.makedirs(f'mesh/{router_hostname}', exist_ok=True) |
|
with open(f'mesh/{router_hostname}/wg{index}.netdev', mode='w+') as netdev: |
|
netdev.write(router_netdev) |
|
|
|
with open(f'mesh/{router_hostname}/wg{index}.network', mode='w+') as network: |
|
network.write(router_network) |
|
|
|
for peer_index, peer in enumerate(non_router_peers): |
|
peer_netdev = f"""[NetDev] |
|
Name = wg{index} |
|
Description = WireGuard mesh .netdev "{peer['hostname']}" to "{router_hostname}" [non-router] |
|
Kind = wireguard |
|
|
|
[WireGuard] |
|
PrivateKey = {peer['private_key']} |
|
# PublicKey = {peer['public_key']} |
|
|
|
[WireGuardPeer] |
|
PublicKey = {root_peer['public_key']} |
|
PresharedKey = {peer['preshared_key']} |
|
AllowedIPs = 10.{index}.123.0/24 |
|
Endpoint = {root_peer['external_ip']}:{root_peer['external_port']} |
|
PersistentKeepalive = 60 |
|
""" |
|
|
|
peer_network = f"""[Match] |
|
Name = wg{index} |
|
|
|
[Network] |
|
Description = WireGuard mesh .network "{peer['hostname']}" to "{router_hostname}" [non-router] |
|
Address = 10.{index}.123.{peer_index + 2}/32 |
|
|
|
[Route] |
|
Gateway = 10.{index}.123.1 |
|
Destination = 10.{index}.123.0/24 |
|
GatewayOnlink=true |
|
""" |
|
|
|
with open(f"mesh/{peer['hostname']}/wg{index}.netdev", mode='w+') as netdev: |
|
netdev.write(peer_netdev) |
|
|
|
with open(f"mesh/{peer['hostname']}/wg{index}.network", mode='w+') as network: |
|
network.write(peer_network) |
|
|
|
|
|
def update_peer_keys(peers): |
|
for peer in peers: |
|
private_key = generate_private_key() |
|
public_key = generate_public_key(private_key) |
|
preshared_key = generate_preshared_key() |
|
peer['private_key'] = private_key |
|
peer['public_key'] = public_key |
|
peer['preshared_key'] = preshared_key |
|
|
|
|
|
if __name__ == '__main__': |
|
for mesh_index, router_peer in enumerate(HOSTS): |
|
update_peer_keys(HOSTS) |
|
generate_config(mesh_index, router_peer['hostname'], HOSTS) |