diff --git a/custom-init/10-torify-wg0.sh b/custom-init/10-torify-wg0.sh new file mode 100644 index 0000000..dcc0760 --- /dev/null +++ b/custom-init/10-torify-wg0.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Wait for WireGuard to be up +for i in {1..30}; do + ip link show wg0 >/dev/null 2>&1 && break + sleep 1 +done + +# Tor transparent proxy ports (from torrc) +TOR_TRANS=9040 +TOR_DNS=5353 + +# Allow WG UDP +iptables -C INPUT -p udp --dport 51820 -j ACCEPT || iptables -A INPUT -p udp --dport 51820 -j ACCEPT +# Loopback + established (idempotent-ish) +iptables -C INPUT -i lo -j ACCEPT || iptables -A INPUT -i lo -j ACCEPT +iptables -C OUTPUT -o lo -j ACCEPT || iptables -A OUTPUT -o lo -j ACCEPT +iptables -C INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT || iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT +iptables -C OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT || iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT + +# === Transparent redirection of wg0 traffic into Tor === +# DNS to Tor DNSPort (UDP + TCP) +iptables -t nat -C PREROUTING -i wg0 -p udp --dport 53 -j REDIRECT --to-ports ${TOR_DNS} \ + || iptables -t nat -A PREROUTING -i wg0 -p udp --dport 53 -j REDIRECT --to-ports ${TOR_DNS} +iptables -t nat -C PREROUTING -i wg0 -p tcp --dport 53 -j REDIRECT --to-ports ${TOR_DNS} \ + || iptables -t nat -A PREROUTING -i wg0 -p tcp --dport 53 -j REDIRECT --to-ports ${TOR_DNS} + +# All TCP to Tor TransPort +iptables -t nat -C PREROUTING -i wg0 -p tcp -j REDIRECT --to-ports ${TOR_TRANS} \ + || iptables -t nat -A PREROUTING -i wg0 -p tcp -j REDIRECT --to-ports ${TOR_TRANS} + +# Fail closed: block anything from wg0 that didn't get redirected +iptables -C FORWARD -o wg0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT \ + || iptables -I FORWARD 1 -o wg0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT +iptables -C FORWARD -i wg0 -p udp -j REJECT --reject-with icmp-port-unreachable \ + || iptables -I FORWARD 2 -i wg0 -p udp -j REJECT --reject-with icmp-port-unreachable +iptables -C FORWARD -i wg0 -p icmp -j REJECT --reject-with icmp-host-unreachable \ + || iptables -I FORWARD 3 -i wg0 -p icmp -j REJECT --reject-with icmp-host-unreachable +iptables -C FORWARD -i wg0 -j DROP || iptables -I FORWARD 4 -i wg0 -j DROP diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..4d95491 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,42 @@ +version: "3.9" + +services: + wireguard: + image: lscr.io/linuxserver/wireguard:latest + container_name: wg-gateway + restart: unless-stopped + cap_add: + - NET_ADMIN + - SYS_MODULE + ports: + - "51820:51820/udp" + environment: + - PUID=1000 + - PGID=1000 + - TZ=Europe/London + # --- Auto-generate server + peers --- + - SERVERURL= # or "auto" if supported by your env + - SERVERPORT=51820 + - PEERS=phone,ipad,laptop # names or a number, e.g. "3" + - INTERNAL_SUBNET=10.66.0.0 # /24 is implied by the image + - ALLOWEDIPS=0.0.0.0/0 # road-warrior: route all traffic + - PEERDNS=10.66.0.1 # optional; we force-redirect DNS anyway + - LOG_CONFS=true # see the generated peer QR codes in logs + sysctls: + net.ipv4.ip_forward: "1" + net.ipv6.conf.all.disable_ipv6: "1" + net.ipv4.conf.all.src_valid_mark: "1" + volumes: + - ./wireguard:/config # WireGuard configs live here + - /lib/modules:/lib/modules # helps with kernel modules + # our startup script that applies Tor iptables rules inside WG's namespace + - ./custom-init:/custom-cont-init.d:ro + + tor: + build: ./tor # same Dockerfile/torrc from earlier + container_name: tor + network_mode: "service:wg-gateway" # share WG’s network namespace + depends_on: + - wireguard + restart: unless-stopped + diff --git a/tor/Dockerfile b/tor/Dockerfile new file mode 100644 index 0000000..6728bff --- /dev/null +++ b/tor/Dockerfile @@ -0,0 +1,14 @@ +FROM debian:stable-slim + +RUN apt-get update && \ + apt-get install -y --no-install-recommends tor iproute2 iptables ca-certificates && \ + rm -rf /var/lib/apt/lists/* + +# Tor data dir +RUN mkdir -p /var/lib/tor && chown -R debian-tor:debian-tor /var/lib/tor && chmod 700 /var/lib/tor + +COPY torrc /etc/tor/torrc + +# By default, run tor in foreground +USER debian-tor +CMD ["tor", "-f", "/etc/tor/torrc"] diff --git a/tor/torrc b/tor/torrc new file mode 100644 index 0000000..1facc28 --- /dev/null +++ b/tor/torrc @@ -0,0 +1,21 @@ +RunAsDaemon 0 +DataDirectory /var/lib/tor + +# We don't expose a SOCKS port; everything is transparently redirected. +SocksPort 0 + +# Transparent TCP proxy and DNS for iptables REDIRECT +TransPort 0.0.0.0:9040 +DNSPort 0.0.0.0:5353 + +# Virtual addressing so DNS answers get mapped by Tor +VirtualAddrNetworkIPv4 10.192.0.0/10 +AutomapHostsOnResolve 1 + +# Reliability/safety +ClientOnly 1 +AvoidDiskWrites 1 + +# (Optional) You can pin/avoid exits with these: +# ExitNodes {us},{nl} +# StrictNodes 1 diff --git a/wg/Dockerfile b/wg/Dockerfile new file mode 100644 index 0000000..5f696b7 --- /dev/null +++ b/wg/Dockerfile @@ -0,0 +1,13 @@ +FROM debian:stable-slim + +RUN apt-get update && \ + apt-get install -y --no-install-recommends wireguard iproute2 iptables bash ca-certificates && \ + rm -rf /var/lib/apt/lists/* + +# WireGuard config will be mounted at runtime +RUN mkdir -p /etc/wireguard + +COPY entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/wg/entrypoint.sh b/wg/entrypoint.sh new file mode 100644 index 0000000..cf54a5a --- /dev/null +++ b/wg/entrypoint.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Ensure forwarding is on +sysctl -w net.ipv4.ip_forward=1 >/dev/null + +# Bring up WireGuard. wg0.conf must define Address=10.66.0.1/24 etc. +ip link add dev wg0 type wireguard || true +wg-quick up wg0 + +# Tor transparent proxy ports in THIS namespace (shared with tor service) +TOR_TRANS=9040 +TOR_DNS=5353 + +# Flush any old rules +iptables -t nat -F || true +iptables -t mangle -F || true +iptables -F || true + +# Default policies +iptables -P INPUT ACCEPT +iptables -P FORWARD ACCEPT +iptables -P OUTPUT ACCEPT + +# Allow WireGuard UDP port 51820 +iptables -A INPUT -p udp --dport 51820 -j ACCEPT + +# Allow loopback +iptables -A INPUT -i lo -j ACCEPT +iptables -A OUTPUT -o lo -j ACCEPT + +# Allow established +iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT +iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT + +# FORWARD: allow from wg0 to local stack (tor) and back +iptables -A FORWARD -i wg0 -j ACCEPT +iptables -A FORWARD -o wg0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT + +# === Transparent redirection of wg0 traffic into Tor === + +# DNS: redirect all DNS from wg clients to Tor DNSPort (supports TCP & UDP) +iptables -t nat -A PREROUTING -i wg0 -p udp --dport 53 -j REDIRECT --to-ports ${TOR_DNS} +iptables -t nat -A PREROUTING -i wg0 -p tcp --dport 53 -j REDIRECT --to-ports ${TOR_DNS} + +# TCP: redirect everything to Tor TransPort +iptables -t nat -A PREROUTING -i wg0 -p tcp -j REDIRECT --to-ports ${TOR_TRANS} + +# Drop any UDP trying to escape (Tor can't carry UDP; better to fail closed) +iptables -A FORWARD -i wg0 -p udp -j REJECT --reject-with icmp-port-unreachable + +# (Optional) prevent bypass: block direct internet from wg0 that is NOT redirected (belt & braces) +# For non-TCP/UDP, just drop +iptables -A FORWARD -i wg0 -p icmp -j REJECT --reject-with icmp-host-unreachable +iptables -A FORWARD -i wg0 -p all -j DROP + +# Health: show status then sleep forever +echo "===== WireGuard status =====" +wg show +echo "===== IP addresses =====" +ip addr +echo "===== iptables (nat) =====" +iptables -t nat -S +echo "===== iptables (filter) =====" +iptables -S + +# Daemonize to keep container alive +tail -f /dev/null