Skip to content

Instantly share code, notes, and snippets.

@alecs
Created May 25, 2026 14:55
Show Gist options
  • Select an option

  • Save alecs/73e7d98e063a14a42b8b9242f975c94f to your computer and use it in GitHub Desktop.

Select an option

Save alecs/73e7d98e063a14a42b8b9242f975c94f to your computer and use it in GitHub Desktop.
wireguard extra routing for existing tunnel, without routing wildcard 0/0; good especially for hostnames that change destination, like cloudfront/aws-alb
#!/bin/bash
if [ "$EUID" -ne 0 ]; then
echo "Error: Please run this script using sudo." >&2
exit 1
fi
MY_IP=""
ROUTED_IPS=""
while [[ $# -gt 0 ]]; do
case "$1" in
--my-ip)
if [[ -n "$2" && "$2" != -* ]]; then
MY_IP="$2"
shift 2
else
echo "Error: Argument for $1 is missing." >&2
exit 1
fi
;;
--routed-ips)
if [[ -n "$2" && "$2" != -* ]]; then
ROUTED_IPS="$2"
shift 2
else
echo "Error: Argument for $1 is missing." >&2
exit 1
fi
;;
*)
echo "Error: Unknown argument: $1" >&2
echo "Usage: sudo $0 --my-ip <wireguard_ip> --routed-ips <ip1,ip2,ip3>" >&2
exit 1
;;
esac
done
if [ ${#MY_IP} -eq 0 ]; then
echo "Error: --my-ip parameter length is 0. This parameter is required." >&2
exit 1
fi
if [ ${#ROUTED_IPS} -eq 0 ]; then
echo "Error: --routed-ips parameter length is 0. This parameter is required." >&2
exit 1
fi
OS_TYPE=$(uname -s)
INTERFACE=""
LINK_ID=""
echo "Detecting WireGuard interface assigned to IP: $MY_IP..."
if [ "$OS_TYPE" = "Darwin" ]; then
INTERFACE=$(netstat -rn -f inet | grep "$MY_IP" | awk '{print $NF}' | head -n 1)
LINK_ID=$(netstat -rn -f inet | grep "$INTERFACE" | awk '!/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/ {print $2}' | head -n 1)
elif [ "$OS_TYPE" = "Linux" ]; then
INTERFACE=$(ip -o addr show | grep "$MY_IP" | awk '{print $2}' | head -n 1)
fi
if [ ${#INTERFACE} -eq 0 ]; then
echo "Error: Could not find an active tunnel interface for IP $MY_IP." >&2
exit 1
fi
echo "Found interface: $INTERFACE"
echo "----------------------------------------"
FINAL_IP_LIST=()
IFS=',' read -r -a RAW_TARGETS <<< "$ROUTED_IPS"
for TARGET in "${RAW_TARGETS[@]}"; do
TARGET=$(echo "$TARGET" | tr -d ' ')
CLEAN_TARGET="${TARGET%%/*}"
if [[ "$CLEAN_TARGET" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
if [[ ! "$TARGET" =~ / ]]; then
TARGET="${TARGET}/32"
fi
FINAL_IP_LIST+=("$TARGET")
else
echo "Resolving FQDN: $TARGET..."
unset TEMP_IPS
while read -r line; do
[ -n "$line" ] && TEMP_IPS+=("$line")
done < <(dig +short "$TARGET" | grep -E '^[0-9.]+$')
if [ ${#TEMP_IPS[@]} -eq 0 ]; then
echo "Warning: Could not resolve any IPs for $TARGET. Skipping." >&2
continue
fi
for RESOLVED_IP in "${TEMP_IPS[@]}"; do
FINAL_IP_LIST+=("${RESOLVED_IP}/32")
done
fi
done
UNIQUE_IP_LIST=($(printf "%s\n" "${FINAL_IP_LIST[@]}" | sort -u))
for TARGET_IP in "${UNIQUE_IP_LIST[@]}"; do
echo "Routing $TARGET_IP through $INTERFACE..."
if [ "$OS_TYPE" = "Darwin" ]; then
route -q -n add -net "$TARGET_IP" -link "$LINK_ID" -ifscope "$INTERFACE"
elif [ "$OS_TYPE" = "Linux" ]; then
ip route add "$TARGET_IP" dev "$INTERFACE"
fi
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment