121 lines
5.1 KiB
PowerShell
121 lines
5.1 KiB
PowerShell
|
|
#Requires -Version 5.1
|
||
|
|
#Requires -RunAsAdministrator
|
||
|
|
|
||
|
|
<#
|
||
|
|
.SYNOPSIS
|
||
|
|
Publica Vite desde WSL2 en la red local mediante el reenvio TCP de Windows.
|
||
|
|
.DESCRIPTION
|
||
|
|
Ejecutar en PowerShell de Windows como administrador, con pnpm dev activo en WSL.
|
||
|
|
Volver a ejecutar si cambia la IP de WSL. Solo admite el perfil de red privado.
|
||
|
|
La API sigue siendo accesible a traves del proxy /api de Vite.
|
||
|
|
Reinicia IP Helper para aplicar las reglas; interrumpe brevemente otros reenvios.
|
||
|
|
#>
|
||
|
|
[CmdletBinding()]
|
||
|
|
param(
|
||
|
|
[System.Net.IPAddress]$ListenAddress = '192.168.0.2',
|
||
|
|
[ValidateRange(1, 65535)]
|
||
|
|
[int]$Port = 5173,
|
||
|
|
[ValidateNotNullOrEmpty()]
|
||
|
|
[string]$Distribution = 'Ubuntu-24.04'
|
||
|
|
)
|
||
|
|
|
||
|
|
Set-StrictMode -Version Latest
|
||
|
|
$ErrorActionPreference = 'Stop'
|
||
|
|
|
||
|
|
if ($ListenAddress.AddressFamily -ne [System.Net.Sockets.AddressFamily]::InterNetwork) {
|
||
|
|
throw 'ListenAddress debe ser una direccion IPv4 del ordenador Windows.'
|
||
|
|
}
|
||
|
|
|
||
|
|
$localAddress = Get-NetIPAddress -AddressFamily IPv4 -IPAddress $ListenAddress.IPAddressToString
|
||
|
|
$profiles = @(Get-NetConnectionProfile -InterfaceIndex $localAddress.InterfaceIndex)
|
||
|
|
if (-not ($profiles | Where-Object { $_.NetworkCategory -eq 'Private' })) {
|
||
|
|
throw 'La interfaz debe tener perfil Privado en Windows. Revisar la red antes de ejecutar el script.'
|
||
|
|
}
|
||
|
|
|
||
|
|
# eth0 evita seleccionar la direccion de un bridge de Docker con hostname -I.
|
||
|
|
$addressOutput = & wsl.exe --distribution $Distribution --exec ip -4 -o addr show dev eth0
|
||
|
|
if ($LASTEXITCODE -ne 0) {
|
||
|
|
throw "No se pudo consultar eth0 en la distribucion $Distribution."
|
||
|
|
}
|
||
|
|
|
||
|
|
$addressMatch = [regex]::Match(($addressOutput -join "`n"), '\binet\s+(\d{1,3}(?:\.\d{1,3}){3})/')
|
||
|
|
if (-not $addressMatch.Success) {
|
||
|
|
throw 'No se encontro una direccion IPv4 en eth0 de WSL.'
|
||
|
|
}
|
||
|
|
|
||
|
|
$wslAddress = [System.Net.IPAddress]::Parse($addressMatch.Groups[1].Value)
|
||
|
|
if (-not (Test-NetConnection -ComputerName $wslAddress.IPAddressToString -Port $Port -InformationLevel Quiet -WarningAction SilentlyContinue)) {
|
||
|
|
throw "WSL no responde en ${wslAddress}:$Port. Comprobar pnpm dev y el puerto anunciado por Vite."
|
||
|
|
}
|
||
|
|
|
||
|
|
# add actualiza tambien el destino del reenvio existente para esta direccion y puerto.
|
||
|
|
& netsh.exe interface portproxy add v4tov4 `
|
||
|
|
listenaddress=$($ListenAddress.IPAddressToString) listenport=$Port `
|
||
|
|
connectaddress=$($wslAddress.IPAddressToString) connectport=$Port protocol=tcp
|
||
|
|
if ($LASTEXITCODE -ne 0) {
|
||
|
|
throw 'No se pudo configurar el reenvio TCP de Windows.'
|
||
|
|
}
|
||
|
|
|
||
|
|
$ruleName = "MetisDesk-WSL-LAN-$($ListenAddress.IPAddressToString)-$Port"
|
||
|
|
$existingRule = Get-NetFirewallRule -Name $ruleName -ErrorAction SilentlyContinue
|
||
|
|
if ($existingRule) {
|
||
|
|
$existingRule | Remove-NetFirewallRule
|
||
|
|
}
|
||
|
|
|
||
|
|
New-NetFirewallRule -Name $ruleName -DisplayName "Metis Desk WSL LAN ($Port)" `
|
||
|
|
-Direction Inbound -Action Allow -Enabled True -Profile Private `
|
||
|
|
-Protocol TCP -LocalAddress $ListenAddress.IPAddressToString -LocalPort $Port `
|
||
|
|
-RemoteAddress LocalSubnet | Out-Null
|
||
|
|
|
||
|
|
# El servicio puede estar activo sin haber aplicado los reenvios registrados.
|
||
|
|
Write-Host 'Reiniciando IP Helper para aplicar el reenvio...'
|
||
|
|
Restart-Service -Name iphlpsvc
|
||
|
|
|
||
|
|
$accessUrl = "http://${ListenAddress}:$Port/"
|
||
|
|
# Una regla creada no garantiza que Windows este escuchando o reenviando HTTP.
|
||
|
|
# Evitar el proxy del sistema permite comprobar directamente el reenvio local.
|
||
|
|
$request = [System.Net.WebRequest]::Create($accessUrl)
|
||
|
|
$request.Proxy = $null
|
||
|
|
$request.Timeout = 10000
|
||
|
|
$request.ReadWriteTimeout = 10000
|
||
|
|
$request.AllowAutoRedirect = $false
|
||
|
|
$response = $null
|
||
|
|
|
||
|
|
try {
|
||
|
|
# Running no garantiza que el listener este listo: esperar hasta diez segundos.
|
||
|
|
$listenerTimer = [System.Diagnostics.Stopwatch]::StartNew()
|
||
|
|
do {
|
||
|
|
$listener = Get-NetTCPConnection -State Listen -LocalPort $Port -ErrorAction SilentlyContinue |
|
||
|
|
Where-Object { $_.LocalAddress -eq $ListenAddress.IPAddressToString -or $_.LocalAddress -eq '0.0.0.0' }
|
||
|
|
if ($listener) {
|
||
|
|
break
|
||
|
|
}
|
||
|
|
if ($listenerTimer.Elapsed.TotalSeconds -ge 10) {
|
||
|
|
throw "Windows no ha abierto el listener IPv4 ${ListenAddress}:$Port tras reiniciar IP Helper."
|
||
|
|
}
|
||
|
|
Start-Sleep -Milliseconds 200
|
||
|
|
} while ($true)
|
||
|
|
|
||
|
|
$response = $request.GetResponse()
|
||
|
|
if ([int]$response.StatusCode -ne 200) {
|
||
|
|
throw "Respuesta HTTP inesperada: $([int]$response.StatusCode)."
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch {
|
||
|
|
Write-Warning 'Las reglas se han creado, pero la comprobacion HTTP desde Windows ha fallado. Se conservan para diagnostico.'
|
||
|
|
& netsh.exe interface portproxy show all
|
||
|
|
Get-NetTCPConnection -State Listen -LocalPort $Port -ErrorAction SilentlyContinue |
|
||
|
|
Format-Table LocalAddress, LocalPort, OwningProcess | Out-Host
|
||
|
|
throw "No se pudo verificar ${accessUrl}: $($_.Exception.Message)"
|
||
|
|
}
|
||
|
|
finally {
|
||
|
|
if ($null -ne $response) {
|
||
|
|
$response.Close()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Write-Host "HTTP verificado desde Windows: $accessUrl -> ${wslAddress}:$Port"
|
||
|
|
Write-Host 'Comprobar ahora el acceso desde otro dispositivo de la red local.'
|
||
|
|
Write-Host "En WSL, establecer APP_ORIGIN=http://${ListenAddress}:$Port en .env y reiniciar pnpm dev."
|
||
|
|
Write-Host 'Volver a ejecutar este script si cambia la IP de WSL.'
|