mirror of
https://github.com/bunny-lab-io/Borealis.git
synced 2026-02-04 12:30:30 -07:00
Continued WireGuard troubleshooting
This commit is contained in:
731
Borealis.ps1
731
Borealis.ps1
@@ -523,6 +523,10 @@ $wireGuardInstallerDir = Join-Path $depsRoot 'VPN_Tunnel_Adapter'
|
|||||||
$wireGuardBootstrapperName = 'wireguard-installer.exe'
|
$wireGuardBootstrapperName = 'wireguard-installer.exe'
|
||||||
$wireGuardBootstrapperPath = Join-Path $wireGuardInstallerDir $wireGuardBootstrapperName
|
$wireGuardBootstrapperPath = Join-Path $wireGuardInstallerDir $wireGuardBootstrapperName
|
||||||
$wireGuardMsiVersion = '0.5.3'
|
$wireGuardMsiVersion = '0.5.3'
|
||||||
|
$wireGuardTunnelLegacyName = 'BorealisWireGuardTunnel'
|
||||||
|
$wireGuardTunnelNameInternal = 'Borealis'
|
||||||
|
$wireGuardTunnelNameFriendly = 'Borealis'
|
||||||
|
$wireGuardTunnelBootstrapAddress = '169.254.255.254/32'
|
||||||
$wireGuardMsiFiles = @{
|
$wireGuardMsiFiles = @{
|
||||||
'X64' = "wireguard-amd64-$wireGuardMsiVersion.msi"
|
'X64' = "wireguard-amd64-$wireGuardMsiVersion.msi"
|
||||||
'AMD64' = "wireguard-amd64-$wireGuardMsiVersion.msi"
|
'AMD64' = "wireguard-amd64-$wireGuardMsiVersion.msi"
|
||||||
@@ -702,6 +706,10 @@ function Install_Agent_Dependencies {
|
|||||||
ServicePresent = $false
|
ServicePresent = $false
|
||||||
DriverPresent = $false
|
DriverPresent = $false
|
||||||
DriverPaths = @()
|
DriverPaths = @()
|
||||||
|
AdapterPresent = $false
|
||||||
|
AdapterNames = @()
|
||||||
|
DedicatedAdapterPresent = $false
|
||||||
|
DedicatedAdapterNames = @()
|
||||||
}
|
}
|
||||||
|
|
||||||
$exeCandidates = @(
|
$exeCandidates = @(
|
||||||
@@ -748,6 +756,29 @@ function Install_Agent_Dependencies {
|
|||||||
$state.DriverPaths = $driverHits | Select-Object -Unique
|
$state.DriverPaths = $driverHits | Select-Object -Unique
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$adapters = Get-WireGuardAdapters
|
||||||
|
if ($adapters) {
|
||||||
|
$state.AdapterPresent = $true
|
||||||
|
$state.AdapterNames = $adapters | Select-Object -ExpandProperty Name -Unique
|
||||||
|
$state.DriverPresent = $true
|
||||||
|
$state.Installed = $true
|
||||||
|
}
|
||||||
|
|
||||||
|
$dedicated = @()
|
||||||
|
foreach ($adapter in ($adapters | Where-Object { $_ })) {
|
||||||
|
if (Test-WireGuardAdapterName -Adapter $adapter -ExpectedName $wireGuardTunnelNameFriendly) {
|
||||||
|
$dedicated += $adapter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($dedicated.Count -gt 0) {
|
||||||
|
$state.DedicatedAdapterPresent = $true
|
||||||
|
$state.DedicatedAdapterNames = $dedicated | Select-Object -ExpandProperty Name -Unique
|
||||||
|
$state.DriverPresent = $true
|
||||||
|
$state.Installed = $true
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
|
||||||
$uninstallRoots = @(
|
$uninstallRoots = @(
|
||||||
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall',
|
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall',
|
||||||
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall'
|
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall'
|
||||||
@@ -836,29 +867,51 @@ function Install_Agent_Dependencies {
|
|||||||
)
|
)
|
||||||
|
|
||||||
$pair = @{ PrivateKey = $null; PublicKey = $null; Source = $null }
|
$pair = @{ PrivateKey = $null; PublicKey = $null; Source = $null }
|
||||||
$cliCandidates = @()
|
$wgCli = $null
|
||||||
if ($WgExe) { $cliCandidates += $WgExe }
|
if ($WgExe -and (Test-Path $WgExe -PathType Leaf)) { $wgCli = $WgExe }
|
||||||
if ($WireGuardExe) { $cliCandidates += $WireGuardExe }
|
|
||||||
|
|
||||||
foreach ($cli in $cliCandidates) {
|
$priv = $null
|
||||||
if (-not $cli -or -not (Test-Path $cli -PathType Leaf)) { continue }
|
if ($wgCli) {
|
||||||
try {
|
try { $priv = (& $wgCli genkey) } catch {}
|
||||||
# Only wg.exe supports genkey; wireguard.exe likely won't, but attempt anyway
|
|
||||||
$priv = (& $cli genkey)
|
|
||||||
if ($priv) {
|
if ($priv) {
|
||||||
$priv = $priv.Trim()
|
$priv = $priv.Trim()
|
||||||
$pair.PrivateKey = $priv
|
$pair.PrivateKey = $priv
|
||||||
$pair.Source = $cli
|
$pair.Source = $wgCli
|
||||||
try {
|
try {
|
||||||
$padLen = 4 - ($priv.Length % 4)
|
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
||||||
$privForPub = $priv
|
$psi.FileName = $wgCli
|
||||||
if ($padLen -lt 4) {
|
$psi.Arguments = 'pubkey'
|
||||||
$privForPub = $priv + ('=' * $padLen)
|
$psi.RedirectStandardInput = $true
|
||||||
|
$psi.RedirectStandardOutput = $true
|
||||||
|
$psi.RedirectStandardError = $true
|
||||||
|
$psi.UseShellExecute = $false
|
||||||
|
$psi.CreateNoWindow = $true
|
||||||
|
if ($psi.PSObject.Properties.Name -contains 'StandardInputEncoding') {
|
||||||
|
$psi.StandardInputEncoding = [System.Text.Encoding]::ASCII
|
||||||
|
}
|
||||||
|
if ($psi.PSObject.Properties.Name -contains 'StandardOutputEncoding') {
|
||||||
|
$psi.StandardOutputEncoding = [System.Text.Encoding]::ASCII
|
||||||
|
}
|
||||||
|
$proc = New-Object System.Diagnostics.Process
|
||||||
|
$proc.StartInfo = $psi
|
||||||
|
$proc.Start() | Out-Null
|
||||||
|
$proc.StandardInput.WriteLine($priv)
|
||||||
|
$proc.StandardInput.Close()
|
||||||
|
$pub = $proc.StandardOutput.ReadToEnd()
|
||||||
|
$proc.WaitForExit()
|
||||||
|
if ($proc.ExitCode -eq 0 -and $pub) {
|
||||||
|
$pair.PublicKey = $pub.Trim()
|
||||||
}
|
}
|
||||||
$pub = ($privForPub | & $cli pubkey)
|
|
||||||
if ($pub) { $pair.PublicKey = $pub.Trim() }
|
|
||||||
} catch {}
|
} catch {}
|
||||||
break
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $pair.PrivateKey -and $WireGuardExe -and (Test-Path $WireGuardExe -PathType Leaf)) {
|
||||||
|
try {
|
||||||
|
$priv = (& $WireGuardExe genkey)
|
||||||
|
if ($priv) {
|
||||||
|
$pair.PrivateKey = $priv.Trim()
|
||||||
|
$pair.Source = $WireGuardExe
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
@@ -878,6 +931,504 @@ function Install_Agent_Dependencies {
|
|||||||
return $pair
|
return $pair
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Find-WireGuardDriverInf {
|
||||||
|
param(
|
||||||
|
[Parameter()][string]$LogName = 'Install.log'
|
||||||
|
)
|
||||||
|
|
||||||
|
$logPrefix = '[WireGuard]'
|
||||||
|
$output = $null
|
||||||
|
try {
|
||||||
|
$output = & pnputil.exe /enum-drivers
|
||||||
|
} catch {
|
||||||
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix pnputil /enum-drivers failed: {0}" -f $_.Exception.Message)
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $output) { return $null }
|
||||||
|
$published = $null
|
||||||
|
$original = $null
|
||||||
|
$provider = $null
|
||||||
|
foreach ($line in ($output -split "`r?`n")) {
|
||||||
|
if (-not $line.Trim()) {
|
||||||
|
if ($published -and ($original -match '^(wireguard|wintun)\.inf$' -or $provider -like '*WireGuard*')) {
|
||||||
|
return $published
|
||||||
|
}
|
||||||
|
$published = $null
|
||||||
|
$original = $null
|
||||||
|
$provider = $null
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ($line -match 'Published Name\s*:\s*(\S+)') {
|
||||||
|
$published = $Matches[1].Trim()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ($line -match 'Original Name\s*:\s*(\S+)') {
|
||||||
|
$original = $Matches[1].Trim()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ($line -match 'Provider Name\s*:\s*(.+)') {
|
||||||
|
$provider = $Matches[1].Trim()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($published -and ($original -match '^(wireguard|wintun)\.inf$' -or $provider -like '*WireGuard*')) {
|
||||||
|
return $published
|
||||||
|
}
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-WireGuardAdapters {
|
||||||
|
param([string]$NameFilter)
|
||||||
|
|
||||||
|
$args = @{
|
||||||
|
Namespace = 'root/StandardCimv2'
|
||||||
|
ClassName = 'MSFT_NetAdapter'
|
||||||
|
ErrorAction = 'SilentlyContinue'
|
||||||
|
}
|
||||||
|
if ($NameFilter) {
|
||||||
|
$args.Filter = "Name='$NameFilter'"
|
||||||
|
} else {
|
||||||
|
$args.Filter = "InterfaceDescription LIKE '%WireGuard%'"
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$opTimeout = (Get-Command Get-CimInstance).Parameters.ContainsKey('OperationTimeoutSec')
|
||||||
|
if ($opTimeout) { $args.OperationTimeoutSec = 10 }
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return Get-CimInstance @args
|
||||||
|
} catch {
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-WireGuardAdapterName {
|
||||||
|
param(
|
||||||
|
[Parameter()][object]$Adapter,
|
||||||
|
[Parameter(Mandatory = $true)][string]$ExpectedName
|
||||||
|
)
|
||||||
|
|
||||||
|
if (-not $Adapter -or -not $ExpectedName) { return $false }
|
||||||
|
$adapterName = $Adapter.Name
|
||||||
|
if (-not $adapterName) { return $false }
|
||||||
|
if ($adapterName.ToString().Trim().ToLowerInvariant() -ne $ExpectedName.ToLowerInvariant()) {
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
$desc = $Adapter.InterfaceDescription
|
||||||
|
if (-not $desc) {
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
if ($desc.ToString() -notlike '*WireGuard*') {
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
return $true
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-WireGuardAdapterByName {
|
||||||
|
param([string]$AdapterName)
|
||||||
|
|
||||||
|
if (-not $AdapterName) { return $null }
|
||||||
|
try {
|
||||||
|
$adapters = Get-WireGuardAdapters -NameFilter $AdapterName
|
||||||
|
if ($adapters) {
|
||||||
|
foreach ($adapter in @($adapters)) {
|
||||||
|
if (Test-WireGuardAdapterName -Adapter $adapter -ExpectedName $AdapterName) {
|
||||||
|
return $adapter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
function Rename-WireGuardAdapterName {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)][string]$OldName,
|
||||||
|
[Parameter(Mandatory = $true)][string]$NewName,
|
||||||
|
[Parameter()][string]$LogName = 'Install.log'
|
||||||
|
)
|
||||||
|
|
||||||
|
$logPrefix = '[WireGuard]'
|
||||||
|
if ($OldName -eq $NewName) { return $true }
|
||||||
|
$args = "interface set interface name=`"$OldName`" newname=`"$NewName`""
|
||||||
|
$proc = Start-Process -FilePath 'netsh.exe' -ArgumentList $args -PassThru -WindowStyle Hidden -ErrorAction SilentlyContinue
|
||||||
|
if (-not $proc) {
|
||||||
|
Write-AgentLog -FileName $LogName -Message "$logPrefix netsh rename failed to start."
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
if (-not $proc.WaitForExit(10000)) {
|
||||||
|
try { $proc.Kill() } catch {}
|
||||||
|
Write-AgentLog -FileName $LogName -Message "$logPrefix netsh rename timed out."
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
if ($proc.ExitCode -ne 0) {
|
||||||
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix netsh rename failed with exit code {0}." -f $proc.ExitCode)
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix Renamed adapter {0} -> {1}" -f $OldName, $NewName)
|
||||||
|
return $true
|
||||||
|
}
|
||||||
|
|
||||||
|
function Remove-WireGuardTunnelService {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)][string]$TunnelName,
|
||||||
|
[Parameter(Mandatory = $true)][string]$WireGuardExe,
|
||||||
|
[Parameter()][string]$LogName = 'Install.log'
|
||||||
|
)
|
||||||
|
|
||||||
|
if (-not $TunnelName) { return }
|
||||||
|
$logPrefix = '[WireGuard]'
|
||||||
|
$serviceName = "WireGuardTunnel$TunnelName"
|
||||||
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix Cleaning tunnel service {0}" -f $serviceName)
|
||||||
|
$serviceExists = $false
|
||||||
|
try {
|
||||||
|
$svc = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
|
||||||
|
if ($svc) { $serviceExists = $true }
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
if ($serviceExists) {
|
||||||
|
try {
|
||||||
|
$proc = Start-Process -FilePath 'sc.exe' -ArgumentList 'stop', $serviceName -PassThru -WindowStyle Hidden -ErrorAction SilentlyContinue
|
||||||
|
if ($proc) {
|
||||||
|
if (-not $proc.WaitForExit(10000)) {
|
||||||
|
try { $proc.Kill() } catch {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
} else {
|
||||||
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix Tunnel service {0} not present; skipping stop/uninstall." -f $serviceName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($serviceExists -and $WireGuardExe -and (Test-Path $WireGuardExe -PathType Leaf)) {
|
||||||
|
try {
|
||||||
|
$proc = Start-Process -FilePath $WireGuardExe -ArgumentList @('/uninstalltunnelservice', $TunnelName) -PassThru -WindowStyle Hidden -ErrorAction SilentlyContinue
|
||||||
|
if ($proc) {
|
||||||
|
if (-not $proc.WaitForExit(15000)) {
|
||||||
|
try { $proc.Kill() } catch {}
|
||||||
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix /uninstalltunnelservice timed out for {0}" -f $TunnelName)
|
||||||
|
} else {
|
||||||
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix /uninstalltunnelservice exit code for {0}: {1}" -f $TunnelName, $proc.ExitCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($serviceExists) {
|
||||||
|
try {
|
||||||
|
$proc = Start-Process -FilePath 'sc.exe' -ArgumentList 'delete', $serviceName -PassThru -WindowStyle Hidden -ErrorAction SilentlyContinue
|
||||||
|
if ($proc) {
|
||||||
|
if (-not $proc.WaitForExit(10000)) {
|
||||||
|
try { $proc.Kill() } catch {}
|
||||||
|
} else {
|
||||||
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix sc delete exit code for {0}: {1}" -f $serviceName, $proc.ExitCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$confPaths = Get-WireGuardConfigPaths -TunnelName $TunnelName
|
||||||
|
foreach ($confPath in $confPaths) {
|
||||||
|
if ($confPath -and (Test-Path $confPath -PathType Leaf)) {
|
||||||
|
Remove-Item -Path $confPath -Force -ErrorAction SilentlyContinue
|
||||||
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix Removed tunnel config {0}" -f $confPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-WireGuardConfigPaths {
|
||||||
|
param([string]$TunnelName)
|
||||||
|
|
||||||
|
if (-not $TunnelName) { return @() }
|
||||||
|
$paths = @()
|
||||||
|
$borealisConfigDir = $null
|
||||||
|
try {
|
||||||
|
if ($scriptDir) {
|
||||||
|
$borealisConfigDir = Join-Path $scriptDir 'Agent\Borealis\Settings\WireGuard'
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
if ($borealisConfigDir) {
|
||||||
|
$paths += $borealisConfigDir
|
||||||
|
}
|
||||||
|
if ($env:ProgramFiles) {
|
||||||
|
$paths += (Join-Path $env:ProgramFiles 'WireGuard\Data\Configurations')
|
||||||
|
}
|
||||||
|
$programDataRoot = if ($env:ProgramData) { $env:ProgramData } else { 'C:\ProgramData' }
|
||||||
|
if ($programDataRoot) {
|
||||||
|
$paths += (Join-Path $programDataRoot 'Borealis\WireGuard\Configurations')
|
||||||
|
}
|
||||||
|
if ($wireGuardInstallerDir) {
|
||||||
|
$paths += $wireGuardInstallerDir
|
||||||
|
}
|
||||||
|
$paths = $paths | Where-Object { $_ }
|
||||||
|
$confPaths = @()
|
||||||
|
foreach ($dir in $paths) {
|
||||||
|
$confPaths += (Join-Path $dir "$TunnelName.conf")
|
||||||
|
}
|
||||||
|
return $confPaths | Select-Object -Unique
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-WireGuardConfigPath {
|
||||||
|
param([string]$TunnelName)
|
||||||
|
|
||||||
|
if (-not $TunnelName) { return $null }
|
||||||
|
$confPaths = Get-WireGuardConfigPaths -TunnelName $TunnelName
|
||||||
|
foreach ($confPath in $confPaths) {
|
||||||
|
if (-not $confPath) { continue }
|
||||||
|
$dir = Split-Path $confPath -Parent
|
||||||
|
try {
|
||||||
|
if ($dir -and -not (Test-Path $dir)) {
|
||||||
|
New-Item -ItemType Directory -Path $dir -Force | Out-Null
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
if ($dir -and (Test-Path $dir)) {
|
||||||
|
return $confPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $confPaths | Select-Object -First 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-WireGuardTunnelServiceConfigPath {
|
||||||
|
param([string]$ServiceName)
|
||||||
|
|
||||||
|
if (-not $ServiceName) { return $null }
|
||||||
|
$regPath = "HKLM:\SYSTEM\CurrentControlSet\Services\$ServiceName"
|
||||||
|
try {
|
||||||
|
$imagePath = (Get-ItemProperty -Path $regPath -Name ImagePath -ErrorAction Stop).ImagePath
|
||||||
|
} catch {
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
if (-not $imagePath) { return $null }
|
||||||
|
$text = $imagePath.ToString()
|
||||||
|
if ($text -match '(?i)/tunnelservice\s+"([^"]+)"') {
|
||||||
|
return $Matches[1]
|
||||||
|
}
|
||||||
|
if ($text -match '(?i)/tunnelservice\s+(\S+)') {
|
||||||
|
return $Matches[1]
|
||||||
|
}
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ensure-WireGuardTunnelAdapter {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)][string]$WireGuardExe,
|
||||||
|
[Parameter()][string]$LogName = 'Install.log'
|
||||||
|
)
|
||||||
|
|
||||||
|
$logPrefix = '[WireGuard]'
|
||||||
|
$friendlyName = $wireGuardTunnelNameFriendly
|
||||||
|
$internalName = $wireGuardTunnelNameInternal
|
||||||
|
$serviceName = "WireGuardTunnel$internalName"
|
||||||
|
|
||||||
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix Ensuring tunnel adapter: {0}" -f $friendlyName)
|
||||||
|
$existing = Get-WireGuardAdapterByName -AdapterName $friendlyName
|
||||||
|
if ($existing) {
|
||||||
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix Adapter already present: {0}" -f $friendlyName)
|
||||||
|
return $true
|
||||||
|
}
|
||||||
|
|
||||||
|
$internalAdapter = Get-WireGuardAdapterByName -AdapterName $internalName
|
||||||
|
if ($internalAdapter) {
|
||||||
|
if ($friendlyName -and $friendlyName -ne $internalName) {
|
||||||
|
$renamed = Rename-WireGuardAdapterName -OldName $internalName -NewName $friendlyName -LogName $LogName
|
||||||
|
if ($renamed) { return $true }
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
return $true
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$wgCliExe = $null
|
||||||
|
try {
|
||||||
|
$wgCliCandidate = Join-Path (Split-Path $WireGuardExe -Parent) 'wg.exe'
|
||||||
|
if (Test-Path $wgCliCandidate -PathType Leaf) { $wgCliExe = $wgCliCandidate }
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
$serviceConfigPath = Get-WireGuardTunnelServiceConfigPath -ServiceName $serviceName
|
||||||
|
$existingService = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
|
||||||
|
$servicePresent = $false
|
||||||
|
if ($existingService -or $serviceConfigPath) { $servicePresent = $true }
|
||||||
|
if ($servicePresent) {
|
||||||
|
$serviceConfigPath = Get-WireGuardTunnelServiceConfigPath -ServiceName $serviceName
|
||||||
|
if ($serviceConfigPath -and -not (Test-Path $serviceConfigPath -PathType Leaf)) {
|
||||||
|
$keyPair = New-WireGuardKeyPair -WireGuardExe $WireGuardExe -WgExe $wgCliExe
|
||||||
|
if ($keyPair.PrivateKey) {
|
||||||
|
$conf = @"
|
||||||
|
[Interface]
|
||||||
|
PrivateKey = $($keyPair.PrivateKey.Trim())
|
||||||
|
Address = $wireGuardTunnelBootstrapAddress
|
||||||
|
ListenPort = 0
|
||||||
|
"@
|
||||||
|
try {
|
||||||
|
$dir = Split-Path $serviceConfigPath -Parent
|
||||||
|
if ($dir -and -not (Test-Path $dir)) {
|
||||||
|
New-Item -ItemType Directory -Path $dir -Force | Out-Null
|
||||||
|
}
|
||||||
|
Set-Content -Path $serviceConfigPath -Value $conf -Encoding ASCII -Force
|
||||||
|
if (Test-Path $serviceConfigPath -PathType Leaf) {
|
||||||
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix Created adapter config at {0}" -f $serviceConfigPath)
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix Failed to write adapter config at {0}: {1}" -f $serviceConfigPath, $_.Exception.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-AgentLog -FileName $LogName -Message "$logPrefix Tunnel service already present; restarting to provision adapter."
|
||||||
|
try { Stop-Service -Name $serviceName -Force -ErrorAction SilentlyContinue } catch {}
|
||||||
|
try { Start-Service -Name $serviceName -ErrorAction SilentlyContinue } catch {}
|
||||||
|
for ($i = 0; $i -lt 10; $i++) {
|
||||||
|
Start-Sleep -Milliseconds 500
|
||||||
|
if (Get-WireGuardAdapterByName -AdapterName $friendlyName) { return $true }
|
||||||
|
}
|
||||||
|
Write-AgentLog -FileName $LogName -Message "$logPrefix Tunnel service present but adapter missing; uninstalling before reinstall."
|
||||||
|
}
|
||||||
|
|
||||||
|
Remove-WireGuardTunnelService -TunnelName $internalName -WireGuardExe $WireGuardExe -LogName $LogName
|
||||||
|
if ($wireGuardTunnelLegacyName -and $wireGuardTunnelLegacyName -ne $internalName) {
|
||||||
|
Remove-WireGuardTunnelService -TunnelName $wireGuardTunnelLegacyName -WireGuardExe $WireGuardExe -LogName $LogName
|
||||||
|
}
|
||||||
|
for ($i = 0; $i -lt 10; $i++) {
|
||||||
|
Start-Sleep -Milliseconds 500
|
||||||
|
$stillPresent = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
|
||||||
|
$stillConfig = Get-WireGuardTunnelServiceConfigPath -ServiceName $serviceName
|
||||||
|
if (-not $stillPresent -and -not $stillConfig) { break }
|
||||||
|
}
|
||||||
|
$serviceStillPresent = $false
|
||||||
|
if (Get-Service -Name $serviceName -ErrorAction SilentlyContinue) { $serviceStillPresent = $true }
|
||||||
|
if (Get-WireGuardTunnelServiceConfigPath -ServiceName $serviceName) { $serviceStillPresent = $true }
|
||||||
|
if ($serviceStillPresent) {
|
||||||
|
Write-AgentLog -FileName $LogName -Message "$logPrefix Tunnel service still present after uninstall; skipping reinstall to avoid WireGuard dialog."
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (-not (Test-Path $wireGuardInstallerDir)) {
|
||||||
|
New-Item -ItemType Directory -Path $wireGuardInstallerDir -Force | Out-Null
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
$keyPair = New-WireGuardKeyPair -WireGuardExe $WireGuardExe -WgExe $wgCliExe
|
||||||
|
if (-not $keyPair.PrivateKey) {
|
||||||
|
Write-AgentLog -FileName $LogName -Message "$logPrefix Failed to generate WireGuard keypair for adapter provision."
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
|
||||||
|
$conf = @"
|
||||||
|
[Interface]
|
||||||
|
PrivateKey = $($keyPair.PrivateKey.Trim())
|
||||||
|
Address = $wireGuardTunnelBootstrapAddress
|
||||||
|
ListenPort = 0
|
||||||
|
"@
|
||||||
|
$confPath = $null
|
||||||
|
$confPaths = Get-WireGuardConfigPaths -TunnelName $internalName
|
||||||
|
if ($serviceConfigPath) {
|
||||||
|
$confPaths = @($serviceConfigPath) + ($confPaths | Where-Object { $_ -ne $serviceConfigPath })
|
||||||
|
}
|
||||||
|
foreach ($candidate in $confPaths) {
|
||||||
|
if (-not $candidate) { continue }
|
||||||
|
$dir = Split-Path $candidate -Parent
|
||||||
|
try {
|
||||||
|
if ($dir -and -not (Test-Path $dir)) {
|
||||||
|
New-Item -ItemType Directory -Path $dir -Force | Out-Null
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
try {
|
||||||
|
Set-Content -Path $candidate -Value $conf -Encoding ASCII -Force
|
||||||
|
if (Test-Path $candidate -PathType Leaf) {
|
||||||
|
$confPath = $candidate
|
||||||
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix Created adapter config at {0}" -f $confPath)
|
||||||
|
$borealisConfigDir = $null
|
||||||
|
try {
|
||||||
|
if ($scriptDir) {
|
||||||
|
$borealisConfigDir = Join-Path $scriptDir 'Agent\Borealis\Settings\WireGuard'
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
if ($borealisConfigDir) {
|
||||||
|
try {
|
||||||
|
$confFull = [System.IO.Path]::GetFullPath($confPath)
|
||||||
|
$borealisFull = [System.IO.Path]::GetFullPath($borealisConfigDir)
|
||||||
|
if ($confFull.ToLowerInvariant().StartsWith($borealisFull.ToLowerInvariant()) -eq $false) {
|
||||||
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix Adapter config stored outside Borealis settings: {0}" -f $confPath)
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix Adapter config not found after write: {0}" -f $candidate)
|
||||||
|
} catch {
|
||||||
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix Failed to write adapter config at {0}: {1}" -f $candidate, $_.Exception.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $confPath) {
|
||||||
|
Write-AgentLog -FileName $LogName -Message "$logPrefix Failed to write adapter config to any candidate path."
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
|
||||||
|
$svcPreInstall = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
|
||||||
|
$svcConfig = Get-WireGuardTunnelServiceConfigPath -ServiceName $serviceName
|
||||||
|
if (-not $svcPreInstall -and -not $svcConfig) {
|
||||||
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix Installing tunnel service {0} for adapter provisioning with config {1}." -f $serviceName, $confPath)
|
||||||
|
$installArgs = "/installtunnelservice `"$confPath`""
|
||||||
|
$proc = Start-Process -FilePath $WireGuardExe -ArgumentList $installArgs -PassThru -WindowStyle Hidden -ErrorAction SilentlyContinue
|
||||||
|
if (-not $proc) {
|
||||||
|
Write-AgentLog -FileName $LogName -Message "$logPrefix /installtunnelservice failed to start."
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
$installTimeoutMs = 60000
|
||||||
|
if (-not $proc.WaitForExit($installTimeoutMs)) {
|
||||||
|
try { $proc.Kill() } catch {}
|
||||||
|
Write-AgentLog -FileName $LogName -Message "$logPrefix /installtunnelservice timed out."
|
||||||
|
$svcAfterTimeout = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
|
||||||
|
if (-not $svcAfterTimeout) {
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
Write-AgentLog -FileName $LogName -Message "$logPrefix Tunnel service present after /installtunnelservice timeout."
|
||||||
|
} else {
|
||||||
|
$installExit = $proc.ExitCode
|
||||||
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix /installtunnelservice exit code: {0}" -f $installExit)
|
||||||
|
if ($installExit -ne 0) {
|
||||||
|
$svcAfterExit = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
|
||||||
|
if (-not $svcAfterExit) {
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
Write-AgentLog -FileName $LogName -Message "$logPrefix Tunnel service present despite non-zero /installtunnelservice exit code."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-AgentLog -FileName $LogName -Message "$logPrefix Tunnel service already present; skipping /installtunnelservice."
|
||||||
|
}
|
||||||
|
try { Start-Service -Name $serviceName -ErrorAction SilentlyContinue } catch {}
|
||||||
|
} catch {
|
||||||
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix Adapter provisioning failed: {0}" -f $_.Exception.Message)
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
|
||||||
|
$finalAdapter = $null
|
||||||
|
$internalAdapter = $null
|
||||||
|
$attempts = 60
|
||||||
|
for ($i = 0; $i -lt $attempts; $i++) {
|
||||||
|
Start-Sleep -Milliseconds 500
|
||||||
|
$finalAdapter = Get-WireGuardAdapterByName -AdapterName $friendlyName
|
||||||
|
if ($finalAdapter) { return $true }
|
||||||
|
$internalAdapter = Get-WireGuardAdapterByName -AdapterName $internalName
|
||||||
|
if ($internalAdapter -and $friendlyName -and $friendlyName -ne $internalName) {
|
||||||
|
Rename-WireGuardAdapterName -OldName $internalName -NewName $friendlyName -LogName $LogName | Out-Null
|
||||||
|
$finalAdapter = Get-WireGuardAdapterByName -AdapterName $friendlyName
|
||||||
|
if ($finalAdapter) { return $true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($internalAdapter -and -not $finalAdapter) {
|
||||||
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix Tunnel adapter present as {0}, but rename to {1} did not complete." -f $internalName, $friendlyName)
|
||||||
|
}
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
|
||||||
function Ensure-WireGuardDriver {
|
function Ensure-WireGuardDriver {
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory = $true)][string]$WireGuardExe,
|
[Parameter(Mandatory = $true)][string]$WireGuardExe,
|
||||||
@@ -914,125 +1465,40 @@ function Install_Agent_Dependencies {
|
|||||||
}
|
}
|
||||||
$state = $stateAfterManager
|
$state = $stateAfterManager
|
||||||
|
|
||||||
$wgCliExe = $null
|
|
||||||
try {
|
try {
|
||||||
$wgCliCandidate = Join-Path (Split-Path $WireGuardExe -Parent) 'wg.exe'
|
$adapterProvisioned = Ensure-WireGuardTunnelAdapter -WireGuardExe $WireGuardExe -LogName $LogName
|
||||||
if (Test-Path $wgCliCandidate -PathType Leaf) { $wgCliExe = $wgCliCandidate }
|
if (-not $adapterProvisioned) {
|
||||||
} catch {}
|
Write-AgentLog -FileName $LogName -Message "$logPrefix Adapter provisioning did not complete."
|
||||||
|
|
||||||
$bootstrapName = 'BorealisBootstrap'
|
|
||||||
$bootstrapDir = Join-Path $env:TEMP 'Borealis-WireGuard-Bootstrap'
|
|
||||||
$bootstrapConf = Join-Path $bootstrapDir "$bootstrapName.conf"
|
|
||||||
try {
|
|
||||||
if (-not (Test-Path $bootstrapDir)) {
|
|
||||||
New-Item -ItemType Directory -Path $bootstrapDir -Force | Out-Null
|
|
||||||
}
|
|
||||||
} catch {}
|
|
||||||
|
|
||||||
$keyPair = New-WireGuardKeyPair -WireGuardExe $WireGuardExe -WgExe $wgCliExe
|
|
||||||
if (-not $keyPair.PrivateKey) {
|
|
||||||
$msg = "$logPrefix Failed to generate WireGuard keypair for driver bootstrap."
|
|
||||||
Write-AgentLog -FileName $LogName -Message $msg
|
|
||||||
throw $msg
|
|
||||||
}
|
|
||||||
|
|
||||||
$peerKey = if ($keyPair.PublicKey) { $keyPair.PublicKey } else { $keyPair.PrivateKey }
|
|
||||||
$conf = @"
|
|
||||||
[Interface]
|
|
||||||
PrivateKey = $($keyPair.PrivateKey)
|
|
||||||
Address = 10.255.255.2/32
|
|
||||||
ListenPort = 0
|
|
||||||
"@
|
|
||||||
if ($keyPair.PublicKey) {
|
|
||||||
$conf += @"
|
|
||||||
|
|
||||||
[Peer]
|
|
||||||
PublicKey = $peerKey
|
|
||||||
AllowedIPs = 10.255.255.1/32
|
|
||||||
"@
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Set-Content -Path $bootstrapConf -Value $conf -Encoding ASCII -Force
|
|
||||||
Write-AgentLog -FileName $LogName -Message ("$logPrefix Created driver bootstrap config at {0}" -f $bootstrapConf)
|
|
||||||
} catch {
|
|
||||||
$msg = "$logPrefix Failed to write bootstrap config: $($_.Exception.Message)"
|
|
||||||
Write-AgentLog -FileName $LogName -Message $msg
|
|
||||||
throw $msg
|
|
||||||
}
|
|
||||||
|
|
||||||
$serviceName = "WireGuardTunnel$bootstrapName"
|
|
||||||
try {
|
|
||||||
Write-AgentLog -FileName $LogName -Message ("$logPrefix Installing bootstrap tunnel service to seed driver ({0})" -f $serviceName)
|
|
||||||
& $WireGuardExe /installtunnelservice $bootstrapConf | Out-Null
|
|
||||||
$installExit = $LASTEXITCODE
|
|
||||||
Write-AgentLog -FileName $LogName -Message ("$logPrefix /installtunnelservice exit code: {0}" -f $installExit)
|
|
||||||
if ($installExit -ne 0) {
|
|
||||||
throw "wireguard.exe /installtunnelservice failed with exit code $installExit"
|
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
$msg = "$logPrefix Failed to install bootstrap tunnel service: $($_.Exception.Message)"
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix Adapter provisioning failed: {0}" -f $_.Exception.Message)
|
||||||
Write-AgentLog -FileName $LogName -Message $msg
|
|
||||||
throw $msg
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Start-Sleep -Seconds 2
|
|
||||||
try {
|
|
||||||
& $WireGuardExe /uninstalltunnelservice $bootstrapName | Out-Null
|
|
||||||
$uninstallExit = $LASTEXITCODE
|
|
||||||
Write-AgentLog -FileName $LogName -Message ("$logPrefix /uninstalltunnelservice exit code: {0}" -f $uninstallExit)
|
|
||||||
Write-AgentLog -FileName $LogName -Message ("$logPrefix Removed bootstrap tunnel service {0}" -f $serviceName)
|
|
||||||
} catch {
|
|
||||||
Write-AgentLog -FileName $LogName -Message ("$logPrefix Cleanup of bootstrap tunnel service failed: {0}" -f $_.Exception.Message)
|
|
||||||
}
|
|
||||||
|
|
||||||
try { Remove-Item -Path $bootstrapConf -Force -ErrorAction SilentlyContinue } catch {}
|
|
||||||
try { Remove-Item -Path $bootstrapDir -Recurse -Force -ErrorAction SilentlyContinue } catch {}
|
|
||||||
|
|
||||||
$post = Get-WireGuardInstallState
|
$post = Get-WireGuardInstallState
|
||||||
$postDriver = $post.DriverPresent
|
$postDriver = $post.DriverPresent
|
||||||
$postMsg = "[WireGuard] Driver presence after bootstrap: $postDriver (Exe: $WireGuardExe)"
|
$postMsg = "[WireGuard] Driver presence after adapter provisioning: $postDriver (Exe: $WireGuardExe)"
|
||||||
Write-AgentLog -FileName $LogName -Message $postMsg
|
Write-AgentLog -FileName $LogName -Message $postMsg
|
||||||
if ($postDriver) { return }
|
if ($postDriver) { return }
|
||||||
|
|
||||||
# Fallback: install Wintun driver directly via pnputil using the official Wintun package
|
$publishedInf = Find-WireGuardDriverInf -LogName $LogName
|
||||||
|
if ($publishedInf) {
|
||||||
|
$infPath = Join-Path $env:WINDIR "INF\$publishedInf"
|
||||||
|
if (Test-Path $infPath -PathType Leaf) {
|
||||||
try {
|
try {
|
||||||
Ensure-WireGuardInstallerFile -Url $wintunDownloadUrl -DestinationPath $wintunZipPath -LogName $LogName
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix Installing WireGuard driver via pnputil: {0}" -f $infPath)
|
||||||
} catch {
|
pnputil.exe /add-driver "`"$infPath`"" /install | Out-Null
|
||||||
Write-AgentLog -FileName $LogName -Message ("$logPrefix Failed to cache Wintun zip: {0}" -f $_.Exception.Message)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Test-Path $wintunZipPath -PathType Leaf) {
|
|
||||||
$extractRoot = Join-Path $env:TEMP 'Borealis-Wintun'
|
|
||||||
try { Remove-Item -Recurse -Force -ErrorAction SilentlyContinue $extractRoot } catch {}
|
|
||||||
try { New-Item -ItemType Directory -Force -Path $extractRoot | Out-Null } catch {}
|
|
||||||
try {
|
|
||||||
Expand-Archive -Path $wintunZipPath -DestinationPath $extractRoot -Force
|
|
||||||
Write-AgentLog -FileName $LogName -Message ("$logPrefix Expanded Wintun zip to {0}" -f $extractRoot)
|
|
||||||
} catch {
|
|
||||||
Write-AgentLog -FileName $LogName -Message ("$logPrefix Failed to expand Wintun zip: {0}" -f $_.Exception.Message)
|
|
||||||
}
|
|
||||||
|
|
||||||
$infPath = Get-ChildItem -Path $extractRoot -Recurse -Filter '*.inf' -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
||||||
if ($infPath -and (Test-Path $infPath.FullName -PathType Leaf)) {
|
|
||||||
try {
|
|
||||||
Write-AgentLog -FileName $LogName -Message ("$logPrefix Installing Wintun driver via pnputil: {0}" -f $infPath.FullName)
|
|
||||||
pnputil.exe /add-driver "`"$($infPath.FullName)`"" /install | Out-Null
|
|
||||||
$postPnP = Get-WireGuardInstallState
|
|
||||||
$postPnPDriver = $postPnP.DriverPresent
|
|
||||||
Write-AgentLog -FileName $LogName -Message ("$logPrefix Driver presence after pnputil install: $postPnPDriver")
|
|
||||||
if (-not $postPnPDriver) {
|
|
||||||
throw "$logPrefix pnputil install completed but driver still missing."
|
|
||||||
}
|
|
||||||
return
|
|
||||||
} catch {
|
} catch {
|
||||||
Write-AgentLog -FileName $LogName -Message ("$logPrefix pnputil driver install failed: {0}" -f $_.Exception.Message)
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix pnputil driver install failed: {0}" -f $_.Exception.Message)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Write-AgentLog -FileName $LogName -Message "$logPrefix No Wintun INF found in extracted package."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw "$logPrefix Driver still missing after bootstrap and pnputil fallback."
|
$postPnP = Get-WireGuardInstallState
|
||||||
|
$postPnPDriver = $postPnP.DriverPresent
|
||||||
|
Write-AgentLog -FileName $LogName -Message ("$logPrefix Driver presence after pnputil install: {0}" -f $postPnPDriver)
|
||||||
|
if ($postPnPDriver) { return }
|
||||||
|
|
||||||
|
throw "$logPrefix Driver still missing after adapter provisioning and pnputil fallback."
|
||||||
}
|
}
|
||||||
|
|
||||||
# AutoHotKey portable
|
# AutoHotKey portable
|
||||||
@@ -1113,12 +1579,18 @@ AllowedIPs = 10.255.255.1/32
|
|||||||
$state = Get-WireGuardInstallState
|
$state = Get-WireGuardInstallState
|
||||||
$stateVersion = if ($state.Version) { $state.Version } else { 'unknown' }
|
$stateVersion = if ($state.Version) { $state.Version } else { 'unknown' }
|
||||||
$stateExe = if ($state.ExePath) { $state.ExePath } else { 'n/a' }
|
$stateExe = if ($state.ExePath) { $state.ExePath } else { 'n/a' }
|
||||||
$stateSummary = "[WireGuard] Detected install state: Installed={0}; Version={1}; Service={2}; Driver={3}; Exe={4}" -f `
|
$stateSummary = "[WireGuard] Detected install state: Installed={0}; Version={1}; Service={2}; Driver={3}; Adapter={4}; BorealisAdapter={5}; Exe={6}" -f `
|
||||||
$state.Installed, $stateVersion, $state.ServicePresent, $state.DriverPresent, $stateExe
|
$state.Installed, $stateVersion, $state.ServicePresent, $state.DriverPresent, $state.AdapterPresent, $state.DedicatedAdapterPresent, $stateExe
|
||||||
Write-AgentLog -FileName $logName -Message $stateSummary
|
Write-AgentLog -FileName $logName -Message $stateSummary
|
||||||
if ($state.DriverPaths -and $state.DriverPaths.Count -gt 0) {
|
if ($state.DriverPaths -and $state.DriverPaths.Count -gt 0) {
|
||||||
Write-AgentLog -FileName $logName -Message ("[WireGuard] Driver paths: {0}" -f ($state.DriverPaths -join '; '))
|
Write-AgentLog -FileName $logName -Message ("[WireGuard] Driver paths: {0}" -f ($state.DriverPaths -join '; '))
|
||||||
}
|
}
|
||||||
|
if ($state.AdapterNames -and $state.AdapterNames.Count -gt 0) {
|
||||||
|
Write-AgentLog -FileName $logName -Message ("[WireGuard] Adapter names: {0}" -f ($state.AdapterNames -join '; '))
|
||||||
|
}
|
||||||
|
if ($state.DedicatedAdapterNames -and $state.DedicatedAdapterNames.Count -gt 0) {
|
||||||
|
Write-AgentLog -FileName $logName -Message ("[WireGuard] Borealis adapter names: {0}" -f ($state.DedicatedAdapterNames -join '; '))
|
||||||
|
}
|
||||||
|
|
||||||
if (-not ($state.Installed -and $state.DriverPresent -and $state.ServicePresent)) {
|
if (-not ($state.Installed -and $state.DriverPresent -and $state.ServicePresent)) {
|
||||||
$installerCandidate = $null
|
$installerCandidate = $null
|
||||||
@@ -1154,8 +1626,8 @@ AllowedIPs = 10.255.255.1/32
|
|||||||
$state = Get-WireGuardInstallState
|
$state = Get-WireGuardInstallState
|
||||||
$postVersion = if ($state.Version) { $state.Version } else { 'unknown' }
|
$postVersion = if ($state.Version) { $state.Version } else { 'unknown' }
|
||||||
$postExe = if ($state.ExePath) { $state.ExePath } else { 'n/a' }
|
$postExe = if ($state.ExePath) { $state.ExePath } else { 'n/a' }
|
||||||
$postSummary = "[WireGuard] Post-install state: Installed={0}; Version={1}; Service={2}; Driver={3}; Exe={4}" -f `
|
$postSummary = "[WireGuard] Post-install state: Installed={0}; Version={1}; Service={2}; Driver={3}; Adapter={4}; BorealisAdapter={5}; Exe={6}" -f `
|
||||||
$state.Installed, $postVersion, $state.ServicePresent, $state.DriverPresent, $postExe
|
$state.Installed, $postVersion, $state.ServicePresent, $state.DriverPresent, $state.AdapterPresent, $state.DedicatedAdapterPresent, $postExe
|
||||||
Write-AgentLog -FileName $logName -Message $postSummary
|
Write-AgentLog -FileName $logName -Message $postSummary
|
||||||
if ($state.Installed -and $state.DriverPresent) {
|
if ($state.Installed -and $state.DriverPresent) {
|
||||||
Write-Host "WireGuard installed and verified (version: $($state.Version))." -ForegroundColor Green
|
Write-Host "WireGuard installed and verified (version: $($state.Version))." -ForegroundColor Green
|
||||||
@@ -1163,10 +1635,14 @@ AllowedIPs = 10.255.255.1/32
|
|||||||
Write-Host "WireGuard installed (driver pending bootstrap)." -ForegroundColor Yellow
|
Write-Host "WireGuard installed (driver pending bootstrap)." -ForegroundColor Yellow
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if ($state.DedicatedAdapterPresent) {
|
||||||
Write-Host "WireGuard already installed (version: $($state.Version))." -ForegroundColor Green
|
Write-Host "WireGuard already installed (version: $($state.Version))." -ForegroundColor Green
|
||||||
|
} else {
|
||||||
|
Write-Host "WireGuard installed (version: $($state.Version)); provisioning Borealis adapter." -ForegroundColor Yellow
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Ensure wintun driver is seeded even before first tunnel is created
|
# Ensure WireGuard driver and Borealis tunnel adapter are provisioned
|
||||||
$wgExe = $state.ExePath
|
$wgExe = $state.ExePath
|
||||||
if (-not $wgExe -or -not (Test-Path $wgExe -PathType Leaf)) {
|
if (-not $wgExe -or -not (Test-Path $wgExe -PathType Leaf)) {
|
||||||
# try default install path
|
# try default install path
|
||||||
@@ -1175,9 +1651,16 @@ AllowedIPs = 10.255.255.1/32
|
|||||||
if ($wgExe -and (Test-Path $wgExe -PathType Leaf)) {
|
if ($wgExe -and (Test-Path $wgExe -PathType Leaf)) {
|
||||||
try {
|
try {
|
||||||
Ensure-WireGuardDriver -WireGuardExe $wgExe -LogName $logName
|
Ensure-WireGuardDriver -WireGuardExe $wgExe -LogName $logName
|
||||||
|
$adapterOk = Ensure-WireGuardTunnelAdapter -WireGuardExe $wgExe -LogName $logName
|
||||||
$finalState = Get-WireGuardInstallState
|
$finalState = Get-WireGuardInstallState
|
||||||
if (-not ($finalState.Installed -and $finalState.DriverPresent)) {
|
if (-not ($finalState.Installed -and $finalState.DriverPresent)) {
|
||||||
throw "WireGuard driver still missing after bootstrap attempts."
|
throw "WireGuard driver still missing after provisioning attempts."
|
||||||
|
}
|
||||||
|
if (-not $finalState.DedicatedAdapterPresent) {
|
||||||
|
throw "Borealis tunnel adapter still missing after provisioning attempts."
|
||||||
|
}
|
||||||
|
if (-not $adapterOk) {
|
||||||
|
Write-AgentLog -FileName $logName -Message "[WireGuard] Borealis tunnel adapter provisioning returned false."
|
||||||
}
|
}
|
||||||
Write-Host "WireGuard driver verified." -ForegroundColor Green
|
Write-Host "WireGuard driver verified." -ForegroundColor Green
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
@@ -22,9 +22,14 @@ import os
|
|||||||
import subprocess
|
import subprocess
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
import re
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, Optional
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
|
try:
|
||||||
|
import winreg # type: ignore
|
||||||
|
except Exception: # pragma: no cover - non-Windows guard
|
||||||
|
winreg = None
|
||||||
from cryptography.hazmat.primitives import serialization
|
from cryptography.hazmat.primitives import serialization
|
||||||
from cryptography.hazmat.primitives.asymmetric import x25519
|
from cryptography.hazmat.primitives.asymmetric import x25519
|
||||||
|
|
||||||
@@ -41,6 +46,9 @@ except Exception: # pragma: no cover - fallback for runtime path issues
|
|||||||
|
|
||||||
ROLE_NAME = "WireGuardTunnel"
|
ROLE_NAME = "WireGuardTunnel"
|
||||||
ROLE_CONTEXTS = ["system"]
|
ROLE_CONTEXTS = ["system"]
|
||||||
|
TUNNEL_NAME = "Borealis"
|
||||||
|
TUNNEL_DISPLAY_NAME = "Borealis"
|
||||||
|
TUNNEL_IDLE_ADDRESS = "169.254.255.254/32"
|
||||||
|
|
||||||
|
|
||||||
def _log_path() -> Path:
|
def _log_path() -> Path:
|
||||||
@@ -130,14 +138,21 @@ class WireGuardClient:
|
|||||||
self.cert_root = base / "Borealis" / "Certificates" / "VPN_Client"
|
self.cert_root = base / "Borealis" / "Certificates" / "VPN_Client"
|
||||||
self.temp_root = base / "Borealis" / "Temp"
|
self.temp_root = base / "Borealis" / "Temp"
|
||||||
self.temp_root.mkdir(parents=True, exist_ok=True)
|
self.temp_root.mkdir(parents=True, exist_ok=True)
|
||||||
self.conf_path = self.temp_root / "borealis-wg-client.conf"
|
self.service_name = TUNNEL_NAME
|
||||||
self.service_name = "borealis-wg-client"
|
self.display_name = TUNNEL_DISPLAY_NAME
|
||||||
|
self.conf_path = self._wireguard_config_path()
|
||||||
self.session: Optional[SessionConfig] = None
|
self.session: Optional[SessionConfig] = None
|
||||||
self.idle_deadline: Optional[float] = None
|
self.idle_deadline: Optional[float] = None
|
||||||
self._idle_thread: Optional[threading.Thread] = None
|
self._idle_thread: Optional[threading.Thread] = None
|
||||||
self._stop_event = threading.Event()
|
self._stop_event = threading.Event()
|
||||||
|
self._session_lock = threading.Lock()
|
||||||
self._client_keys = _generate_client_keys(self.cert_root)
|
self._client_keys = _generate_client_keys(self.cert_root)
|
||||||
self._wg_exe = self._resolve_wireguard_exe()
|
self._wg_exe = self._resolve_wireguard_exe()
|
||||||
|
self._last_install_already_present = False
|
||||||
|
try:
|
||||||
|
self._ensure_idle_service()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
def _resolve_wireguard_exe(self) -> str:
|
def _resolve_wireguard_exe(self) -> str:
|
||||||
candidates = [
|
candidates = [
|
||||||
@@ -149,6 +164,148 @@ class WireGuardClient:
|
|||||||
return candidate
|
return candidate
|
||||||
return "wireguard.exe"
|
return "wireguard.exe"
|
||||||
|
|
||||||
|
def _service_id(self) -> str:
|
||||||
|
return f"WireGuardTunnel${self.service_name}"
|
||||||
|
|
||||||
|
def _service_reg_path(self) -> str:
|
||||||
|
return f"SYSTEM\\CurrentControlSet\\Services\\{self._service_id()}"
|
||||||
|
|
||||||
|
def _service_reg_exists(self) -> bool:
|
||||||
|
if winreg is None:
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, self._service_reg_path())
|
||||||
|
return True
|
||||||
|
except FileNotFoundError:
|
||||||
|
return False
|
||||||
|
except PermissionError:
|
||||||
|
_write_log("WireGuard service registry check denied; treating as present.")
|
||||||
|
return True
|
||||||
|
except Exception as exc:
|
||||||
|
_write_log(f"WireGuard service registry check failed: {exc}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _service_image_path(self) -> Optional[str]:
|
||||||
|
if winreg is None:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, self._service_reg_path())
|
||||||
|
value, _ = winreg.QueryValueEx(key, "ImagePath")
|
||||||
|
return str(value) if value else None
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _service_config_path(self) -> Optional[Path]:
|
||||||
|
image_path = self._service_image_path()
|
||||||
|
if not image_path:
|
||||||
|
return None
|
||||||
|
match = re.search(r'(?i)/tunnelservice\s+"([^"]+)"', image_path)
|
||||||
|
if match:
|
||||||
|
return Path(match.group(1))
|
||||||
|
match = re.search(r"(?i)/tunnelservice\s+(\S+)", image_path)
|
||||||
|
if match:
|
||||||
|
return Path(match.group(1))
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _wireguard_config_path(self) -> Path:
|
||||||
|
settings_dir = self.temp_root.parent / "Settings" / "WireGuard"
|
||||||
|
candidates = [
|
||||||
|
settings_dir,
|
||||||
|
Path(os.environ.get("ProgramFiles", "C:\\Program Files")) / "WireGuard" / "Data" / "Configurations",
|
||||||
|
Path(os.environ.get("ProgramData", "C:\\ProgramData")) / "Borealis" / "WireGuard" / "Configurations",
|
||||||
|
self.temp_root,
|
||||||
|
]
|
||||||
|
for config_dir in candidates:
|
||||||
|
candidate = config_dir / f"{self.service_name}.conf"
|
||||||
|
if candidate.is_file():
|
||||||
|
return candidate
|
||||||
|
for config_dir in candidates:
|
||||||
|
try:
|
||||||
|
config_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
return config_dir / f"{self.service_name}.conf"
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
return self.temp_root / f"{self.service_name}.conf"
|
||||||
|
|
||||||
|
def _write_config(self, text: str) -> bool:
|
||||||
|
return self._write_config_to(self.conf_path, text)
|
||||||
|
|
||||||
|
def _write_config_to(self, path: Path, text: str) -> bool:
|
||||||
|
try:
|
||||||
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
path.write_text(text, encoding="ascii")
|
||||||
|
return True
|
||||||
|
except Exception as exc:
|
||||||
|
_write_log(f"Failed to write WireGuard config at {path}: {exc}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _render_idle_config(self) -> str:
|
||||||
|
private_key = self._client_keys["private"]
|
||||||
|
return "\n".join(
|
||||||
|
[
|
||||||
|
"[Interface]",
|
||||||
|
f"PrivateKey = {private_key}",
|
||||||
|
f"Address = {TUNNEL_IDLE_ADDRESS}",
|
||||||
|
"ListenPort = 0",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
def _service_exists(self) -> bool:
|
||||||
|
code, _, _ = self._run(["sc.exe", "query", self._service_id()])
|
||||||
|
if code == 0:
|
||||||
|
return True
|
||||||
|
return self._service_reg_exists()
|
||||||
|
|
||||||
|
def _install_service(self) -> bool:
|
||||||
|
code, out, err = self._run([self._wg_exe, "/installtunnelservice", str(self.conf_path)])
|
||||||
|
self._last_install_already_present = False
|
||||||
|
if code != 0:
|
||||||
|
if "already installed and running" in err.lower():
|
||||||
|
self._last_install_already_present = True
|
||||||
|
_write_log("WireGuard tunnel service already installed; skipping install.")
|
||||||
|
return True
|
||||||
|
if "access is denied" in err.lower():
|
||||||
|
_write_log("Failed to install WireGuard tunnel service: access denied; ensure agent runs elevated.")
|
||||||
|
return False
|
||||||
|
_write_log(f"Failed to install WireGuard tunnel service: code={code} err={err}")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _restart_service(self) -> bool:
|
||||||
|
service_id = self._service_id()
|
||||||
|
stop_code, _, stop_err = self._run(["sc.exe", "stop", service_id])
|
||||||
|
if stop_code != 0 and stop_err:
|
||||||
|
_write_log(f"WireGuard stop service returned code={stop_code} err={stop_err}")
|
||||||
|
time.sleep(1)
|
||||||
|
start_code, _, start_err = self._run(["sc.exe", "start", service_id])
|
||||||
|
if start_code != 0 and start_err:
|
||||||
|
_write_log(f"WireGuard start service returned code={start_code} err={start_err}")
|
||||||
|
return start_code == 0
|
||||||
|
|
||||||
|
def _ensure_adapter_name(self) -> None:
|
||||||
|
if self.service_name == self.display_name:
|
||||||
|
return
|
||||||
|
args = [
|
||||||
|
"netsh.exe",
|
||||||
|
"interface",
|
||||||
|
"set",
|
||||||
|
"interface",
|
||||||
|
f'name="{self.service_name}"',
|
||||||
|
f'newname="{self.display_name}"',
|
||||||
|
]
|
||||||
|
self._run(args)
|
||||||
|
|
||||||
|
def _ensure_idle_service(self) -> None:
|
||||||
|
if self._service_exists():
|
||||||
|
return
|
||||||
|
if not Path(self._wg_exe).is_file():
|
||||||
|
return
|
||||||
|
idle_config = self._render_idle_config()
|
||||||
|
if not self._write_config(idle_config):
|
||||||
|
return
|
||||||
|
if self._install_service():
|
||||||
|
self._ensure_adapter_name()
|
||||||
|
|
||||||
def _validate_token(self, token: Dict[str, Any], *, signing_client: Optional[Any] = None) -> None:
|
def _validate_token(self, token: Dict[str, Any], *, signing_client: Optional[Any] = None) -> None:
|
||||||
payload = dict(token or {})
|
payload = dict(token or {})
|
||||||
signature = payload.pop("signature", None)
|
signature = payload.pop("signature", None)
|
||||||
@@ -232,6 +389,7 @@ class WireGuardClient:
|
|||||||
self._idle_thread = t
|
self._idle_thread = t
|
||||||
|
|
||||||
def start_session(self, session: SessionConfig, *, signing_client: Optional[Any] = None) -> None:
|
def start_session(self, session: SessionConfig, *, signing_client: Optional[Any] = None) -> None:
|
||||||
|
with self._session_lock:
|
||||||
if self.session:
|
if self.session:
|
||||||
_write_log("Rejecting start_session: existing session already active.")
|
_write_log("Rejecting start_session: existing session already active.")
|
||||||
return
|
return
|
||||||
@@ -243,29 +401,57 @@ class WireGuardClient:
|
|||||||
return
|
return
|
||||||
|
|
||||||
rendered = self._render_config(session)
|
rendered = self._render_config(session)
|
||||||
self.conf_path.write_text(rendered, encoding="utf-8")
|
if not self._write_config(rendered):
|
||||||
|
_write_log("Failed to write WireGuard client config.")
|
||||||
|
return
|
||||||
_write_log(f"Rendered WireGuard client config to {self.conf_path}")
|
_write_log(f"Rendered WireGuard client config to {self.conf_path}")
|
||||||
|
|
||||||
# Pre-stop any orphaned tunnel service using the same name
|
service_config_path = self._service_config_path()
|
||||||
self.stop_session(reason="preflight", ignore_missing=True)
|
if service_config_path and service_config_path != self.conf_path:
|
||||||
|
if self._write_config_to(service_config_path, rendered):
|
||||||
|
_write_log(f"Rendered WireGuard client config to service path {service_config_path}")
|
||||||
|
|
||||||
code, out, err = self._run([self._wg_exe, "/installtunnelservice", str(self.conf_path)])
|
if not self._service_exists():
|
||||||
if code != 0:
|
if not self._install_service():
|
||||||
_write_log(f"Failed to install WireGuard client tunnel: code={code} err={err}")
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
service_present = self._service_exists()
|
||||||
|
if not service_present and self._last_install_already_present:
|
||||||
|
_write_log("WireGuard tunnel service presence inferred from install response.")
|
||||||
|
service_present = True
|
||||||
|
if not service_present:
|
||||||
|
_write_log("WireGuard tunnel service still missing after install attempt.")
|
||||||
|
return
|
||||||
|
|
||||||
|
self._restart_service()
|
||||||
|
self._ensure_adapter_name()
|
||||||
|
|
||||||
self.session = session
|
self.session = session
|
||||||
self.idle_deadline = time.time() + max(60, session.idle_seconds)
|
self.idle_deadline = time.time() + max(60, session.idle_seconds)
|
||||||
_write_log("WireGuard client session started; idle timer armed.")
|
_write_log("WireGuard client session started; idle timer armed.")
|
||||||
self._start_idle_monitor()
|
self._start_idle_monitor()
|
||||||
|
|
||||||
def stop_session(self, reason: str = "stop", ignore_missing: bool = False) -> None:
|
def stop_session(self, reason: str = "stop", ignore_missing: bool = False) -> None:
|
||||||
code, out, err = self._run([self._wg_exe, "/uninstalltunnelservice", self.service_name])
|
with self._session_lock:
|
||||||
if code != 0:
|
if not self._service_exists():
|
||||||
if not ignore_missing:
|
if not ignore_missing:
|
||||||
_write_log(f"Failed to uninstall WireGuard client tunnel: code={code} err={err}")
|
_write_log("WireGuard tunnel service not found when stopping session.")
|
||||||
else:
|
self.session = None
|
||||||
|
self.idle_deadline = None
|
||||||
|
self._stop_event.set()
|
||||||
|
return
|
||||||
|
|
||||||
|
idle_config = self._render_idle_config()
|
||||||
|
wrote_idle = self._write_config(idle_config)
|
||||||
|
service_config_path = self._service_config_path()
|
||||||
|
if service_config_path and service_config_path != self.conf_path:
|
||||||
|
wrote_idle = self._write_config_to(service_config_path, idle_config) or wrote_idle
|
||||||
|
if wrote_idle:
|
||||||
|
self._restart_service()
|
||||||
|
self._ensure_adapter_name()
|
||||||
_write_log(f"WireGuard client session stopped (reason={reason}).")
|
_write_log(f"WireGuard client session stopped (reason={reason}).")
|
||||||
|
elif not ignore_missing:
|
||||||
|
_write_log("Failed to write idle WireGuard config.")
|
||||||
self.session = None
|
self.session = None
|
||||||
self.idle_deadline = None
|
self.idle_deadline = None
|
||||||
self._stop_event.set()
|
self._stop_event.set()
|
||||||
|
|||||||
106
Docs/Codex/WireGuard_Troubleshooting.md
Normal file
106
Docs/Codex/WireGuard_Troubleshooting.md
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
# Borealis WireGuard Troubleshooting Handoff
|
||||||
|
|
||||||
|
This file is a self-contained handoff prompt + context for a new Codex agent to resume WireGuard tunnel troubleshooting.
|
||||||
|
|
||||||
|
## Prompt to Use in a New Codex Session
|
||||||
|
|
||||||
|
Copy/paste the prompt below into a new Codex chat:
|
||||||
|
|
||||||
|
"""
|
||||||
|
You are a new Codex agent working in d:\Github\Borealis. Please do the following:
|
||||||
|
|
||||||
|
1) Read AGENTS.md, Docs/Codex/BOREALIS_AGENT.md, Docs/Codex/BOREALIS_ENGINE.md, Docs/Codex/REVERSE_TUNNELS.md, then Docs/Codex/WireGuard_Troubleshooting.md.
|
||||||
|
2) Investigate why the WireGuard tunnel does not come up (remote shell timeouts) even though the Engine emits vpn_tunnel_start.
|
||||||
|
3) Focus on the WireGuard client lifecycle in Data/Agent/Roles/role_WireGuardTunnel.py and the bootstrap logic in Borealis.ps1 (WireGuard adapter provisioning).
|
||||||
|
4) Use Data/Agent for edits (runtime under Agent/ is ephemeral). Keep the adapter name "Borealis" and ensure idempotent behavior. Do not rely on the PIA adapter.
|
||||||
|
5) Provide concrete fixes + verification steps. Be careful with Windows services and avoid GUI popup dialogs when possible.
|
||||||
|
"""
|
||||||
|
|
||||||
|
## Environment / Scope
|
||||||
|
|
||||||
|
- Workspace: d:\Github\Borealis
|
||||||
|
- Host OS: Windows 10/11 (build 26200). Current tests run on the Windows 11 machine that also runs Engine + Agent.
|
||||||
|
- Agent/Engine launch: via Borealis.ps1, always elevated as admin.
|
||||||
|
- Network: Engine + Agent run on the same host during testing (Engine endpoint is "localhost:30000").
|
||||||
|
- WireGuard version: wireguard.exe 0.5.3, wg.exe 1.0.20210914.
|
||||||
|
- PIA (Private Internet Access) is installed and supplies a wintun driver (pia-wintun.sys). Do NOT treat the PIA adapter as the Borealis adapter.
|
||||||
|
|
||||||
|
## Desired Behavior
|
||||||
|
|
||||||
|
- Agent has a dedicated WireGuard adapter named "Borealis" (Description shows "WireGuard Tunnel").
|
||||||
|
- Adapter provisioning is idempotent: if "Borealis" exists, do not recreate it.
|
||||||
|
- WireGuard config should be stored under Agent\Borealis\Settings\WireGuard\Borealis.conf (preferred) and not only in Program Files.
|
||||||
|
- Agent should bring up the WireGuard tunnel on vpn_tunnel_start, then remote shell / RDP / VNC / SSH should flow through it.
|
||||||
|
- On stop/idle, the tunnel should be torn down and firewall rules removed.
|
||||||
|
|
||||||
|
## Recent Changes (Current Repo State)
|
||||||
|
|
||||||
|
- Data/Agent/Roles/role_WireGuardTunnel.py
|
||||||
|
- Service name fix: WireGuard tunnel service is "WireGuardTunnel$Borealis".
|
||||||
|
- Config path preference: Agent\Borealis\Settings\WireGuard.
|
||||||
|
- Uses registry ImagePath to locate the actual service config when needed.
|
||||||
|
- Adds a session lock to prevent concurrent start/stop.
|
||||||
|
- Borealis.ps1
|
||||||
|
- WireGuard config search order includes Agent\Borealis\Settings\WireGuard.
|
||||||
|
- Adapter provisioning reads the service ImagePath to write config when service exists.
|
||||||
|
- Avoids /installtunnelservice if service still present to prevent GUI error dialogs.
|
||||||
|
- Adapter name is "Borealis".
|
||||||
|
|
||||||
|
Note: Data/Agent changes only apply to runtime after Borealis.ps1 re-stages the agent under Agent/.
|
||||||
|
|
||||||
|
## Symptoms from Fresh Logs (2026-01-12 19:29)
|
||||||
|
|
||||||
|
Agent (Agent/Logs/VPN_Tunnel/tunnel.log):
|
||||||
|
- "WireGuard tunnel service already installed; skipping install."
|
||||||
|
- "WireGuard tunnel service still missing after install attempt."
|
||||||
|
|
||||||
|
Engine (Engine/Logs/VPN_Tunnel/tunnel.log):
|
||||||
|
- vpn_tunnel_session_create for agent LAB-OPERATOR-01_..._SYSTEM
|
||||||
|
- WireGuard listener installed (service=borealis-wg)
|
||||||
|
- vpn_api_status_response status=up
|
||||||
|
|
||||||
|
Engine (Engine/Logs/VPN_Tunnel/remote_shell.log):
|
||||||
|
- repeated vpn_shell_connect_attempt to 10.255.0.2:47002
|
||||||
|
- timeouts
|
||||||
|
|
||||||
|
Agent (Agent/Logs/VPN_Tunnel/remote_shell.log):
|
||||||
|
- VPN shell server listening on 0.0.0.0:47002
|
||||||
|
|
||||||
|
Net effect: engine believes tunnel is "up", but remote shell cannot reach 10.255.0.2. This implies the WireGuard client tunnel is not actually up on the agent.
|
||||||
|
|
||||||
|
## Key Paths
|
||||||
|
|
||||||
|
- Agent WireGuard role: Data/Agent/Roles/role_WireGuardTunnel.py
|
||||||
|
- Agent VPN shell role: Data/Agent/Roles/role_VpnShell.py
|
||||||
|
- Engine WireGuard manager: Data/Engine/services/VPN/wireguard_server.py
|
||||||
|
- Engine tunnel service: Data/Engine/services/VPN/vpn_tunnel_service.py
|
||||||
|
- Agent tunnel logs: Agent/Logs/VPN_Tunnel/tunnel.log
|
||||||
|
- Agent shell logs: Agent/Logs/VPN_Tunnel/remote_shell.log
|
||||||
|
- Engine tunnel logs: Engine/Logs/VPN_Tunnel/tunnel.log
|
||||||
|
- Engine shell logs: Engine/Logs/VPN_Tunnel/remote_shell.log
|
||||||
|
- Agent WireGuard config: Agent/Borealis/Settings/WireGuard/Borealis.conf
|
||||||
|
|
||||||
|
## Known WireGuard Services / Names
|
||||||
|
|
||||||
|
- Engine listener service name: "borealis-wg"
|
||||||
|
- Agent tunnel service name: "WireGuardTunnel$Borealis"
|
||||||
|
- Adapter name in Control Panel: "Borealis"
|
||||||
|
|
||||||
|
## Suggested Verification Commands
|
||||||
|
|
||||||
|
- Check agent service:
|
||||||
|
- Get-Service -Name "WireGuardTunnel$Borealis"
|
||||||
|
- Get-ItemProperty "HKLM:\\SYSTEM\\CurrentControlSet\\Services\\WireGuardTunnel$Borealis" | Select-Object ImagePath
|
||||||
|
- Confirm adapter exists:
|
||||||
|
- Get-NetAdapter -IncludeHidden | Where-Object { $_.InterfaceDescription -like "*WireGuard*" } | Select-Object Name, Status, InterfaceDescription, ifIndex
|
||||||
|
- Check WireGuard state:
|
||||||
|
- "C:\\Program Files\\WireGuard\\wg.exe" show
|
||||||
|
|
||||||
|
## Troubleshooting Focus Areas
|
||||||
|
|
||||||
|
- Ensure runtime is up-to-date (Borealis.ps1 re-staging Data/Agent -> Agent/).
|
||||||
|
- Validate service detection vs. WireGuard install output (sc.exe vs registry).
|
||||||
|
- Confirm the config file used by the service matches Agent/Borealis/Settings/WireGuard/Borealis.conf.
|
||||||
|
- Confirm /installtunnelservice is not invoked when service already exists (avoid WireGuard GUI errors).
|
||||||
|
- Confirm the WireGuard tunnel actually connects (wg.exe show handshake) before attempting remote shell.
|
||||||
|
|
||||||
Reference in New Issue
Block a user