Skip to content

Instantly share code, notes, and snippets.

@kafeg
Last active January 15, 2025 15:09
Show Gist options
  • Save kafeg/c40abad3b8987f2e3eeace2c595c8dcc to your computer and use it in GitHub Desktop.
Save kafeg/c40abad3b8987f2e3eeace2c595c8dcc to your computer and use it in GitHub Desktop.
Synology WireGuard and AmneziaWG build script: kernel module and tools
#!/bin/sh
set -x
# Place the manage.sh, awg (or wg), awg-quick (or wg-quick), amneziawg.ko (or wireguard.ko) and your wg0.conf somewhere to filesystem on Synology
# Use start/stop for manage as regular process or installsvc/uninstallsvc/startsvc/stopsvc to manage as systemd service
WG="awg"
WGQUICK="awg-quick"
KMOD="amneziawg.ko"
CONF="wg0.conf"
SVCNAME="amneziawg"
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
echo "Script directory: $SCRIPT_DIR"
# Function to check if the script is running as root
require_root() {
if [ "$EUID" -ne 0 ]; then
echo "This script must be run as root. Please re-run as root or with sudo."
exit 1
fi
}
# Function to perform common checks
check_environment() {
REQUIRED_FILES=("$CONF" "$WG" "$WGQUICK" $KMOD)
for FILE in "${REQUIRED_FILES[@]}"; do
if [ ! -f "$SCRIPT_DIR/$FILE" ]; then
echo "Error: Required file $FILE is missing in the script directory."
exit 1
fi
done
for FILE in "$WG" "$WGQUICK"; do
if [ ! -x "$SCRIPT_DIR/$FILE" ]; then
echo "Error: $FILE does not have execution permissions."
exit 1
fi
done
ARCH=$(uname -m)
if ! file $SCRIPT_DIR/$WG | grep -q "$ARCH" || ! file $SCRIPT_DIR/$KMOD | grep -q "$ARCH"; then
echo "Error: One or more binaries are not built for the current architecture ($ARCH)."
exit 1
fi
if ! grep -qE "^#?DNS" $SCRIPT_DIR/$CONF && ! grep -qE "^AllowedIPs.*0\.0\.0\.0/0|::/0" $SCRIPT_DIR/$CONF; then
echo "Error: $CONF does not meet the required conditions. Ensure DNS lines are commented or removed and AllowedIPs does not include 0.0.0.0/0 or ::/0 (to prevent all traffic go over VPN, use something like 10.8.1.0/24 instead)."
exit 1
fi
}
require_root
case $1 in
start)
check_environment
/sbin/insmod $SCRIPT_DIR/$KMOD
$SCRIPT_DIR/$WGQUICK up $SCRIPT_DIR/$CONF
exit 0
;;
stop)
check_environment
$SCRIPT_DIR/$WGQUICK down $SCRIPT_DIR/$CONF
/sbin/rmmod $SCRIPT_DIR/$KMOD
exit 0
;;
startsvc)
check_environment
systemctl start $SVCNAME.service
;;
stopsvc)
check_environment
systemctl stop $SVCNAME.service
;;
status)
check_environment
/sbin/lsmod | grep $SVCNAME
$SCRIPT_DIR/$WG show
systemctl status amneziawg.service
journalctl -u amneziawg.service
;;
installsvc)
check_environment
SCRIPT_PATH=$(readlink -f "$0")
SCRIPT_DIR=$(dirname "$SCRIPT_PATH")
SERVICE_FILE_CONTENT="""[Unit]
Description=Manage $SVCNAME
After=network.target
[Service]
Type=simple
ExecStart=$SCRIPT_DIR/manage.sh start
ExecStop=$SCRIPT_DIR/manage.sh stop
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
"""
SERVICE_PATH="/etc/systemd/system/$SVCNAME.service"
echo "$SERVICE_FILE_CONTENT" | sudo tee $SERVICE_PATH > /dev/null
systemctl daemon-reload
systemctl enable $SVCNAME.service
echo "Service installed and enabled on boot."
;;
uninstallsvc)
check_environment
SERVICE_PATH="/etc/systemd/system/$SVCNAME.service"
if [ -f $SERVICE_PATH ]; then
systemctl disable $SVCNAME.service
rm -f $SERVICE_PATH
systemctl daemon-reload
echo "Service uninstalled."
else
echo "Service file not found. Nothing to uninstall."
fi
;;
*)
echo "Usage: $0 {start|stop|status|installsvc|uninstallsvc}"
exit 1
;;
esac
#!/bin/bash
# This script helps to cross-compile the WireGuard and AmneziaWG for Synology host (intel/arm targets) on Linux x64 host (for e.g. Ubuntu 22.04 and above).
# It compiles kernel module and wg/wg-quick tools.
# Usage:
# - download and save for e.g. to '/opt/syno-wg/syno-wg-build.sh'
# - detect your DSM version and device processor architecture. Use ssh to Synology and execute:
# - - awk -F '\"' '/majorversion/ {maj=$2} /minorversion/ {min=$2} END {print maj "." min}' /etc.defaults/VERSION
# - - awk -F '\"' '/platform_name/ {print $2}' /etc.defaults/synoinfo.conf
# - output can be:
# - - 7.2
# - - r1000 or rtd1296, ...
# - call the script:
# - - cd opt/syno-wg/
# - - ./syno-wg-build.sh -v 7.2 -a r1000 -t wg # build WireGuard using toolchain for Intel-based Synology and DSM 7.2
# - - ./syno-wg-build.sh -v 7.2 -a r1000 -t awg # build AmneziaWG using toolchain for Intel-based Synology and DSM 7.2
# - - ./syno-wg-build.sh -v 7.2 -a rtd1296 -t wg # build WireGuard using toolchain for ARM Synology and DSM 7.2
# - - ./syno-wg-build.sh -v 7.2 -a rtd1296 -t awg # build AmneziaWG using toolchain for ARM Synology and DSM 7.2
# - results are for example (<DSM_ARCH>-<DSM_VER> templated):
# - - build_env/ds.r1000-7.2/opt/wg-r1000-7.2/wg-out/
# - - build_env/ds.r1000-7.2/opt/awg-r1000-7.2/awg-out/
# - - build_env/ds.rtd1296-7.2/opt/wg-rtd1296-7.2/wg-out/
# - - build_env/ds.rtd1296-7.2/opt/awg-rtd1296-7.2/awg-out/
CURRENT=`pwd`
# Check for x64 Linux host
if [ "$(uname -m)" != "x86_64" ] || [ "$(uname -s)" != "Linux" ]; then
echo "This script must be run on a x64 Linux host."
exit 1
fi
# Usage function
usage() {
echo "Usage: $0 -v <DSM version> -a <DSM architecture> -t <wg type>"
echo " -v DSM version (e.g., 7.2)"
echo " -a DSM architecture (e.g., avoton, broadwell, etc.)"
echo " -t WG type ('wg' WireGuard or 'awg' for AmneziaWG)"
echo
echo "To determine DSM version on your Synology device, run the following command:"
echo " awk -F '\"' '/majorversion/ {maj=\$2} /minorversion/ {min=\$2} END {print maj \".\" min}' /etc.defaults/VERSION"
echo
echo "To determine DSM architecture on your Synology device, run the following command:"
echo " awk -F '\"' '/platform_name/ {print \$2}' /etc.defaults/synoinfo.conf"
exit 1
}
# Parse input parameters
while getopts "v:a:t:" opt; do
case $opt in
v) DSM_VER="$OPTARG" ;;
a) DSM_ARCH="$OPTARG" ;;
t) WG_TYPE="$OPTARG" ;;
*) usage ;;
esac
done
# Validate input parameters
if [ -z "$DSM_VER" ] || [ -z "$DSM_ARCH" ] || [ -z "$WG_TYPE" ]; then
echo "Error: Missing required parameters."
usage
fi
if [ "$WG_TYPE" != "wg" ] && [ "$WG_TYPE" != "awg" ]; then
echo "Error: WG type must be 'wg' WireGuard or 'awg' for AmneziaWG."
usage
fi
# Print parameters
echo "DSM Version: $DSM_VER"
echo "DSM Architecture: $DSM_ARCH"
echo "WG Type: $WG_TYPE"
# Clone Synology toolchain scripts
echo "Checking Synology toolchain scripts..."
if [ ! -d "pkgscripts-ng" ]; then
git clone https://github.com/SynologyOpenSource/pkgscripts-ng || { echo "Failed to clone pkgscripts-ng repository."; exit 1; }
else
echo "Synology toolchain scripts already present, skipping clone."
fi
# Prepare toolchain
CHROOT_DIR="$CURRENT/build_env/ds.$DSM_ARCH-$DSM_VER"
OPT_DIR="$CHROOT_DIR/opt/$WG_TYPE-$DSM_ARCH-$DSM_VER"
OPT_DIR_CHROOT="/opt/$WG_TYPE-$DSM_ARCH-$DSM_VER"
if [ ! -d "$CHROOT_DIR" ]; then
sudo $CURRENT/pkgscripts-ng/EnvDeploy -v "$DSM_VER" -p "$DSM_ARCH" --noclear || { echo "Failed to prepare toolchain for DSM version $DSM_VER and architecture $DSM_ARCH."; exit 1; }
sudo chown -R $(whoami):$(whoami) "$CURRENT"
else
echo "Toolchain environment already exists, skipping setup."
fi
mkdir -p "$OPT_DIR"
# Determine libmnl and WG versions
LIBMNL_URL="https://netfilter.org/projects/libmnl/files/?C=M;O=D"
BASE_WIREGUARD_URL="https://git.zx2c4.com"
WIREGUARD_REPO_NAME="wireguard-linux-compat"
WIREGUARD_TOOLS_REPO_NAME="wireguard-tools"
BASE_AWG_URL="https://github.com/amnezia-vpn"
AWG_REPO_NAME="amneziawg-linux-kernel-module"
AWG_TOOLS_REPO_NAME="amneziawg-tools"
# Download and extract latest libmnl if not already downloaded
LIBMNL_VERSION=$(wget --no-hsts -q "$LIBMNL_URL" -O - | grep -oP 'a href="libmnl-\K[0-9.]*?(?=\.tar\.bz2)' | head -n 1)
echo "Detected libmnl version: $LIBMNL_VERSION"
LIBMNL_ARCHIVE="$OPT_DIR/libmnl-$LIBMNL_VERSION.tar.bz2"
if [ ! -f "$LIBMNL_ARCHIVE" ]; then
echo "Downloading libmnl version: $LIBMNL_VERSION"
wget "https://netfilter.org/projects/libmnl/files/libmnl-$LIBMNL_VERSION.tar.bz2" -O "$LIBMNL_ARCHIVE" || { echo "Failed to download libmnl."; exit 1; }
sudo rm -rf $OPT_DIR/libmnl-$LIBMNL_VERSION
tar -xjf "$LIBMNL_ARCHIVE" -C "$OPT_DIR" || { echo "Failed to extract libmnl."; exit 1; }
else
echo "libmnl version $LIBMNL_VERSION already downloaded and unpacked."
fi
# Clone WG or AWG repositories into opt directory
if [ "$WG_TYPE" == "wg" ]; then
echo "Checking WireGuard repositories..."
[ ! -d "$OPT_DIR/$WIREGUARD_REPO_NAME" ] && git clone "$BASE_WIREGUARD_URL/$WIREGUARD_REPO_NAME" "$OPT_DIR/$WIREGUARD_REPO_NAME" || echo "WireGuard kernel module repository already present."
[ ! -d "$OPT_DIR/$WIREGUARD_TOOLS_REPO_NAME" ] && git clone "$BASE_WIREGUARD_URL/$WIREGUARD_TOOLS_REPO_NAME" "$OPT_DIR/$WIREGUARD_TOOLS_REPO_NAME" || echo "WireGuard tools repository already present."
else
echo "Checking AmneziaWG repositories..."
[ ! -d "$OPT_DIR/$AWG_REPO_NAME" ] && git clone "$BASE_AWG_URL/$AWG_REPO_NAME" "$OPT_DIR/$AWG_REPO_NAME" || echo "AmneziaWG kernel module repository already present."
[ ! -d "$OPT_DIR/$AWG_TOOLS_REPO_NAME" ] && git clone "$BASE_AWG_URL/$AWG_TOOLS_REPO_NAME" "$OPT_DIR/$AWG_TOOLS_REPO_NAME" || echo "AmneziaWG tools repository already present."
fi
# Print all versions
echo "Libmnl version: $LIBMNL_VERSION"
if [ "$WG_TYPE" == "wg" ]; then
echo "WireGuard kernel module cloned to: $OPT_DIR/$WIREGUARD_REPO_NAME"
echo "WireGuard tools cloned to: $OPT_DIR/$WIREGUARD_TOOLS_REPO_NAME"
else
echo "AmneziaWG kernel module cloned to: $OPT_DIR/$AWG_REPO_NAME"
echo "AmneziaWG tools cloned to: $OPT_DIR/$AWG_TOOLS_REPO_NAME"
fi
CROSS_COMPILE_ARGS=""
CROSS_COMPILE_LIBMNL_CONFIG_ARGS=""
CROSS_COMPILE_PATH=""
if [ -f $CHROOT_DIR/usr/local/aarch64-unknown-linux-gnu/bin/aarch64-unknown-linux-gnu-gcc ]; then
ARM64_PREFIX="/usr/local/aarch64-unknown-linux-gnu/bin/aarch64-unknown-linux-gnu-"
CROSS_COMPILE_ARGS="ARCH=arm64 CROSS_COMPILE=$ARM64_PREFIX CC=${ARM64_PREFIX}gcc LD=${ARM64_PREFIX}ld AR=${ARM64_PREFIX}ar RANLIB=${ARM64_PREFIX}ranlib CCLD=${ARM64_PREFIX}gcc" #"CFLAGS=\"--sysroot=/usr/local/sysroot\" LDFLAGS=\"--sysroot=/usr/local/sysroot\""
CROSS_COMPILE_LIBMNL_CONFIG_ARGS="--host=aarch64-unknown-linux-gnu"
CROSS_COMPILE_PATH="/usr/local/aarch64-unknown-linux-gnu/bin"
fi
# Build libmnl within chroot
echo "Building libmnl within chroot..."
if [ -d "$CHROOT_DIR" ]; then
sudo chroot "$CHROOT_DIR" /bin/bash -c "\
export PATH="$CROSS_COMPILE_PATH:$PATH" && \
echo $PATH && \
cd $OPT_DIR_CHROOT/libmnl-$LIBMNL_VERSION && ./configure $CROSS_COMPILE_LIBMNL_CONFIG_ARGS --prefix=/usr && make $CROSS_COMPILE_ARGS && make install"
if [ $? -ne 0 ]; then
echo "libmnl build failed."
exit 1
else
echo "libmnl build completed successfully."
fi
file $OPT_DIR_CHROOT/libmnl-1.0.5/src/.libs/libmnl.so.0.2.0
else
echo "Chroot environment not found, libmnl build cannot proceed."
exit 1
fi
#exit 1
# Build WireGuard or AWG kernel module within chroot
echo "Building $WG_TYPE kernel module within chroot..."
if [ -d "$CHROOT_DIR" ]; then
sudo chroot "$CHROOT_DIR" /bin/bash -c "\
if [ \"$WG_TYPE\" == \"wg\" ]; then
export PATH="$CROSS_COMPILE_PATH:$PATH" && \
echo $PATH && \
cd $OPT_DIR_CHROOT/$WIREGUARD_REPO_NAME/src && \
sed \"s#KERNELDIR ?= .*#KERNELDIR ?= /usr/local/sysroot/usr/lib/modules/DSM-$DSM_VER/build#\" -i Makefile && \
make $CROSS_COMPILE_ARGS && mkdir -p $OPT_DIR_CHROOT/wg-out && cp wireguard.ko $OPT_DIR_CHROOT/wg-out/
else
export PATH="$CROSS_COMPILE_PATH:$PATH" && \
echo $PATH && \
cd $OPT_DIR_CHROOT/$AWG_REPO_NAME/src && \
sed \"s#KERNELDIR ?= .*#KERNELDIR ?= /usr/local/sysroot/usr/lib/modules/DSM-$DSM_VER/build#\" -i Makefile && \
sed \"s#KERNELRELEASE ?= .*#KERNELRELEASE ?= 1#\" -i Makefile && \
rm -f kernel && ln -s /usr/local/sysroot/usr/lib/modules/DSM-$DSM_VER/build kernel && \
pwd && ls -alh ./ && ls -alh ./kernel/ && \
make $CROSS_COMPILE_ARGS && mkdir -p $OPT_DIR_CHROOT/awg-out && cp amneziawg.ko $OPT_DIR_CHROOT/awg-out/
fi"
if [ $? -ne 0 ]; then
echo "$WG_TYPE kernel module build failed."
exit 1
else
echo "$WG_TYPE kernel module build completed successfully."
fi
else
echo "Chroot environment not found, $WG_TYPE kernel module build cannot proceed."
exit 1
fi
# Build WireGuard or AWG tools within chroot
echo "Building $WG_TYPE tools within chroot..."
if [ -d "$CHROOT_DIR" ]; then
sudo chroot "$CHROOT_DIR" /bin/bash -c "\
if [ \"$WG_TYPE\" == \"wg\" ]; then
export PATH="$CROSS_COMPILE_PATH:$PATH" && \
echo $PATH && \
cd $OPT_DIR_CHROOT/$WIREGUARD_TOOLS_REPO_NAME/src && \
make $CROSS_COMPILE_ARGS && mkdir -p $OPT_DIR_CHROOT/wg-out && cp wg $OPT_DIR_CHROOT/wg-out/wg && cp wg-quick/linux.bash $OPT_DIR_CHROOT/wg-out/wg-quick && \
chmod a+x $OPT_DIR_CHROOT/wg-out/wg*
else
export PATH="$CROSS_COMPILE_PATH:$PATH" && \
echo $PATH && \
cd $OPT_DIR_CHROOT/$AWG_TOOLS_REPO_NAME/src && \
make $CROSS_COMPILE_ARGS && mkdir -p $OPT_DIR_CHROOT/awg-out && cp wg $OPT_DIR_CHROOT/awg-out/awg && cp wg-quick/linux.bash $OPT_DIR_CHROOT/awg-out/awg-quick && \
chmod a+x $OPT_DIR_CHROOT/awg-out/awg*
fi"
if [ $? -ne 0 ]; then
echo "$WG_TYPE tools build failed."
exit 1
else
echo "$WG_TYPE tools build completed successfully."
fi
else
echo "Chroot environment not found, $WG_TYPE tools build cannot proceed."
exit 1
fi
sudo chown -R $(whoami):$(whoami) "$OPT_DIR"
if [ "$WG_TYPE" == "wg" ]; then
ls -alh $OPT_DIR/wg-out/
file $OPT_DIR/wg-out/*
file $OPT_DIR/libmnl-1.0.5/src/.libs/libmnl.so.0.2.0
else
ls -alh $OPT_DIR/awg-out/
file $OPT_DIR/awg-out/*
file $OPT_DIR/libmnl-1.0.5/src/.libs/libmnl.so.0.2.0
fi
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment