Files
ports/net/amnezia-tools/files/patch-wg-quick_freebsd.bash
2026-10-04 04:07:15 +00:00

425 lines
13 KiB
Bash

--- wg-quick/freebsd.bash.orig 2025-12-12 22:28:42 UTC
+++ wg-quick/freebsd.bash
@@ -25,11 +25,18 @@ CONFIG_FILE=""
POST_DOWN=( )
SAVE_CONFIG=0
CONFIG_FILE=""
+DESCRIPTION=""
+USERLAND=0
+MONITOR=1
+TRACK_DNS_CHANGES=0
PROGRAM="${0##*/}"
ARGS=( "$@" )
IS_AWG_ON=0
+declare -A ROUTES
+declare -A ENDPOINTS_MAP
+
cmd() {
echo "[#] $*" >&3
"$@"
@@ -40,7 +47,7 @@ die() {
exit 1
}
-CONFIG_SEARCH_PATHS=( /etc/amnezia/amneziawg /usr/local/etc/amnezia/amneziawg )
+CONFIG_SEARCH_PATHS=( ${AWG_QUICK_CONFIG_SEARCH_PATHS:-%%ETCDIR%%} )
unset ORIGINAL_TMPDIR
make_temp() {
@@ -64,7 +71,7 @@ parse_options() {
}
parse_options() {
- local interface_section=0 line key value stripped path v
+ local interface_section=0 line key value stripped path v last_public_key
CONFIG_FILE="$1"
if [[ $CONFIG_FILE =~ ^[a-zA-Z0-9_=+.-]{1,15}$ ]]; then
for path in "${CONFIG_SEARCH_PATHS[@]}"; do
@@ -82,7 +89,7 @@ parse_options() {
stripped="${line%%\#*}"
key="${stripped%%=*}"; key="${key##*([[:space:]])}"; key="${key%%*([[:space:]])}"
value="${stripped#*=}"; value="${value##*([[:space:]])}"; value="${value%%*([[:space:]])}"
- [[ $key == "["* ]] && interface_section=0
+ [[ $key == "["* ]] && interface_section=0 && last_public_key=""
[[ $key == "[Interface]" ]] && interface_section=1
if [[ $interface_section -eq 1 ]]; then
case "$key" in
@@ -96,9 +103,14 @@ parse_options() {
PreDown) PRE_DOWN+=( "$value" ); continue ;;
PostUp) POST_UP+=( "$value" ); continue ;;
PostDown) POST_DOWN+=( "$value" ); continue ;;
+ Description) DESCRIPTION="$value"; continue ;;
SaveConfig) read_bool SAVE_CONFIG "$value"; continue ;;
+ UserLand) read_bool USERLAND "$value"; continue ;;
+ Monitor) read_bool MONITOR "$value"; continue ;;
+ TrackDNSChanges) TRACK_DNS_CHANGES="$value"; continue ;;
esac
case "$key" in
+
Jc);&
Jmin);&
Jmax);&
@@ -116,6 +128,17 @@ parse_options() {
I4);&
I5) IS_AWG_ON=1;;
esac
+ else
+ case "$key" in
+ PublicKey) last_public_key="$value" ;;
+ Routes) ROUTES["$last_public_key"]="$value"; continue ;;
+ Endpoint)
+ endpoint_host="${value%%:*}"
+ if ! [[ "$endpoint_host" =~ ^[0-9]+ ]]; then
+ ENDPOINTS_MAP["$last_public_key"]="$endpoint_host"
+ fi
+ ;;
+ esac
fi
WG_CONFIG+="$line"$'\n'
done < "$CONFIG_FILE"
@@ -136,20 +159,24 @@ add_if() {
add_if() {
local ret rc
- local cmd="ifconfig wg create name "$INTERFACE""
- if [[ $IS_AWG_ON == 1 ]]; then
- cmd="amneziawg-go "$INTERFACE"";
- fi
- if ret="$(cmd $cmd 2>&1 >/dev/null)"; then
- return 0
- fi
- rc=$?
- if [[ $ret == *"ifconfig: ioctl SIOCSIFNAME (set name): File exists"* ]]; then
- echo "$ret" >&3
- return $rc
- fi
- echo "[!] Missing WireGuard kernel support ($ret). Falling back to slow userspace implementation." >&3
+ local cmd="ifconfig amn create name "$INTERFACE""
+ if [[ $USERLAND == 0 ]]; then
+ if [ -n "$DESCRIPTION" ]; then
+ ret="$(cmd $cmd description "$DESCRIPTION" 2>&1 >/dev/null)" && return 0
+ else
+ ret="$(cmd $cmd 2>&1 >/dev/null)" && return 0
+ fi
+ rc=$?
+ if [[ $ret == *"ifconfig: ioctl SIOCSIFNAME (set name): File exists"* ]]; then
+ echo "$ret" >&3
+ return $rc
+ fi
+ fi
+ echo "[!] Missing Amnezia kernel support ($ret). Falling back to slow userspace implementation." >&3
cmd "${WG_QUICK_USERSPACE_IMPLEMENTATION:-amneziawg-go}" "$INTERFACE"
+ if [ -n "$DESCRIPTION" ]; then
+ cmd ifconfig $INTERFACE description "$DESCRIPTION"
+ fi
}
del_routes() {
@@ -181,9 +208,9 @@ del_if() {
if [[ -S /var/run/amneziawg/$INTERFACE.sock ]]; then
cmd rm -f "/var/run/amneziawg/$INTERFACE.sock"
else
- cmd ifconfig "$INTERFACE" destroy
+ cmd ifconfig -n "$INTERFACE" destroy
fi
- while ifconfig "$INTERFACE" >/dev/null 2>&1; do
+ while ifconfig -n "$INTERFACE" >/dev/null 2>&1; do
# HACK: it would be nice to `route monitor` here and wait for RTM_IFANNOUNCE
# but it turns out that the announcement is made before the interface
# disappears so we sometimes get a hang. So, we're instead left with polling
@@ -193,21 +220,21 @@ up_if() {
}
up_if() {
- cmd ifconfig "$INTERFACE" up
+ cmd ifconfig -n "$INTERFACE" up
}
add_addr() {
if [[ $1 == *:* ]]; then
- cmd ifconfig "$INTERFACE" inet6 "$1" alias
+ cmd ifconfig -n "$INTERFACE" inet6 "$1" alias
else
- cmd ifconfig "$INTERFACE" inet "$1" alias
+ cmd ifconfig -n "$INTERFACE" inet "$1" alias
fi
}
set_mtu() {
local mtu=0 endpoint output family
if [[ -n $MTU ]]; then
- cmd ifconfig "$INTERFACE" mtu "$MTU"
+ cmd ifconfig -n "$INTERFACE" mtu "$MTU"
return
fi
while read -r _ endpoint; do
@@ -215,14 +242,16 @@ set_mtu() {
family=inet
[[ ${BASH_REMATCH[1]} == *:* ]] && family=inet6
output="$(route -n get "-$family" "${BASH_REMATCH[1]}" || true)"
- [[ $output =~ interface:\ ([^ ]+)$'\n' && $(ifconfig "${BASH_REMATCH[1]}") =~ mtu\ ([0-9]+) && ${BASH_REMATCH[1]} -gt $mtu ]] && mtu="${BASH_REMATCH[1]}"
- done < <(wg show "$INTERFACE" endpoints)
+ [[ $output =~ interface:\ ([^ ]+)$'\n' && $(ifconfig -n "${BASH_REMATCH[1]}") =~ mtu\ ([0-9]+) && ${BASH_REMATCH[1]} -gt $mtu ]] && mtu="${BASH_REMATCH[1]}"
+ done < <(awg show "$INTERFACE" endpoints)
if [[ $mtu -eq 0 ]]; then
read -r output < <(route -n get default || true) || true
- [[ $output =~ interface:\ ([^ ]+)$'\n' && $(ifconfig "${BASH_REMATCH[1]}") =~ mtu\ ([0-9]+) && ${BASH_REMATCH[1]} -gt $mtu ]] && mtu="${BASH_REMATCH[1]}"
+ [[ $output =~ interface:\ ([^ ]+)$'\n' && $(ifconfig -n "${BASH_REMATCH[1]}") =~ mtu\ ([0-9]+) && ${BASH_REMATCH[1]} -gt $mtu ]] && mtu="${BASH_REMATCH[1]}"
fi
- [[ $mtu -gt 0 ]] || mtu=1500
- cmd ifconfig "$INTERFACE" mtu $(( mtu - 80 ))
+ if [[ $mtu -gt 0 && $mtu -lt 1420 ]]; then
+ # setup MTU only if discovered MTU is less then default
+ cmd ifconfig -n "$INTERFACE" mtu $(( mtu - 80 )) || true
+ fi
}
@@ -249,7 +278,7 @@ collect_endpoints() {
while read -r _ endpoint; do
[[ $endpoint =~ ^\[?([a-z0-9:.]+)\]?:[0-9]+$ ]] || continue
ENDPOINTS+=( "${BASH_REMATCH[1]}" )
- done < <(wg show "$INTERFACE" endpoints)
+ done < <(awg show "$INTERFACE" endpoints)
}
set_endpoint_direct_route() {
@@ -304,25 +333,108 @@ monitor_daemon() {
}
monitor_daemon() {
- echo "[+] Backgrounding route monitor" >&2
+ [[ $MONITOR -eq 0 ]] && return 0
+
+ if [[ $1 == "spawn" ]]; then
+ # re-run this function over daemon to detach from session
+ echo "[+] Backgrounding route monitor" >&2
+ env TMPDIR="${ORIGINAL_TMPDIR}" daemon $0 monitor-daemon ${INTERFACE}
+ return 0
+ fi
+
(make_temp
trap 'del_routes; clean_temp; exit 0' INT TERM EXIT
exec >/dev/null 2>&1
- exec 19< <(exec route -n monitor)
+ exec 19< <(exec stdbuf -oL route -n monitor)
local event pid=$!
# TODO: this should also check to see if the endpoint actually changes
# in response to incoming packets, and then call set_endpoint_direct_route
# then too. That function should be able to gracefully cleanup if the
# endpoints change.
while read -u 19 -r event; do
- [[ $event == RTM_* ]] || continue
- ifconfig "$INTERFACE" >/dev/null 2>&1 || break
+ ifconfig -n "$INTERFACE" >/dev/null 2>&1 || break
[[ $AUTO_ROUTE4 -eq 1 || $AUTO_ROUTE6 -eq 1 ]] && set_endpoint_direct_route
# TODO: set the mtu as well, but only if up
done
kill $pid) & disown
}
+wg_endpoints() {
+ awk '
+ BEGIN { RS=""; FS="\n" }
+ /Peer/ {
+ pk=""; ep=""
+ for (i = 1; i <= NF; i++) {
+ if ($i ~ /^PublicKey[ \t]*=/) {
+ pk = $i
+ sub(/^PublicKey[ \t]*=[ \t]*/, "", pk)
+ }
+ if ($i ~ /^Endpoint[ \t]*=/) {
+ ep = $i
+ sub(/^Endpoint[ \t]*=[ \t]*/, "", ep)
+ split(ep, parts, ":")
+ host = parts[1]
+ port = parts[2]
+ }
+ }
+ if (pk != "" && host != "" && port != "") {
+ print pk, host, port
+ }
+ }
+ '
+}
+
+tracker_pid_file() {
+ echo "/var/run/awg-quick.dns-tracker.${INTERFACE}.pid"
+}
+
+monitor_dns_changes() {
+ local pk peer_ip port peer_host host_ip
+
+ [[ $TRACK_DNS_CHANGES -eq 0 ]] && return 0
+
+ if [[ $1 == "spawn" ]]; then
+ # re-run this function over daemon to detach from session
+ echo "[+] Backgrounding DNS tracker" >&2
+ env TMPDIR="${ORIGINAL_TMPDIR}" daemon $0 monitor-dns-changes ${INTERFACE}
+ return 0
+ fi
+
+ pid_file="$(tracker_pid_file)"
+ [[ -f "$pid_file" ]] && kill $(cat "$pid_file") 2>/dev/null || true
+
+ (
+ trap 'rm -f "$pid_file"; exit 0' INT TERM EXIT
+
+ set -e
+ while true; do
+ sleep $TRACK_DNS_CHANGES &
+ wait $!
+
+ $cmd awg showconf "$INTERFACE" 2> /dev/null | wg_endpoints | \
+ while read -r pk peer_ip port; do
+ peer_host="${ENDPOINTS_MAP[$pk]}"
+ if [[ -n "$peer_host" ]]; then
+ host_ip=$(host "$peer_host" 2>/dev/null | awk '/has address/ { print $4; exit; }') || continue
+
+ if [[ "$host_ip" = "$peer_ip" ]]; then
+ #echo "$pk matches ${peer_ip} <=> ${host_ip}"
+ :
+ else
+ logger -t awg-quick -p local0.notice \
+ "$INTERFACE/$pk host $peer_host:" \
+ "IP missmatch: $host_ip != $peer_ip, configuring endpoint" || true
+ $cmd awg set "$INTERFACE" peer "$pk" endpoint "$peer_host:$port" || true
+ fi
+ fi
+ done
+
+ done
+ ) </dev/null >/dev/null 2>&1 3>&- & disown
+ echo "$!" > "$pid_file"
+}
+
+
HAVE_SET_DNS=0
set_dns() {
[[ ${#DNS[@]} -gt 0 ]] || return 0
@@ -361,7 +473,7 @@ set_config() {
}
set_config() {
- echo "$WG_CONFIG" | cmd wg setconf "$INTERFACE" /dev/stdin
+ echo "$WG_CONFIG" | cmd awg setconf "$INTERFACE" /dev/stdin
}
save_config() {
@@ -393,7 +505,7 @@ save_config() {
done
old_umask="$(umask)"
umask 077
- current_config="$(cmd wg showconf "$INTERFACE")"
+ current_config="$(cmd awg showconf "$INTERFACE")"
trap 'rm -f "$CONFIG_FILE.tmp"; clean_temp; exit' INT TERM EXIT
echo "${current_config/\[Interface\]$'\n'/$new_config}" > "$CONFIG_FILE.tmp" || die "Could not write configuration file"
sync "$CONFIG_FILE.tmp"
@@ -419,7 +531,7 @@ cmd_usage() {
followed by \`.conf'. Otherwise, INTERFACE is an interface name, with
configuration found at:
${CONFIG_SEARCH_PATHS[@]/%//INTERFACE.conf}.
- It is to be readable by wg(8)'s \`setconf' sub-command, with the exception
+ It is to be readable by awg(8)'s \`setconf' sub-command, with the exception
of the following additions to the [Interface] section, which are handled
by $PROGRAM:
@@ -436,13 +548,27 @@ cmd_usage() {
- SaveConfig: if set to \`true', the configuration is saved from the current
state of the interface upon shutdown.
- See wg-quick(8) for more info and examples.
+ See awg-quick(8) for more info and examples.
_EOF
}
+get_routes() {
+ while read -r pub_key i; do
+ if [[ -v "ROUTES[$pub_key]" ]]; then
+ for route in ${ROUTES[$pub_key]//,/ }; do
+ echo "$route"
+ done
+ else
+ for j in $i; do
+ [[ $j =~ ^[0-9a-z:.]+/[0-9]+$ ]] && echo "$j"
+ done
+ fi
+ done < <(awg show "$INTERFACE" allowed-ips) | sort -nr -k 2 -t /
+}
+
cmd_up() {
local i
- [[ -z $(ifconfig "$INTERFACE" 2>/dev/null) ]] || die "\`$INTERFACE' already exists"
+ [[ -z $(ifconfig -n "$INTERFACE" 2>/dev/null) ]] || die "\`$INTERFACE' already exists"
trap 'del_if; del_routes; clean_temp; exit' INT TERM EXIT
add_if
execute_hooks "${PRE_UP[@]}"
@@ -453,26 +579,31 @@ cmd_up() {
set_mtu
up_if
set_dns
- for i in $(while read -r _ i; do for i in $i; do [[ $i =~ ^[0-9a-z:.]+/[0-9]+$ ]] && echo "$i"; done; done < <(wg show "$INTERFACE" allowed-ips) | sort -nr -k 2 -t /); do
+ for i in $(get_routes); do
add_route "$i"
done
[[ $AUTO_ROUTE4 -eq 1 || $AUTO_ROUTE6 -eq 1 ]] && set_endpoint_direct_route
- monitor_daemon
+ monitor_daemon spawn
+ monitor_dns_changes spawn
execute_hooks "${POST_UP[@]}"
trap 'clean_temp; exit' INT TERM EXIT
}
cmd_down() {
- [[ " $(wg show interfaces) " == *" $INTERFACE "* ]] || die "\`$INTERFACE' is not a WireGuard interface"
+ [[ " $(awg show interfaces) " == *" $INTERFACE "* ]] || die "\`$INTERFACE' is not a Amnezia interface"
execute_hooks "${PRE_DOWN[@]}"
[[ $SAVE_CONFIG -eq 0 ]] || save_config
del_if
unset_dns
+ if [[ -f "$(tracker_pid_file)" ]]; then
+ kill $(cat "$(tracker_pid_file)") 2>/dev/null
+ rm -f "$(tracker_pid_file)"
+ fi
execute_hooks "${POST_DOWN[@]}"
}
cmd_save() {
- [[ " $(wg show interfaces) " == *" $INTERFACE "* ]] || die "\`$INTERFACE' is not a WireGuard interface"
+ [[ " $(awg show interfaces) " == *" $INTERFACE "* ]] || die "\`$INTERFACE' is not a Amnezia interface"
save_config
}
@@ -480,6 +611,10 @@ cmd_strip() {
echo "$WG_CONFIG"
}
+cmd_reload() {
+ cmd awg setconf "$INTERFACE" <(cmd_strip)
+}
+
# ~~ function override insertion point ~~
make_temp
@@ -503,6 +638,18 @@ elif [[ $# -eq 2 && $1 == strip ]]; then
auto_su
parse_options "$2"
cmd_strip
+elif [[ $# -eq 2 && $1 == reload ]]; then
+ auto_su
+ parse_options "$2"
+ cmd_reload
+elif [[ $# -eq 2 && $1 == "monitor-daemon" ]]; then
+ auto_su
+ parse_options "$2"
+ monitor_daemon
+elif [[ $# -eq 2 && $1 == "monitor-dns-changes" ]]; then
+ auto_su
+ parse_options "$2"
+ monitor_dns_changes
else
cmd_usage
exit 1