mikrotik-chr-installer/chr-installer-adv-vpn-ru.sh
2026-03-10 12:00:01 +03:00

770 lines
32 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
set -e
# Цвета для вывода
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
log_debug() { echo -e "${CYAN}[DEBUG]${NC} $1"; }
# ============================================
# ГЕНЕРАЦИЯ КЛЮЧЕЙ И ПАРОЛЕЙ
# ============================================
generate_password() {
local length=$1
tr -dc 'A-Za-z0-9' < /dev/urandom | head -c "$length"
}
generate_wireguard_key() {
# Генерация WireGuard ключей через base64
# Приватный ключ - 32 байта случайных данных в base64
head -c 32 /dev/urandom | base64
}
# ============================================
# САНИТИЗАЦИЯ ВХОДНЫХ ДАННЫХ
# ============================================
sanitize_input() {
local input="$1"
# Удаляем опасные символы: ; " ' ` $ \ / и переносы строк
echo "$input" | tr -d ';"'\''`$\\/\n\r' | head -c 64
}
# ============================================
# КОНФИГУРАЦИЯ
# ============================================
CHR_VERSION="7.16.1"
# URL будет установлен после определения режима загрузки (UEFI/Legacy)
CHR_URL=""
CHR_ZIP=""
CHR_IMG=""
WORK_DIR="/tmp/chr-install"
MOUNT_POINT="/mnt/chr"
# Настройки CHR (пароль генерируется автоматически если не указан)
ADMIN_PASSWORD=""
DNS_SERVERS="8.8.8.8,8.8.4.4"
ROUTER_NAME="MikroTik-VPN"
TIMEZONE="Europe/Moscow"
# VPN настройки
VPN_POOL="10.10.10.0/24"
VPN_POOL_START="10.10.10.2"
VPN_POOL_END="10.10.10.254"
VPN_LOCAL_IP="10.10.10.1"
VPN_USER="vpnuser"
VPN_USER_PASSWORD=""
IPSEC_SECRET=""
WG_SERVER_PORT="51820"
WG_SERVER_PRIVATE_KEY=""
WG_NETWORK="10.10.20.0/24"
OVPN_PORT="1194"
OVPN_TCP_PORT="1195"
SSTP_PORT="8443"
# Флаги
FORCE_DOWNLOAD=false
AUTO_YES=false
AUTO_REBOOT=false
FORCE_LEGACY=false
# ============================================
# ПАРСИНГ АРГУМЕНТОВ
# ============================================
usage() {
echo "Использование: $0 [опции]"
echo ""
echo "Скрипт установки CHR как VPN-сервера со всеми протоколами:"
echo " - PPTP (порт 1723)"
echo " - L2TP/IPsec (порт 1701, UDP 500/4500)"
echo " - SSTP (порт 8443)"
echo " - OpenVPN (порт 1194 UDP/TCP, 1195 TCP)"
echo " - WireGuard (порт 51820)"
echo ""
echo "Опции:"
echo " --force Принудительно скачать образ заново"
echo " --yes, -y Без подтверждений (автоматический режим)"
echo " --reboot Автоматическая перезагрузка (требует --yes)"
echo " --version VER Версия CHR (по умолчанию: $CHR_VERSION)"
echo " --password PASS Пароль admin (генерируется автоматически)"
echo " --name NAME Имя роутера (по умолчанию: $ROUTER_NAME)"
echo " --timezone TZ Часовой пояс (по умолчанию: $TIMEZONE)"
echo " --dns SERVERS DNS серверы (по умолчанию: $DNS_SERVERS)"
echo " --vpn-user USER VPN пользователь (по умолчанию: $VPN_USER)"
echo " --vpn-pass PASS Пароль VPN (генерируется автоматически)"
echo " --vpn-pool CIDR VPN пул адресов (по умолчанию: $VPN_POOL)"
echo " --ipsec-secret S IPsec Pre-Shared Key (генерируется автоматически)"
echo " --wg-port PORT WireGuard порт (по умолчанию: $WG_SERVER_PORT)"
echo " --legacy Принудительно использовать Legacy BIOS (не UEFI)"
echo " -h, --help Показать справку"
echo ""
echo "Примеры:"
echo " $0 --yes --reboot # Автоустановка VPN сервера"
echo " $0 --vpn-user myuser --vpn-pass secret123"
echo " $0 --ipsec-secret MyIPsecKey123"
exit 0
}
while [[ $# -gt 0 ]]; do
case $1 in
--force)
FORCE_DOWNLOAD=true
shift
;;
--yes|-y)
AUTO_YES=true
shift
;;
--reboot)
AUTO_REBOOT=true
shift
;;
--legacy)
FORCE_LEGACY=true
shift
;;
--version)
CHR_VERSION="$2"
CHR_URL="https://download.mikrotik.com/routeros/${CHR_VERSION}/chr-${CHR_VERSION}.img.zip"
CHR_ZIP="chr-${CHR_VERSION}.img.zip"
CHR_IMG="chr-${CHR_VERSION}.img"
shift 2
;;
--password)
ADMIN_PASSWORD=$(sanitize_input "$2")
shift 2
;;
--name)
ROUTER_NAME=$(sanitize_input "$2")
shift 2
;;
--timezone)
TIMEZONE=$(sanitize_input "$2")
shift 2
;;
--dns)
DNS_SERVERS=$(sanitize_input "$2")
shift 2
;;
--vpn-user)
VPN_USER=$(sanitize_input "$2")
shift 2
;;
--vpn-pass)
VPN_USER_PASSWORD=$(sanitize_input "$2")
shift 2
;;
--vpn-pool)
VPN_POOL=$(sanitize_input "$2")
shift 2
;;
--ipsec-secret)
IPSEC_SECRET=$(sanitize_input "$2")
shift 2
;;
--wg-port)
WG_SERVER_PORT="$2"
shift 2
;;
-h|--help)
usage
;;
*)
log_error "Неизвестная опция: $1"
usage
;;
esac
done
# ============================================
# ГЕНЕРАЦИЯ КЛЮЧЕЙ (если не заданы)
# ============================================
log_info "Генерация ключей и паролей..."
if [[ -z "$ADMIN_PASSWORD" ]]; then
ADMIN_PASSWORD=$(generate_password 16)
log_info "Сгенерирован пароль admin: $ADMIN_PASSWORD"
fi
if [[ -z "$VPN_USER_PASSWORD" ]]; then
VPN_USER_PASSWORD=$(generate_password 16)
log_info "Сгенерирован пароль VPN: $VPN_USER_PASSWORD"
fi
if [[ -z "$IPSEC_SECRET" ]]; then
IPSEC_SECRET=$(generate_password 12)
log_info "Сгенерирован IPsec PSK: $IPSEC_SECRET"
fi
# WireGuard ключ сервера
WG_SERVER_PRIVATE_KEY=$(generate_wireguard_key)
log_info "Сгенерирован WireGuard ключ сервера"
# ============================================
# ПРОВЕРКА ROOT
# ============================================
if [[ $EUID -ne 0 ]]; then
log_error "Скрипт должен запускаться от root"
exit 1
fi
# ============================================
# ОПРЕДЕЛЕНИЕ РЕЖИМА ЗАГРУЗКИ (UEFI/LEGACY)
# ============================================
if [[ "$FORCE_LEGACY" == true ]]; then
BOOT_MODE="LEGACY"
log_info "Режим загрузки: Legacy BIOS (принудительно)"
elif [[ -d /sys/firmware/efi ]]; then
BOOT_MODE="UEFI"
log_info "Режим загрузки: UEFI (используется fat-chr образ)"
else
BOOT_MODE="LEGACY"
log_info "Режим загрузки: Legacy BIOS"
fi
# Установка URL в зависимости от режима загрузки
if [[ "$BOOT_MODE" == "UEFI" ]]; then
# UEFI образ fat-chr 7.16 (проверенный, autorun.scr работает)
CHR_URL="https://github.com/tikoci/fat-chr/releases/download/Build11085703131-jaclaz/chr-7.16.uefi-fat-jaclaz.raw"
CHR_ZIP=""
CHR_IMG="chr-7.16.uefi-fat.raw"
log_info "UEFI: используется fat-chr 7.16 (autorun.scr поддерживается)"
else
# Официальный MikroTik образ для Legacy BIOS
CHR_URL="https://download.mikrotik.com/routeros/${CHR_VERSION}/chr-${CHR_VERSION}.img.zip"
CHR_ZIP="chr-${CHR_VERSION}.img.zip"
CHR_IMG="chr-${CHR_VERSION}.img"
fi
# ============================================
# ПРОВЕРКА ЗАВИСИМОСТЕЙ
# ============================================
log_info "Проверка зависимостей..."
REQUIRED_TOOLS="wget unzip fdisk dd mount umount file md5sum xxd"
MISSING_TOOLS=""
for tool in $REQUIRED_TOOLS; do
if ! command -v $tool &> /dev/null; then
MISSING_TOOLS="$MISSING_TOOLS $tool"
fi
done
if [[ -n "$MISSING_TOOLS" ]]; then
log_warn "Отсутствуют утилиты:$MISSING_TOOLS"
log_info "Попытка установки..."
if command -v apt-get &> /dev/null; then
apt-get update && apt-get install -y wget unzip fdisk coreutils mount xxd file parted dosfstools
elif command -v yum &> /dev/null; then
yum install -y wget unzip util-linux coreutils vim-common file parted dosfstools
elif command -v dnf &> /dev/null; then
dnf install -y wget unzip util-linux coreutils vim-common file parted dosfstools
else
log_error "Установи вручную:$MISSING_TOOLS"
exit 1
fi
fi
log_info "Все зависимости в порядке"
# ============================================
# ПОДГОТОВКА РАБОЧЕЙ ДИРЕКТОРИИ
# ============================================
mkdir -p "$WORK_DIR"
cd "$WORK_DIR"
log_info "Рабочая директория: $WORK_DIR"
log_debug "Свободное место: $(df -h "$WORK_DIR" | tail -1 | awk '{print $4}')"
# ============================================
# СКАЧИВАНИЕ ОБРАЗА
# ============================================
if [[ "$FORCE_DOWNLOAD" == true ]] || [[ ! -f "$CHR_IMG" ]]; then
rm -f "$CHR_ZIP" "$CHR_IMG" "${CHR_IMG}.modified"
if [[ "$BOOT_MODE" == "UEFI" ]]; then
# UEFI: скачиваем RAW образ напрямую
log_info "Скачивание fat-chr 7.16 (UEFI)..."
wget --progress=bar:force -O "$CHR_IMG" "$CHR_URL"
ACTUAL_SIZE=$(stat -c%s "$CHR_IMG")
log_debug "Размер скачанного файла: $ACTUAL_SIZE байт"
if [[ $ACTUAL_SIZE -lt 100000000 ]]; then
log_error "Файл слишком маленький, скачивание неполное"
exit 1
fi
else
# Legacy: скачиваем ZIP и распаковываем
log_info "Скачивание CHR ${CHR_VERSION} (Legacy)..."
wget --progress=bar:force -O "$CHR_ZIP" "$CHR_URL"
ACTUAL_SIZE=$(stat -c%s "$CHR_ZIP")
log_debug "Размер скачанного файла: $ACTUAL_SIZE байт"
if [[ $ACTUAL_SIZE -lt 30000000 ]]; then
log_error "Файл слишком маленький, скачивание неполное"
exit 1
fi
FILE_TYPE=$(file "$CHR_ZIP")
log_debug "Тип файла: $FILE_TYPE"
if echo "$FILE_TYPE" | grep -q "Zip archive"; then
log_info "Распаковка ZIP..."
unzip -o "$CHR_ZIP"
elif echo "$FILE_TYPE" | grep -q "gzip"; then
log_info "Распаковка GZIP..."
gunzip -c "$CHR_ZIP" > "$CHR_IMG"
else
log_error "Неизвестный формат: $FILE_TYPE"
exit 1
fi
rm -f "$CHR_ZIP"
fi
else
log_info "Используется существующий образ: $CHR_IMG"
fi
# ============================================
# ВАЛИДАЦИЯ ОБРАЗА
# ============================================
log_info "Валидация образа..."
if [[ ! -f "$CHR_IMG" ]]; then
log_error "Образ не найден!"
ls -la "$WORK_DIR"
exit 1
fi
IMG_SIZE=$(stat -c%s "$CHR_IMG")
log_debug "Размер образа: $IMG_SIZE байт ($(( IMG_SIZE / 1024 / 1024 )) MB)"
MBR_SIG=$(xxd -s 510 -l 2 -p "$CHR_IMG")
if [[ "$MBR_SIG" != "55aa" ]]; then
log_error "Неверная MBR сигнатура: $MBR_SIG (ожидается 55aa)"
exit 1
fi
log_debug "MBR сигнатура: OK (55aa)"
ORIGINAL_MD5=$(md5sum "$CHR_IMG" | awk '{print $1}')
log_info "MD5 оригинального образа: $ORIGINAL_MD5"
log_info "Образ прошёл валидацию ✓"
# ============================================
# ОПРЕДЕЛЕНИЕ СЕТЕВЫХ ПАРАМЕТРОВ
# ============================================
log_info "Определение сетевых параметров..."
INTERFACE=$(ip route | grep default | awk '{print $5}' | head -n1)
ADDRESS=$(ip addr show "$INTERFACE" 2>/dev/null | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | head -n1)
GATEWAY=$(ip route | grep default | awk '{print $3}' | head -n1)
SERVER_IP="${ADDRESS%/*}"
NETMASK="${ADDRESS#*/}"
if [[ -z "$INTERFACE" || -z "$ADDRESS" || -z "$GATEWAY" ]]; then
log_error "Не удалось определить сетевые параметры"
log_error "INTERFACE=$INTERFACE ADDRESS=$ADDRESS GATEWAY=$GATEWAY"
exit 1
fi
# Функция проверки - находится ли gateway в той же подсети
check_same_subnet() {
local ip="$1"
local gw="$2"
local mask="$3"
# Конвертируем IP в число
IFS='.' read -r i1 i2 i3 i4 <<< "$ip"
IFS='.' read -r g1 g2 g3 g4 <<< "$gw"
# Вычисляем маску
local full_mask=$(( 0xFFFFFFFF << (32 - mask) & 0xFFFFFFFF ))
local m1=$(( (full_mask >> 24) & 255 ))
local m2=$(( (full_mask >> 16) & 255 ))
local m3=$(( (full_mask >> 8) & 255 ))
local m4=$(( full_mask & 255 ))
# Сравниваем сетевые части
if [[ $((i1 & m1)) -eq $((g1 & m1)) ]] && \
[[ $((i2 & m2)) -eq $((g2 & m2)) ]] && \
[[ $((i3 & m3)) -eq $((g3 & m3)) ]] && \
[[ $((i4 & m4)) -eq $((g4 & m4)) ]]; then
return 0 # В одной подсети
else
return 1 # В разных подсетях
fi
}
# Проверяем, находится ли gateway в той же подсети
if check_same_subnet "$SERVER_IP" "$GATEWAY" "$NETMASK"; then
GATEWAY_IN_SUBNET=true
log_info "Gateway в той же подсети"
else
GATEWAY_IN_SUBNET=false
log_info "Gateway в другой подсети - используем network=$GATEWAY"
fi
log_info "Интерфейс: $INTERFACE | Адрес: $ADDRESS | Шлюз: $GATEWAY"
# ============================================
# ОПРЕДЕЛЕНИЕ ДИСКА
# ============================================
log_info "Определение целевого диска..."
echo ""
lsblk -d -o NAME,SIZE,MODEL,TYPE | grep -E "(NAME|disk)"
echo ""
# Определяем диск по корневому разделу (исключает fd0, sr0 и т.д.)
DISK_DEVICE=""
ROOT_PART=$(findmnt -n -o SOURCE / 2>/dev/null)
if [[ -n "$ROOT_PART" ]]; then
DISK_DEVICE=$(lsblk -ndo PKNAME "$ROOT_PART" 2>/dev/null)
[[ -n "$DISK_DEVICE" ]] && DISK_DEVICE="/dev/$DISK_DEVICE"
fi
# Fallback: первый реальный диск (исключаем floppy, cdrom, loop)
if [[ -z "$DISK_DEVICE" ]]; then
DISK_DEVICE=$(lsblk -ndo NAME,TYPE | awk '$2=="disk" && $1!~/^(fd|sr|loop)/ {print "/dev/"$1; exit}')
fi
if [[ -z "$DISK_DEVICE" ]]; then
log_error "Диск не найден"
exit 1
fi
DISK_SIZE=$(lsblk -ndo SIZE "$DISK_DEVICE")
log_warn "Целевой диск: $DISK_DEVICE ($DISK_SIZE)"
# ============================================
# СОЗДАНИЕ AUTORUN С VPN НАСТРОЙКОЙ
# ============================================
log_info "Создание autorun.scr с настройкой VPN серверов..."
CHR_IMG_MOD="${CHR_IMG}.modified"
cp "$CHR_IMG" "$CHR_IMG_MOD"
mkdir -p "$MOUNT_POINT"
# Диагностика структуры разделов
log_debug "Структура разделов образа:"
fdisk -l "$CHR_IMG_MOD" 2>/dev/null | head -20 || true
# Определение номера раздела с данными
# fat-chr 7.16 и Legacy MikroTik: раздел 2 (Linux filesystem)
ROOT_PART_NUM=2
log_debug "Используем раздел $ROOT_PART_NUM"
OFFSET_SECTORS=$(fdisk -l "$CHR_IMG_MOD" 2>/dev/null | grep "${CHR_IMG_MOD}${ROOT_PART_NUM}" | sed 's/\*//' | awk '{print $2}')
if [[ -z "$OFFSET_SECTORS" ]]; then
OFFSET_BYTES=33571840
else
OFFSET_BYTES=$((OFFSET_SECTORS * 512))
fi
log_debug "Монтирование раздела $ROOT_PART_NUM с offset: $OFFSET_BYTES"
mount -o loop,offset="$OFFSET_BYTES" "$CHR_IMG_MOD" "$MOUNT_POINT"
log_debug "Содержимое смонтированного раздела:"
ls -la "$MOUNT_POINT/" || true
if [[ ! -d "$MOUNT_POINT/rw" ]]; then
log_warn "Директория /rw не существует, создаём..."
mkdir -p "$MOUNT_POINT/rw"
fi
# Удаляем флаги которые могут блокировать выполнение autorun.scr
rm -f "$MOUNT_POINT/UPGRADED" "$MOUNT_POINT/rw/REBOOT" 2>/dev/null
log_debug "Удалены флаги UPGRADED, REBOOT"
log_debug "Содержимое /rw:"
ls -la "$MOUNT_POINT/rw/" 2>/dev/null || echo "(пусто или не существует)"
# Создание autorun (без комментариев для совместимости с RouterOS)
# Формируем команды маршрута в зависимости от расположения gateway
# Если gateway в другой подсети, используем network= для указания gateway
if [[ "$GATEWAY_IN_SUBNET" == "true" ]]; then
IP_ADD_CMD="/ip address add address=${ADDRESS} interface=ether1"
else
IP_ADD_CMD="/ip address add address=${ADDRESS} interface=ether1 network=${GATEWAY}"
fi
cat > "$MOUNT_POINT/rw/autorun.scr" <<EOF
/ip dhcp-client remove [find]
${IP_ADD_CMD}
/ip route add dst-address=0.0.0.0/0 gateway=${GATEWAY}
/ip dns set servers=${DNS_SERVERS}
/user set 0 name=admin password=${ADMIN_PASSWORD}
/system identity set name=${ROUTER_NAME}
/system clock set time-zone-name=${TIMEZONE}
/system ntp client set enabled=yes
/system ntp client servers add address=pool.ntp.org
/ip service set telnet disabled=yes
/ip service set ftp disabled=yes
/ip service set www disabled=yes
/ip service set api disabled=yes
/ip service set api-ssl disabled=yes
/ip service set ssh disabled=no port=22
/ip service set winbox disabled=no
/ip neighbor discovery-settings set discover-interface-list=none
/tool mac-server set allowed-interface-list=none
/tool mac-server mac-winbox set allowed-interface-list=none
/tool mac-server ping set enabled=no
/ip pool add name=vpn-pool ranges=${VPN_POOL_START}-${VPN_POOL_END}
/ppp profile add name=vpn-profile local-address=${VPN_LOCAL_IP} remote-address=vpn-pool dns-server=${DNS_SERVERS} use-encryption=yes
/ppp secret add name=${VPN_USER} password=${VPN_USER_PASSWORD} profile=vpn-profile service=any
/interface pptp-server server set enabled=yes default-profile=vpn-profile authentication=mschap2
/interface l2tp-server server set enabled=yes default-profile=vpn-profile authentication=mschap2 use-ipsec=yes ipsec-secret=${IPSEC_SECRET}
/certificate add name=sstp-ca common-name=sstp-ca days-valid=3650 key-size=2048 key-usage=key-cert-sign,crl-sign
/certificate sign sstp-ca
/certificate add name=sstp-server common-name=${SERVER_IP} days-valid=3650 key-size=2048 key-usage=digital-signature,key-encipherment,tls-server
/certificate sign sstp-server ca=sstp-ca
/certificate set sstp-server trusted=yes
/interface sstp-server server set enabled=yes default-profile=vpn-profile authentication=mschap2 certificate=sstp-server port=${SSTP_PORT}
/certificate add name=ovpn-ca common-name=ovpn-ca days-valid=3650 key-size=2048 key-usage=key-cert-sign,crl-sign
/certificate sign ovpn-ca
/certificate add name=ovpn-server common-name=ovpn-server days-valid=3650 key-size=2048 key-usage=digital-signature,key-encipherment,tls-server
/certificate sign ovpn-server ca=ovpn-ca
/certificate set ovpn-server trusted=yes
/certificate add name=ovpn-client common-name=ovpn-client days-valid=3650 key-size=2048 key-usage=tls-client
/certificate sign ovpn-client ca=ovpn-ca
/interface ovpn-server server set enabled=yes default-profile=vpn-profile certificate=ovpn-server port=${OVPN_PORT}
/interface wireguard add name=wg0 listen-port=${WG_SERVER_PORT} private-key="${WG_SERVER_PRIVATE_KEY}"
/ip address add address=${WG_NETWORK%.*}.1/24 interface=wg0
/ip firewall nat add chain=srcnat src-address=${VPN_POOL} action=masquerade
/ip firewall nat add chain=srcnat src-address=${WG_NETWORK} action=masquerade
/ip firewall nat add chain=dstnat protocol=tcp dst-port=${OVPN_TCP_PORT} action=redirect to-ports=${OVPN_PORT}
/ip firewall filter add chain=input connection-state=established,related action=accept
/ip firewall filter add chain=input connection-state=invalid action=drop
/ip firewall filter add chain=input protocol=tcp dst-port=22 src-address-list=ssh_blacklist action=drop
/ip firewall filter add chain=input protocol=tcp dst-port=22 connection-state=new src-address-list=ssh_stage3 action=add-src-to-address-list address-list=ssh_blacklist address-list-timeout=1w
/ip firewall filter add chain=input protocol=tcp dst-port=22 connection-state=new src-address-list=ssh_stage2 action=add-src-to-address-list address-list=ssh_stage3 address-list-timeout=1m
/ip firewall filter add chain=input protocol=tcp dst-port=22 connection-state=new src-address-list=ssh_stage1 action=add-src-to-address-list address-list=ssh_stage2 address-list-timeout=1m
/ip firewall filter add chain=input protocol=tcp dst-port=22 connection-state=new action=add-src-to-address-list address-list=ssh_stage1 address-list-timeout=1m
/ip firewall filter add chain=input protocol=tcp dst-port=8291 src-address-list=winbox_blacklist action=drop
/ip firewall filter add chain=input protocol=tcp dst-port=8291 connection-state=new src-address-list=winbox_stage3 action=add-src-to-address-list address-list=winbox_blacklist address-list-timeout=1w
/ip firewall filter add chain=input protocol=tcp dst-port=8291 connection-state=new src-address-list=winbox_stage2 action=add-src-to-address-list address-list=winbox_stage3 address-list-timeout=1m
/ip firewall filter add chain=input protocol=tcp dst-port=8291 connection-state=new src-address-list=winbox_stage1 action=add-src-to-address-list address-list=winbox_stage2 address-list-timeout=1m
/ip firewall filter add chain=input protocol=tcp dst-port=8291 connection-state=new action=add-src-to-address-list address-list=winbox_stage1 address-list-timeout=1m
/ip dns set allow-remote-requests=no
/ip firewall filter add chain=input protocol=udp dst-port=53 action=drop
/ip firewall filter add chain=input protocol=tcp dst-port=53 action=drop
/ip firewall filter add chain=input protocol=icmp action=accept
/ip firewall filter add chain=input protocol=tcp dst-port=22 action=accept
/ip firewall filter add chain=input protocol=tcp dst-port=8291 action=accept
/ip firewall filter add chain=input protocol=tcp dst-port=1723 action=accept
/ip firewall filter add chain=input protocol=gre action=accept
/ip firewall filter add chain=input protocol=udp dst-port=500 action=accept
/ip firewall filter add chain=input protocol=udp dst-port=4500 action=accept
/ip firewall filter add chain=input protocol=udp dst-port=1701 action=accept
/ip firewall filter add chain=input protocol=ipsec-esp action=accept
/ip firewall filter add chain=input protocol=ipsec-ah action=accept
/ip firewall filter add chain=input protocol=tcp dst-port=${SSTP_PORT} action=accept
/ip firewall filter add chain=input protocol=tcp dst-port=${OVPN_PORT} action=accept
/ip firewall filter add chain=input protocol=udp dst-port=${OVPN_PORT} action=accept
/ip firewall filter add chain=input protocol=tcp dst-port=${OVPN_TCP_PORT} action=accept
/ip firewall filter add chain=input protocol=udp dst-port=${WG_SERVER_PORT} action=accept
/ip firewall filter add chain=input action=drop
/ip firewall filter add chain=forward connection-state=established,related action=accept
/ip firewall filter add chain=forward connection-state=invalid action=drop
/ip firewall filter add chain=forward src-address=${VPN_POOL} action=accept
/ip firewall filter add chain=forward src-address=${WG_NETWORK} action=accept
/ip firewall filter add chain=forward action=drop
/system script add name=backup-script source="/system backup save name=auto-backup"
/system scheduler add name=daily-backup interval=1d on-event=backup-script start-time=03:00:00
/system logging add topics=firewall action=memory
/system logging add topics=error action=memory
/system logging add topics=warning action=memory
/system logging add topics=pptp action=memory
/system logging add topics=l2tp action=memory
/system logging add topics=sstp action=memory
/system logging add topics=ovpn action=memory
/ip firewall nat add chain=srcnat out-interface=ether1 action=masquerade
/file remove [find name~"autorun"]
EOF
sync
# Для fat-chr (UEFI) дублируем autorun.scr в разные места
if [[ "$BOOT_MODE" == "UEFI" ]]; then
cp "$MOUNT_POINT/rw/autorun.scr" "$MOUNT_POINT/autorun.scr" 2>/dev/null || true
log_debug "Скопирован autorun.scr в корень раздела (для fat-chr)"
fi
log_debug "autorun.scr создан (строки 30-40):"
cat -n "$MOUNT_POINT/rw/autorun.scr" | sed -n '30,45p'
log_debug "Размер autorun.scr: $(wc -c < "$MOUNT_POINT/rw/autorun.scr") байт, строк: $(wc -l < "$MOUNT_POINT/rw/autorun.scr")"
if [[ ! -s "$MOUNT_POINT/rw/autorun.scr" ]]; then
log_error "autorun.scr пустой или не создан!"
umount "$MOUNT_POINT"
exit 1
fi
sync
umount "$MOUNT_POINT"
sync
# Проверка что autorun.scr сохранился в образе
log_debug "Проверка сохранения autorun.scr..."
mount -o loop,offset="$OFFSET_BYTES",ro "$CHR_IMG_MOD" "$MOUNT_POINT"
SAVED_SIZE=$(wc -c < "$MOUNT_POINT/rw/autorun.scr" 2>/dev/null || echo "0")
log_debug "Размер autorun.scr после umount/mount: $SAVED_SIZE байт"
if [[ "$SAVED_SIZE" -lt 100 ]]; then
log_error "autorun.scr не сохранился! Размер: $SAVED_SIZE байт"
cat "$MOUNT_POINT/rw/autorun.scr" 2>/dev/null || true
umount "$MOUNT_POINT"
exit 1
fi
log_debug "Первые строки сохранённого autorun.scr:"
head -5 "$MOUNT_POINT/rw/autorun.scr"
umount "$MOUNT_POINT"
# Проверка MD5 после модификации
MODIFIED_MD5=$(md5sum "$CHR_IMG_MOD" | awk '{print $1}')
log_debug "MD5 после модификации: $MODIFIED_MD5"
# Проверка MBR после модификации
MBR_SIG_MOD=$(xxd -s 510 -l 2 -p "$CHR_IMG_MOD")
if [[ "$MBR_SIG_MOD" != "55aa" ]]; then
log_error "MBR повреждён после модификации! Сигнатура: $MBR_SIG_MOD"
exit 1
fi
log_debug "MBR после модификации: OK"
FINAL_IMG="$CHR_IMG_MOD"
log_info "VPN настройка подготовлена ✓"
# ============================================
# ФИНАЛЬНОЕ ПОДТВЕРЖДЕНИЕ
# ============================================
echo ""
echo "============================================"
echo -e "${YELLOW} ТОЧКА НЕВОЗВРАТА!${NC}"
echo "============================================"
echo ""
echo "Образ: $FINAL_IMG"
echo "Диск: $DISK_DEVICE ($DISK_SIZE)"
echo "Режим: $BOOT_MODE"
echo "IP: $ADDRESS"
echo "Шлюз: $GATEWAY"
echo "Имя: $ROUTER_NAME"
echo "Часовой пояс: $TIMEZONE"
echo ""
echo -e "${GREEN}VPN серверы:${NC}"
echo " ✓ PPTP (порт 1723)"
echo " ✓ L2TP/IPsec (порт 1701, UDP 500/4500)"
echo " ✓ SSTP (порт $SSTP_PORT)"
echo " ✓ OpenVPN (порт $OVPN_PORT UDP/TCP, $OVPN_TCP_PORT TCP)"
echo " ✓ WireGuard (порт $WG_SERVER_PORT)"
echo ""
echo -e "${CYAN}Учётные данные VPN:${NC}"
echo " Пользователь: $VPN_USER"
echo " Пароль: $VPN_USER_PASSWORD"
echo " IPsec PSK: $IPSEC_SECRET"
echo " VPN пул: $VPN_POOL"
echo ""
echo -e "${CYAN}WireGuard:${NC}"
echo " Сервер: ${SERVER_IP}:${WG_SERVER_PORT}"
echo " Сеть: $WG_NETWORK"
echo " Server PrivKey: $WG_SERVER_PRIVATE_KEY"
echo " (Peer добавить вручную после получения публичного ключа клиента)"
echo ""
echo -e "${RED}ВСЕ ДАННЫЕ НА $DISK_DEVICE БУДУТ УНИЧТОЖЕНЫ!${NC}"
echo ""
if [[ "$AUTO_YES" == true ]]; then
log_warn "Автоматический режим (--yes), продолжаем без подтверждения..."
else
read -p "Введи 'YES' для продолжения: " confirm
if [[ "$confirm" != "YES" ]]; then
log_info "Отменено"
exit 0
fi
fi
# ============================================
# ЗАПИСЬ НА ДИСК
# ============================================
log_info "Запись образа на $DISK_DEVICE..."
log_info "Перевод файловой системы в read-only..."
sync
echo 1 > /proc/sys/kernel/sysrq
echo u > /proc/sysrq-trigger
sleep 2
dd if="$FINAL_IMG" of="$DISK_DEVICE" bs=4M oflag=sync status=progress
log_info "Запись завершена"
# ============================================
# ЗАВЕРШЕНИЕ
# ============================================
echo ""
log_info "=========================================="
log_info "Установка VPN-сервера завершена!"
log_info "=========================================="
echo ""
echo "CHR будет доступен: ${SERVER_IP}"
echo ""
echo -e "${GREEN}═══════════════════════════════════════════${NC}"
echo -e "${GREEN} СОХРАНИТЕ ЭТИ ДАННЫЕ!${NC}"
echo -e "${GREEN}═══════════════════════════════════════════${NC}"
echo ""
echo "Сервер: ${SERVER_IP}"
echo "Admin пароль: ${ADMIN_PASSWORD}"
echo ""
echo "PPTP/L2TP/SSTP/OpenVPN:"
echo " Пользователь: ${VPN_USER}"
echo " Пароль: ${VPN_USER_PASSWORD}"
echo " IPsec PSK: ${IPSEC_SECRET}"
echo ""
echo "WireGuard:"
echo " Endpoint: ${SERVER_IP}:${WG_SERVER_PORT}"
echo " Server Key: ${WG_SERVER_PRIVATE_KEY}"
echo " Сеть: ${WG_NETWORK}"
echo " Публичный ключ сервера получить: /interface wireguard print"
echo " Добавить peer: /interface wireguard peers add interface=wg0 public-key=КЛЮЧ_КЛИЕНТА allowed-address=10.10.20.2/32"
echo ""
echo -e "${GREEN}═══════════════════════════════════════════${NC}"
echo ""
if [[ "$AUTO_YES" == true && "$AUTO_REBOOT" == true ]]; then
log_info "Автоматическая перезагрузка через 5 секунд..."
sleep 5
echo 1 > /proc/sys/kernel/sysrq
echo s > /proc/sysrq-trigger
sleep 1
echo u > /proc/sysrq-trigger
sleep 1
echo b > /proc/sysrq-trigger
elif [[ "$AUTO_YES" == true ]]; then
log_info "Перезагрузи вручную: reboot"
else
read -p "Перезагрузить сейчас? (y/n): " do_reboot
if [[ "$do_reboot" == "y" ]]; then
log_info "Перезагрузка..."
sleep 2
echo 1 > /proc/sys/kernel/sysrq
echo s > /proc/sysrq-trigger
sleep 1
echo u > /proc/sysrq-trigger
sleep 1
echo b > /proc/sysrq-trigger
else
log_info "Перезагрузи вручную: reboot"
fi
fi