feat(mesh): add selected Telegram and OpenRouter egress policy
This commit is contained in:
parent
6e88f2c833
commit
56bb3d7f7c
2 changed files with 80 additions and 1 deletions
|
|
@ -22,6 +22,7 @@
|
||||||
./tuwunel-admin.nix # matrix admin web UI (systemd, статический бинарник)
|
./tuwunel-admin.nix # matrix admin web UI (systemd, статический бинарник)
|
||||||
./pi-web.nix # pi-web (web UI для pi coding agent, systemd + npm global)
|
./pi-web.nix # pi-web (web UI для pi coding agent, systemd + npm global)
|
||||||
./mesh-clients.nix # Sol-style client pool (wg-clients1)
|
./mesh-clients.nix # Sol-style client pool (wg-clients1)
|
||||||
|
./mesh-egress.nix # Sol-style selected-destination egress policy
|
||||||
];
|
];
|
||||||
|
|
||||||
# First server-to-server WireGuard backbone link: heather ↔ hyacinth.
|
# First server-to-server WireGuard backbone link: heather ↔ hyacinth.
|
||||||
|
|
@ -57,7 +58,9 @@
|
||||||
peers = [
|
peers = [
|
||||||
{
|
{
|
||||||
publicKey = "BxTH8+MiA8Hv48UfpWJDVXIhbO5HgO2KTBEXIqqr23k=";
|
publicKey = "BxTH8+MiA8Hv48UfpWJDVXIhbO5HgO2KTBEXIqqr23k=";
|
||||||
allowedIPs = [ "10.99.0.2/32" "10.0.0.2/32" ];
|
# Match all destinations for future policy routes; allowedIPsAsRoutes=false
|
||||||
|
# keeps this from installing a default route automatically.
|
||||||
|
allowedIPs = [ "0.0.0.0/0" ];
|
||||||
endpoint = "195.242.119.59:51820";
|
endpoint = "195.242.119.59:51820";
|
||||||
persistentKeepalive = 25;
|
persistentKeepalive = 25;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
76
hosts/heather/mesh-egress.nix
Normal file
76
hosts/heather/mesh-egress.nix
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
# Static, Sol-style destination policy for selected traffic via the EU peer.
|
||||||
|
# This is policy routing, not application learning: prefixes are declared here,
|
||||||
|
# and OpenRouter addresses are refreshed from DNS on a timer.
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
let
|
||||||
|
ip = "${pkgs.iproute2}/bin/ip";
|
||||||
|
getent = "${pkgs.glibc}/bin/getent";
|
||||||
|
routeScript = pkgs.writeShellScript "mesh-egress-routes" ''
|
||||||
|
set -eu
|
||||||
|
${ip} link show wg-mesh >/dev/null
|
||||||
|
|
||||||
|
# Rebuild the destination table, while leaving the normal main table alone.
|
||||||
|
${ip} route flush table 1101 2>/dev/null || true
|
||||||
|
${ip} rule del pref 1101 2>/dev/null || true
|
||||||
|
${ip} rule add pref 1101 lookup 1101
|
||||||
|
|
||||||
|
add_route() {
|
||||||
|
prefix="$1"
|
||||||
|
${ip} route replace "$prefix" dev wg-mesh table 1101
|
||||||
|
}
|
||||||
|
|
||||||
|
# Telegram DC ranges (static destination policy, as in Sol's prefix lists).
|
||||||
|
for prefix in \
|
||||||
|
91.105.192.0/23 \
|
||||||
|
91.108.0.0/22 \
|
||||||
|
91.108.4.0/22 \
|
||||||
|
91.108.8.0/22 \
|
||||||
|
91.108.12.0/22 \
|
||||||
|
91.108.16.0/22 \
|
||||||
|
91.108.20.0/22 \
|
||||||
|
91.108.56.0/22 \
|
||||||
|
95.161.64.0/20 \
|
||||||
|
149.154.160.0/20; do
|
||||||
|
add_route "$prefix"
|
||||||
|
done
|
||||||
|
|
||||||
|
# OpenRouter is behind a CDN; refresh its current IPv4 addresses. We do
|
||||||
|
# not route all Cloudflare, only the names used by the API/web endpoint.
|
||||||
|
for name in openrouter.ai www.openrouter.ai api.openrouter.ai; do
|
||||||
|
${getent} ahostsv4 "$name" 2>/dev/null | ${pkgs.gawk}/bin/awk '{print $1}' | sort -u | while read -r addr; do
|
||||||
|
[ -n "$addr" ] || continue
|
||||||
|
add_route "$addr/32"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
# Clients whose selected destinations match table 1101 are forwarded to
|
||||||
|
# hyacinth. Other traffic keeps Heather's normal route.
|
||||||
|
networking.nat = {
|
||||||
|
enable = true;
|
||||||
|
internalInterfaces = [ "wg-clients1" ];
|
||||||
|
externalInterface = "enp7s0";
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.mesh-egress-routes = {
|
||||||
|
description = "Install Sol-style selected destination routes via hyacinth";
|
||||||
|
wantedBy = [ "network-online.target" ];
|
||||||
|
after = [ "network-online.target" "wireguard-wg-mesh.service" ];
|
||||||
|
wants = [ "wireguard-wg-mesh.service" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
ExecStart = routeScript;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.timers.mesh-egress-routes = {
|
||||||
|
description = "Refresh selected mesh egress destinations";
|
||||||
|
wantedBy = [ "timers.target" ];
|
||||||
|
timerConfig = {
|
||||||
|
OnBootSec = "30s";
|
||||||
|
OnUnitActiveSec = "5min";
|
||||||
|
Unit = "mesh-egress-routes.service";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue