diff --git a/WireGuard/NOTES.md b/WireGuard/NOTES.md new file mode 100644 index 0000000..d21d924 --- /dev/null +++ b/WireGuard/NOTES.md @@ -0,0 +1,54 @@ +# WireGuard road-warrior na MikroTiku (router-hosted) + +Nastaveno 2026-06-18 podle runbooku `wireguard-mikrotik-runbook.md`. + +## Router +- **MikrotikFirewall** (hEX, RouterOS 7.19.6), LAN IP `192.168.1.2`, SSH port **22**. +- WAN = `pppoe-out1`, veřejná IP `78.80.38.51` (PPPoE, bere se jako statická). + +## DŮLEŽITÉ — proč port 51821, ne 51820 +Na routeru **už běží jiná WireGuard VPN na Unraidu** (`192.168.1.76`): NAT rule +„WireGuard to Unraid" DST-NATuje příchozí UDP **51820** na Unraid. Proto tahle +nová, **na routeru hostovaná** VPN běží na **UDP 51821** (51820 by se nikdy +nedostalo k routeru). Existující Unraid VPN ani tunel `10.253.0.0/24` nejsou dotčené. + +## Parametry této VPN +| | | +|---|---| +| WG rozhraní | `wg-vpn`, listen-port **51821** | +| Server public key | `CGGFHYR83W8IuTB46cJ49IuL/tL3w4yu3o0hQh0Cxwo=` | +| Tunelová síť | `10.10.10.0/24`, router `10.10.10.1` | +| Klienti | `10.10.10.2` (client2), `.3` (client3), `.4` (client4) | +| Endpoint | `78.80.38.51:51821` | +| Split tunel | AllowedIPs = `192.168.1.0/24` (jen LAN přes VPN) | +| DNS klientů | `192.168.1.2` (router) | + +## Přidané firewall pravidla (jen accept, nic nemazáno/nepřeřazeno) +- input: accept udp dst-port 51821 in-interface=pppoe-out1 „WireGuard in (router)" +- input: accept in-interface=wg-vpn „WG -> router (DNS/ping)" (DNS a ping na router z tunelu) +- forward: accept in-interface=wg-vpn „WG -> LAN" +Všechna vložena PŘED příslušné `drop` v daném chainu. +NAT hairpin **nepřidán** — LAN hosti mají router jako default gw, návratová cesta funguje. + +## Skripty +- `rosrun.py` — spouští RouterOS příkazy přes SSH. Creds z env: `ROS_HOST/ROS_PORT/ROS_USER/ROS_PASS`. + Pozn.: v Git Bash nutné `MSYS_NO_PATHCONV=1` a příkazy přes stdin (ne `--cmd`, mangluje `/...`). +- `gen_clients.py` — generuje klíče (wg.exe) + `.conf` + QR PNG do `wg-clients/`, a `_peers_add.rsc`. + +## Klientské konfigurace +`wg-clients/clientN.conf` (import na notebook) + `wg-clients/clientN.png` (QR pro mobilní app). +**Obsahují privátní klíče** — po rozdání na zařízení smaž, ať neleží zbytečně. + +## Test (jen zvenku, ne z LAN!) +Telefon na mobilních datech → naskenuj QR → ověř `ping 192.168.1.2`. Z LAN to +handshake neudělá (accept je vázán na in-interface=pppoe-out1, hairpin pro 51821 není). + +## Rollback +``` +/interface wireguard peers remove [find interface=wg-vpn] +/ip firewall filter remove [find comment="WG -> LAN"] +/ip firewall filter remove [find comment="WG -> router (DNS/ping)"] +/ip firewall filter remove [find comment="WireGuard in (router)"] +/ip address remove [find interface=wg-vpn] +/interface wireguard remove [find name=wg-vpn] +``` diff --git a/WireGuard/gen_clients.py b/WireGuard/gen_clients.py new file mode 100644 index 0000000..e517344 --- /dev/null +++ b/WireGuard/gen_clients.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +"""Generate WireGuard road-warrior client configs + QR PNGs, and emit RouterOS peer-add commands.""" +import subprocess, pathlib, qrcode + +WG = r"C:\Program Files\WireGuard\wg" +SERVER_PUB = "CGGFHYR83W8IuTB46cJ49IuL/tL3w4yu3o0hQh0Cxwo=" +ENDPOINT = "78.80.38.51:51821" +LAN = "192.168.1.0/24" # split tunnel -> only LAN goes through VPN +DNS = "192.168.1.2" # router LAN IP + +CLIENTS = [2, 3, 4] +outdir = pathlib.Path(__file__).resolve().parent / "wg-clients" +outdir.mkdir(exist_ok=True) + + +def wg(*args, inp=None): + return subprocess.run([WG, *args], input=inp, capture_output=True, + text=True, check=True).stdout.strip() + + +peer_cmds = [] +for i in CLIENTS: + name = f"client{i}" + priv = wg("genkey") + pub = wg("pubkey", inp=priv) + psk = wg("genpsk") + + conf = f"""[Interface] +PrivateKey = {priv} +Address = 10.10.10.{i}/32 +DNS = {DNS} + +[Peer] +PublicKey = {SERVER_PUB} +PresharedKey = {psk} +AllowedIPs = {LAN} +Endpoint = {ENDPOINT} +PersistentKeepalive = 25 +""" + (outdir / f"{name}.conf").write_text(conf, encoding="utf-8") + + img = qrcode.make(conf) + img.save(outdir / f"{name}.png") + + peer_cmds.append( + f'/interface wireguard peers add interface=wg-vpn ' + f'public-key="{pub}" preshared-key="{psk}" ' + f'allowed-address=10.10.10.{i}/32 comment="{name}"' + ) + print(f"[ok] {name}: pub={pub} -> {name}.conf, {name}.png") + +(outdir / "_peers_add.rsc").write_text("\n".join(peer_cmds) + "\n", encoding="utf-8") +print("\n--- RouterOS peer-add commands written to wg-clients/_peers_add.rsc ---") +for c in peer_cmds: + print(c) diff --git a/WireGuard/rollback_unraid_wg.rsc b/WireGuard/rollback_unraid_wg.rsc new file mode 100644 index 0000000..216b704 --- /dev/null +++ b/WireGuard/rollback_unraid_wg.rsc @@ -0,0 +1,8 @@ +# ROLLBACK — obnova Unraid WireGuard objektů na routeru MikrotikFirewall +# Odstraněno 2026-06-18 na žádost uživatele. Spusť tyto příkazy pro obnovu. +/ip firewall nat add chain=dstnat action=dst-nat to-addresses=192.168.1.76 to-ports=51820 protocol=udp in-interface=pppoe-out1 dst-port=51820 comment="WireGuard to Unraid" +/ip firewall filter add chain=input action=accept protocol=udp in-interface=pppoe-out1 dst-port=51820 comment="Allow WireGuard" +/ip firewall filter add chain=forward action=accept src-address=10.253.0.0/24 comment="Allow VPN to LAN" +/ip firewall filter add chain=forward action=accept dst-address=10.253.0.0/24 comment="Allow LAN to VPN" +/ip route add dst-address=10.253.0.0/24 gateway=192.168.1.76 comment="Route to WireGuard VPN via Unraid" +# Pozn.: po obnově zkontroluj pořadí filter pravidel (accept musí být PŘED drop). diff --git a/WireGuard/rosrun.py b/WireGuard/rosrun.py new file mode 100644 index 0000000..a90d71d --- /dev/null +++ b/WireGuard/rosrun.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +"""Run RouterOS commands over SSH. Creds from env: ROS_HOST, ROS_PORT, ROS_USER, ROS_PASS. +Commands: one per line on stdin, or via --cmd. Prints output per command.""" +import os, sys, paramiko + +host = os.environ["ROS_HOST"] +port = int(os.environ.get("ROS_PORT", "22")) +user = os.environ["ROS_USER"] +pw = os.environ["ROS_PASS"] + +cmds = [] +if "--cmd" in sys.argv: + cmds = [sys.argv[sys.argv.index("--cmd") + 1]] +else: + cmds = [l.rstrip("\n") for l in sys.stdin if l.strip()] + +cli = paramiko.SSHClient() +cli.set_missing_host_key_policy(paramiko.AutoAddPolicy()) +cli.connect(host, port=port, username=user, password=pw, + look_for_keys=False, allow_agent=False, timeout=20) + +for c in cmds: + print(f"\n===== CMD: {c}") + stdin, stdout, stderr = cli.exec_command(c, timeout=30) + out = stdout.read().decode("utf-8", "replace") + err = stderr.read().decode("utf-8", "replace") + sys.stdout.write(out) + if err.strip(): + sys.stdout.write("--- stderr ---\n" + err) +cli.close() diff --git a/WireGuard/wg-clients/_peers_add.rsc b/WireGuard/wg-clients/_peers_add.rsc new file mode 100644 index 0000000..5b2c21b --- /dev/null +++ b/WireGuard/wg-clients/_peers_add.rsc @@ -0,0 +1,3 @@ +/interface wireguard peers add interface=wg-vpn public-key="nToZ1GzONgfW1ve3O1WeEpGbgzUMhDVKE7qrD/Jc23c=" preshared-key="Y6eHm6MbLa+tyleSgwbPc8oJqLZkXZkMEUJZDU7f5kg=" allowed-address=10.10.10.2/32 comment="client2" +/interface wireguard peers add interface=wg-vpn public-key="tqA98HvVupGGYpR1PUe7/j9DO8MtaNP3Fh5tkpqgqD0=" preshared-key="94TmjBE+mTZi3KDy/tWefq/wXPpvmBtjPlX/LZnAKbE=" allowed-address=10.10.10.3/32 comment="client3" +/interface wireguard peers add interface=wg-vpn public-key="j/3kzNQ6vmUL4xFmqq5PL6Qf1xVWPzVWEXoOkBIDxFk=" preshared-key="pHR1441168wSrjlLZ2E44J4WrHpLRuWdjfsNHk23CQ8=" allowed-address=10.10.10.4/32 comment="client4" diff --git a/WireGuard/wg-clients/client2.conf b/WireGuard/wg-clients/client2.conf new file mode 100644 index 0000000..a8f67e6 --- /dev/null +++ b/WireGuard/wg-clients/client2.conf @@ -0,0 +1,11 @@ +[Interface] +PrivateKey = YPvh0rKU+xi82eQftBucCnuQzZNqk9jOHLwfEH0wsGk= +Address = 10.10.10.2/32 +DNS = 192.168.1.2 + +[Peer] +PublicKey = CGGFHYR83W8IuTB46cJ49IuL/tL3w4yu3o0hQh0Cxwo= +PresharedKey = Y6eHm6MbLa+tyleSgwbPc8oJqLZkXZkMEUJZDU7f5kg= +AllowedIPs = 192.168.1.0/24 +Endpoint = 78.80.38.51:51821 +PersistentKeepalive = 25 diff --git a/WireGuard/wg-clients/client2.png b/WireGuard/wg-clients/client2.png new file mode 100644 index 0000000..4ec3979 Binary files /dev/null and b/WireGuard/wg-clients/client2.png differ diff --git a/WireGuard/wg-clients/client3.conf b/WireGuard/wg-clients/client3.conf new file mode 100644 index 0000000..dda89ef --- /dev/null +++ b/WireGuard/wg-clients/client3.conf @@ -0,0 +1,11 @@ +[Interface] +PrivateKey = 8JFWJp/zvoRYl7w2Jon0Xv+9YidiguiC26qGbr4ozlg= +Address = 10.10.10.3/32 +DNS = 192.168.1.2 + +[Peer] +PublicKey = CGGFHYR83W8IuTB46cJ49IuL/tL3w4yu3o0hQh0Cxwo= +PresharedKey = 94TmjBE+mTZi3KDy/tWefq/wXPpvmBtjPlX/LZnAKbE= +AllowedIPs = 192.168.1.0/24 +Endpoint = 78.80.38.51:51821 +PersistentKeepalive = 25 diff --git a/WireGuard/wg-clients/client3.png b/WireGuard/wg-clients/client3.png new file mode 100644 index 0000000..62dac88 Binary files /dev/null and b/WireGuard/wg-clients/client3.png differ diff --git a/WireGuard/wg-clients/client4.conf b/WireGuard/wg-clients/client4.conf new file mode 100644 index 0000000..7f1e60c --- /dev/null +++ b/WireGuard/wg-clients/client4.conf @@ -0,0 +1,11 @@ +[Interface] +PrivateKey = oLcUtFkDW/e0/xmDgdBMlWIpGGL+eOvMxgnyXxtd5Ww= +Address = 10.10.10.4/32 +DNS = 192.168.1.2 + +[Peer] +PublicKey = CGGFHYR83W8IuTB46cJ49IuL/tL3w4yu3o0hQh0Cxwo= +PresharedKey = pHR1441168wSrjlLZ2E44J4WrHpLRuWdjfsNHk23CQ8= +AllowedIPs = 192.168.1.0/24 +Endpoint = 78.80.38.51:51821 +PersistentKeepalive = 25 diff --git a/WireGuard/wg-clients/client4.png b/WireGuard/wg-clients/client4.png new file mode 100644 index 0000000..98aa1fd Binary files /dev/null and b/WireGuard/wg-clients/client4.png differ