To avoid some bugs in wg-quick and/or iptables on my Synology:
- I set up the wireguard device manually.
- I used network namespaces to create an explicit tunnel namespace. I then specified DNS for this namespace only.
Credit where credit is due. I got this idea from the Wireguard website. https://www.wireguard.com/netns/#the-new-namespace-solution
The solution posted on the site does it the other way. Everything is set up to tunnel and the namespace is set up for the exception.
Bash functions to link the docker netns for a container to the system.
#!/bin/bash
# Get docker container PID
docker_get_pid() {
CONTAINER_NAME="$1"
PID=$(/usr/local/bin/docker inspect -f '{{.State.Pid}}' "$CONTAINER_NAME")
if [ -z "$PID" ] || [ "$PID" -eq "0" ]; then
return 1
else
printf "%s" "$PID"
return 0
fi
}
# Symlink docker network namespace into /var/run
docker_get_netns() {
CONTAINER_NAME="$1"
if ! PID=$(docker_get_pid "$CONTAINER_NAME"); then
>&2 echo "Error: PID not found."
exit 1
else
ln -sfTv /proc/"$PID"/ns/net /var/run/netns/"$CONTAINER_NAME"
fi
}
# Put a wireguard interface (wg0) into the docker network namespace
docker_setup_wg() {
CONTAINER_NAME="$1"
PRIVATE_KEY_FILE="$2"
PEER_KEY="$3"
ENDPOINT="$4"
ALLOWED_IPS="$5"
LOCAL_IP="$6"
docker_get_netns "$CONTAINER_NAME"
ip link add wg0 type wireguard
ip link set wg0 netns "$CONTAINER_NAME"
ip netns exec "$CONTAINER_NAME" wg set wg0 \
private-key "$PRIVATE_KEY_FILE" \
peer "$PEER_KEY" \
endpoint "$ENDPOINT" \
allowed-ips "$ALLOWED_IPS"
ip netns exec "$CONTAINER_NAME" ip addr add "$LOCAL_IP" dev wg0
ip netns exec "$CONTAINER_NAME" ip link set mtu 1420 up dev wg0
ip netns exec "$CONTAINER_NAME" ip route del default
ip netns exec "$CONTAINER_NAME" ip route add default dev wg0
}
# Wait for the container to be up and running
until docker_get_pid container 2>/dev/null
do
>&2 printf "Waiting for PID from container...\n"
sleep 1
done
# Wait for the container to boot
printf "\nPID exists.\nWaiting for container to boot 15s."
sleep 15
# Load the environment variables
. ./environment
# Pushes wg0 into the docker netns
printf "Setting up Wireguard...\n"
docker_setup_wg \
container \
"private.key" \
"$(<peer.key)" \
"$ENDPOINT" \
"$ALLOWED_IPS" \
"$LOCAL_IP" || { >&2 echo "Interface setup failed. Does it already exist?"; exit 1; }
# Override container /etc/resolv.conf
printf "Overriding container resolv.conf.\n"
/usr/local/bin/docker exec container /bin/bash -c 'printf "nameserver 1.1.1.1\nnameserver 1.0.0.1\n" > /etc/resolv.conf'