LogoThreatmatic
Troubleshooting

Windows Agent / schannel Connectivity

Diagnosing and fixing WireGuard tunnel failures for the Windows TMAgent/schannel client.

WireGuard tunnel service won't start after a reboot

Symptom: the TMAgent (agentv200rc29.exe or similar, installed under C:\Program Files\TMAgent) is running and connects to the engine fine, but the local WireGuard tunnel never comes up. In Windows Services, WireGuardTunnel$schannel shows Stopped even though its Start type is Automatic.

Two independent causes have been seen to produce this. Check both — fixing one does not guarantee the other isn't also present.

Step 1 — check what actually failed

Look at the Windows System event log for Service Control Manager events mentioning WireGuard:

Get-WinEvent -FilterHashtable @{LogName="System"; ProviderName="Service Control Manager"} -MaxEvents 20 |
  Where-Object { $_.Message -like "*WireGuard*" } |
  Select-Object TimeCreated, Id, Message

For a more precise error, dump WireGuard's own internal log — it reports the exact failure point (interface creation, driver, or socket bind) that the Windows service error alone doesn't show:

& "C:\Program Files\WireGuard\wireguard.exe" /dumplog

or read C:\Program Files\WireGuard\Data\log.bin's LastWriteTime to confirm whether a start attempt is even reaching the tunnel process at all.

Cause A — a Windows UDP port exclusion overlaps WireGuard's listen port

If the log shows something like:

Could not bind socket to 0.0.0.0:51820 (0xc0000022)
Unable to bring up adapter: Access is denied.

this is not a schannel or TMAgent problem — it's Windows itself refusing the bind because the port falls inside a reserved exclusion range. Check:

netsh int ipv4 show excludedportrange protocol=udp

Look for a range (without a trailing *, i.e. not an "administered" exclusion) that covers 51820 — e.g. 51752–51851. This is typically a dynamic reservation from Hyper-V/WSL2/Docker Desktop's NAT driver, re-created on every boot. Fix by restarting the Windows NAT driver service:

net stop winnat
net start winnat

Re-check the excluded range — it should no longer cover 51820. This alone briefly interrupts Docker/WSL2 networking (a few seconds), so warn the user before running it if other work depends on a live container connection at that moment.

Cause B — the WireGuardNT virtual adapter isn't being instantiated

If Cause A doesn't apply (no port conflict), or the tunnel still won't start after fixing it, check whether the actual virtual network adapter exists in Device Manager:

Get-PnpDevice -Class Net | Where-Object { $_.FriendlyName -like "*WireGuard*" }

If nothing is listed at all (not even in an Error state), sc.exe start will fail with:

[SC] StartService FAILED 1058:
The service cannot be started, either because it is disabled or because it has no enabled devices associated with it.

First confirm the driver package itself is intact (this rules out a corrupted WireGuard install):

pnputil /enum-drivers | Select-String -Pattern "wireguard" -Context 3,3

If the driver is present but no device instance exists, this is usually a broader Windows networking-stack issue, not specific to WireGuard. Check whether other VPN products on the same machine are also affected — e.g. PANGP (GlobalProtect) or Fortinet's SSL VPN adapter showing Error status in Get-PnpDevice -Class Net. If so, that confirms it's an NDIS/virtual-adapter subsystem problem introduced by the reboot (or a recent Windows Update), not a schannel bug. Fix with a full network stack reset, which requires a restart to take effect:

netsh winsock reset
netsh int ip reset
# then restart the machine

This resets Winsock LSPs and the IP stack broadly — it can affect other networking tools on the machine, not just WireGuard. It has, in practice, fixed the WireGuard/schannel adapter specifically without necessarily clearing the same Error state on other vendors' VPN adapters (PANGP, Fortinet) — don't assume it fully resolved the underlying cause just because schannel came back.

Reinstalling the tunnel service manually

If the service registration itself looks broken (present but permanently Stopped, or sc.exe start reports the service doesn't exist despite Get-Service showing it), reinstall it from the TMAgent's own config file:

& "C:\Program Files\WireGuard\wireguard.exe" /uninstalltunnelservice schannel
& "C:\Program Files\WireGuard\wireguard.exe" /installtunnelservice "C:\Program Files\TMAgent\schannel\schannel.conf"

/installtunnelservice can silently register the service without actually starting it when a same-named service already exists (even a broken/stopped one) — it will return exit code 0 either way. Always verify with Get-Service afterward, and if it's still Stopped, start it explicitly:

sc.exe start 'WireGuardTunnel$schannel'

Use single quotes (or a backtick before $) around the service name in PowerShell — a double-quoted "WireGuardTunnel$schannel" gets $schannel interpolated as an (empty) variable, and sc.exe will report the service doesn't exist even though Get-Service shows it does.

Verifying the fix

Confirm the service is running and a real peer handshake is happening, not just that the process started:

Get-Service WireGuardTunnel*
wg

A working tunnel shows a recent latest handshake timestamp (well under a minute old) and nonzero transfer bytes for at least one peer.

Where TMAgent's own logs live

The agent's log directory is C:\ProgramData\TMAgent\, not under Program Files — specifically C:\ProgramData\TMAgent\tmagent.log. This shows the agent's own connection state to the engine (got engine connection, config loaded, putting peer / tunnel not running, not adding peer, etc.) and is the right place to check whether the agent is healthy before assuming the problem is WireGuard-specific. Note: agent-app-data (under Program Files\TMAgent) is typically empty — don't expect logs there.

Inspecting the local WFP firewall policy

TMAgent installs its own Windows Filtering Platform (WFP) filters for local ZTNA enforcement (egress allow rules, mostly at FWPM_LAYER_ALE_AUTH_CONNECT_V4). To see everything currently registered, including filters from other vendors:

netsh wfp show filters file="C:\path\to\wfpfilters.xml"

Search the resulting XML for Threatmatic/TMAgent/schannel to find TMAgent's own filters, and for the relevant layer (FWPM_LAYER_ALE_AUTH_CONNECT_V4 for outbound TCP, FWPM_LAYER_ALE_AUTH_LISTEN_V4 for listen/bind authorization) to see whether a specific block is in play. In practice, TMAgent's filters have only ever been observed as narrow PERMIT rules for specific ports/processes — a missing permit is a different problem from an active block, and neither has so far been the actual cause of a WireGuard bind failure (see Cause A/B above instead).

How is this guide?

Last updated on

On this page