#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if [[ -f "${SCRIPT_DIR}/../lib/common.sh" ]]; then # shellcheck source=../lib/common.sh source "${SCRIPT_DIR}/../lib/common.sh" elif [[ -f "/usr/local/lib/wireguard-automation/lib/common.sh" ]]; then # shellcheck source=/usr/local/lib/wireguard-automation/lib/common.sh source "/usr/local/lib/wireguard-automation/lib/common.sh" else echo "Не найден common.sh" >&2 exit 1 fi LOG_FILE="/var/log/wireguard-peerctl.log" WG_META_FILE="/etc/wireguard/wg-meta.env" usage() { cat <<'USAGE' Использование: wg-peerctl.sh add \ --client-name \ --client-public-key \ [--client-address <10.66.66.X/32>] \ [--client-preshared-key ] \ [--persistent-keepalive 25] Описание: Скрипт добавляет peer в конфигурацию WireGuard-сервера идемпотентно. Если peer с таким public key уже существует, повторно не добавляет. USAGE } load_meta() { [[ -f "$WG_META_FILE" ]] || die "Не найден $WG_META_FILE. Сначала выполните install_server.sh" # shellcheck disable=SC1090 source "$WG_META_FILE" WG_INTERFACE="${WG_INTERFACE:-wg0}" WG_NETWORK="${WG_NETWORK:-10.66.66.0/24}" WG_PORT="${WG_PORT:-51820}" SERVER_PUBLIC_IP="${SERVER_PUBLIC_IP:-}" SERVER_DNS="${SERVER_DNS:-1.1.1.1}" WG_CONF="/etc/wireguard/${WG_INTERFACE}.conf" } next_client_ip() { local network="$1" local base base="${network%.*}" local used used="$(grep -E '^AllowedIPs\s*=\s*' "$WG_CONF" | awk -F'=' '{print $2}' | tr ',' '\n' | sed 's/ //g' | grep -E '^10\.[0-9]+\.[0-9]+\.[0-9]+/32$' | sed 's#/32##' || true)" local i candidate for i in $(seq 2 254); do candidate="${base}.${i}" if ! grep -qx "$candidate" <<< "$used"; then echo "${candidate}/32" return 0 fi done return 1 } peer_exists_by_pubkey() { local pubkey="$1" grep -Fq "PublicKey = $pubkey" "$WG_CONF" } extract_peer_address_by_pubkey() { local pubkey="$1" awk -v pk="$pubkey" ' $0 ~ /^\[Peer\]/ {in_peer=1; key=""; addr=""} in_peer && $0 ~ /^PublicKey[[:space:]]*=/ { sub(/^[^=]*=[[:space:]]*/, "", $0); key=$0 } in_peer && $0 ~ /^AllowedIPs[[:space:]]*=/ { sub(/^[^=]*=[[:space:]]*/, "", $0); addr=$0 } in_peer && key==pk && addr!="" {print addr; exit} ' "$WG_CONF" | awk -F',' '{print $1}' | xargs } apply_config() { if systemctl is-active --quiet "wg-quick@${WG_INTERFACE}"; then wg syncconf "$WG_INTERFACE" <(wg-quick strip "$WG_CONF") else systemctl restart "wg-quick@${WG_INTERFACE}" fi } cmd_add() { local client_name="" local client_pubkey="" local client_address="" local client_psk="" local keepalive="25" while [[ $# -gt 0 ]]; do case "$1" in --client-name) client_name="$2"; shift 2 ;; --client-public-key) client_pubkey="$2"; shift 2 ;; --client-address) client_address="$2"; shift 2 ;; --client-preshared-key) client_psk="$2"; shift 2 ;; --persistent-keepalive) keepalive="$2"; shift 2 ;; *) die "Неизвестный аргумент: $1" ;; esac done [[ -n "$client_name" ]] || die "Не указан --client-name" [[ -n "$client_pubkey" ]] || die "Не указан --client-public-key" client_name="$(sanitize_name "$client_name")" [[ -n "$client_name" ]] || die "Некорректное имя клиента" load_meta [[ -f "$WG_CONF" ]] || die "Не найден конфиг WireGuard: $WG_CONF" local server_pubkey server_pubkey="$(cat /etc/wireguard/server_public.key)" if peer_exists_by_pubkey "$client_pubkey"; then local existing_addr existing_addr="$(extract_peer_address_by_pubkey "$client_pubkey")" cat <> "$WG_CONF" apply_config cat <