Skip to content

Instantly share code, notes, and snippets.

@omarmciver
Created December 2, 2025 20:12
Show Gist options
  • Select an option

  • Save omarmciver/ec586c0a7de290730f4e7181920cc338 to your computer and use it in GitHub Desktop.

Select an option

Save omarmciver/ec586c0a7de290730f4e7181920cc338 to your computer and use it in GitHub Desktop.
# wsl-vpn-arp-fix.ps1
# Fixes WSL2 connectivity after Cisco VPN reconnects by syncing ARP from Windows
# Requires: Run as Administrator
Write-Host ""
Write-Host "=== Fix WSL VPN (Adapter-based ARP Sync) ===" -ForegroundColor Cyan
# Match Cisco AnyConnect / Secure Client adapter
$adapterPattern = "Cisco"
# Optional: target a specific WSL distro
$distroName = $null
function Invoke-Wsl {
param([string]$Command)
if ($distroName) { wsl -d $distroName -e sh -c "$Command" }
else { wsl -e sh -c "$Command" }
}
# 1. Identify VPN adapter
$vpnAdapter = Get-NetAdapter |
Where-Object {
$_.InterfaceDescription -match $adapterPattern -and $_.Status -eq "Up"
} |
Select-Object -First 1
if (-not $vpnAdapter) {
Write-Host "ERROR: No active Cisco adapter detected." -ForegroundColor Red
exit 1
}
Write-Host "VPN Adapter: $($vpnAdapter.Name) ($($vpnAdapter.InterfaceDescription))" -ForegroundColor Green
# 2. Determine default route assigned to this adapter
$defaultRoute = Get-NetRoute -DestinationPrefix "0.0.0.0/0" |
Where-Object { $_.InterfaceIndex -eq $vpnAdapter.ifIndex } |
Sort-Object -Property RouteMetric, Metric |
Select-Object -First 1
if (-not $defaultRoute) {
Write-Host "ERROR: No default route found on Cisco adapter." -ForegroundColor Red
exit 1
}
$gatewayIP = $defaultRoute.NextHop
Write-Host "Gateway IP: $gatewayIP" -ForegroundColor Green
# 3. Ensure the ARP entry exists
Test-Connection -Count 1 -Quiet -ErrorAction SilentlyContinue $gatewayIP | Out-Null
$gw = Get-NetNeighbor |
Where-Object {
$_.IPAddress -eq $gatewayIP -and
$_.InterfaceIndex -eq $vpnAdapter.ifIndex
} |
Select-Object -First 1
if (-not $gw) {
Write-Host "ERROR: No ARP entry for gateway. Try generating traffic first." -ForegroundColor Red
exit 1
}
$mac = $gw.LinkLayerAddress -replace '-', ':'
Write-Host "Gateway MAC: $mac" -ForegroundColor Green
# 4. Determine WSL interface
$vpnInterface = Invoke-Wsl "ip route show default | grep '$gatewayIP' | awk '{print \`$5}'"
$vpnInterface = $vpnInterface.Trim()
if (-not $vpnInterface) {
Write-Host "WARN: Cannot detect WSL interface, assuming eth0." -ForegroundColor Yellow
$vpnInterface = "eth0"
}
Write-Host "WSL VPN interface: $vpnInterface" -ForegroundColor Green
# 5. Clear stale ARP entries
Invoke-Wsl "sudo ip neigh del $gatewayIP dev eth0 2>/dev/null || true" | Out-Null
Invoke-Wsl "sudo ip neigh del $gatewayIP dev eth1 2>/dev/null || true" | Out-Null
# 6. Inject permanent ARP entry
Invoke-Wsl "sudo ip neigh replace $gatewayIP lladdr $mac nud permanent dev $vpnInterface" | Out-Null
# 7. Verify
$arpStatus = Invoke-Wsl "ip neigh show $gatewayIP"
Write-Host $arpStatus -ForegroundColor Cyan
if ($arpStatus -match "PERMANENT") {
Write-Host ""
Write-Host "SUCCESS: WSL ARP entry repaired." -ForegroundColor Green
# Quick connectivity test
$test = Invoke-Wsl "curl -sI --connect-timeout 5 https://www.google.com | head -n 1"
Write-Host "Connectivity test: $test" -ForegroundColor Green
} else {
Write-Host "FAILED: Could not set ARP entry." -ForegroundColor Red
exit 1
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment