Машина переехала в сеть с серым адресом, извне до неё не достучаться. Туннель поднимается с её стороны наружу, машина получает постоянный 10.90.0.2, по которому её видит сервер. Через туннель идёт только трафик до сервера - интернет машины не затрагивается. Ключевая пара создаётся на самой машине, наружу уходит только открытый ключ. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
176 lines
7.6 KiB
PowerShell
176 lines
7.6 KiB
PowerShell
# Подключает машину ASR к серверу Talkscore через WireGuard.
|
|
#
|
|
# Зачем: у машины серый адрес, извне до неё не достучаться. Туннель она
|
|
# поднимает сама, наружу, и получает постоянный адрес 10.90.0.2, по которому
|
|
# сервер Talkscore к ней обращается.
|
|
#
|
|
# Через туннель ходит только трафик до 10.90.0.1 - обычный интернет машины
|
|
# не затрагивается.
|
|
#
|
|
# Запускать от имени администратора:
|
|
# powershell -ExecutionPolicy Bypass -File vpn-connect.ps1
|
|
#
|
|
# Проверить состояние:
|
|
# powershell -ExecutionPolicy Bypass -File vpn-connect.ps1 -Status
|
|
|
|
param(
|
|
[switch]$Status,
|
|
[switch]$Remove,
|
|
[string]$ServerPublicKey = "Qd9nsSZI1yAusMHSD68EWWa+1xZzO2coYY4iutJAa1Y=",
|
|
[string]$ServerEndpoint = "77.233.223.232:51820",
|
|
[string]$ClientAddress = "10.90.0.2/32",
|
|
[string]$ServerAddress = "10.90.0.1"
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
$TunnelName = "talkscore"
|
|
$WgDir = "$env:ProgramFiles\WireGuard"
|
|
$WgExe = Join-Path $WgDir "wg.exe"
|
|
$WireGuard = Join-Path $WgDir "wireguard.exe"
|
|
|
|
function Write-Step($text) { Write-Host "`n $text" -ForegroundColor Cyan }
|
|
function Write-Good($text) { Write-Host " $text" -ForegroundColor Green }
|
|
function Write-Warn($text) { Write-Host " $text" -ForegroundColor Yellow }
|
|
function Write-Bad($text) { Write-Host " $text" -ForegroundColor Red }
|
|
|
|
function Assert-Admin {
|
|
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
|
$principal = New-Object Security.Principal.WindowsPrincipal($identity)
|
|
if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
|
Write-Bad "Нужны права администратора: туннель ставится как служба Windows."
|
|
Write-Bad "Запустите PowerShell от имени администратора и повторите."
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
function Install-WireGuard {
|
|
if (Test-Path $WgExe) {
|
|
Write-Good "WireGuard уже установлен"
|
|
return
|
|
}
|
|
Write-Step "Ставлю WireGuard..."
|
|
# winget есть не на всех сборках, поэтому запасной путь - прямая загрузка.
|
|
$installed = $false
|
|
if (Get-Command winget -ErrorAction SilentlyContinue) {
|
|
winget install --id WireGuard.WireGuard --silent --accept-source-agreements `
|
|
--accept-package-agreements 2>&1 | Out-Null
|
|
$installed = Test-Path $WgExe
|
|
}
|
|
if (-not $installed) {
|
|
$url = "https://download.wireguard.com/windows-client/wireguard-installer.exe"
|
|
$tmp = Join-Path $env:TEMP "wireguard-installer.exe"
|
|
Write-Warn "winget не сработал, качаю установщик напрямую"
|
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
|
Invoke-WebRequest -Uri $url -OutFile $tmp -UseBasicParsing
|
|
Write-Warn "Может открыться окно установщика - пройдите его, скрипт подождёт."
|
|
Start-Process -FilePath $tmp -Wait
|
|
Remove-Item $tmp -Force -ErrorAction SilentlyContinue
|
|
}
|
|
if (-not (Test-Path $WgExe)) {
|
|
Write-Bad "Установить не удалось. Поставьте вручную: https://www.wireguard.com/install/"
|
|
exit 1
|
|
}
|
|
Write-Good "WireGuard установлен"
|
|
}
|
|
|
|
function Get-TunnelService {
|
|
Get-Service -Name "WireGuardTunnel`$$TunnelName" -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
function Show-Status {
|
|
$service = Get-TunnelService
|
|
if (-not $service) {
|
|
Write-Warn "Туннель не установлен. Запустите скрипт без ключей."
|
|
return
|
|
}
|
|
Write-Host " Служба: $($service.Status)"
|
|
if ($service.Status -ne "Running") {
|
|
Write-Warn "Туннель установлен, но не запущен: Start-Service '$($service.Name)'"
|
|
return
|
|
}
|
|
& $WgExe show $TunnelName
|
|
Write-Step "Проверка связи с сервером"
|
|
if (Test-Connection -ComputerName $ServerAddress -Count 2 -Quiet) {
|
|
Write-Good "$ServerAddress отвечает - туннель работает"
|
|
} else {
|
|
Write-Bad "$ServerAddress не отвечает."
|
|
Write-Bad "Обычная причина: публичный ключ этой машины ещё не добавлен на сервер."
|
|
}
|
|
}
|
|
|
|
function Remove-Tunnel {
|
|
if (-not (Get-TunnelService)) { Write-Warn "Туннеля нет"; return }
|
|
& $WireGuard /uninstalltunnelservice $TunnelName
|
|
Write-Good "Туннель удалён"
|
|
}
|
|
|
|
# --- основной сценарий ---
|
|
|
|
Assert-Admin
|
|
|
|
if ($Status) { Show-Status; exit 0 }
|
|
if ($Remove) { Remove-Tunnel; exit 0 }
|
|
|
|
Install-WireGuard
|
|
|
|
if (Get-TunnelService) {
|
|
Write-Warn "Туннель '$TunnelName' уже установлен."
|
|
Write-Warn "Чтобы пересоздать с новым ключом: запустите с -Remove, затем снова без ключей."
|
|
Show-Status
|
|
exit 0
|
|
}
|
|
|
|
Write-Step "Создаю ключи..."
|
|
# Ключевая пара делается здесь, на этой машине. Закрытый ключ её не покидает,
|
|
# наружу уходит только открытый - его и добавляют на сервер.
|
|
$privateKey = (& $WgExe genkey)
|
|
$publicKey = ($privateKey | & $WgExe pubkey)
|
|
|
|
$config = @"
|
|
[Interface]
|
|
PrivateKey = $privateKey
|
|
Address = $ClientAddress
|
|
|
|
[Peer]
|
|
PublicKey = $ServerPublicKey
|
|
Endpoint = $ServerEndpoint
|
|
# Только адрес сервера: остальной трафик машины через туннель не идёт.
|
|
AllowedIPs = $ServerAddress/32
|
|
# Серый адрес живёт за NAT, и без периодических пакетов сопоставление
|
|
# в таблице провайдера протухает через пару минут.
|
|
PersistentKeepalive = 25
|
|
"@
|
|
|
|
$configPath = Join-Path $env:TEMP "$TunnelName.conf"
|
|
# ASCII: в конфиге только ключи и адреса, кириллицы нет, а WireGuard
|
|
# разбирает файл построже большинства программ.
|
|
[IO.File]::WriteAllText($configPath, $config, [Text.Encoding]::ASCII)
|
|
|
|
Write-Step "Устанавливаю туннель как службу..."
|
|
& $WireGuard /installtunnelservice $configPath
|
|
Start-Sleep -Seconds 3
|
|
|
|
# Файл содержит закрытый ключ, а WireGuard уже скопировал конфигурацию себе.
|
|
Remove-Item $configPath -Force -ErrorAction SilentlyContinue
|
|
|
|
$service = Get-TunnelService
|
|
if (-not $service) {
|
|
Write-Bad "Служба не появилась. Посмотрите журнал в приложении WireGuard."
|
|
exit 1
|
|
}
|
|
Set-Service -Name $service.Name -StartupType Automatic
|
|
Write-Good "Туннель установлен и будет подниматься при загрузке"
|
|
|
|
Write-Host ""
|
|
Write-Host ("=" * 70)
|
|
Write-Host " ОТКРЫТЫЙ КЛЮЧ ЭТОЙ МАШИНЫ - передайте его для добавления на сервер:"
|
|
Write-Host ""
|
|
Write-Host " $publicKey" -ForegroundColor Yellow
|
|
Write-Host ""
|
|
Write-Host " Это не секрет, его можно пересылать открыто."
|
|
Write-Host " Пока ключ не добавлен на сервер, туннель работать не будет."
|
|
Write-Host ("=" * 70)
|
|
|
|
Write-Step "Текущее состояние"
|
|
Show-Status
|