-
-
Save lschuermann/7e5de6e00358d1312c86e2144d7352b4 to your computer and use it in GitHub Desktop.
Mininet network to test WireGuard peer and endpoint-to-endpoint MTU issues
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import subprocess | |
import tempfile | |
from mininet.net import Mininet | |
from mininet.cli import CLI | |
from mininet.log import setLogLevel, info | |
basePort = 50000 | |
tunnelIdx = 0 | |
def wireguardKeypair(): | |
privkeyGen = subprocess.run( | |
["/usr/bin/env", "wg", "genkey"], | |
stdout=subprocess.PIPE, | |
) | |
privkeyGen.check_returncode() | |
pubkeyGen = subprocess.run( | |
["/usr/bin/env", "wg", "pubkey"], | |
input=privkeyGen.stdout, | |
stdout=subprocess.PIPE, | |
) | |
privkeyGen.check_returncode() | |
return ( | |
privkeyGen.stdout.decode("utf-8").strip(), | |
pubkeyGen.stdout.decode("utf-8").strip(), | |
) | |
def wireguardTunnel(hostA, hostAIP, tunnelIPA, hostB, hostBIP, tunnelIPB, allowedIPsA=None, allowedIPsB=None): | |
global tunnelIdx | |
for host in [hostA, hostB]: | |
if not hasattr(host, "wireguardTunnels"): | |
setattr(host, "wireguardTunnels", {}) | |
hostA.wireguardTunnels[tunnelIdx] = { | |
"keypair": wireguardKeypair(), | |
"listenPort": basePort + tunnelIdx, | |
"tunnelIP": tunnelIPA, | |
"endpointIP": hostAIP, | |
"allowedIPs": allowedIPsA if allowedIPsA is not None else [f"{tunnelIPB}/32"], | |
} | |
hostB.wireguardTunnels[tunnelIdx] = { | |
"keypair": wireguardKeypair(), | |
"listenPort": basePort + tunnelIdx, | |
"tunnelIP": tunnelIPB, | |
"endpointIP": hostBIP, | |
"allowedIPs": allowedIPsB if allowedIPsB is not None else [f"{tunnelIPA}/32"], | |
} | |
for host, peer in [(hostA, hostB), (hostB, hostA)]: | |
tunnel = host.wireguardTunnels[tunnelIdx] | |
peerTunnel = peer.wireguardTunnels[tunnelIdx] | |
host.cmd(f"ip link add wg{tunnelIdx} type wireguard") | |
host.cmd(f"ip link set wg{tunnelIdx} up") | |
host.cmd(f"ip address add {tunnel['tunnelIP']}/32 dev wg{tunnelIdx}") | |
with tempfile.NamedTemporaryFile() as privkeyFile: | |
privkeyFile.write(tunnel["keypair"][0].encode("utf-8")) | |
privkeyFile.flush() | |
host.cmd(f"wg set wg{tunnelIdx} private-key {privkeyFile.name}") | |
host.cmd(f"wg set wg{tunnelIdx} listen-port {tunnel['listenPort']}") | |
host.cmd(("wg set wg{} peer {} endpoint {}:{} {} " | |
+ "persistent-keepalive 10").format( | |
tunnelIdx, | |
peerTunnel["keypair"][1], | |
peerTunnel["endpointIP"], | |
peerTunnel["listenPort"], | |
" ".join([f"allowed-ips {ip}" for ip in tunnel["allowedIPs"]]) | |
)) | |
host.cmd(f"ip route add {peerTunnel['tunnelIP']} dev wg{tunnelIdx} src {tunnel['tunnelIP']}") | |
tunnelIdx += 1 | |
return tunnelIdx - 1 | |
setLogLevel("info") | |
net = Mininet(topo=None, build=False) | |
info("*** Add switches\n") | |
s1 = net.addSwitch("s1", failMode="standalone") | |
s2 = net.addSwitch("s2", failMode="standalone") | |
s3 = net.addSwitch("s3", failMode="standalone") | |
s4 = net.addSwitch("s4", failMode="standalone") | |
info("*** Add hosts\n") | |
h1 = net.addHost("h1", ip="10.0.0.1/24") | |
h2 = net.addHost("h2", ip="10.0.0.2/24") | |
h3 = net.addHost("h3", ip="10.0.1.2/24") | |
h4 = net.addHost("h4", ip="10.0.2.2/24") | |
h5 = net.addHost("h5", ip="192.168.1.2/24") | |
# Manually assign v6 addresses, as mininet does not support IPv6 | |
v6Links = [] | |
def v6Link(link, addr): | |
global v6Links | |
v6Links += [(link.intf1, addr)] | |
# Connect h1 to h2 | |
v6Link(net.addLink(h1, s1), "fd00:0:0:0::1/64") | |
v6Link(net.addLink(h2, s1), "fd00:0:0:0::2/64") | |
# Connect h2 to h3 | |
v6Link(net.addLink(h2, s2, params1={"ip": "10.0.1.1/24"}), "fd00:0:0:1::1/64") | |
v6Link(net.addLink(h3, s2), "fd00:0:0:1::2/64") | |
# Connect h3 to h4 | |
v6Link(net.addLink(h3, s3, params1={"ip": "10.0.2.1/24"}), "fd00:0:0:2::1/64") | |
v6Link(net.addLink(h4, s3), "fd00:0:0:2::2/64") | |
# Connect h4 to h5 | |
net.addLink(h4, s4, params1={"ip": "192.168.1.1/24"}) | |
net.addLink(h5, s4) | |
info("*** Starting network\n") | |
net.start() | |
# Install all of the IPv6 addresses | |
for intf, v6addr in v6Links: | |
intf.node.cmd(f"ip -6 addr add {v6addr} dev {intf.name}") | |
for host in [h1, h2, h3, h4, h5]: | |
host.cmd("sysctl net.ipv4.ipfrag_low_thresh=0") | |
host.cmd("sysctl net.ipv4.ipfrag_high_thresh=0") | |
host.cmd("sysctl net.ipv4.ip_forward=1") | |
host.cmd("sysctl net.ipv6.ipfrag_low_thresh=0") | |
host.cmd("sysctl net.ipv6.ipfrag_high_thresh=0") | |
host.cmd("sysctl net.ipv6.conf.all.forwarding=1") | |
# Populate regular L3 routing tables (done manually here, tedious but | |
# works) | |
h1.cmd("ip route add 10.0.1.0/24 via 10.0.0.2") | |
h1.cmd("ip -6 route add fd00:0:0:1::/64 via fd00:0:0:0::2") | |
h1.cmd("ip route add 10.0.2.0/24 via 10.0.0.2") | |
h1.cmd("ip -6 route add fd00:0:0:2::/64 via fd00:0:0:0::2") | |
h1.cmd("ip route add 10.0.3.0/24 via 10.0.0.2") | |
h1.cmd("ip -6 route add fd00:0:0:3::/64 via fd00:0:0:0::2") | |
h2.cmd("ip route add 10.0.2.0/24 via 10.0.1.2") | |
h2.cmd("ip -6 route add fd00:0:0:2::/64 via fd00:0:0:1::2") | |
h2.cmd("ip route add 10.0.3.0/24 via 10.0.1.2") | |
h2.cmd("ip -6 route add fd00:0:0:3::/64 via fd00:0:0:1::2") | |
h3.cmd("ip route add 10.0.0.0/24 via 10.0.1.1") | |
h3.cmd("ip -6 route add fd00:0:0:0::/64 via fd00:0:0:1::1") | |
h3.cmd("ip route add 10.0.3.0/24 via 10.0.2.2") | |
h3.cmd("ip -6 route add fd00:0:0:3::/64 via fd00:0:0:2::2") | |
h4.cmd("ip route add 10.0.0.0/24 via 10.0.2.1") | |
h4.cmd("ip -6 route add fd00:0:0:0::/64 via fd00:0:0:2::1") | |
h4.cmd("ip route add 10.0.1.0/24 via 10.0.2.1") | |
h4.cmd("ip -6 route add fd00:0:0:1::/64 via fd00:0:0:2::1") | |
h1h4Tunnel = wireguardTunnel( | |
h1, "fd00:0:0:0::1", "192.168.0.1", | |
h4, "fd00:0:0:2::2", "192.168.0.2", | |
allowedIPsA = ["192.168.0.2/32", "192.168.1.0/24"], | |
) | |
h1.cmd(f"ip route add 192.168.1.0/24 dev wg{h1h4Tunnel}") | |
h5.cmd("ip route add 192.168.0.0/24 via 192.168.1.1") | |
CLI(net) | |
net.stop() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment