Last active
April 14, 2023 17:38
-
-
Save rlcamp/e3f1e99a4d9dee51c88bc2a5f4b68b13 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# campbell, 2022-2023 | |
# Given a mesh of already-mutually-known peers, initially not fully connected with non-stale | |
# handshakes, this script will propagate knowledge of current endpoints to peers which need | |
# them, such that in the steady state, the network is fully-connected and will self-heal if | |
# an endpoint moves around. | |
# This conservative implementation requires that a peer already be known to wireguard in | |
# order to have its endpoint updated. No provision is made for having peers forward traffic | |
# indirectly, if a direct handshake cannot be made. The scheme is meant to stay out of the | |
# way of other static configuration of the same wireguard interface. To configure a peer for | |
# eligibility to have its endpoint updated via this scheme, simply ensure it has a leaf CIDR | |
# and a defined PersistentKeepalive. | |
# Details: each node implements a transmit and receive thread. The transmit thread | |
# periodically examines "wg show $IFACE dump" and finds peers with non-stale handshakes, leaf | |
# CIDRs, and defined PersistentKeepalive, and sends one UDP packet (within the wg network) to | |
# each of these peers, containing the public key and endpoint of each other such peer. The | |
# receive thread listens for such packets on $IFACE, and if the given public key matches a | |
# known peer with a stale handshake meeting the CIDR and PersistentKeepalive criteria, the | |
# endpoint is updated. | |
IFACE=$1 | |
# thorough cleanup of child processes on exit | |
trap "trap - SIGTERM && kill -- -$$" SIGTERM SIGINT EXIT | |
while true; do | |
# for each pair of peers with a nonzero persistent-keepalive, non-LAN endpoint, NON-stale handshake, and leaf cidr ... | |
wg show "$IFACE" dump | awk ' | |
$8 + 0 && $3 !~ /^10\./ && $5 + 185 > systime() && match($4, /[a-f0-9.:]+\/(32|128)/) { | |
ip = substr($4, RSTART, RLENGTH); | |
sub(/\/.*$/, "", ip); | |
a[$1] = (ip ~/:/ ? "[" ip "]" : ip); | |
e[$1] = $3 | |
} | |
END { | |
for (p in a) | |
for (q in a) | |
if (p != q) | |
system("printf '\''" p " " e[p] "\n'\'' | socat -u STDIN UDP-SENDTO:" a[q] ":45153") | |
}' | |
sleep 60 | |
done & | |
while read -r KEY EP; do | |
# if the pubkey is a known peer with nonzero persistent-keepalive, non-local IP, stale handshake, and leaf CIDR ... | |
wg show "$IFACE" dump | awk '$8 + 0 && $3 !~ /^10\./ && $5 + 185 < systime() && $4 ~/\/(32|128)/' | grep "$KEY" >/dev/null && | |
wg set "$IFACE" peer "$KEY" endpoint "$EP" && printf 'set %s to %s\n' "$KEY" "$EP" >&2 | |
done < <(exec socat -u UDP-RECV:45153,reuseaddr,so-bindtodevice="$IFACE" STDOUT) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment