diff --git a/net/amnezia-tools/Makefile b/net/amnezia-tools/Makefile index e08b9a55ec85..f48a8948fd1f 100644 --- a/net/amnezia-tools/Makefile +++ b/net/amnezia-tools/Makefile @@ -1,43 +1,43 @@ PORTNAME= amnezia DISTVERSIONPREFIX= v DISTVERSION= 1.0.20241018 -PORTREVISION= 3 +PORTREVISION= 4 CATEGORIES= net net-vpn PKGNAMESUFFIX= -tools MAINTAINER= vova@zote.me COMMENT= Fast, modern and secure VPN Tunnel with AmneziaVPN anti-detection WWW= https://github.com/amnezia-vpn/amneziawg-tools/ LICENSE= GPLv2 RUN_DEPENDS= bash:shells/bash USES= gmake shebangfix USE_GITHUB= yes GH_ACCOUNT= amnezia-vpn GH_PROJECT= amneziawg-tools USE_RC_SUBR= ${PORTNAME} SHEBANG_FILES= wg-quick/freebsd.bash MAKE_ARGS+= DEBUG=no \ WITH_BASHCOMPLETION=yes \ WITH_SYSTEMDUNITS=no MAKE_ENV+= MANDIR="${PREFIX}/share/man" \ SYSCONFDIR="${PREFIX}/etc" WRKSRC_SUBDIR= src post-patch: @${REINPLACE_CMD} -e 's|wg s|awg s|g; \ s|/usr/local/etc/wireguard|${ETCDIR}|' \ ${WRKSRC}/completion/wg-quick.bash-completion @${REINPLACE_CMD} -e 's|%%ETCDIR%%|${ETCDIR}|' \ ${WRKSRC}/wg-quick/freebsd.bash post-install: @${RMDIR} ${STAGEDIR}${ETCDIR}/amneziawg ${STRIP_CMD} ${STAGEDIR}${PREFIX}/bin/awg .include diff --git a/net/amnezia-tools/files/amnezia.in b/net/amnezia-tools/files/amnezia.in index 893d7e58677c..98010c013bdb 100644 --- a/net/amnezia-tools/files/amnezia.in +++ b/net/amnezia-tools/files/amnezia.in @@ -1,82 +1,82 @@ #!/bin/sh # PROVIDE: amnezia # REQUIRE: NETWORKING # KEYWORD: shutdown # # amnezia_enable (bool): Set to "YES" to enable amnezia. # (default: "NO") # # amnezia_interfaces (str): List of interfaces to bring up/down # on start/stop. (eg: "amn0 amn1") # (default: "") # amnezia_env (str): Environment variables for the userspace # implementation. (eg: "LOG_LEVEL=debug") # # amnezia_kmod (str): Kernel module to load. # (default: "if_amn", "" - no module) # # amnezia_confdirs (str): Directory to store the configuration files. # (default: "%%ETCDIR%%") . /etc/rc.subr name=amnezia rcvar=amnezia_enable extra_commands="reload status" start_cmd="${name}_start" stop_cmd="${name}_stop" reload_cmd="${name}_reload" status_cmd="${name}_status" amnezia_start() { kmod=${amnezia_kmod:-if_amn} ${amnezia_env:+eval export $amnezia_env} [ -n "${kmod}" ] && kldstat -q -n ${kmod} || kldload -n ${kmod} for interface in ${amnezia_interfaces}; do - daemon %%PREFIX%%/bin/awg-quick up ${interface} + %%PREFIX%%/bin/awg-quick up ${interface} done } amnezia_stop() { for interface in ${amnezia_interfaces}; do %%PREFIX%%/bin/awg-quick down ${interface} done } amnezia_reload() { ${amnezia_env:+eval export $amnezia_env} for interface in ${amnezia_interfaces}; do %%PREFIX%%/bin/awg-quick reload ${interface} done } amnezia_status() { ${amnezia_env:+eval export $amnezia_env} amnezia_status="0" for interface in ${amnezia_interfaces}; do %%PREFIX%%/bin/awg show ${interface} || amnezia_status="1" done return ${amnezia_status} } load_rc_config $name : ${amnezia_enable="NO"} : ${amnezia_interfaces=""} : ${amnezia_env=""} : ${amnezia_kmod="if_amn"} : ${amnezia_confdirs="%%ETCDIR%%"} ${amnezia_confdirs:+eval export AWG_QUICK_CONFIG_SEARCH_PATHS="$amnezia_confdirs"} run_rc_command "$1" diff --git a/net/amnezia-tools/files/patch-wg-quick_freebsd.bash b/net/amnezia-tools/files/patch-wg-quick_freebsd.bash index 8ac17f331400..e4f2cfe40c0a 100644 --- a/net/amnezia-tools/files/patch-wg-quick_freebsd.bash +++ b/net/amnezia-tools/files/patch-wg-quick_freebsd.bash @@ -1,337 +1,360 @@ ---- wg-quick/freebsd.bash.orig 2025-10-19 18:21:50 UTC +--- wg-quick/freebsd.bash.orig 2025-12-03 19:32:16 UTC +++ wg-quick/freebsd.bash @@ -25,11 +25,20 @@ CONFIG_FILE="" POST_DOWN=( ) SAVE_CONFIG=0 CONFIG_FILE="" +DESCRIPTION="" +USERLAND=0 +MONITOR=1 +TRACK_DNS_CHANGES=0 PROGRAM="${0##*/}" ARGS=( "$@" ) IS_ASESCURITY_ON=0 + +declare -A ROUTES +declare -A ENDPOINTS_MAP + + cmd() { echo "[#] $*" >&3 "$@" @@ -40,7 +49,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 +73,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 +91,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 +105,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);& @@ -109,6 +123,17 @@ parse_options() { H3);& H4) IS_ASESCURITY_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" @@ -129,19 +154,22 @@ add_if() { add_if() { local ret rc - local cmd="ifconfig wg create name "$INTERFACE"" - if [[ $IS_ASESCURITY_ON == 1 ]]; then + local cmd="ifconfig amn create name "$INTERFACE"" + if [[ $USERLAND == 1 ]]; then cmd="amneziawg-go "$INTERFACE""; fi - if ret="$(cmd $cmd 2>&1 >/dev/null)"; then - return 0 + 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 - echo "[!] Missing WireGuard kernel support ($ret). Falling back to slow userspace implementation." >&3 + echo "[!] Missing Amnezia kernel support ($ret). Falling back to slow userspace implementation." >&3 cmd "${WG_QUICK_USERSPACE_IMPLEMENTATION:-amneziawg-go}" "$INTERFACE" } @@ -209,7 +237,7 @@ set_mtu() { [[ ${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) + 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]}" @@ -242,7 +270,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() { -@@ -297,18 +325,18 @@ monitor_daemon() { +@@ -297,18 +325,25 @@ monitor_daemon() { } monitor_daemon() { +- echo "[+] Backgrounding route monitor" >&2 + [[ $MONITOR -eq 0 ]] && return 0 - echo "[+] Backgrounding route monitor" >&2 ++ ++ 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 [[ $AUTO_ROUTE4 -eq 1 || $AUTO_ROUTE6 -eq 1 ]] && set_endpoint_direct_route # TODO: set the mtu as well, but only if up -@@ -316,6 +344,76 @@ monitor_daemon() { +@@ -316,6 +351,82 @@ monitor_daemon() { 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 + -+ echo "[+] Backgrounding DNS tracker" >&2 ++ 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 2>&1 3>&- & disown + echo "$!" > "$pid_file" +} + + HAVE_SET_DNS=0 set_dns() { [[ ${#DNS[@]} -gt 0 ]] || return 0 -@@ -354,7 +452,7 @@ set_config() { +@@ -354,7 +465,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() { -@@ -386,7 +484,7 @@ save_config() { +@@ -386,7 +497,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" -@@ -412,7 +510,7 @@ cmd_usage() { +@@ -412,7 +523,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: -@@ -429,10 +527,24 @@ cmd_usage() { +@@ -429,10 +540,24 @@ 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" -@@ -446,26 +558,31 @@ cmd_up() { +@@ -446,26 +571,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_dns_changes +- 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 } -@@ -473,6 +590,10 @@ cmd_strip() { +@@ -473,6 +603,10 @@ cmd_strip() { echo "$WG_CONFIG" } +cmd_reload() { + cmd awg setconf "$INTERFACE" <(cmd_strip) +} + # ~~ function override insertion point ~~ make_temp -@@ -496,6 +617,10 @@ elif [[ $# -eq 2 && $1 == strip ]]; then +@@ -496,6 +630,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