Sign inSign up

friseer/synology-tor-client

By friseer

•Updated 6 months ago

Tor client image for Synology DSM with transparent WireGuard path support

Image
Networking
Security
0

234

friseer/synology-tor-client repository overview

⁠synology-tor-client

Tor client image for Synology DSM with transparent WireGuard path support.

⁠What this is

This image is meant for Synology DSM setups where exactly one selected WireGuard peer should go out through Tor.

Typical use case:

  • WireGuard is already running on the Synology NAS
  • one selected peer should use Tor
  • the rest of the NAS should stay untouched

⁠Prerequisite

This image is intended to provide an explicit Tor path through a Synology DSM system.

In the published example, this Tor path is carried through an existing WireGuard container setup.

This is the recommended setup if you want the same selected Tor path from both internal and external clients.

This image itself is not limited to DS2422+.

⁠What this is not

This is not a full VPN appliance.

This is not a ready-made all-in-one stack for every environment.

This image expects runtime configuration.

You must adapt the example values to your own setup.

⁠Example compose.yaml (requires an existing WireGuard container)

services:
  tor-client:
    image: friseer/synology-tor-client:latest
    container_name: tor-client
    restart: unless-stopped
    network_mode: "container:wg-easy"
    cap_add:
      - NET_ADMIN
    volumes:
      - ./torrc:/etc/tor/torrc:ro
      - ./entrypoint.sh:/usr/local/bin/entrypoint.sh:ro

⁠Example torrc

ClientOnly 1
SocksPort 0
TransPort 10.8.0.1:9040
DNSPort 10.8.0.1:9053
AutomapHostsOnResolve 1
VirtualAddrNetworkIPv4 10.192.0.0/10
Log notice stdout

⁠Example entrypoint.sh

#!/bin/sh
set -eu

SRC_IP="10.8.0.4/32"
WG_IF="wg0"
WG_ADDR="10.8.0.1"
TOR_TRANS_PORT="9040"
TOR_DNS_PORT="9053"

IPT="iptables"
if command -v iptables-legacy >/dev/null 2>&1; then
  IPT="iptables-legacy"
fi

nat_add() {
  chain="$1"
  shift
  if ! $IPT -t nat -C "$chain" "$@" 2>/dev/null; then
    $IPT -t nat -A "$chain" "$@"
  fi
}

nat_del() {
  chain="$1"
  shift
  if $IPT -t nat -C "$chain" "$@" 2>/dev/null; then
    $IPT -t nat -D "$chain" "$@"
  fi
}

flt_add() {
  chain="$1"
  shift
  if ! $IPT -C "$chain" "$@" 2>/dev/null; then
    $IPT -A "$chain" "$@"
  fi
}

flt_del() {
  chain="$1"
  shift
  if $IPT -C "$chain" "$@" 2>/dev/null; then
    $IPT -D "$chain" "$@"
  fi
}

cleanup() {
  nat_del PREROUTING -i "$WG_IF" -s "$SRC_IP" -p tcp --syn -j REDIRECT --to-ports "$TOR_TRANS_PORT"
  nat_del PREROUTING -i "$WG_IF" -s "$SRC_IP" -p udp --dport 53 -j REDIRECT --to-ports "$TOR_DNS_PORT"

  flt_del INPUT -i "$WG_IF" -s 10.8.0.4/32 -p tcp -d "$WG_ADDR" --dport "$TOR_TRANS_PORT" -j ACCEPT
  flt_del INPUT -i "$WG_IF" -s 10.8.0.4/32 -p udp -d "$WG_ADDR" --dport "$TOR_DNS_PORT" -j ACCEPT
  flt_del INPUT -i "$WG_IF" -p tcp -d "$WG_ADDR" --dport "$TOR_TRANS_PORT" -j DROP
  flt_del INPUT -i "$WG_IF" -p udp -d "$WG_ADDR" --dport "$TOR_DNS_PORT" -j DROP

  flt_del FORWARD -i "$WG_IF" -s "$SRC_IP" -p udp -j DROP
  flt_del FORWARD -i "$WG_IF" -s "$SRC_IP" -j DROP
}

trap 'cleanup' EXIT INT TERM

i=0
while [ "$i" -lt 30 ]; do
  if ip -4 addr show dev "$WG_IF" 2>/dev/null | grep -q "$WG_ADDR/"; then
    break
  fi
  i=$((i + 1))
  sleep 1
done

if ! ip -4 addr show dev "$WG_IF" 2>/dev/null | grep -q "$WG_ADDR/"; then
  echo "wg0 with $WG_ADDR not ready"
  exit 1
fi

tor -f /etc/tor/torrc &
TOR_PID="$!"

i=0
while [ "$i" -lt 30 ]; do
  if ss -ltn 2>/dev/null | grep -q "${WG_ADDR}:${TOR_TRANS_PORT}" \
     && ss -lun 2>/dev/null | grep -q "${WG_ADDR}:${TOR_DNS_PORT}"; then
    break
  fi
  i=$((i + 1))
  sleep 1
done

flt_add INPUT -i "$WG_IF" -s 10.8.0.4/32 -p tcp -d "$WG_ADDR" --dport "$TOR_TRANS_PORT" -j ACCEPT
flt_add INPUT -i "$WG_IF" -s 10.8.0.4/32 -p udp -d "$WG_ADDR" --dport "$TOR_DNS_PORT" -j ACCEPT
flt_add INPUT -i "$WG_IF" -p tcp -d "$WG_ADDR" --dport "$TOR_TRANS_PORT" -j DROP
flt_add INPUT -i "$WG_IF" -p udp -d "$WG_ADDR" --dport "$TOR_DNS_PORT" -j DROP

nat_add PREROUTING -i "$WG_IF" -s "$SRC_IP" -p tcp --syn -j REDIRECT --to-ports "$TOR_TRANS_PORT"
nat_add PREROUTING -i "$WG_IF" -s "$SRC_IP" -p udp --dport 53 -j REDIRECT --to-ports "$TOR_DNS_PORT"

flt_add FORWARD -i "$WG_IF" -s "$SRC_IP" -p udp -j DROP
flt_add FORWARD -i "$WG_IF" -s "$SRC_IP" -j DROP

wait "$TOR_PID"

⁠What you must change

In torrc:

  • replace 10.8.0.1 with the WireGuard interface address inside your WireGuard container

In entrypoint.sh:

  • replace SRC_IP="10.8.0.4/32" with the selected peer IP that should go through Tor
  • replace WG_ADDR="10.8.0.1" with the WireGuard interface address inside the container
  • if your interface is not wg0, also change WG_IF="wg0"

In compose.yaml:

  • if your WireGuard container is not named wg-easy, change: network_mode: "container:wg-easy"

⁠WireGuard role in this setup

WireGuard is not the purpose of this image.

WireGuard is the transport layer used in the published example so that selected clients can be routed through the same explicit Tor path via the Synology NAS.

The example uses:

  • container name: wg-easy
  • interface name: wg0

Install or recover WireGuard first on DS2422+ / v1000, then add this image on top.

⁠Start

docker compose up -d

⁠Check

From the selected WireGuard client path:

curl -4 https://check.torproject.org/api/ip

Expected result:

"IsTor": true

Tag summary

Content type

Image

Digest

sha256:d849ddfd7…

Size

36 MB

Last updated

6 months ago

docker pull friseer/synology-tor-client