Re-resolve WireGuard peers' endpoint names
systemd-networkd resolves an endpoint name once, when it creates the device. A peer behind a dynamic DNS name that changes its address was never found again until the next restart. A timer (router.wireguardEndpointRefresh, default 1min, null for off) runs wg set for the peers with a name whose last handshake is older than 135 seconds, as wireguard-tools' reresolve-dns does. Working tunnels are left alone. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AeFqV9dZrK6nipHkPfyM4F
This commit is contained in:
+41
-2
@@ -168,6 +168,12 @@ pkgs.testers.runNixOSTest {
|
||||
networking.interfaces.eth1.ipv4.addresses = lib.mkForce [ ];
|
||||
networking.interfaces.eth2.ipv4.addresses = lib.mkForce [ ];
|
||||
|
||||
# Names for peer endpoints, so the test can move them.
|
||||
networking.hosts = {
|
||||
"203.0.113.60" = [ "siteb.test" ];
|
||||
"203.0.113.70" = [ "ghost.test" ];
|
||||
};
|
||||
|
||||
environment.etc = lib.listToAttrs (
|
||||
map
|
||||
(n: {
|
||||
@@ -182,7 +188,14 @@ pkgs.testers.runNixOSTest {
|
||||
"s2s"
|
||||
"ff"
|
||||
]
|
||||
);
|
||||
)
|
||||
// {
|
||||
# A tunnel to a peer that does not exist: it never has a handshake.
|
||||
"wg/ghost.key" = {
|
||||
text = key.router-rw.priv;
|
||||
mode = "0600";
|
||||
};
|
||||
};
|
||||
|
||||
router = {
|
||||
enable = true;
|
||||
@@ -230,11 +243,20 @@ pkgs.testers.runNixOSTest {
|
||||
sourceAddresses = [ "192.168.10.1" ];
|
||||
peers.siteb = {
|
||||
publicKey = key.siteb.pub;
|
||||
endpoint = "203.0.113.60:51821";
|
||||
endpoint = "siteb.test:51821";
|
||||
allowedIPs = [ "192.168.50.0/24" ];
|
||||
persistentKeepalive = 5;
|
||||
};
|
||||
};
|
||||
ghost = {
|
||||
privateKeyFile = "/etc/wg/ghost.key";
|
||||
zone = "ghost";
|
||||
peers.nobody = {
|
||||
publicKey = key.laptop.pub;
|
||||
endpoint = "ghost.test:51830";
|
||||
allowedIPs = [ "192.168.77.0/24" ];
|
||||
};
|
||||
};
|
||||
# Provider tunnel: only the listed destinations go through it.
|
||||
ff = {
|
||||
privateKeyFile = "/etc/wg/ff.key";
|
||||
@@ -362,6 +384,23 @@ pkgs.testers.runNixOSTest {
|
||||
for dev in ("wg-rw", "wg-s2s", "wg-ff"):
|
||||
router.wait_until_succeeds(f"wg show {dev} latest-handshakes | awk '$2 > 0' | grep -q .")
|
||||
|
||||
with subtest("peer endpoint names are looked up again, but only for peers without a handshake"):
|
||||
router.succeed("systemctl is-enabled router-wireguard-reresolve.timer")
|
||||
router.succeed("wg show wg-ghost endpoints | grep -q 203.0.113.70:51830")
|
||||
# The names now have other addresses.
|
||||
router.succeed("rm /etc/hosts; printf '127.0.0.1 localhost\\n203.0.113.71 ghost.test\\n203.0.113.99 siteb.test\\n' > /etc/hosts")
|
||||
router.succeed("systemctl start router-wireguard-reresolve.service")
|
||||
router.succeed("wg show wg-ghost endpoints | grep -q 203.0.113.71:51830")
|
||||
router.succeed("journalctl -u router-wireguard-reresolve --no-pager | grep -q 'endpoint 203.0.113.70:51830 -> 203.0.113.71:51830'")
|
||||
# The working tunnel keeps its endpoint (it has a fresh handshake).
|
||||
router.succeed("wg show wg-s2s endpoints | grep -q 203.0.113.60:51821")
|
||||
# A name that does not resolve leaves the endpoint as it was.
|
||||
router.succeed("printf '127.0.0.1 localhost\\n' > /etc/hosts")
|
||||
router.succeed("systemctl start router-wireguard-reresolve.service")
|
||||
router.succeed("wg show wg-ghost endpoints | grep -q 203.0.113.71:51830")
|
||||
router.succeed("journalctl -u router-wireguard-reresolve --no-pager | grep -q 'ghost.test:51830'")
|
||||
router.succeed("rm /etc/hosts; ln -s /etc/static/hosts /etc/hosts")
|
||||
|
||||
with subtest("road warrior: dual-stack tunnel to the router, DNS and SSH over it"):
|
||||
laptop.succeed("ping -c 1 -W 2 10.100.0.1")
|
||||
laptop.succeed("ping -6 -c 1 -W 2 fd42:100::1")
|
||||
|
||||
Reference in New Issue
Block a user