From 214845d71e39d1f7b7b86b2d403cf5e9bf448898 Mon Sep 17 00:00:00 2001 From: rope Date: Tue, 15 Sep 2026 14:59:40 +0100 Subject: [PATCH] Reflect Pelican game ports for LAN clients --- services/router.nix | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/services/router.nix b/services/router.nix index 85c3156..2f50ae4 100644 --- a/services/router.nix +++ b/services/router.nix @@ -83,6 +83,18 @@ let forwards = lib.concatMap expandForward portsData.forward; + # LAN clients normally resolve nordhammer.it to 10.0.0.1 through AdGuard. + # Some game/browser stacks retain or independently resolve the public WAN + # address, though. Reflect only Pelican's allocation range back to its LAN + # destination so those clients take the same path as an external player. + # Selecting the declared forward keeps this in sync with ports.toml. + pelicanForwards = builtins.filter + (f: f.name == "Pelican game servers") + forwards; + lanGameReflectionRules = lib.concatMapStringsSep "\n " + (f: ''${f.proto} dport ${f.port} dnat to ${f.dest} comment "${f.name} LAN reflection"'') + pelicanForwards; + # nftables accepts port-range literals like "26901-26902" as-is. dnatRules = lib.concatMapStringsSep "\n " (f: ''${f.proto} dport ${f.port} dnat to ${f.dest} comment "${f.name}"'') @@ -286,10 +298,16 @@ in chain prerouting { type nat hook prerouting priority -100; policy accept; iifname "eno1" jump port_forwards + # Hairpin only public/local-address requests from the LAN. Direct + # 10.0.0.x traffic and every non-Pelican port remain untouched. + iifname "eth0" ip daddr != 10.0.0.0/24 fib daddr type local jump lan_game_reflection } chain port_forwards { ${dnatRules} } + chain lan_game_reflection { + ${lanGameReflectionRules} + } chain postrouting { type nat hook postrouting priority 100; policy accept; oifname "eno1" masquerade