Created
December 2, 2025 20:12
-
-
Save omarmciver/ec586c0a7de290730f4e7181920cc338 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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