Skip to content

Instantly share code, notes, and snippets.

@andrew-aladjev
Last active April 26, 2024 07:03
Show Gist options
  • Save andrew-aladjev/441d201db80e87d954e672c4b3d2dc28 to your computer and use it in GitHub Desktop.
Save andrew-aladjev/441d201db80e87d954e672c4b3d2dc28 to your computer and use it in GitHub Desktop.
Route for multiple wireguard clients
#!/bin/bash
set -e
set -o pipefail
WG_ROUTING_TABLE="$1"
WG_INTERFACE="$2"
# Removing IPV4 routing table.
ip -4 route flush dev "$WG_INTERFACE" table "$WG_ROUTING_TABLE" || :
# Removing IPV6 routing table.
ip -6 route flush dev "$WG_INTERFACE" table "$WG_ROUTING_TABLE" || :
#!/bin/bash
set -e
set -o pipefail
DIR=$(dirname "${BASH_SOURCE[0]}")
WG_ROUTING_TABLE="$1"
WG_INTERFACE="$2"
IPV4_NETWORK="$3"
IPV6_NETWORK="$4"
METRIC="$5"
# Routing IPV4 network.
ip -4 route add "$IPV4_NETWORK" dev "$WG_INTERFACE" metric "$METRIC" table "$WG_ROUTING_TABLE" || :
# Routing IPV6 network.
ip -6 route add "$IPV6_NETWORK" dev "$WG_INTERFACE" metric "$METRIC" table "$WG_ROUTING_TABLE" || :
# Getting hosts from wg endpoints.
readarray -t WG_HOSTS <<< $(
cat "${DIR}/"wg*.conf |
{ grep -i "endpoint\s*=" || :; } |
sed "s/.*endpoint\s*=\s*//gi" |
sed "s/:.*//g" || :
)
# Collecting IPs from hosts.
WG_IPSV4=()
WG_IPSV6=()
for WG_HOST in "${WG_HOSTS[@]}"; do
WG_HOST_IPSV4=$(getent ahostsv4 "$WG_HOST" | grep "STREAM" | cut -d " " -f 1 || :)
for WG_HOST_IPV4 in "${WG_HOST_IPSV4[@]}"; do
if [ ! -z "$WG_HOST_IPV4" ]; then
WG_IPSV4+=("$WG_HOST_IPV4")
fi
done
WG_HOST_IPSV6=$(getent ahostsv6 "$WG_HOST" | grep "STREAM" | cut -d " " -f 1 || :)
for WG_HOST_IPV6 in "${WG_HOST_IPSV6[@]}"; do
if [ ! -z "$WG_HOST_IPV6" ]; then
WG_IPSV6+=("$WG_HOST_IPV6")
fi
done
done
# Getting networks from wg addresses.
readarray -t WG_NETWORKS <<< $(
cat "${DIR}/"wg*.conf |
{ grep -i "address\s*=" || :; } |
sed "s/.*address\s*=\s*//gi" |
sed "s/\s*,\s*/,/g" || :
)
# Collecting IPs from networks.
for WG_NETWORK in "${WG_NETWORKS[@]}"; do
readarray -t WG_NETWORK_IPS <<< $(tr "," "\n" <<< "$WG_NETWORK" || :)
for WG_NETWORK_IP in "${WG_NETWORK_IPS[@]}"; do
if [ ! -z "$WG_NETWORK_IP" ]; then
if [[ "$WG_NETWORK_IP" =~ ":" ]]; then
WG_IPSV6+=("$WG_NETWORK_IP")
else
WG_IPSV4+=("$WG_NETWORK_IP")
fi
fi
done
done
# Getting IPV4 networks from main routing table.
readarray -t WG_IPV4_NETWORKS <<< $(ip -4 route show table main | cut -d " " -f 1 || :)
for WG_IPV4_NETWORK in "${WG_IPV4_NETWORKS[@]}"; do
if [ "$WG_IPV4_NETWORK" != "default" ]; then
WG_IPSV4+=("$WG_IPV4_NETWORK")
fi
done
# Getting IPV6 networks from main routing table.
readarray -t WG_IPV6_NETWORKS <<< $(ip -6 route show table main | cut -d " " -f 1 || :)
for WG_IPV6_NETWORK in "${WG_IPV6_NETWORKS[@]}"; do
if [ "$WG_IPV6_NETWORK" != "default" ]; then
WG_IPSV6+=("$WG_IPV6_NETWORK")
fi
done
# Getting sorted and unique IPs.
readarray -t WG_IPSV4 <<< $(printf "%s\n" "${WG_IPSV4[@]}" | sort -u)
readarray -t WG_IPSV6 <<< $(printf "%s\n" "${WG_IPSV6[@]}" | sort -u)
# Calculating IP patterns.
function join_by {
local d=${1-} f=${2-}
if shift 2; then
printf %s "$f" "${@/#/$d}"
fi
}
WG_IPV4_PATTERN=$(join_by "," "${WG_IPSV4[@]}")
WG_IPV6_PATTERN=$(join_by "," "${WG_IPSV6[@]}")
# Excluding IP patterns from default networks.
readarray -t WG_DEFAULT_IPV4_NETWORKS <<< $(python3 "${DIR}/WireGuard_Excluded_IPs.py" "0.0.0.0/0" "$WG_IPV4_PATTERN" || :)
readarray -t WG_DEFAULT_IPV6_NETWORKS <<< $(python3 "${DIR}/WireGuard_Excluded_IPs.py" "::/0" "$WG_IPV6_PATTERN" || :)
# Adding IPV4 default network routes.
for WG_DEFAULT_IPV4_NETWORK in "${WG_DEFAULT_IPV4_NETWORKS[@]}"; do
ip -4 route add "$WG_DEFAULT_IPV4_NETWORK" dev "$WG_INTERFACE" metric "$METRIC" table "$WG_ROUTING_TABLE" || :
done
# Adding IPV6 default network routes.
for WG_DEFAULT_IPV6_NETWORK in "${WG_DEFAULT_IPV6_NETWORKS[@]}"; do
ip -6 route add "$WG_DEFAULT_IPV6_NETWORK" dev "$WG_INTERFACE" metric "$METRIC" table "$WG_ROUTING_TABLE" || :
done
# Adding rule for IPV4 routing table.
IPV4_RULES=$(ip -4 rule list table "$WG_ROUTING_TABLE")
if [ -z "$IPV4_RULES" ]; then
ip -4 rule add table "$WG_ROUTING_TABLE" || :
fi
# Adding rule for IPV6 routing table.
IPV6_RULES=$(ip -6 rule list table "$WG_ROUTING_TABLE")
if [ -z "$IPV6_RULES" ]; then
ip -6 rule add table "$WG_ROUTING_TABLE" || :
fi
[Interface]
PrivateKey = <key>
Address = 10.20.3.2/32, fd10:20:3::2/128
Table = off
PostUp = /etc/wireguard/route-up.client.sh 51820 wg0 10.20.3.0/24 fd10:20:3::/64 10
PreDown = /etc/wireguard/route-down.client.sh 51820 wg0
[Peer]
PublicKey = <key>
# Address = 10.20.3.1/24, fd10:20:3::1/64
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = <domain>:<port>
PersistentKeepalive = 25
@andrew-aladjev
Copy link
Author

andrew-aladjev commented Apr 25, 2024

Excluder script is here. You can have as many wireguards on the client as you want. Please be aware that you need to use the same table number 51820 for all wgs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment