Skip to content

Commit

Permalink
add support for wireguard
Browse files Browse the repository at this point in the history
Signed-off-by: Piotr Bocheński <piotr@bochen.ski>
  • Loading branch information
b0ch3nski committed Jan 1, 2025
1 parent 030f4d9 commit 673f4dd
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 19 deletions.
8 changes: 5 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# syntax=docker/dockerfile:1.9.0
# syntax=docker/dockerfile:1.12-labs
ARG DEBIAN_VERSION
FROM debian:${DEBIAN_VERSION}-slim
SHELL ["/bin/bash", "-Eeuo", "pipefail", "-c"]
SHELL ["/bin/bash", "-euxo", "pipefail", "-c"]

RUN apt-get update; \
apt-get install -y --no-install-recommends --no-install-suggests \
ca-certificates \
wireguard-tools \
netcat-openbsd \
microsocks \
iproute2 \
Expand All @@ -25,6 +27,6 @@ RUN apt-get update; \

COPY init.sh /usr/local/bin/

EXPOSE 53/udp 1080/tcp
EXPOSE 53/udp 1080/tcp 1180/tcp

CMD ["init.sh"]
12 changes: 5 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@ IMAGE_NAME := b0ch3nski/vpnc-dnsmasq-socks5
IMAGE_VERSION ?= $(or $(shell git describe --tags --always),latest)
IMAGE_PLATFORMS ?= linux/amd64,linux/386,linux/arm64,linux/arm/v7

BUILD_TIME ?= $(shell date -u '+%Y-%m-%d %H:%M:%S')
LAST_COMMIT_HASH ?= $(shell git log -1 --format=%H)
LAST_COMMIT_TIME ?= $(shell git log -1 --format=%cd --date=format:'%Y-%m-%d %H:%M:%S')

DEBIAN_VERSION ?= bookworm

build:
Expand All @@ -14,9 +10,11 @@ build:
--push \
--platform="$(IMAGE_PLATFORMS)" \
--build-arg DEBIAN_VERSION="$(DEBIAN_VERSION)" \
--label="build.time=$(BUILD_TIME)" \
--label="commit.hash=$(LAST_COMMIT_HASH)" \
--label="commit.time=$(LAST_COMMIT_TIME)" \
--label="org.opencontainers.image.title=$(IMAGE_NAME)" \
--label="org.opencontainers.image.version=$(IMAGE_VERSION)" \
--label="org.opencontainers.image.url=https://github.com/$(IMAGE_NAME)" \
--label="org.opencontainers.image.revision=$(shell git log -1 --format=%H)" \
--label="org.opencontainers.image.created=$(shell date --iso-8601=seconds)" \
--tag="$(IMAGE_NAME):$(IMAGE_VERSION)" \
--tag="$(IMAGE_NAME):latest" \
.
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@ not for you.

## usage

```
```sh
docker run \
--detach \
--name="vpnc" \
--restart unless-stopped \
--cap-add NET_ADMIN \
--security-opt="no-new-privileges:true" \
--device /dev/net/tun:/dev/net/tun \
--publish 127.0.0.1:1080:1080/tcp \
--publish 127.0.0.1:1180:1180/tcp \
--publish 127.0.0.1:53:53/udp \
Expand All @@ -54,6 +55,31 @@ When presented with QR code, decode it. The result will look similar to example
otpauth://totp/<...>?secret=xxxxxxxxxxxxxxxx
```

## wireguard

Initially I've made this as a workaround for using `vpnc` in an isolated environment - which did it's job fine for
months. Lately I've started toying around with [Cloudflare Zero Trust WARP][cf-warp] (which essentially is based on
`wireguard`) and decided that I might reuse some of the code base from this project. It turned out that changes are so
small I could make it work in a single repo without breaking anything.

Wireguard support has been added in **v0.4** and can be controlled using following environment variables:
```sh
--env WG_ENDPOINT="engage.cloudflareclient.com:2408" \
--env WG_PUBLIC_KEY="my-public-key" \
--env WG_PRIVATE_KEY="my-private-key" \
--env WG_ADDRESS="100.96.0.2" \
--env WG_MTU="1280" \
--env WG_ALLOWED_IPS="100.64.0.0/10, 1.1.1.1/32, 1.0.0.1/32" \
--env MAIN_DNS="1.1.1.1 1.0.0.1" \
...
```

If you are also interested in using [Cloudflare WARP][cf-warp], config for Wireguard can be easily obtained using
[warp.sh][warp.sh] script.

[cf-warp]: https://developers.cloudflare.com/cloudflare-one/connections/connect-devices/warp
[warp.sh]: https://github.com/rany2/warp.sh

## disclaimer

This project was made for fun and learning purposes and shall not be used in real workloads. Use it with extra care and
Expand Down
47 changes: 39 additions & 8 deletions init.sh
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
#!/usr/bin/env bash
set -Eeo pipefail
set -eo pipefail
[ "${DEBUG}" = "on" ] && set -x

RESOLV_CONF="/etc/resolv.conf"
VPNC_CONF="/etc/vpnc/vpn.conf"
DNS_CONF="/etc/dnsmasq.d/dns.conf"

wait_for_port() { while ! nc -z 127.0.0.1 ${1}; do sleep 0.5; done; }
get_resolv_nameserver() { awk '/^nameserver/ { print $2; exit }' "${RESOLV_CONF}"; }
curl_wrapper() { curl --insecure --location --silent --show-error --fail-with-body --max-time 10 --socks5-hostname "127.0.0.1:${MICROSOCKS_PORT}" --write-out "\n" "${1}"; }
print_current_ip() { echo -e "==> Current public IP address:\n$(curl_wrapper "http://api.ipify.org")"; }

trap 'echo "==> Exit signal received - goodbye!"; exit 0' INT TERM

: "${MICROSOCKS_PORT:=1080}"
echo "==> Starting MicroSocks"
Expand All @@ -20,11 +21,21 @@ echo "==> MicroSocks started"
DNS_SERVERS=( $(echo ${MAIN_DNS:-$(get_resolv_nameserver)} ${EXTRA_DNS}) )
echo -e "==> Got DNS servers:\n${DNS_SERVERS[@]}"

# start VPNC when all required variables are set
# determine VPN technology
if [ "${IPSEC_GATEWAY}" ] && [ "${IPSEC_ID}" ] && [ "${IPSEC_SECRET}" ] && [ "${XAUTH_USER}" ] && [ "${XAUTH_PASS}" ]; then
VPN_TYPE="vpnc"
elif [ "${WG_ENDPOINT}" ] && [ "${WG_PRIVATE_KEY}" ] && [ "${WG_PUBLIC_KEY}" ] && [ "${WG_ADDRESS}" ]; then
VPN_TYPE="wireguard"
fi

if [ "${VPN_TYPE}" ]; then
: "${VPN_INTERFACE:=tun123}"
print_current_ip
fi

DEFAULT_ROUTE="$(ip -4 route | grep '^default' | head -1)"
if [ "${VPN_TYPE}" = "vpnc" ]; then
VPNC_CONF="/etc/vpnc/vpn.conf"
DEFAULT_ROUTE="$(ip -o -4 route show to default)"
DEFAULT_GATEWAY="$(awk '{ print $3 }' <<< ${DEFAULT_ROUTE})"
DEFAULT_INTERFACE="$(awk '{ print $5 }' <<< ${DEFAULT_ROUTE})"

Expand All @@ -38,7 +49,6 @@ if [ "${IPSEC_GATEWAY}" ] && [ "${IPSEC_ID}" ] && [ "${IPSEC_SECRET}" ] && [ "${
iptables -A INPUT -s "${dns}/32" -p udp -m udp --sport 53 -m u32 --u32 "28 & 0x000F = 0x3" -j DROP
done

: "${VPN_INTERFACE:=tun123}"
cat << EOF > "${VPNC_CONF}"
IPSec gateway ${IPSEC_GATEWAY}
IPSec ID ${IPSEC_ID}
Expand Down Expand Up @@ -70,6 +80,28 @@ EOF
echo -e "==> DNS server from VPNC:\n${VPNC_DNS}"
DNS_SERVERS+=( $(echo ${VPNC_DNS}) )

elif [ "${VPN_TYPE}" = "wireguard" ]; then
WG_CONF="/etc/wireguard/${VPN_INTERFACE}.conf"
cat << EOF > "${WG_CONF}"
[Interface]
PrivateKey = ${WG_PRIVATE_KEY}
Address = ${WG_ADDRESS}
MTU = ${WG_MTU:-1420}
[Peer]
PublicKey = ${WG_PUBLIC_KEY}
AllowedIPs = ${WG_ALLOWED_IPS:-0.0.0.0/0}
Endpoint = ${WG_ENDPOINT}
PersistentKeepalive = 25
EOF

echo "==> Starting WireGuard to '${WG_ENDPOINT}' as '${WG_ADDRESS}'..."
wg-quick up "${VPN_INTERFACE}"
echo "==> WireGuard started"
wg show "${VPN_INTERFACE}"
fi

if [ "${VPN_TYPE}" ]; then
# handle traffic routed from outside of the container so it can be used as a gateway
iptables -t nat -A POSTROUTING -o "${VPN_INTERFACE}" -j MASQUERADE
fi
Expand Down Expand Up @@ -130,9 +162,10 @@ min-cache-ttl=${DNS_CACHE_TTL}
max-cache-ttl=${DNS_CACHE_TTL}
no-hosts
no-resolv
all-servers
log-async=100
EOF
# in case of vpnc, query all DNS servers - public ones might be faster, but internal are still needed
[ "${VPN_TYPE}" = "vpnc" ] && echo "all-servers" >> "${DNS_CONF}"
[ -f "${ADDN_HOSTS_FILE}" ] && echo "addn-hosts=${ADDN_HOSTS_FILE}" >> "${DNS_CONF}"
[ "${DEBUG}" = "on" ] && echo "log-queries=extra" >> "${DNS_CONF}"
for dns in "${DNS_SERVERS[@]}"; do
Expand All @@ -156,8 +189,6 @@ echo -e "==> Current routing table:\n$(ip -4 route)"
echo -e "==> Current iptables rules:\n$(iptables --list-rules)"
echo -e "==> Current iptables NAT rules:\n$(iptables --table=nat --list-rules)"

trap 'echo "==> Exit signal received - goodbye!"; exit 0' INT TERM

while true; do
curl_wrapper "${HEALTHCHECK_URL:-http://api.ipify.org}"
sleep ${HEALTHCHECK_INTERVAL:-60} &
Expand Down

0 comments on commit 673f4dd

Please sign in to comment.