499 lines
17 KiB
Bash
Executable File
499 lines
17 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
# shellcheck source=../lib/common.sh
|
|
source "${PROJECT_ROOT}/lib/common.sh"
|
|
|
|
LOG_FILE="/var/log/wireguard-client-install.log"
|
|
NON_INTERACTIVE=0
|
|
|
|
WG_INTERFACE="wg0"
|
|
CLIENT_NAME=""
|
|
CLIENT_DNS=""
|
|
TUNNEL_MODE=""
|
|
SPLIT_ALLOWED_IPS=""
|
|
ADVERTISE_SUBNETS=""
|
|
|
|
SERVER_HOST=""
|
|
SERVER_USER="root"
|
|
SSH_PORT="22"
|
|
SSH_AUTH_METHOD="key"
|
|
SSH_PASSWORD=""
|
|
|
|
KEEPALIVE="25"
|
|
CLIENT_ADDRESS_PREFIX="24"
|
|
FORWARDING_MODE="disabled"
|
|
|
|
usage() {
|
|
cat <<'USAGE'
|
|
Установка WireGuard-клиента и автоматическая регистрация на сервере.
|
|
Каждый запуск выполняет полный reset предыдущей клиентской конфигурации для выбранного интерфейса.
|
|
|
|
Использование:
|
|
install_client.sh [опции]
|
|
|
|
Опции:
|
|
--non-interactive Режим без вопросов
|
|
--interface <name> Интерфейс клиента (по умолчанию: wg0)
|
|
--client-name <name> Имя клиента (по умолчанию: hostname)
|
|
--mode <full|split> full: весь трафик, split: только выбранные сети
|
|
--allowed-ips <cidr,cidr> Для режима split
|
|
--dns <ip> DNS для клиента (если не задан, берется с сервера)
|
|
--client-address-prefix <1-32> Префикс маски адреса интерфейса клиента (по умолчанию: 24)
|
|
--advertise-subnets <cidr,...> Сети за клиентом, которые нужно маршрутизировать через него (например 192.168.33.0/24)
|
|
|
|
--server-host <host> IP/домен WireGuard-сервера
|
|
--server-user <user> SSH-пользователь (по умолчанию: root)
|
|
--ssh-port <port> SSH-порт (по умолчанию: 22)
|
|
--ssh-auth <key|password> Тип SSH-аутентификации (по умолчанию: key)
|
|
--ssh-password <password> Пароль SSH (используйте осторожно)
|
|
|
|
-h, --help Показать помощь
|
|
USAGE
|
|
}
|
|
|
|
on_error() {
|
|
local code=$?
|
|
log_error "Клиентская настройка завершилась с ошибкой (код: ${code}). Лог: ${LOG_FILE}"
|
|
exit "$code"
|
|
}
|
|
trap on_error ERR
|
|
|
|
parse_args() {
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--non-interactive)
|
|
NON_INTERACTIVE=1; shift ;;
|
|
--interface)
|
|
WG_INTERFACE="$2"; shift 2 ;;
|
|
--client-name)
|
|
CLIENT_NAME="$2"; shift 2 ;;
|
|
--mode)
|
|
TUNNEL_MODE="$2"; shift 2 ;;
|
|
--allowed-ips)
|
|
SPLIT_ALLOWED_IPS="$2"; shift 2 ;;
|
|
--dns)
|
|
CLIENT_DNS="$2"; shift 2 ;;
|
|
--client-address-prefix)
|
|
CLIENT_ADDRESS_PREFIX="$2"; shift 2 ;;
|
|
--advertise-subnets)
|
|
ADVERTISE_SUBNETS="$2"; shift 2 ;;
|
|
--server-host)
|
|
SERVER_HOST="$2"; shift 2 ;;
|
|
--server-user)
|
|
SERVER_USER="$2"; shift 2 ;;
|
|
--ssh-port)
|
|
SSH_PORT="$2"; shift 2 ;;
|
|
--ssh-auth)
|
|
SSH_AUTH_METHOD="$2"; shift 2 ;;
|
|
--ssh-password)
|
|
SSH_PASSWORD="$2"; shift 2 ;;
|
|
-h|--help)
|
|
usage; exit 0 ;;
|
|
*)
|
|
die "Неизвестный аргумент: $1"
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
validate_inputs() {
|
|
is_valid_port "$SSH_PORT" || die "Некорректный SSH-порт: $SSH_PORT"
|
|
[[ "$SSH_AUTH_METHOD" == "key" || "$SSH_AUTH_METHOD" == "password" ]] || die "--ssh-auth должен быть key или password"
|
|
[[ "$TUNNEL_MODE" == "full" || "$TUNNEL_MODE" == "split" ]] || die "--mode должен быть full или split"
|
|
[[ "$CLIENT_ADDRESS_PREFIX" =~ ^[0-9]+$ ]] || die "--client-address-prefix должен быть числом 1..32"
|
|
((CLIENT_ADDRESS_PREFIX >= 1 && CLIENT_ADDRESS_PREFIX <= 32)) || die "--client-address-prefix должен быть в диапазоне 1..32"
|
|
if [[ -n "$ADVERTISE_SUBNETS" ]]; then
|
|
is_valid_cidr_list "$ADVERTISE_SUBNETS" || die "Некорректный список --advertise-subnets"
|
|
fi
|
|
|
|
if [[ -z "$SERVER_HOST" ]]; then
|
|
die "Не указан --server-host"
|
|
fi
|
|
|
|
if [[ -n "$SPLIT_ALLOWED_IPS" ]]; then
|
|
is_valid_cidr_list "$SPLIT_ALLOWED_IPS" || die "Некорректный список --allowed-ips"
|
|
fi
|
|
}
|
|
|
|
collect_inputs() {
|
|
if [[ -z "$CLIENT_NAME" ]]; then
|
|
CLIENT_NAME="$(hostname -s)"
|
|
fi
|
|
CLIENT_NAME="$(sanitize_name "$CLIENT_NAME")"
|
|
[[ -n "$CLIENT_NAME" ]] || die "Некорректное имя клиента"
|
|
|
|
if [[ -z "$SERVER_HOST" && ! $NON_INTERACTIVE -eq 1 ]]; then
|
|
read -r -p "Введите IP/домен сервера: " SERVER_HOST
|
|
fi
|
|
|
|
if [[ -z "$TUNNEL_MODE" ]]; then
|
|
if ((NON_INTERACTIVE)); then
|
|
TUNNEL_MODE="full"
|
|
else
|
|
echo "Выберите режим маршрутизации:"
|
|
echo " 1) весь трафик через VPN (full)"
|
|
echo " 2) только выбранные сети (split)"
|
|
read -r -p "Ваш выбор [1/2, по умолчанию 1]: " mode_choice
|
|
case "${mode_choice:-1}" in
|
|
1) TUNNEL_MODE="full" ;;
|
|
2) TUNNEL_MODE="split" ;;
|
|
*) die "Некорректный выбор" ;;
|
|
esac
|
|
fi
|
|
fi
|
|
|
|
if [[ "$SSH_AUTH_METHOD" == "password" && -z "$SSH_PASSWORD" ]]; then
|
|
if ((NON_INTERACTIVE)); then
|
|
die "Для --ssh-auth password нужно указать --ssh-password"
|
|
fi
|
|
ask_secret "Введите SSH-пароль для ${SERVER_USER}@${SERVER_HOST}" SSH_PASSWORD
|
|
fi
|
|
|
|
validate_inputs
|
|
}
|
|
|
|
detect_client_lan_subnets() {
|
|
ip -o -4 route show scope link 2>/dev/null | awk '
|
|
{
|
|
cidr=$1
|
|
dev=""
|
|
for (i=1; i<=NF; i++) {
|
|
if ($i=="dev") { dev=$(i+1); break }
|
|
}
|
|
if (cidr ~ /^127\./ || cidr ~ /^169\.254\./) next
|
|
if (dev ~ /^(lo|wg|docker|veth|br-|tun|tap)/) next
|
|
if (cidr ~ /^([0-9]{1,3}\.){3}[0-9]{1,3}\/[0-9]+$/) print cidr
|
|
}
|
|
' | sort -u | paste -sd, -
|
|
}
|
|
|
|
install_packages() {
|
|
pkg_has_install_candidate() {
|
|
local pkg="$1"
|
|
local candidate
|
|
candidate="$(apt-cache policy "$pkg" 2>/dev/null | awk '/Candidate:/ {print $2; exit}')"
|
|
[[ -n "$candidate" && "$candidate" != "(none)" ]]
|
|
}
|
|
|
|
apt_install_if_missing wireguard wireguard-tools iproute2 openssh-client sshpass ca-certificates
|
|
|
|
if ! command -v resolvconf >/dev/null 2>&1; then
|
|
if pkg_has_install_candidate openresolv; then
|
|
apt_install_if_missing openresolv
|
|
elif pkg_has_install_candidate resolvconf; then
|
|
apt_install_if_missing resolvconf
|
|
else
|
|
log_warn "Пакеты openresolv/resolvconf недоступны. DNS-строка в wg0.conf будет пропущена."
|
|
fi
|
|
fi
|
|
}
|
|
|
|
reset_existing_client_install() {
|
|
log_warn "Выполняю полный reset предыдущей конфигурации клиента (${WG_INTERFACE})"
|
|
|
|
local unit="wg-quick@${WG_INTERFACE}.service"
|
|
systemctl disable --now "$unit" >/dev/null 2>&1 || true
|
|
wg-quick down "$WG_INTERFACE" >/dev/null 2>&1 || true
|
|
|
|
rm -f \
|
|
"/etc/wireguard/${WG_INTERFACE}.conf" \
|
|
"/etc/wireguard/${WG_INTERFACE}_client_private.key" \
|
|
"/etc/wireguard/${WG_INTERFACE}_client_public.key" \
|
|
"/etc/wireguard/${WG_INTERFACE}_client_psk.key"
|
|
|
|
log_info "Старые конфиг/ключи клиента удалены для интерфейса ${WG_INTERFACE}"
|
|
}
|
|
|
|
ssh_base_cmd() {
|
|
echo "ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=10 -p ${SSH_PORT} ${SERVER_USER}@${SERVER_HOST}"
|
|
}
|
|
|
|
run_ssh() {
|
|
local remote_cmd="$1"
|
|
local base
|
|
base="$(ssh_base_cmd)"
|
|
|
|
if [[ "$SSH_AUTH_METHOD" == "password" ]]; then
|
|
require_cmd sshpass
|
|
SSHPASS="$SSH_PASSWORD" sshpass -e bash -c "$base \"$remote_cmd\""
|
|
else
|
|
bash -c "$base \"$remote_cmd\""
|
|
fi
|
|
}
|
|
|
|
resolve_server_ip() {
|
|
getent ahostsv4 "$SERVER_HOST" | awk '{print $1; exit}'
|
|
}
|
|
|
|
generate_keys() {
|
|
mkdir -p /etc/wireguard
|
|
chmod 700 /etc/wireguard
|
|
|
|
CLIENT_PRIV_KEY_PATH="/etc/wireguard/${WG_INTERFACE}_client_private.key"
|
|
CLIENT_PUB_KEY_PATH="/etc/wireguard/${WG_INTERFACE}_client_public.key"
|
|
CLIENT_PSK_PATH="/etc/wireguard/${WG_INTERFACE}_client_psk.key"
|
|
|
|
if [[ ! -f "$CLIENT_PRIV_KEY_PATH" ]]; then
|
|
umask 077
|
|
wg genkey | tee "$CLIENT_PRIV_KEY_PATH" | wg pubkey > "$CLIENT_PUB_KEY_PATH"
|
|
wg genpsk > "$CLIENT_PSK_PATH"
|
|
log_success "Сгенерированы клиентские ключи"
|
|
else
|
|
if [[ ! -f "$CLIENT_PUB_KEY_PATH" ]]; then
|
|
wg pubkey < "$CLIENT_PRIV_KEY_PATH" > "$CLIENT_PUB_KEY_PATH"
|
|
fi
|
|
if [[ ! -f "$CLIENT_PSK_PATH" ]]; then
|
|
wg genpsk > "$CLIENT_PSK_PATH"
|
|
fi
|
|
log_info "Ключи клиента уже существуют, переиспользую"
|
|
fi
|
|
|
|
safe_chmod_600 "$CLIENT_PRIV_KEY_PATH"
|
|
safe_chmod_600 "$CLIENT_PUB_KEY_PATH"
|
|
safe_chmod_600 "$CLIENT_PSK_PATH"
|
|
}
|
|
|
|
register_peer_on_server() {
|
|
local pub psk remote_cmd response
|
|
pub="$(cat "$CLIENT_PUB_KEY_PATH")"
|
|
psk="$(cat "$CLIENT_PSK_PATH")"
|
|
|
|
remote_cmd="/usr/local/sbin/wg-peerctl add --client-name '${CLIENT_NAME}' --client-public-key '${pub}' --client-preshared-key '${psk}' --persistent-keepalive '${KEEPALIVE}'"
|
|
if [[ -n "$ADVERTISE_SUBNETS" ]]; then
|
|
remote_cmd+=" --client-routes '${ADVERTISE_SUBNETS}'"
|
|
fi
|
|
response="$(run_ssh "$remote_cmd")"
|
|
|
|
SERVER_RESPONSE_RAW="$response"
|
|
|
|
kv_get() {
|
|
local key="$1"
|
|
printf '%s\n' "$response" | sed -n "s/^${key}=//p" | head -n1
|
|
}
|
|
|
|
SERVER_STATUS="$(kv_get STATUS)"
|
|
CLIENT_ADDRESS="$(kv_get CLIENT_ADDRESS)"
|
|
SERVER_PUBLIC_KEY="$(kv_get SERVER_PUBLIC_KEY)"
|
|
SERVER_ENDPOINT="$(kv_get SERVER_ENDPOINT)"
|
|
SERVER_DNS_REMOTE="$(kv_get SERVER_DNS)"
|
|
SERVER_WG_NETWORK="$(kv_get WG_NETWORK)"
|
|
|
|
[[ -n "$SERVER_PUBLIC_KEY" ]] || die "Сервер не вернул SERVER_PUBLIC_KEY"
|
|
[[ -n "$CLIENT_ADDRESS" ]] || die "Сервер не вернул CLIENT_ADDRESS"
|
|
[[ -n "$SERVER_ENDPOINT" ]] || die "Сервер не вернул SERVER_ENDPOINT"
|
|
}
|
|
|
|
build_allowed_ips() {
|
|
if [[ "$TUNNEL_MODE" == "full" ]]; then
|
|
ALLOWED_IPS="0.0.0.0/0,::/0"
|
|
else
|
|
if [[ -n "$SPLIT_ALLOWED_IPS" ]]; then
|
|
ALLOWED_IPS="$SPLIT_ALLOWED_IPS"
|
|
elif [[ -n "${SERVER_WG_NETWORK:-}" ]]; then
|
|
ALLOWED_IPS="$SERVER_WG_NETWORK"
|
|
log_info "Режим split: --allowed-ips не задан, использую сеть WG сервера: ${ALLOWED_IPS}"
|
|
else
|
|
die "Режим split: не удалось определить --allowed-ips автоматически"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
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
|
|
fi
|
|
|
|
local server_ip gw iface
|
|
server_ip="$(resolve_server_ip || true)"
|
|
gw="$(detect_default_gateway || true)"
|
|
iface="$(detect_default_iface || true)"
|
|
|
|
if [[ -n "$server_ip" && -n "$gw" && -n "$iface" ]]; then
|
|
PRE_UP="PreUp = ip route add ${server_ip}/32 via ${gw} dev ${iface} 2>/dev/null || true"
|
|
POST_DOWN="PostDown = ip route del ${server_ip}/32 via ${gw} dev ${iface} 2>/dev/null || true"
|
|
else
|
|
log_warn "Не удалось вычислить route-exception до сервера. Использую стандартное поведение wg-quick."
|
|
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
|
|
net.ipv4.conf.all.rp_filter=2
|
|
net.ipv4.conf.default.rp_filter=2
|
|
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() {
|
|
local ip_only
|
|
ip_only="${CLIENT_ADDRESS%%/*}"
|
|
CLIENT_INTERFACE_ADDRESS="${ip_only}/${CLIENT_ADDRESS_PREFIX}"
|
|
}
|
|
|
|
write_client_config() {
|
|
local conf="/etc/wireguard/${WG_INTERFACE}.conf"
|
|
local dns
|
|
local include_dns=0
|
|
|
|
dns="$CLIENT_DNS"
|
|
if [[ -z "$dns" ]]; then
|
|
dns="${SERVER_DNS_REMOTE:-1.1.1.1}"
|
|
fi
|
|
|
|
if command -v resolvconf >/dev/null 2>&1; then
|
|
include_dns=1
|
|
else
|
|
log_warn "Команда resolvconf не найдена. Пропускаю строку DNS в конфиге WireGuard."
|
|
fi
|
|
|
|
if [[ -f "$conf" ]]; then
|
|
backup_file "$conf"
|
|
fi
|
|
|
|
{
|
|
echo "[Interface]"
|
|
echo "PrivateKey = $(cat "$CLIENT_PRIV_KEY_PATH")"
|
|
echo "Address = ${CLIENT_INTERFACE_ADDRESS}"
|
|
if ((include_dns)); then
|
|
echo "DNS = ${dns}"
|
|
fi
|
|
if [[ -n "$PRE_UP" ]]; then
|
|
echo "$PRE_UP"
|
|
fi
|
|
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}"
|
|
echo "PresharedKey = $(cat "$CLIENT_PSK_PATH")"
|
|
echo "Endpoint = ${SERVER_ENDPOINT}"
|
|
echo "AllowedIPs = ${ALLOWED_IPS}"
|
|
echo "PersistentKeepalive = ${KEEPALIVE}"
|
|
} > "$conf"
|
|
|
|
safe_chmod_600 "$conf"
|
|
}
|
|
|
|
apply_client_config() {
|
|
local unit="wg-quick@${WG_INTERFACE}.service"
|
|
if systemctl list-unit-files | grep -q "^${unit}"; then
|
|
systemctl restart "$unit" || true
|
|
fi
|
|
systemd_enable_now "$unit"
|
|
}
|
|
|
|
print_routes_info() {
|
|
log_info "Текущая таблица маршрутов клиента (до применения уже была прочитана системой):"
|
|
ip route show | sed 's/^/ /'
|
|
}
|
|
|
|
print_summary() {
|
|
local st
|
|
st="$(systemctl is-active "wg-quick@${WG_INTERFACE}" 2>/dev/null || true)"
|
|
|
|
cat <<EOF_SUMMARY
|
|
|
|
================ ИТОГОВАЯ СВОДКА ================
|
|
Клиент: ${CLIENT_NAME}
|
|
Интерфейс: ${WG_INTERFACE}
|
|
Сервис: ${st}
|
|
Конфиг клиента: /etc/wireguard/${WG_INTERFACE}.conf
|
|
Endpoint сервера: ${SERVER_ENDPOINT}
|
|
Маршруты (AllowedIPs):${ALLOWED_IPS}
|
|
Адрес интерфейса: ${CLIENT_INTERFACE_ADDRESS}
|
|
Режим туннеля: ${TUNNEL_MODE}
|
|
SSH сервер: ${SERVER_USER}@${SERVER_HOST}:${SSH_PORT}
|
|
Статус регистрации: ${SERVER_STATUS}
|
|
Сети за клиентом: ${ADVERTISE_SUBNETS:-не объявлены}
|
|
LAN forwarding/NAT: ${FORWARDING_MODE}
|
|
Лог: ${LOG_FILE}
|
|
=================================================
|
|
EOF_SUMMARY
|
|
}
|
|
|
|
main() {
|
|
parse_args "$@"
|
|
|
|
require_root
|
|
check_os_supported
|
|
require_cmd awk
|
|
require_cmd sed
|
|
require_cmd ip
|
|
require_cmd ssh
|
|
|
|
collect_inputs
|
|
|
|
reset_existing_client_install
|
|
print_routes_info
|
|
install_packages
|
|
generate_keys
|
|
if [[ -z "$ADVERTISE_SUBNETS" ]]; then
|
|
ADVERTISE_SUBNETS="$(detect_client_lan_subnets || true)"
|
|
if [[ -n "$ADVERTISE_SUBNETS" ]]; then
|
|
log_info "Автоопределены сети за клиентом: ${ADVERTISE_SUBNETS}"
|
|
fi
|
|
fi
|
|
register_peer_on_server
|
|
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
|
|
|
|
# Не держим пароль в переменной дольше необходимого.
|
|
unset SSH_PASSWORD
|
|
log_success "Настройка клиента завершена"
|
|
}
|
|
|
|
main "$@"
|