76 lines
2.4 KiB
Nix
76 lines
2.4 KiB
Nix
# 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";
|
|
};
|
|
};
|
|
}
|