Client: auto-enable LAN forwarding/NAT; GUI: relax online status window

This commit is contained in:
Ruslan
2026-04-14 12:40:37 +03:00
parent 69f51bd5d7
commit 54868b99cd
3 changed files with 54 additions and 2 deletions

View File

@@ -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`, чтобы сервер маршрутизировал эту сеть через клиента. Если за клиентом есть локальная сеть (например `192.168.33.0/24`), передайте `--advertise-subnets 192.168.33.0/24`, чтобы сервер маршрутизировал эту сеть через клиента.
Если `--advertise-subnets` не задан, скрипт автоматически пытается определить LAN-сети клиента и объявить их на сервере. Если `--advertise-subnets` не задан, скрипт автоматически пытается определить LAN-сети клиента и объявить их на сервере.
В режиме `split`, если `--allowed-ips` не задан, скрипт автоматически использует сеть WG сервера. В режиме `split`, если `--allowed-ips` не задан, скрипт автоматически использует сеть WG сервера.
При объявлении сетей за клиентом скрипт автоматически включает `ip_forward` и добавляет правила `iptables` (forward + nat) через `PostUp/PostDown`.
### Non-interactive пример (SSH-ключ) ### Non-interactive пример (SSH-ключ)

View File

@@ -24,6 +24,7 @@ SSH_PASSWORD=""
KEEPALIVE="25" KEEPALIVE="25"
CLIENT_ADDRESS_PREFIX="24" CLIENT_ADDRESS_PREFIX="24"
FORWARDING_MODE="disabled"
usage() { usage() {
cat <<'USAGE' cat <<'USAGE'
@@ -303,6 +304,12 @@ build_allowed_ips() {
build_route_hooks_if_needed() { build_route_hooks_if_needed() {
PRE_UP="" PRE_UP=""
POST_DOWN="" 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 if [[ "$TUNNEL_MODE" != "full" ]]; then
return return
@@ -321,6 +328,39 @@ build_route_hooks_if_needed() {
fi 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" <<EOF_FWD
net.ipv4.ip_forward=1
EOF_FWD
sysctl --system >/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() { build_client_interface_address() {
local ip_only local ip_only
ip_only="${CLIENT_ADDRESS%%/*}" ip_only="${CLIENT_ADDRESS%%/*}"
@@ -360,6 +400,14 @@ write_client_config() {
if [[ -n "$POST_DOWN" ]]; then if [[ -n "$POST_DOWN" ]]; then
echo "$POST_DOWN" echo "$POST_DOWN"
fi 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
echo "[Peer]" echo "[Peer]"
echo "PublicKey = ${SERVER_PUBLIC_KEY}" echo "PublicKey = ${SERVER_PUBLIC_KEY}"
@@ -403,6 +451,7 @@ Endpoint сервера: ${SERVER_ENDPOINT}
SSH сервер: ${SERVER_USER}@${SERVER_HOST}:${SSH_PORT} SSH сервер: ${SERVER_USER}@${SERVER_HOST}:${SSH_PORT}
Статус регистрации: ${SERVER_STATUS} Статус регистрации: ${SERVER_STATUS}
Сети за клиентом: ${ADVERTISE_SUBNETS:-не объявлены} Сети за клиентом: ${ADVERTISE_SUBNETS:-не объявлены}
LAN forwarding/NAT: ${FORWARDING_MODE}
Лог: ${LOG_FILE} Лог: ${LOG_FILE}
================================================= =================================================
EOF_SUMMARY EOF_SUMMARY
@@ -434,6 +483,7 @@ main() {
build_allowed_ips build_allowed_ips
build_client_interface_address build_client_interface_address
build_route_hooks_if_needed build_route_hooks_if_needed
build_lan_nat_hooks_if_needed
write_client_config write_client_config
apply_client_config apply_client_config
print_summary print_summary

View File

@@ -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") WG_META_FILE = os.environ.get("WG_META_FILE", "/etc/wireguard/wg-meta.env")
ADMIN_USER = os.environ.get("ADMIN_USER", "admin") ADMIN_USER = os.environ.get("ADMIN_USER", "admin")
ADMIN_PASSWORD = os.environ.get("ADMIN_PASSWORD", "") ADMIN_PASSWORD = os.environ.get("ADMIN_PASSWORD", "")
ONLINE_WINDOW_SEC = int(os.environ.get("ONLINE_WINDOW_SEC", "1800"))
def db_conn(): def db_conn():
@@ -181,7 +182,7 @@ def index():
for row in db_peers: for row in db_peers:
rt = runtime.get(row["public_key"], {}) rt = runtime.get(row["public_key"], {})
ts = int(rt.get("latest_handshake_ts", 0) or 0) 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"]) seen.add(row["public_key"])
items.append( items.append(
{ {
@@ -203,7 +204,7 @@ def index():
if pk in seen: if pk in seen:
continue continue
ts = int(rt.get("latest_handshake_ts", 0) or 0) 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( items.append(
{ {
"id": None, "id": None,