CHAT_OUTPUT_BEGIN
COMMAND_ID=SUPPORT-261007-WINDOWS-DACHA-WATCHDOG-SANITIZED-SOURCE-99758R1
STATUS=OK
RC=0
HOST=pve01
MODE=read-only
COMPONENT=windows-dacha-watchdog-sanitized-source
REFERENCE_REGISTER_CHECK=OK
REFERENCE_SHA256=5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66
ERROR_REGISTER_CHECK=OK
ERROR_REGISTER_SHA256=3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0
COMMAND_SHA256=82372359d1dfece3cca84734e47b1a82a17c43fb88ef3c8c418ee0f99f500497
DUPLICATE_FAILED_COMMAND_BLOCKED=false
EXECUTION_STARTED=true
CHANGE_DECLARED=false
RESULT_CONTRACT_VALID=true
RESULT_CONTRACT_STATUS=NOT_APPLICABLE
RESULT_CONTRACT_ERROR=NONE
COMMAND_RC=0
CHANGES_MADE=false
ROLLBACK_STARTED=false
ROLLBACK_RESTORED=null
MUTATION_OUTCOME=NO_MUTATION
SANITIZED=yes
SECRETS_INCLUDED=no
PRIVATE_ADDRESSES_INCLUDED=no
RAW_EVIDENCE_SHA256=07576991b3bcf03a1f05666fc4f906e8ce3bab611b76ac9d0e0cd4f2ff28da02
SANITIZED_OUTPUT_SHA256=07576991b3bcf03a1f05666fc4f906e8ce3bab611b76ac9d0e0cd4f2ff28da02
OUTPUT_BEGIN
WINDOWS_DACHA_WATCHDOG_SANITIZED_SOURCE=V1
MODE=read-only
NO_MUTATION=true
WINDOWS_LOCAL_INSPECT_RC=0
WINDOWS_EVIDENCE_PRESENT=true
WATCHDOG_SHORTCUT_MATCH_COUNT=1
WATCHDOG_PS1_RESOLVED=true
WATCHDOG_PS1_BASENAME=watchdog.ps1
WATCHDOG_PS1_SIZE=5001
WATCHDOG_LINE_COUNT=169
SANITIZED_SOURCE_BEGIN
SRC|001|$ErrorActionPreference='SilentlyContinue'
SRC|003|$HostKey='<HOSTKEY>'
SRC|004|$PlinkPath='<PATH> Files\PuTTY\plink.exe'
SRC|005|$Target='<IP>'
SRC|006|$FailureStreak=0
SRC|008|function Get-Listeners {
SRC|009|    try {
SRC|010|        return @(Get-NetTCPConnection -State Listen -LocalPort 64020 -ErrorAction SilentlyContinue)
SRC|011|    } catch {
SRC|012|        return @()
SRC|013|    }
SRC|014|}
SRC|016|function Get-ProcessCommandLine([int]$processId) {
SRC|017|    try {
SRC|018|        $proc = Get-CimInstance Win32_Process -Filter "ProcessId=$processId"
SRC|019|        if ($proc) { return [string]$proc.CommandLine }
SRC|020|    } catch {}
SRC|021|    return ''
SRC|022|}
SRC|024|function Test-ExactOwner([int]$processId) {
SRC|025|    $commandLine = Get-ProcessCommandLine $processId
SRC|026|    if ([string]::IsNullOrWhiteSpace($commandLine)) { return $false }
SRC|028|    return (
SRC|029|        $commandLine -match '(?i)\bplink(\.exe)?\b' -and
SRC|030|        $commandLine -match '(?i)-L\s+127\.0\.0\.1:64020:127\.0\.0\.1:64020' -and
SRC|031|        $commandLine -match '(?i)root@192\.168\.50\.11' -and
SRC|032|        $commandLine -match [regex]::Escape($HostKey)
SRC|033|    )
SRC|034|}
SRC|036|function Test-Tcp22 {
SRC|037|    $client = $null
SRC|038|    try {
SRC|039|        $client = New-Object Net.Sockets.TcpClient
SRC|040|        $task = $client.ConnectAsync($Target, 22)
SRC|041|        if (-not $task.Wait(1800)) { return $false }
SRC|042|        return $client.Connected
SRC|043|    } catch {
SRC|044|        return $false
SRC|045|    } finally {
SRC|046|        try { if ($client) { $client.Close() } } catch {}
SRC|047|    }
SRC|048|}
SRC|050|function Test-Tcp64020 {
SRC|051|    $client = $null
SRC|052|    try {
SRC|053|        $client = New-Object Net.Sockets.TcpClient
SRC|054|        $task = $client.ConnectAsync('<IP>', 64020)
SRC|055|        if (-not $task.Wait(1200)) { return $false }
SRC|056|        return $client.Connected
SRC|057|    } catch {
SRC|058|        return $false
SRC|059|    } finally {
SRC|060|        try { if ($client) { $client.Close() } } catch {}
SRC|061|    }
SRC|062|}
SRC|064|function Test-Socks {
SRC|065|    $curl = (Get-Command curl.exe -ErrorAction SilentlyContinue).Source
SRC|066|    if (-not $curl) { return $false }
SRC|068|    try {
SRC|069|        $code = ((& $curl '-sS' '-o' 'NUL' '--connect-timeout' '4' '--max-time' '10' '-w' '%{http_code}' '--socks5-hostname' '<IP>:64020' 'https://api.telegram.org' 2>$null) | Out-String).Trim()
SRC|070|        return ($LASTEXITCODE -eq 0 -and $code -match '^[1-5][0-9][0-9]$' -and $code -ne '000')
SRC|071|    } catch {
SRC|072|        return $false
SRC|073|    }
SRC|074|}
SRC|076|function Get-ExactPlinkPids {
SRC|077|    $result = New-Object 'System.Collections.Generic.List[int]'
SRC|078|    try {
SRC|079|        foreach ($proc in (Get-CimInstance Win32_Process -Filter "Name='plink.exe'" -ErrorAction SilentlyContinue)) {
SRC|080|            if (Test-ExactOwner ([int]$proc.ProcessId)) {
SRC|081|                $result.Add([int]$proc.ProcessId)
SRC|082|            }
SRC|083|        }
SRC|084|    } catch {}
SRC|085|    return @($result | Sort-Object -Unique)
SRC|086|}
SRC|088|function Start-Route {
SRC|089|    if (-not (Test-Path -LiteralPath $PlinkPath -PathType Leaf)) { return $false }
SRC|090|    if (-not (Test-Tcp22)) { return $false }
SRC|092|    $proc = $null
SRC|093|    try {
SRC|094|        $psi = New-Object Diagnostics.ProcessStartInfo
SRC|095|        $psi.FileName = $PlinkPath
SRC|096|        $psi.UseShellExecute = $false
SRC|097|        $psi.CreateNoWindow = $true
SRC|098|        $psi.Arguments = "-batch -agent -noshare -no-antispoof -ssh -4 -P 22 -hostkey <HOSTKEY_OR_VAR> -N -L <IP>:64020:<IP>:64020 <USER>@<IP>"
SRC|099|        $proc = [Diagnostics.Process]::Start($psi)
SRC|100|    } catch {
SRC|101|        return $false
SRC|102|    }
SRC|104|    if ($null -eq $proc) { return $false }
SRC|106|    for ($i = 1; $i -le 30; $i++) {
SRC|107|        Start-Sleep -Milliseconds 500
SRC|108|        $rows = Get-Listeners
SRC|109|        $owners = @($rows | ForEach-Object { $_.OwningProcess } | Where-Object { $_ -gt 0 } | Sort-Object -Unique)
SRC|111|        if ($owners.Count -eq 1 -and $owners[0] -eq $proc.Id -and (Test-Tcp64020)) {
SRC|112|            return $true
SRC|113|        }
SRC|115|        try {
SRC|116|            if ($proc.HasExited) { break }
SRC|117|        } catch {}
SRC|118|    }
SRC|120|    try {
SRC|121|        if (-not $proc.HasExited) {
SRC|122|            Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue
SRC|123|        }
SRC|124|    } catch {}
SRC|126|    return $false
SRC|127|}
SRC|129|while ($true) {
SRC|130|    $rows = Get-Listeners
SRC|131|    $owners = @($rows | ForEach-Object { $_.OwningProcess } | Where-Object { $_ -gt 0 } | Sort-Object -Unique)
SRC|133|    if ($rows.Count -eq 0) {
SRC|134|        $FailureStreak = 0
SRC|136|        foreach ($staleProcessId in (Get-ExactPlinkPids)) {
SRC|137|            try {
SRC|138|                Stop-Process -Id $staleProcessId -Force -ErrorAction SilentlyContinue
SRC|139|            } catch {}
SRC|140|        }
SRC|142|        Start-Route | Out-Null
SRC|143|    }
SRC|144|    elseif ($owners.Count -eq 1 -and (Test-ExactOwner ([int]$owners[0]))) {
SRC|145|        if (Test-Socks) {
SRC|146|            $FailureStreak = 0
SRC|147|        }
SRC|148|        else {
SRC|149|            $FailureStreak++
SRC|151|            if ($FailureStreak -ge 3) {
SRC|152|                try {
SRC|153|                    Stop-Process -Id ([int]$owners[0]) -Force -ErrorAction SilentlyContinue
SRC|154|                } catch {}
SRC|156|                $FailureStreak = 0
SRC|157|                Start-Sleep -Seconds 1
SRC|158|                Start-Route | Out-Null
SRC|159|            }
SRC|160|        }
SRC|161|    }
SRC|162|    else {
SRC|163|        # Safety hold: never terminate an unknown or competing owner.
SRC|164|        $FailureStreak = 0
SRC|165|    }
SRC|167|    Start-Sleep -Seconds 12
SRC|168|}
SANITIZED_SOURCE_END
RUNNING_WATCHDOG_PS_COUNT=2
RUNNING_BRIDGE_PS_COUNT=2
REC|CURRENT_PLINK|IDX=1|HAS_R=false|HAS_L=true|HAS_D=false|HAS_64020=true|HAS_64022=false|HAS_AGENT=true|HAS_BATCH=true|HAS_N=true
CURRENT_PLINK_COUNT=1
WATCHDOG_PS1_SHA256=7738599c1d229c105f1073f04b420063bd776f3444b3f6fcf7d09bd320cce0e3
WATCHDOG_PS1_SHA_MATCH=true
PVE64020_LISTENER_COUNT=0
PVE64020_SSHD_OWNER_COUNT=0
CLUSTER_QUORATE=true
NETBIRD_LAZY=false
NETBIRD_MANAGEMENT=true
NETBIRD_SIGNAL=true
NETBIRD_CONNECTED=5
DECISION=PASS_WINDOWS_DACHA_WATCHDOG_SANITIZED_SOURCE
NEXT_GATE=EXACT_WATCHDOG_LOGIC_REPAIR
TASK_RESULT=WINDOWS_DACHA_WATCHDOG_SANITIZED_SOURCE
CHANGES_MADE=false
ROLLBACK_STARTED=false
ROLLBACK_RESTORED=null
MUTATION_OUTCOME=NO_MUTATION
HOMELAB_RESULT_CONTRACT={"version":1,"command_id":"SUPPORT-261007-WINDOWS-DACHA-WATCHDOG-SANITIZED-SOURCE-99758R1","status":"OK","changes_made":false,"rollback_started":false,"rollback_restored":null}

OUTPUT_END
CHAT_OUTPUT_END
