#
VirtualBox automatic port forward
The reason why this is in its own section it's because it's generic enough to be followed for any distro, as the changes are minimal.
Make sure you have installed the VirtualBox Guest Additions, that's a requirement. Same goes for PowerShell v7.
Warning
These methods require, and have only been tested on, Ubuntu 21.10+. If you use another distro, you'd have to look up how to follow the same steps there. It's basically running netstat
and having the ability to restart the VirtualBox Guest Additions service (vboxadd
and vboxadd-service
) every minute or so, because it seems to crash after a while and it doesn't let run netstat
anymore claiming the user can't log on, but that's not true.
First, make sure your user has permissions to run /usr/bin/netstat
and /usr/bin/service
(if on a systemd-based distro) as root. Otherwise, you'll need to use sudo
and visudo
and make some changes in the /etc/sudoers
file, of course, replacing user
with your Linux username:
user ALL=(ALL) NOPASSWD: /usr/bin/netstat, /usr/sbin/service
Create a PowerShell script somewhere in your computer. I've named it C:\_scripts\VBoxWSLSVC.ps1
. Leave it empty for now. First, let's make a shortcut for it:
Use your Windows Start Menu to look out for the PowerShell shortcut. Copy it on your desktop or something, or create a new shortcut by looking for
pwsh.exe
. It could be found atC:\Program Files\PowerShell\7
. Right-click it and choose "Create shortcut". If it asks to create it on the desktop, click yes.Right-click the shortcut
Click Properties.
Change Target to look like this:
"C:\Program Files\PowerShell\7\pwsh.exe" "C:\_scripts\VBoxWSLSVC.ps1"
Click on Compatibility tab
Enable "Run this program as administrator"
Click OK
Now, put this as the content for your PowerShell script and edit the first lines accordingly. When you fire up your VM, you run the new PowerShell shortcut you just created (so this script runs as administrator) and it'll be watching the VM for new ports opened every 5 seconds, and apply the corresponding NAT port forwarding rules. Automagically!
Danger!
Before running this script, make sure to manually delete all port forwarding rules set in your VM's NAT interface (we set one in the Setup step, remember?), otherwise it'll throw some errors.
Warning
This script is in constant development, but it works well for now.
$VMNAME = "WSL2"
$USER = "user"
$PASS = "pass"
$VBOXMANAGE = "C:\Program Files\Oracle\VirtualBox\VBoxManage.exe"
$restartCounter = 0
while($true)
{
##############################################################################################################################
# Get existing rules
##############################################################################################################################
$existingRules = @()
$existingRulesOutput = & $VBOXMANAGE showvminfo $VMNAME
$existingRulesMatches = [regex]::Matches($existingRulesOutput,'NIC \d Rule\(\d*?\):.*?\[(.*?)-(.*?)\]');
foreach($ruleMatch in $existingRulesMatches)
{
$port = $ruleMatch.Groups[2].Value
$proto = $ruleMatch.Groups[1].Value
$existingRules += [PSCustomObject]@{ "Port"=$port; "Protocol"=$proto }
}
##############################################################################################################################
# Get currently open ports
##############################################################################################################################
$newPorts = @()
$netstatOutput = & $VBOXMANAGE guestcontrol $VMNAME run --username $USER --password $PASS "/usr/bin/sudo" -- "/usr/bin/netstat" "-ant"
$portMatches = [regex]::matches($netstatOutput,'([a-z]{1,}?)\s*\d*\s*\d*\s*\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:(\d{1,5})\s*0\.0\.0\.0');
foreach ($portMatch in $portMatches)
{
$port = $portMatch.Groups[2].Value;
$proto = $portMatch.Groups[1].Value;
if ($port -eq 53) { continue; }
if ($port -eq 41339) { continue; }
$newPorts += [PSCustomObject]@{ "Port"=$port; "Protocol"=$proto }
}
##############################################################################################################################
# Prepare new rules
##############################################################################################################################
$newRules = @{}
$currentRules = @{}
foreach($rule in $newPorts) {
$port = $rule.Port
$proto = $rule.Protocol
$newRules["$proto-$port"] = $true
}
foreach($rule in $existingRules) {
$port = $rule.Port
$proto = $rule.Protocol
$currentRules["$proto-$port"] = $true
}
##############################################################################################################################
# Remove unused ports
##############################################################################################################################
foreach($key in $currentRules.Keys)
{
$rule = $newRules[$key]
$split = $key.Split('-')
$proto = $split[0]
$port = $split[1]
if($rule -eq $null) {
& $VBOXMANAGE controlvm $VMNAME natpf1 delete "[$key]"
Write-Host "Port $port ($proto) closed" -ForegroundColor Red
}
}
##############################################################################################################################
# Add new ports
##############################################################################################################################
foreach($key in $newRules.Keys)
{
$split = $key.Split('-')
$proto = $split[0]
$port = $split[1]
$rule = $currentRules[$key]
if($rule -eq $null) {
& $VBOXMANAGE controlvm $VMNAME natpf1 "[$key],$proto,,${port},,${port}"
Write-Host "Port $port ($proto) opened" -ForegroundColor Green
}
}
echo ...
Start-Sleep -s 5
$restartCounter = $restartCounter + 1
if ($restartCounter -eq 6 || $restartCounter -gt 6) {
$restartCounter = 0
echo Restart
& $VBOXMANAGE guestcontrol $VMNAME run --username $USER --password $PASS --wait-stdout --wait-stderr --ignore-operhaned-processes --timeout 10000 "/usr/bin/sudo" -- "/usr/sbin/service" "vboxadd-service" "restart"
Start-Sleep -s 1
& $VBOXMANAGE guestcontrol $VMNAME run --username $USER --password $PASS --wait-stdout --wait-stderr --ignore-operhaned-processes --timeout 10000 "/usr/bin/sudo" -- "/usr/sbin/service" "vboxadd" "restart"
}
}