From 54868b99cdd434f6aec4acbb72b19d3b4a6b9ed6 Mon Sep 17 00:00:00 2001 From: Ruslan Date: Tue, 14 Apr 2026 12:40:37 +0300 Subject: [PATCH] Client: auto-enable LAN forwarding/NAT; GUI: relax online status window --- README.md | 1 + client/install_client.sh | 50 ++++++++++++++++++++++++++++++++++++++++ gui/app.py | 5 ++-- 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4bb5540..85c964d 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,7 @@ tmp="$(mktemp -d)" && curl -fL "https://git.ruslan.xyz/ruslan/Wireguard_server/a Если за клиентом есть локальная сеть (например `192.168.33.0/24`), передайте `--advertise-subnets 192.168.33.0/24`, чтобы сервер маршрутизировал эту сеть через клиента. Если `--advertise-subnets` не задан, скрипт автоматически пытается определить LAN-сети клиента и объявить их на сервере. В режиме `split`, если `--allowed-ips` не задан, скрипт автоматически использует сеть WG сервера. +При объявлении сетей за клиентом скрипт автоматически включает `ip_forward` и добавляет правила `iptables` (forward + nat) через `PostUp/PostDown`. ### Non-interactive пример (SSH-ключ) diff --git a/client/install_client.sh b/client/install_client.sh index 441e109..c8a79dc 100755 --- a/client/install_client.sh +++ b/client/install_client.sh @@ -24,6 +24,7 @@ SSH_PASSWORD="" KEEPALIVE="25" CLIENT_ADDRESS_PREFIX="24" +FORWARDING_MODE="disabled" usage() { cat <<'USAGE' @@ -303,6 +304,12 @@ build_allowed_ips() { build_route_hooks_if_needed() { PRE_UP="" POST_DOWN="" + POST_UP_EXTRA_1="" + POST_UP_EXTRA_2="" + POST_UP_EXTRA_3="" + POST_DOWN_EXTRA_1="" + POST_DOWN_EXTRA_2="" + POST_DOWN_EXTRA_3="" if [[ "$TUNNEL_MODE" != "full" ]]; then return @@ -321,6 +328,39 @@ build_route_hooks_if_needed() { fi } +detect_iface_for_cidr() { + local cidr="$1" + ip -4 route show "$cidr" 2>/dev/null | awk '{for (i=1; i<=NF; i++) if ($i=="dev") {print $(i+1); exit}}' +} + +build_lan_nat_hooks_if_needed() { + [[ -n "$ADVERTISE_SUBNETS" ]] || return + + local first_cidr lan_iface wg_net + first_cidr="$(echo "$ADVERTISE_SUBNETS" | awk -F',' '{gsub(/ /,"",$1); print $1}')" + lan_iface="$(detect_iface_for_cidr "$first_cidr" || true)" + [[ -n "$lan_iface" ]] || lan_iface="$(detect_default_iface || true)" + [[ -n "$lan_iface" ]] || { log_warn "Не удалось определить LAN-интерфейс для NAT/forwarding."; return; } + + wg_net="${SERVER_WG_NETWORK:-10.66.66.0/24}" + + local fwd="/etc/sysctl.d/99-wireguard-client-forwarding.conf" + cat > "$fwd" </dev/null || true + + POST_UP_EXTRA_1="PostUp = iptables -C FORWARD -i ${WG_INTERFACE} -o ${lan_iface} -j ACCEPT 2>/dev/null || iptables -A FORWARD -i ${WG_INTERFACE} -o ${lan_iface} -j ACCEPT" + POST_UP_EXTRA_2="PostUp = iptables -C FORWARD -i ${lan_iface} -o ${WG_INTERFACE} -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || iptables -A FORWARD -i ${lan_iface} -o ${WG_INTERFACE} -m state --state RELATED,ESTABLISHED -j ACCEPT" + POST_UP_EXTRA_3="PostUp = iptables -t nat -C POSTROUTING -s ${wg_net} -o ${lan_iface} -j MASQUERADE 2>/dev/null || iptables -t nat -A POSTROUTING -s ${wg_net} -o ${lan_iface} -j MASQUERADE" + + POST_DOWN_EXTRA_1="PostDown = iptables -D FORWARD -i ${WG_INTERFACE} -o ${lan_iface} -j ACCEPT 2>/dev/null || true" + POST_DOWN_EXTRA_2="PostDown = iptables -D FORWARD -i ${lan_iface} -o ${WG_INTERFACE} -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || true" + POST_DOWN_EXTRA_3="PostDown = iptables -t nat -D POSTROUTING -s ${wg_net} -o ${lan_iface} -j MASQUERADE 2>/dev/null || true" + + FORWARDING_MODE="enabled via ${lan_iface} (wg:${wg_net})" +} + build_client_interface_address() { local ip_only ip_only="${CLIENT_ADDRESS%%/*}" @@ -360,6 +400,14 @@ write_client_config() { if [[ -n "$POST_DOWN" ]]; then echo "$POST_DOWN" fi + if [[ -n "$POST_UP_EXTRA_1" ]]; then + echo "$POST_UP_EXTRA_1" + echo "$POST_UP_EXTRA_2" + echo "$POST_UP_EXTRA_3" + echo "$POST_DOWN_EXTRA_1" + echo "$POST_DOWN_EXTRA_2" + echo "$POST_DOWN_EXTRA_3" + fi echo echo "[Peer]" echo "PublicKey = ${SERVER_PUBLIC_KEY}" @@ -403,6 +451,7 @@ Endpoint сервера: ${SERVER_ENDPOINT} SSH сервер: ${SERVER_USER}@${SERVER_HOST}:${SSH_PORT} Статус регистрации: ${SERVER_STATUS} Сети за клиентом: ${ADVERTISE_SUBNETS:-не объявлены} +LAN forwarding/NAT: ${FORWARDING_MODE} Лог: ${LOG_FILE} ================================================= EOF_SUMMARY @@ -434,6 +483,7 @@ main() { build_allowed_ips build_client_interface_address build_route_hooks_if_needed + build_lan_nat_hooks_if_needed write_client_config apply_client_config print_summary diff --git a/gui/app.py b/gui/app.py index f9bd6ac..a9e21c6 100644 --- a/gui/app.py +++ b/gui/app.py @@ -18,6 +18,7 @@ WG_INTERFACE = os.environ.get("WG_INTERFACE", "wg0") WG_META_FILE = os.environ.get("WG_META_FILE", "/etc/wireguard/wg-meta.env") ADMIN_USER = os.environ.get("ADMIN_USER", "admin") ADMIN_PASSWORD = os.environ.get("ADMIN_PASSWORD", "") +ONLINE_WINDOW_SEC = int(os.environ.get("ONLINE_WINDOW_SEC", "1800")) def db_conn(): @@ -181,7 +182,7 @@ def index(): for row in db_peers: rt = runtime.get(row["public_key"], {}) ts = int(rt.get("latest_handshake_ts", 0) or 0) - is_online = ts > 0 and (now - ts) <= 180 + is_online = ts > 0 and (now - ts) <= ONLINE_WINDOW_SEC seen.add(row["public_key"]) items.append( { @@ -203,7 +204,7 @@ def index(): if pk in seen: continue ts = int(rt.get("latest_handshake_ts", 0) or 0) - is_online = ts > 0 and (now - ts) <= 180 + is_online = ts > 0 and (now - ts) <= ONLINE_WINDOW_SEC items.append( { "id": None,