Skip to content

Instantly share code, notes, and snippets.

@stvhay
Last active December 4, 2022 07:09
Show Gist options
  • Save stvhay/9e37059abe96db5c7439323f55c373c0 to your computer and use it in GitHub Desktop.
Save stvhay/9e37059abe96db5c7439323f55c373c0 to your computer and use it in GitHub Desktop.
Set up wireguard with a network namespace such that you can specify what processes tunnel.

Synology/wg

To avoid some bugs in wg-quick and/or iptables on my Synology:

  1. I set up the wireguard device manually.
  2. 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.

Docker Notes

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'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment