feat: update awg tools

This commit is contained in:
s.shchipunov
2025-09-29 00:18:20 +07:00
parent 199ec6a51a
commit 19495ca05a
3 changed files with 136 additions and 94 deletions

View File

@@ -1,25 +1,18 @@
#
# Copyright (C) 2016-2019 Jason A. Donenfeld <Jason@zx2c4.com>
# Copyright (C) 2016 Baptiste Jonglez <openwrt@bitsofnetworks.org>
# Copyright (C) 2016-2017 Dan Luedtke <mail@danrl.com>
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=amneziawg-tools PKG_NAME:=amneziawg-tools
PKG_VERSION:=1.0.20250903
PKG_RELEASE:=1
PKG_VERSION:=1.0.20240213 PKG_SOURCE_PROTO:=git
PKG_RELEASE:=$(AUTORELEASE) PKG_SOURCE_URL:=https://github.com/amnezia-vpn/amneziawg-tools.git
# Version: latest stable release tag
PKG_SOURCE:=v$(PKG_VERSION).tar.gz PKG_SOURCE_VERSION:=v$(PKG_VERSION)
PKG_SOURCE_URL:=https://github.com/amnezia-vpn/amneziawg-tools/archive/refs/tags/
PKG_HASH:=4bde122630c9ddb1ec013c3e958f2c613b9eea56834674dda92fcb423c6f4d10
PKG_LICENSE:=GPL-2.0 PKG_LICENSE:=GPL-2.0
PKG_LICENSE_FILES:=COPYING PKG_LICENSE_FILES:=COPYING
PKG_BUILD_DIR=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
include $(INCLUDE_DIR)/package.mk include $(INCLUDE_DIR)/package.mk
@@ -28,32 +21,29 @@ MAKE_VARS += PLATFORM=linux
define Package/amneziawg-tools define Package/amneziawg-tools
CATEGORY:=Network CATEGORY:=Network
URL:=https://www.wireguard.com SUBMENU:=VPN
MAINTAINER:=Jason A. Donenfeld <Jason@zx2c4.com> URL:=https://amnezia.org/
TITLE:=WireGuard userspace control program (wg) MAINTAINER:=Amnezia Admin <admin@amnezia.org>
TITLE:=AmneziaWG userspace control program (awg)
DEPENDS:= \ DEPENDS:= \
+@BUSYBOX_CONFIG_IP \ +@BUSYBOX_CONFIG_IP \
+@BUSYBOX_CONFIG_FEATURE_IP_LINK +@BUSYBOX_CONFIG_FEATURE_IP_LINK
endef endef
define Package/amneziawg-tools/description define Package/amneziawg-tools/description
WireGuard is a novel VPN that runs inside the Linux Kernel and utilizes Amnezia VPN simple and free app to run a self-hosted VPN with
state-of-the-art cryptography. It aims to be faster, simpler, leaner, and high privacy requirements.
more useful than IPSec, while avoiding the massive headache. It intends to
be considerably more performant than OpenVPN. WireGuard is designed as a
general purpose VPN for running on embedded interfaces and super computers
alike, fit for many different circumstances. It uses UDP.
This package provides the userspace control program for WireGuard, This package provides the userspace control program for AmneziaWG,
`wg(8)`, a netifd protocol helper, and a re-resolve watchdog script. `awg`, a netifd protocol helper, and a re-resolve watchdog script.
endef endef
define Package/amneziawg-tools/install define Package/amneziawg-tools/install
$(INSTALL_DIR) $(1)/usr/bin/ $(INSTALL_DIR) $(1)/usr/bin/
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/wg $(1)/usr/bin/amneziawg $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/wg $(1)/usr/bin/awg
$(INSTALL_BIN) ./files/amneziawg_watchdog $(1)/usr/bin/ $(INSTALL_BIN) ./files/amneziawg_watchdog $(1)/usr/bin/
$(INSTALL_DIR) $(1)/lib/netifd/proto/ $(INSTALL_DIR) $(1)/lib/netifd/proto/
$(INSTALL_BIN) ./files/amneziawg.sh $(1)/lib/netifd/proto/ $(INSTALL_BIN) ./files/amneziawg.sh $(1)/lib/netifd/proto/
endef endef
$(eval $(call BuildPackage,amneziawg-tools)) $(eval $(call BuildPackage,amneziawg-tools))

View File

@@ -2,9 +2,11 @@
# Copyright 2016-2017 Dan Luedtke <mail@danrl.com> # Copyright 2016-2017 Dan Luedtke <mail@danrl.com>
# Licensed to the public under the Apache License 2.0. # Licensed to the public under the Apache License 2.0.
WG=/usr/bin/amneziawg # shellcheck disable=SC1091,SC3003,SC3043
if [ ! -x $WG ]; then
logger -t "amnezia-wg" "error: missing amneziawg-tools (${WG})" AWG=/usr/bin/awg
if [ ! -x $AWG ]; then
logger -t "amneziawg" "error: missing amneziawg-tools (${AWG})"
exit 0 exit 0
fi fi
@@ -24,25 +26,34 @@ proto_amneziawg_init_config() {
proto_config_add_int "awg_jmax" proto_config_add_int "awg_jmax"
proto_config_add_int "awg_s1" proto_config_add_int "awg_s1"
proto_config_add_int "awg_s2" proto_config_add_int "awg_s2"
proto_config_add_int "awg_h1" proto_config_add_int "awg_s3"
proto_config_add_int "awg_h2" proto_config_add_int "awg_s4"
proto_config_add_int "awg_h3" proto_config_add_string "awg_h1"
proto_config_add_int "awg_h4" proto_config_add_string "awg_h2"
proto_config_add_string "awg_h3"
proto_config_add_string "awg_h4"
proto_config_add_string "awg_i1"
proto_config_add_string "awg_i2"
proto_config_add_string "awg_i3"
proto_config_add_string "awg_i4"
proto_config_add_string "awg_i5"
# shellcheck disable=SC2034
available=1 available=1
# shellcheck disable=SC2034
no_proto_task=1 no_proto_task=1
} }
proto_amneziawg_is_kernel_mode() { proto_amneziawg_is_kernel_mode() {
if [ ! -e /sys/module/amneziawg ]; then if [ ! -e /sys/module/amneziawg ]; then
modprobe amneziawg > /dev/null 2&>1 || true modprobe amneziawg > /dev/null 2>&1 || true
if [ -e /sys/module/amneziawg ]; then if [ -e /sys/module/amneziawg ]; then
return 0 return 0
else else
if [ ! command -v "${WG_QUICK_USERSPACE_IMPLEMENTATION:-amneziawg-go}" >/dev/null ]; then if ! command -v "${WG_QUICK_USERSPACE_IMPLEMENTATION:-amneziawg-go}" >/dev/null; then
ret=$? ret=$?
echo "Please install either kernel module (kmod-amneziawg package) or user-space implementation in /usr/bin/amneziawg-go." echo "Please install either kernel module (kmod-amneziawg package) or user-space implementation in /usr/bin/amneziawg-go."
exit $? exit $ret
else else
return 1 return 1
fi fi
@@ -83,13 +94,13 @@ proto_amneziawg_setup_peer() {
return 0 return 0
fi fi
echo "[Peer]" >> "${wg_cfg}" echo "[Peer]" >> "${awg_cfg}"
echo "PublicKey=${public_key}" >> "${wg_cfg}" echo "PublicKey=${public_key}" >> "${awg_cfg}"
if [ "${preshared_key}" ]; then if [ "${preshared_key}" ]; then
echo "PresharedKey=${preshared_key}" >> "${wg_cfg}" echo "PresharedKey=${preshared_key}" >> "${awg_cfg}"
fi fi
for allowed_ip in $allowed_ips; do for allowed_ip in ${allowed_ips}; do
echo "AllowedIPs=${allowed_ip}" >> "${wg_cfg}" echo "AllowedIPs=${allowed_ip}" >> "${awg_cfg}"
done done
if [ "${endpoint_host}" ]; then if [ "${endpoint_host}" ]; then
case "${endpoint_host}" in case "${endpoint_host}" in
@@ -105,10 +116,10 @@ proto_amneziawg_setup_peer() {
else else
endpoint="${endpoint}:51820" endpoint="${endpoint}:51820"
fi fi
echo "Endpoint=${endpoint}" >> "${wg_cfg}" echo "Endpoint=${endpoint}" >> "${awg_cfg}"
fi fi
if [ "${persistent_keepalive}" ]; then if [ "${persistent_keepalive}" ]; then
echo "PersistentKeepalive=${persistent_keepalive}" >> "${wg_cfg}" echo "PersistentKeepalive=${persistent_keepalive}" >> "${awg_cfg}"
fi fi
if [ ${route_allowed_ips} -ne 0 ]; then if [ ${route_allowed_ips} -ne 0 ]; then
@@ -140,7 +151,7 @@ ensure_key_is_generated() {
oldmask="$(umask)" oldmask="$(umask)"
umask 077 umask 077
ucitmp="$(mktemp -d)" ucitmp="$(mktemp -d)"
private_key="$("${WG}" genkey)" private_key="$("${AWG}" genkey)"
uci -q -t "$ucitmp" set network."$1".private_key="$private_key" && \ uci -q -t "$ucitmp" set network."$1".private_key="$private_key" && \
uci -q -t "$ucitmp" commit network uci -q -t "$ucitmp" commit network
rm -rf "$ucitmp" rm -rf "$ucitmp"
@@ -150,23 +161,35 @@ ensure_key_is_generated() {
proto_amneziawg_setup() { proto_amneziawg_setup() {
local config="$1" local config="$1"
local wg_dir="/tmp/wireguard" local awg_dir="/tmp/amneziawg"
local wg_cfg="${wg_dir}/${config}" local awg_cfg="${awg_dir}/${config}"
local private_key local private_key
local listen_port local listen_port
local addresses
local mtu local mtu
local fwmark
local ip6prefix
local nohostroute
local tunlink
# Amnezia WG specific parameters # AmneziaWG specific parameters
local awg_jc local awg_jc
local awg_jmin local awg_jmin
local awg_jmax local awg_jmax
local awg_s1 local awg_s1
local awg_s2 local awg_s2
local awg_s3
local awg_s4
local awg_h1 local awg_h1
local awg_h2 local awg_h2
local awg_h3 local awg_h3
local awg_h4 local awg_h4
local awg_i1
local awg_i2
local awg_i3
local awg_i4
local awg_i5
ensure_key_is_generated "${config}" ensure_key_is_generated "${config}"
@@ -185,18 +208,25 @@ proto_amneziawg_setup() {
config_get awg_jmax "${config}" "awg_jmax" config_get awg_jmax "${config}" "awg_jmax"
config_get awg_s1 "${config}" "awg_s1" config_get awg_s1 "${config}" "awg_s1"
config_get awg_s2 "${config}" "awg_s2" config_get awg_s2 "${config}" "awg_s2"
config_get awg_s3 "${config}" "awg_s3"
config_get awg_s4 "${config}" "awg_s4"
config_get awg_h1 "${config}" "awg_h1" config_get awg_h1 "${config}" "awg_h1"
config_get awg_h2 "${config}" "awg_h2" config_get awg_h2 "${config}" "awg_h2"
config_get awg_h3 "${config}" "awg_h3" config_get awg_h3 "${config}" "awg_h3"
config_get awg_h4 "${config}" "awg_h4" config_get awg_h4 "${config}" "awg_h4"
config_get awg_i1 "${config}" "awg_i1"
config_get awg_i2 "${config}" "awg_i2"
config_get awg_i3 "${config}" "awg_i3"
config_get awg_i4 "${config}" "awg_i4"
config_get awg_i5 "${config}" "awg_i5"
if proto_amneziawg_is_kernel_mode; then if proto_amneziawg_is_kernel_mode; then
logger -t "amneziawg" "info: using kernel-space kmod-amneziawg for ${WG}" logger -t "amneziawg" "info: using kernel-space kmod-amneziawg for ${AWG}"
ip link del dev "${config}" 2>/dev/null ip link del dev "${config}" 2>/dev/null
ip link add dev "${config}" type amneziawg ip link add dev "${config}" type amneziawg
else else
logger -t "amneziawg" "info: using user-space amneziawg-go for ${WG}" logger -t "amneziawg" "info: using user-space amneziawg-go for ${AWG}"
rm -f "/var/run/wireguard/${config}.sock" rm -f "/var/run/amneziawg/${config}.sock"
amneziawg-go "${config}" amneziawg-go "${config}"
fi fi
@@ -207,53 +237,73 @@ proto_amneziawg_setup() {
proto_init_update "${config}" 1 proto_init_update "${config}" 1
umask 077 umask 077
mkdir -p "${wg_dir}" mkdir -p "${awg_dir}"
echo "[Interface]" > "${wg_cfg}" echo "[Interface]" > "${awg_cfg}"
echo "PrivateKey=${private_key}" >> "${wg_cfg}" echo "PrivateKey=${private_key}" >> "${awg_cfg}"
if [ "${listen_port}" ]; then if [ "${listen_port}" ]; then
echo "ListenPort=${listen_port}" >> "${wg_cfg}" echo "ListenPort=${listen_port}" >> "${awg_cfg}"
fi fi
if [ "${fwmark}" ]; then if [ "${fwmark}" ]; then
echo "FwMark=${fwmark}" >> "${wg_cfg}" echo "FwMark=${fwmark}" >> "${awg_cfg}"
fi fi
# AWG # AmneziaWG parameters
if [ "${awg_jc}" ]; then if [ "${awg_jc}" ]; then
echo "Jc = ${awg_jc}" >> "${wg_cfg}" echo "Jc=${awg_jc}" >> "${awg_cfg}"
fi fi
if [ "${awg_jmin}" ]; then if [ "${awg_jmin}" ]; then
echo "Jmin = ${awg_jmin}" >> "${wg_cfg}" echo "Jmin=${awg_jmin}" >> "${awg_cfg}"
fi fi
if [ "${awg_jmax}" ]; then if [ "${awg_jmax}" ]; then
echo "Jmax = ${awg_jmax}" >> "${wg_cfg}" echo "Jmax=${awg_jmax}" >> "${awg_cfg}"
fi fi
if [ "${awg_s1}" ]; then if [ "${awg_s1}" ]; then
echo "S1 = ${awg_s1}" >> "${wg_cfg}" echo "S1=${awg_s1}" >> "${awg_cfg}"
fi fi
if [ "${awg_s2}" ]; then if [ "${awg_s2}" ]; then
echo "S2 = ${awg_s2}" >> "${wg_cfg}" echo "S2=${awg_s2}" >> "${awg_cfg}"
fi
if [ "${awg_s3}" ]; then
echo "S3=${awg_s3}" >> "${awg_cfg}"
fi
if [ "${awg_s4}" ]; then
echo "S4=${awg_s4}" >> "${awg_cfg}"
fi fi
if [ "${awg_h1}" ]; then if [ "${awg_h1}" ]; then
echo "H1 = ${awg_h1}" >> "${wg_cfg}" echo "H1=${awg_h1}" >> "${awg_cfg}"
fi fi
if [ "${awg_h2}" ]; then if [ "${awg_h2}" ]; then
echo "H2 = ${awg_h2}" >> "${wg_cfg}" echo "H2=${awg_h2}" >> "${awg_cfg}"
fi fi
if [ "${awg_h3}" ]; then if [ "${awg_h3}" ]; then
echo "H3 = ${awg_h3}" >> "${wg_cfg}" echo "H3=${awg_h3}" >> "${awg_cfg}"
fi fi
if [ "${awg_h4}" ]; then if [ "${awg_h4}" ]; then
echo "H4 = ${awg_h4}" >> "${wg_cfg}" echo "H4=${awg_h4}" >> "${awg_cfg}"
fi
if [ "${awg_i1}" ]; then
echo "I1=${awg_i1}" >> "${awg_cfg}"
fi
if [ "${awg_i2}" ]; then
echo "I2=${awg_i2}" >> "${awg_cfg}"
fi
if [ "${awg_i3}" ]; then
echo "I3=${awg_i3}" >> "${awg_cfg}"
fi
if [ "${awg_i4}" ]; then
echo "I4=${awg_i4}" >> "${awg_cfg}"
fi
if [ "${awg_i5}" ]; then
echo "I5=${awg_i5}" >> "${awg_cfg}"
fi fi
config_foreach proto_amneziawg_setup_peer "amneziawg_${config}" config_foreach proto_amneziawg_setup_peer "amneziawg_${config}"
# apply configuration file # Apply configuration file
${WG} setconf ${config} "${wg_cfg}" ${AWG} setconf "${config}" "${awg_cfg}"
WG_RETURN=$? AWG_RETURN=$?
rm -f "${wg_cfg}" rm -f "${awg_cfg}"
if [ ${WG_RETURN} -ne 0 ]; then if [ ${AWG_RETURN} -ne 0 ]; then
sleep 5 sleep 5
proto_setup_failed "${config}" proto_setup_failed "${config}"
exit 1 exit 1
@@ -282,7 +332,8 @@ proto_amneziawg_setup() {
# endpoint dependency # endpoint dependency
if [ "${nohostroute}" != "1" ]; then if [ "${nohostroute}" != "1" ]; then
${WG} show "${config}" endpoints | \ # shellcheck disable=SC2034
${AWG} show "${config}" endpoints | \
sed -E 's/\[?([0-9.:a-f]+)\]?:([0-9]+)/\1 \2/' | \ sed -E 's/\[?([0-9.:a-f]+)\]?:([0-9]+)/\1 \2/' | \
while IFS=$'\t ' read -r key address port; do while IFS=$'\t ' read -r key address port; do
[ -n "${port}" ] || continue [ -n "${port}" ] || continue
@@ -295,14 +346,13 @@ proto_amneziawg_setup() {
proto_amneziawg_teardown() { proto_amneziawg_teardown() {
local config="$1" local config="$1"
proto_amneziawg_check_installed
if proto_amneziawg_is_kernel_mode; then if proto_amneziawg_is_kernel_mode; then
ip link del dev "${config}" >/dev/null 2>&1 ip link del dev "${config}" >/dev/null 2>&1
else else
rm -f /var/run/wireguard/${config}.sock rm -f "/var/run/amneziawg/${config}.sock"
fi fi
} }
[ -n "$INCLUDE_ONLY" ] || { [ -n "$INCLUDE_ONLY" ] || {
add_protocol amneziawg add_protocol amneziawg
} }

View File

@@ -11,12 +11,13 @@
# Run this script from cron every minute: # Run this script from cron every minute:
# echo '* * * * * /usr/bin/wireguard_watchdog' >> /etc/crontabs/root # echo '* * * * * /usr/bin/wireguard_watchdog' >> /etc/crontabs/root
# shellcheck disable=SC1091,SC3043
. /lib/functions.sh . /lib/functions.sh
check_peer_activity() { check_peer_activity() {
local cfg=$1 local cfg="$1"
local iface=$2 local iface="$2"
local disabled local disabled
local public_key local public_key
local endpoint_host local endpoint_host
@@ -26,7 +27,7 @@ check_peer_activity() {
local idle_seconds local idle_seconds
config_get_bool disabled "${cfg}" "disabled" 0 config_get_bool disabled "${cfg}" "disabled" 0
config_get public_key "${cfg}" "public_key" config_get public_key "${cfg}" "public_key"
config_get endpoint_host "${cfg}" "endpoint_host" config_get endpoint_host "${cfg}" "endpoint_host"
config_get endpoint_port "${cfg}" "endpoint_port" config_get endpoint_port "${cfg}" "endpoint_port"
@@ -35,34 +36,35 @@ check_peer_activity() {
return 0 return 0
fi fi
persistent_keepalive=$(wg show ${iface} persistent-keepalive | grep ${public_key} | awk '{print $2}') persistent_keepalive=$(awg show "${iface}" persistent-keepalive | grep "${public_key}" | awk '{print $2}')
# only process peers with endpoints and keepalive set # only process peers with endpoints and keepalive set
[ -z ${endpoint_host} ] && return 0; [ -z "${endpoint_host}" ] && return 0;
[ -z ${persistent_keepalive} -o ${persistent_keepalive} = "off" ] && return 0; if [ -z "${persistent_keepalive}" ] || [ "${persistent_keepalive}" = "off" ]; then return 0; fi
# skip IP addresses # skip IP addresses
# check taken from packages/net/ddns-scripts/files/dynamic_dns_functions.sh # check taken from packages/net/ddns-scripts/files/dynamic_dns_functions.sh
local IPV4_REGEX="[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" local IPV4_REGEX="[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}"
local IPV6_REGEX="\(\([0-9A-Fa-f]\{1,4\}:\)\{1,\}\)\(\([0-9A-Fa-f]\{1,4\}\)\{0,1\}\)\(\(:[0-9A-Fa-f]\{1,4\}\)\{1,\}\)" local IPV6_REGEX="\(\([0-9A-Fa-f]\{1,4\}:\)\{1,\}\)\(\([0-9A-Fa-f]\{1,4\}\)\{0,1\}\)\(\(:[0-9A-Fa-f]\{1,4\}\)\{1,\}\)"
local IPV4=$(echo ${endpoint_host} | grep -m 1 -o "$IPV4_REGEX$") # do not detect ip in 0.0.0.0.example.com local IPV4 IPV6
local IPV6=$(echo ${endpoint_host} | grep -m 1 -o "$IPV6_REGEX") IPV4="$(echo "${endpoint_host}" | grep -m 1 -o "$IPV4_REGEX$")" # do not detect ip in 0.0.0.0.example.com
[ -n "${IPV4}" -o -n "${IPV6}" ] && return 0; IPV6="$(echo "${endpoint_host}" | grep -m 1 -o "$IPV6_REGEX")"
[ -n "${IPV4}${IPV6}" ] && return 0;
# re-resolve endpoint hostname if not responding for too long # re-resolve endpoint hostname if not responding for too long
last_handshake=$(wg show ${iface} latest-handshakes | grep ${public_key} | awk '{print $2}') last_handshake=$(awg show "${iface}" latest-handshakes | grep "${public_key}" | awk '{print $2}')
[ -z ${last_handshake} ] && return 0; [ -z "${last_handshake}" ] && return 0;
idle_seconds=$(($(date +%s)-${last_handshake})) idle_seconds=$(($(date +%s)-${last_handshake}))
[ ${idle_seconds} -lt 150 ] && return 0; [ ${idle_seconds} -lt 150 ] && return 0;
logger -t "wireguard_monitor" "${iface} endpoint ${endpoint_host}:${endpoint_port} is not responding for ${idle_seconds} seconds, trying to re-resolve hostname" logger -t "amneziawg_monitor" "${iface} endpoint ${endpoint_host}:${endpoint_port} is not responding for ${idle_seconds} seconds, trying to re-resolve hostname"
wg set ${iface} peer ${public_key} endpoint "${endpoint_host}:${endpoint_port}" awg set "${iface}" peer "${public_key}" endpoint "${endpoint_host}:${endpoint_port}"
} }
# query ubus for all active wireguard interfaces # query ubus for all active wireguard interfaces
wg_ifaces=$(ubus -S call network.interface dump | jsonfilter -e '@.interface[@.up=true]' | jsonfilter -a -e '@[@.proto="wireguard"].interface' | tr "\n" " ") awg_ifaces=$(ubus -S call network.interface dump | jsonfilter -e '@.interface[@.up=true]' | jsonfilter -a -e '@[@.proto="amneziawg"].interface' | tr "\n" " ")
# check every peer in every active wireguard interface # check every peer in every active wireguard interface
config_load network config_load network
for iface in $wg_ifaces; do for iface in $awg_ifaces; do
config_foreach check_peer_activity "wireguard_${iface}" "${iface}" config_foreach check_peer_activity "amneziawg_${iface}" "${iface}"
done done