前言
对于 WireGuard DDNS 刷新,Linux 中早有脚本,OpenWrt 中也有 wireguard_watchdog
只要直接设个定时任务就行了:
*/2 * * * * /usr/bin/wireguard_watchdog
但是,对于 Windows ,虽然有客户端,但官方一直都没集成 DDNS 解析,所以这边记录一下!
临时脚本
以前图省事,临时写了一个简陋的 bat:
@echo off
:loop
ping -n 1 192.168.11.1 > nul :: 改成要 ping 通的 wg
if %errorlevel% neq 0 (
net stop "WireGuard Tunnel: wg0" && net start "WireGuard Tunnel: wg0" :: 服务里面查看启动 wg Windows 客户端后的服务名称,一般“:”后的就是你的配置名
)
echo %DATE% %TIME% : I'M STILL ALIVE !
timeout /t 600 > nul
goto loop
pause
右键管理员身份运行就行了,大致是每隔一段时间 ping 一次 wg 目标,ping 不通就重启服务,问题有几个:
- 不通用(基本上 wg 配置好名称就写死了)
- 无开机启动
- 有个界面会一直挂在任务栏中
对我日常试用来说,影响基本很小,也达到了我的要求。但在某一次 wg 目标的外网 IP 改变了,恰恰这台 Windows 又擅自给我重启了。。。杯具发生了。。。
特别感谢
https://kenvix.com/post/wireguard-ddns-windows
为什么这次写在前面了呢?因为后面的可以不看,直接照着这位大佬的抄就行了,我只是拾人牙慧,外加一些自己的感想~
脚本
基本思路是这样的,把脚本做成 Windows 服务。首先如下脚本保存为 WireGuard-Reresolve.ps1
:
# Copyright (C) 2021 Max Schulze. All Rights Reserved.
# Modified by Kenvix <i@kenvix.com> @ 2023/9/15
#
# near-literal Translation of the linux version by Jason A. Donenfeld
# to decrypt the dpapi Credentials, you have to be the same user as the wireguard tunnel service, i.e. "nt authority\system", check with "whoami"
# this script might be called by task scheduler as
# powershell -NoProfile -NoLogo -NonInteractive -ExecutionPolicy Bypass -Command ./WireGuard-Reresolve.ps1 -LoopRunAsCron -DelaySeconds 600
# if you want to try it in cmd, remember to elevate the user, i.e. with psexec from sysutils
# psexec -s -i powershell -NoPr...
#Requires -RunAsAdministrator
param(
[switch]$LoopRunAsCron = $false,
[int]$DelaySeconds = 600
)
Set-StrictMode -Version 3
Add-Type -AssemblyName System.Security
function WireGuard-Reresolve {
param(
[Parameter(Mandatory=$true)]
[string]$File
)
Set-Variable CONFIG_FILE -Value $File.ToString().Trim('"')
if (-not (Test-Path -Path $CONFIG_FILE)) {
throw New-Object System.IO.FileNotFoundException("Wireguard Config $CONFIG_FILE File not found.", $CONFIG_FILE)
}
$byteCrypted = ((Get-Content -LiteralPath $CONFIG_FILE -Encoding Byte -ReadCount 0))
$config = [System.Security.Cryptography.ProtectedData]::Unprotect($byteCrypted,$null,[System.Security.Cryptography.DataProtectionScope]::LocalMachine)
$config = [System.Text.UTF8Encoding]::UTF8.GetString($config)
Set-Variable Interface -Option Constant -Value $(if ($CONFIG_FILE -match '.?([a-zA-Z0-9_=+.-]{1,64})\.conf.dpapi$') { $matches[1] } else { $null })
function process_peer () {
if (-not $PEER_SECTION -or ($PUBLIC_KEY -eq $null) -or ($ENDPOINT -eq $null)) { return }
if (-not ((& wg show "$INTERFACE" latest-handshakes) -replace $PUBLIC_KEY -match ('[0-9]+'))) { return }
if (((Get-Date) - (New-Object -Type DateTime -ArgumentList 1970,1,1,0,0,0,0).AddSeconds($matches[0]).ToLocalTime()).TotalSeconds -le 135) { return }
(& wg set "$INTERFACE" peer "$PUBLIC_KEY" endpoint "$ENDPOINT")
reset_peer_section
}
function reset_peer_section () {
Set-Variable PEER_SECTION -Value $null
Set-Variable PUBLIC_KEY -Value $null
Set-Variable ENDPOINT -Value $null
}
reset_peer_section
Set-Variable PEER_SECTION -Value $null
foreach ($line in $config.Split([Environment]::NewLine,[StringSplitOptions]::RemoveEmptyEntries))
{
if ($line.Trim().length -gt 0) {
$stripped = $line.Trim() -ireplace '\#.*'
$key = $stripped -ireplace '=.*'; $key = $key.Trim()
$val = $stripped -ireplace '^.*?='; $val = $val.Trim()
if ($key -match '\[.*') { process_peer; reset_peer_section; }
if ($key -eq '[Peer]') { $PEER_SECTION = $true }
if ($PEER_SECTION) {
switch ($key) {
"PublicKey" { $PUBLIC_KEY = $val; continue; }
"Endpoint" { $ENDPOINT = $val; continue; }
}
}
}
}
process_peer
}
function WireGuard-Reresolve-All-Active {
Get-Service -Name "WireGuardTunnel$*" `
| Where-Object {$_.Status -eq "Running"} `
| ForEach-Object { $_.Name.Substring(16) } `
| ForEach-Object { Get-ChildItem -File "$env:programfiles\wireguard\data\configurations\$_.conf.dpapi" } `
| ForEach-Object { WireGuard-Reresolve $_.FullName}
}
if ($LoopRunAsCron) {
echo "Running as Cron DelaySeconds=$DelaySeconds"
while ($true) {
WireGuard-Reresolve-All-Active
Start-Sleep -Seconds $DelaySeconds
}
}
这个脚本同 wg 官方的脚本一样,也是检查 wg keepalive 的时间,如果超过了规定值就重新解析一下 DDNS 服务!
设置 powershell 权限
管理员身份运行 powershell,输入如下命令:
Set-ExecutionPolicy RemoteSigned
回车后输入 y
再回车,确认更改策略。
做成服务
这一步是最最最坑的,我差点放弃!🤦
因为本着能懒则懒的原则,不想多下一个应用,首先 cmd 管理员中用 SC
添加了服务,结果启动失败!然后 powershell 管理员中用 New-Service
添加了服务,启动依然不行!而大佬的备注中有一句:
该脚本必须以 SYSTEM 用户身份执行,否则无法解密 WireGuard 的配置文件。
我曾一度为服务如何试用 SYSTEM 账户运行而找原因。。。事实证明这也是我遇到的问题之一,但要靠后的多。。。
最后,还是下载了 shawl ,只是个单文件,找个目录放就行了!之后管理员身份运行 cmd,定位到 shawl 文件所在目录下,添加下服务:
shawl add --name WireGuard-Reresolve -- powershell -NoProfile -NoLogo -NonInteractive -ExecutionPolicy Bypass -Command "D:\wg\WireGuard-Reresolve.ps1" -LoopRunAsCron -DelaySeconds 250
"D:\wg\WireGuard-Reresolve.ps1"
这里的路径改成你自己的脚本路径!奇迹发生,服务居然启动起来了。。。。。。
对服务配置 SYSTEM 权限
首先 Win+R
打开运行框,输入 services.msc
打开服务窗口,选择我们刚刚添加的服务 WireGuard-Reresolve 双击编辑,切换到登录框配置如下:
选择此账户,输入 nt authority\system
即 SYSTEM 账户,然后输入你的登录密码确认,就更改服务了!可以点启动,启动下服务,看看进程里面是否以 SYSTEM 运行了!
shawl.exe
同目录下会自动生成日志,可以关注运行情况!
Comments 4 条评论
博主 27241500
一个脚本搞定的事情:
schtasks /create /tn “update_wg” /ru system /sc minute /mo 2 /tr " ‘C:Program FilesWireGuardwg.exe’ syncconf wg0 d:wg0.conf "
博主 刘祖韬
schtasks /create /tn “update_wg” /ru system /sc minute /mo 2 /tr " ‘C:Program FilesWireGuardwg.exe’ syncconf wg0 d:wg0.conf "
博主 刘祖韬
上面exe文件路径的反斜杠被网站吞并了,需要自己加上。
博主 刘祖韬
就windows系统里面添加一个任务,2分钟运行一次,wg.exe去重新读一下配置文件,如果dns对应的ip地址变了,会自动按芯的ip地址配置。