#!/bin/bash # kssh-tun — управление peer-ами WireGuard-сервера для keenetic_ssh-web tunnel. # Установлен через tunnel/server-install.sh в /usr/local/bin/kssh-tun. set -e ENV_FILE="/etc/wireguard/.kssh-tun.env" [ -f "$ENV_FILE" ] || { echo "Сервер не инициализирован. Запустите server-install.sh." >&2; exit 1; } # shellcheck disable=SC1090 . "$ENV_FILE" PEERS_DIR="$WG_DIR/peers" CONF="$WG_DIR/$WG_IF.conf" require_root() { if [ "$(id -u)" -ne 0 ]; then echo "Нужны права root (sudo)." >&2; exit 1; fi } regen_conf() { umask 077 TMP="$(mktemp)" cat > "$TMP" <> "$TMP" # peer: $NAME ($CLIENT_IP) [Peer] PublicKey = $CLIENT_PUB AllowedIPs = $CLIENT_IP/32 EOF ) done fi install -m 600 "$TMP" "$CONF" rm -f "$TMP" # Самый надёжный способ применить новый конфиг: рестарт wg-quick@WG_IF. # `wg syncconf` через process substitution падал молча на части систем. if command -v systemctl >/dev/null 2>&1 && \ systemctl is-enabled "wg-quick@$WG_IF" >/dev/null 2>&1; then systemctl restart "wg-quick@$WG_IF" || \ echo "warning: systemctl restart wg-quick@$WG_IF не удался" >&2 elif ip link show "$WG_IF" >/dev/null 2>&1; then TMP_STRIP="$(mktemp)" if wg-quick strip "$WG_IF" > "$TMP_STRIP" 2>/dev/null; then wg syncconf "$WG_IF" "$TMP_STRIP" || \ echo "warning: wg syncconf не удался — перезапустите wg-quick@$WG_IF" >&2 fi rm -f "$TMP_STRIP" fi } next_ip() { USED="$WG_SERVER_IP" if [ -d "$PEERS_DIR" ]; then for f in "$PEERS_DIR"/*.peer; do [ -f "$f" ] || continue ip=$(. "$f"; echo "$CLIENT_IP") USED="$USED $ip" done fi for i in $(seq 2 254); do candidate="${WG_SUBNET_PREFIX}.$i" case " $USED " in *" $candidate "*) ;; *) echo "$candidate"; return 0;; esac done echo "Нет свободного IP в подсети ${WG_SUBNET_PREFIX}.0/24" >&2 return 1 } print_env_block() { PEER_FILE="$1" # shellcheck disable=SC1090 . "$PEER_FILE" SERVER_PUB=$(cat "$WG_DIR/server_public.key") PUB_IP="$(curl -s4 -m 3 ifconfig.me 2>/dev/null || hostname -I | awk '{print $1}')" echo echo "============================================================" echo "Peer '$NAME' → $CLIENT_IP. Скопируйте 5 строк ниже на роутер" echo "(можно блоком, можно по одной — работает в любом shell):" echo cat <" >&2; exit 1; } shift || true DNAT_PORTS_ARG="" while [ $# -gt 0 ]; do case "$1" in --dnat) DNAT_PORTS_ARG="${2:-}" shift 2 || true ;; --dnat=*) DNAT_PORTS_ARG="${1#--dnat=}" shift || true ;; *) echo "Неизвестный аргумент: $1" >&2 echo "usage: kssh-tun add [--dnat 81,79]" >&2 exit 1 ;; esac done case "$NAME" in *[!a-zA-Z0-9_-]*) echo "Имя: только [a-zA-Z0-9_-]" >&2; exit 1;; esac mkdir -p "$PEERS_DIR" PEER_FILE="$PEERS_DIR/$NAME.peer" if [ -f "$PEER_FILE" ]; then echo "Peer '$NAME' уже существует — повторно вывожу ENV-блок:" else umask 077 CLIENT_IP="$(next_ip)" CLIENT_PRIV="$(wg genkey)" CLIENT_PUB="$(echo "$CLIENT_PRIV" | wg pubkey)" cat > "$PEER_FILE" <" >&2; exit 1; } PEER_FILE="$PEERS_DIR/$NAME.peer" [ -f "$PEER_FILE" ] || { echo "нет peer-а: $NAME" >&2; exit 1; } print_env_block "$PEER_FILE" ;; remove|rm|del) require_root NAME="${1:-}" [ -z "$NAME" ] && { echo "usage: kssh-tun remove " >&2; exit 1; } PEER_FILE="$PEERS_DIR/$NAME.peer" [ -f "$PEER_FILE" ] || { echo "нет peer-а: $NAME" >&2; exit 1; } rm -f "$PEER_FILE" regen_conf echo "Удалён: $NAME" ;; _regen) require_root regen_conf ;; status) if command -v wg >/dev/null 2>&1; then wg show "$WG_IF" 2>/dev/null || echo "(wg-интерфейс $WG_IF не поднят)" fi ;; ""|help|-h|--help) cat < [--dnat 81,79] добавить peer, вывести ENV-блок для роутера kssh-tun show повторно вывести ENV-блок kssh-tun list список peer-ов kssh-tun remove удалить peer kssh-tun status wg show $WG_IF Конфиг: $WG_DIR/$WG_IF.conf (регенерируется автоматически) Peer-файлы: $PEERS_DIR/*.peer EOF ;; *) echo "Неизвестная команда: $cmd. См. kssh-tun help" >&2 exit 1 ;; esac