microsoft/WSL

Windows Defender Firewall blocks access from WSL2

dmchurch opened this issue Β· 67 comments

  • Your Windows build number: 10.0.18917.1000

  • What you're doing and what's happening:
    Trying to run X11 apps from my Ubuntu installation, which I just upgraded from WSL1 to WSL2. I've configured the X server (VcXsrv) to accept TCP connections, and I've put the IP address of the Windows host into the DISPLAY variable, but the connection times out. Digging into it, I've discovered that the vEthernet adapter is treated as an "Unidentified Network", and so it gets the Public firewall access rules (which, unsurprisingly, includes blocking port 6000). If I disable the firewall entirely, I can connect to the X server just fine. This worked under WSL1, of course.

  • What's wrong / what should be happening instead:
    Connections from a WSL2 VM should be treated as privileged and not subject to firewall rules, probably?

  • Strace of the failing command, if applicable:

$ strace xev
execve("/usr/bin/xev", ["xev"], 0x7ffeee6e64a0 /* 21 vars */) = 0
brk(NULL)                               = 0x55feb7684000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
[cut for brevity]
close(3)                                = 0
socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_TCP) = 3
setsockopt(3, SOL_TCP, TCP_NODELAY, [1], 4) = 0
setsockopt(3, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(6000), sin_addr=inet_addr("172.17.252.209")}, 16 [hangs here...]

I have the same issue. It would also be nice if it were possible to change the network profile of the vEthernet adapter that WSL2 creates to Private. This way, we could at least disable the firewall for private networks. I tried doing this in PowerShell, but PS claims the adapter doesn't exist (I'm using the correct alias):

PS C:\Users\Jeff> Set-NetConnectionProfile -InterfaceAlias "vEthernet (WSL)" -NetworkCategory Private
Set-NetConnectionProfile : No MSFT_NetConnectionProfile objects found with property 'InterfaceAlias' equal to
'vEthernet (WSL)'.  Verify the value of the property and retry.
At line:1 char:1
+ Set-NetConnectionProfile -InterfaceAlias "vEthernet (WSL)" -NetworkCa ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (vEthernet (WSL):String) [Set-NetConnectionProfile], CimJobException
    + FullyQualifiedErrorId : CmdletizationQuery_NotFound_InterfaceAlias,Set-NetConnectionProfile

I want to connect from WSL2 to X410. And this works currently:
Check Settings -> Firewall -> Advance Settings.
In the opened window, check in-site rules, you can find TCP & UDP rules of X410. You can double click each rule, switch to advance tab in the dialog, check on all three checkboxes: domain, private, universal. This changes the profile private to all.

For xeyes demo:

sudo apt install libgtk2.0-0 libxss1 libasound2
export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):0.0
sudo apt install x11-apps -y && xeyes

Allowing traffic for Public networks via firewall rules works as described by @faymek, But it's kind-of working on my nerves security-wise.

So I tried to make the network private using the tricks mentioned here and here, but to no avail. Even after disabling and re-enabling the device (vEthernet (WSL) / Hyper-V Virtual Ethernet Adapter) the firewall still blocks it. And rebooting the host recreates the keys in the registry. I even tried protecting the keys with access permissions, but Windows can still overwrite them on reboot.

@jovton also having the same problem. After disabling public profile vEthernet WSL rule - it works untill reboot. Tried with admin privileges also - button "apply" is simply disabled, all you can do is either "OK" or "Cancel" - which in term disabling defender rule for current session only.

Is there any solution to this? Or maybe script I can run at startup to make it automatic?

@sandric: I wrote this PS script to deal with the WSL2 IP address changing on reboot:

https://github.com/paul-reilly/WSL2-Xming-Init

It works with firewall active on my machine at least.

upon reboot, I disable the firewall on the WSL2 interface with an Administrator Powershell:

Copyright (C) Microsoft Corporation. All rights reserved.

Try the new cross-platform PowerShell https://aka.ms/pscore6

PS C:\WINDOWS\system32> Set-NetFirewallProfile -DisabledInterfaceAliases "vEthernet (WSL)"

this only works after I've launched the X client that is trying to talk to my VcXsrv

I launch my X client (xterm) with a desktop shortcut whose "Target" is set to:

C:\Windows\System32\wsl.exe /mnt/c/Users/me/wslrun.sh /usr/bin/X11/xterm -ls

Where wslrun.sh is:

#!/bin/bash
exec 1> wslrun.log 2>&1

PATH=/usr/bin:/bin
# DISPLAY to default gateway
ip_r_l_default=( $(ip r l default) )
export DISPLAY=${ip_r_l_default[2]}:0.0
cd ~
nohup "$@" &
# don't understand why I need this sleep
sleep 1

Tedious parts of this:

  1. the Powershell script, which has to run on every reboot
  2. the fact that the WSL2 interface dies whenever I change WiFi networks (all X clients die, poo)

Just chiming in that it was very unintuitive to figure out that the network being created was marked public and that's why I couldn't actually access host services due to the firewall. I'd expect it to be marked private.

I have the same issue. It would also be nice if it were possible to change the network profile of the vEthernet adapter that WSL2 creates to Private. This way, we could at least disable the firewall for private networks. I tried doing this in PowerShell, but PS claims the adapter doesn't exist (I'm using the correct alias):

PS C:\Users\Jeff> Set-NetConnectionProfile -InterfaceAlias "vEthernet (WSL)" -NetworkCategory Private
Set-NetConnectionProfile : No MSFT_NetConnectionProfile objects found with property 'InterfaceAlias' equal to
'vEthernet (WSL)'.  Verify the value of the property and retry.
At line:1 char:1
+ Set-NetConnectionProfile -InterfaceAlias "vEthernet (WSL)" -NetworkCa ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (vEthernet (WSL):String) [Set-NetConnectionProfile], CimJobException
    + FullyQualifiedErrorId : CmdletizationQuery_NotFound_InterfaceAlias,Set-NetConnectionProfile

This would just be a workaround and is not good.

All you need to do is add an inbound firewall rule using the program name

C:\Program Files\VcXsrv\vcxsrv.exe

For the record, I added some more surgical options and documented here:

https://github.com/cascadium/wsl-windows-toolbar-launcher#firewall-rules

For me though the ideal solution would be for this to work:

#4619

Confirmed adding the firewall rule and limiting the source IP scope range works. Functional and secure!

Firewall

Just a note, the settings from the above comment work for me, but I had trouble finding them: control panel > system and security > windows defender firewall > advanced settings > inbound rules > edit the vcxvsrv rule for public networks.

Also, since the hostname is in the DNS forwarder, you can do

export DISPLAY=$(host $HOST | head -n1 | cut -d' ' -f4):0

to set the display

Confirmed adding the firewall rule and limiting the source IP scope range works. Functional and secure!

Firewall

I tried this method but it didn't work. After some searching I find that there are two block rule of "VcXsrv windows xserver" in my firewall rule list and these rules take precedence. Windows OS will add rules to your firewall when you first start VcXsrv windows xserver, and you should disable these rules manually(not remove it, or Windows OS will try to add it again when you open VcXsrv next time).

@QingGo You just need to edit the TCP rule for "VcXsrv windows xserver" from Block to Allow, no need to disable and create a new rule. I have successfully used this approach to allow WSL 2 connect to a Postgres SQL installed on Windows.

P/S: can someone enlighten me why we limit the IP range to 172.16.0.0/12 ?

@QingGo You just need to edit the TCP rule for "VcXsrv windows xserver" from Block to Allow, no need to disable and create a new rule. I have successfully used this approach to allow WSL 2 connect to a Postgres SQL installed on Windows.

P/S: can someone enlighten me why we limit the IP range to 172.16.0.0/12 ?

It's a standard private ip subnet range that wsl seems to rattle around:

https://tools.ietf.org/html/rfc1918

WSL may pick the ip range 192.168.0.0/16 too:

image

This firewall setting should cover all case

image

Hmm if you add that range, you get most home networks, and there's some chance of an attack via a compromised printer or whatever.
Granted, very unlikely but not impossible.

The rule should only allow connections from the local pc.

Because powershell allows we to modify firewall rule, so I think writing a script to update wsl 2 ip address for each inbound rules maybe a good idea, we only need to create the rules manually once and run the script after windows startup. Some thing like this: (run in admin shell)

Import-Module -Name 'NetSecurity'

$wsl2Ip = wsl.exe /bin/bash -c "ip addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}'"

Get-NetFirewallRule -Direction Inbound | Where-Object {
    $_.DisplayName -eq "postgres.exe" `
        -and ($_ | Get-NetFirewallPortFilter).Protocol -eq "TCP"
} | ForEach-Object {
    Set-NetFirewallRule -Name $_.Name -RemoteAddress $wsl2Ip
}

Related to #4150

This is the script I use, run via Task Scheduler on login, sourced from #4150 :

$remoteip = wsl.exe /bin/bash -c "ip addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}'"
$found = $remoteip -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}';

if( !$found ){
  echo "The Script Exited, the ip address of WSL 2 cannot be found";
  exit;
}

#[Ports]

#All the ports you want to forward separated by comma
$ports=@(80,8080,443,10000,3000,5000);


#[Static ip]
#You can change the addr to your ip config to listen to a specific address
$addr='0.0.0.0';
$ports_a = $ports -join ",";


#Remove Firewall Exception Rules
iex "Remove-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' ";

#adding Exception Rules for inbound and outbound Rules
iex "New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Outbound -LocalPort $ports_a -Action Allow -Protocol TCP";
iex "New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Inbound -RemoteAddress $remoteip -Action Allow -Protocol TCP";

for( $i = 0; $i -lt $ports.length; $i++ ){
  $port = $ports[$i];
  iex "netsh interface portproxy delete v4tov4 listenport=$port listenaddress=$addr";
  iex "netsh interface portproxy add v4tov4 listenport=$port listenaddress=$addr connectport=$port connectaddress=$remoteip";
}

Cross WSL 2 distro access via ports published to Windows host should work bypassing all firewalls. Am I right? In the case of Docker Desktop Kubernetes integration using HTTP port 6443 works well. Is it a firewall issue or something else, like of difference between Kubernetes and Docker proxy implementation?

#4585 (comment) Might be helpful for solving firewall problem.

#4585 (comment) Might be helpful for solving firewall problem.

Inlining here since this issue ended up being the landing zone. Props go to @dansanduleac

New-NetFirewallRule -DisplayName "WSL" -Direction Inbound  -InterfaceAlias "vEthernet (WSL)"  -Action Allow

#4585 (comment) Might be helpful for solving firewall problem.

Inlining here since this issue ended up being the landing zone. Props go to @dansanduleac

New-NetFirewallRule -DisplayName "WSL" -Direction Inbound  -InterfaceAlias "vEthernet (WSL)"  -Action Allow

I've found that this configuration does not persist across Windows reboots. Actually I think the rule does persist, it just stops working and I have to create another copy of the rule. Is this a me problem or more general? Running the regular, non-insider 2004 build.

I've found that this configuration does not persist across Windows reboots

I think (but can't prove) that is because the WSL interface is transient as opposed to a permanent fixture of a WSL install. The hangout for that is open issues #4467 #4210 et al.

In my setup I created one init script for WSL2 and one PowerShell script which set up windows settings. WSL script calls powershell script.

I call it when I need it for Android development, that's how it works for me. I created PowerShell script because multiple commands are required and they require administrator priveleges. I did it to reduce the number of times I need to click "Yes" in Windows to 1 :)

The following workaround works for me:

Set-NetFirewallProfile -Name $(Get-NetConnectionProfile).NetworkCategory -DisabledInterfaceAliases $(Get-NetAdapter | Where-Object Name -like 'WSL').Name

The following workaround works for me:

Set-NetFirewallProfile -Name $(Get-NetConnectionProfile).NetworkCategory -DisabledInterfaceAliases $(Get-NetAdapter | Where-Object Name -like 'WSL').Name

Sure until GPO reapplies it

The following workaround works for me:
Set-NetFirewallProfile -Name $(Get-NetConnectionProfile).NetworkCategory -DisabledInterfaceAliases $(Get-NetAdapter | Where-Object Name -like 'WSL').Name

Sure until GPO reapplies it

The following GPO section could help too:

Computer Configuration -> Policies -> Windows Settings -> Scripts (Startup / Shutdown)

This works, even persists after a reboot. Basically what was already suggested, but using the interface name instead of IP (the IP changes, the interface name does not).

Run this in an elevated PowerShell: New-NetFirewallRule -DisplayName "WSL" -Direction Inbound -InterfaceAlias "vEthernet (WSL)" -Action Allow

Credit to @dansanduleac in this comment.

I inspected the "WSL" rule using the Windows Defender Firewall application and it seems like an allow-everything type of inbound rule. Even if you try creating a new rule via the wizard in the Widows Defender Firewall application, it doesn't give you any option to choose the adapter.

I could be wrong but it seems like the -InterfaceAlias is not doing anything in that PS command and all we're setting is up is a very generic inbound rule that allows all traffic inbound (seems very unsafe).

Could someone please explain how we can confirm that the rule which is set up using that command is specifically tied to inbound connections coming in through the vEthernet adapter?

rmja commented

I found the following to work for me:
Open windows firewall settings, and remove the vEthernet (WSL) connection for each of the Domain, Private, and Public profiles:
image

I was having trouble getting my X11 server to work with WSL2, but I fixed it after reading this thread. I had to allow VcXsrv to communicate through my firewall. Appreciate your help everyone πŸ™‚

I found the following to work for me:
Open windows firewall settings, and remove the vEthernet (WSL) connection for each of the Domain, Private, and Public profiles:
image

@rmja excellent. I think what you propose here is the best solution! You can just uncheck vEthernet instead of configuring a risky inbound firewall rule.

I found the following to work for me:

@rmja and @avzero07, is it not the same as Set-NetFirewallProfile -DisabledInterfaceAliases "vEthernet (WSL)" from above in this thread?

Between this and New-NetFirewallRule -DisplayName "WSL" -Direction Inbound -InterfaceAlias "vEthernet (WSL)" -Action Allow (also from this thread) I'd pick the latter because it doesn't result in the alerted Windows Firewall icon in the systray.

Ideally, it'd be great to have a separate Network Profile (under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles) for vEthernet (WSL), which we could then set to Public or Private similar to what we can do for WiFi.

I've been looking at this, but I haven't figured out yet how to create a custom Windows Network Profile and assign an interface to it.

Updated: following this similar Docker issue, I've tried adding *NdisDeviceType to the vEthernet (WSL) registry key under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class. The goal was make it appear under a separate Windows network profile, so I could use Set-NetConnectionProfile -InterfaceAlias 'vEthernet (WSL)' -NetworkCategory Private to make it private.

Sadly, that did not work and *NdisDeviceType disappeared after a reboot.

Then I tried to create a new profile manually: New-CimInstance -Namespace root/StandardCimv2 -ClassName MSFT_NetConnectionProfile -Property @{Name="WSL"}, so I could try adding vEthernet (WSL) to it somehow. This produced an error: The requested operation is not supported.

I did the following to make it working with Bitdefender Firewall as above solutions did not resolve it.

  1. Create file %USERPROFILE%\wsl-eth0.cmd with the following content and replace 192.168.33.17 with the desired IP address
@echo off
wsl -d Ubuntu -u root ip addr replace 192.168.33.17/24 broadcast 192.168.33.255 dev eth0 label eth0:1
netsh interface ip add address "vEthernet (WSL)" 192.168.33.27 255.255.255.0
  1. Open start menu, type run. Then type shell:startup. Create file wsl-eth0.vbs with the following content
Set WinScriptHost = CreateObject("WScript.Shell")
WinScriptHost.Run Chr(34) & "%USERPROFILE%\wsl-eth0.cmd" & Chr(34), 0
Set WinScriptHost = Nothing
  1. Bitdefender Firewall setup
  • Bring up the Bitdefender interface.
  • Click on Protection, on the left side menu, then click Settings under the Firewall module.
  • Click on Network Adapters and select Home/Office for vEthernet (WSL)
  • Click on Rules -> Add rule and select "Apply this rule to all applications", Network Type: Home/Office.
  • Click on Advanced Settings and input 192.168.33.17 as Custom Remote Address IP, then hit Save.
  1. After restarting the computer run ip addr show eth0 on WSL to get the IP address of your Ubuntu machine and confirm that it is the one you set above.

If the profile was set to Private by default, none of his hokey firewall business would be required. And considering its a NAT Interface behind the main host networkk(s), it's certainly a private network.

In the interim, it would be nice to set it manually as a Private Interface, but on Windows 10 Home, it doesn't show up in the list of adapters in the Control Panel and does not show up in a Get-NetConnectionProfile cmdlet call in PowerShell. The only thing it shows up in is an ipconfig /all call.

Note that if you have a machine (like my work-managed laptop) that has local firewall rules turned off by GPO...

image

...then the following won't work for you:

New-NetFirewallRule -DisplayName "WSL" -Direction Inbound -InterfaceAlias "vEthernet (WSL)" -Action Allow

You can (I think) infer this by the following line from the result from Net-NetFirewallRule: "EnforcementStatus: NotApplicable"

You should get the equivalent rule added by your domain administrators... maybe create an OU for power-users or developers etc.

But when you can't (yet) get it done via appropriate firewall policy, the following will work, with the priviso that Windows Defender will raise this as an insecurity.

Set-NetFirewallProfile -DisabledInterfaceAliases "vEthernet (WSL)"

Regarding this option:

New-NetFirewallRule -Name "WSL" -DisplayName "WSL" -Direction Inbound -InterfaceAlias "vEthernet (WSL)" -Action Allow

@avzero07 asked:

I inspected the "WSL" rule using the Windows Defender Firewall application and it seems like an allow-everything type of inbound rule. Even if you try creating a new rule via the wizard in the Widows Defender Firewall application, it doesn't give you any option to choose the adapter.

I could be wrong but it seems like the -InterfaceAlias is not doing anything in that PS command and all we're setting is up is a very generic inbound rule that allows all traffic inbound (seems very unsafe).

Could someone please explain how we can confirm that the rule which is set up using that command is specifically tied to inbound connections coming in through the vEthernet adapter?

You can check that the rule only applies to the named interface using this command:

Get-NetFirewallInterfaceFilter -AssociatedNetFirewallRule (Get-NetFirewallRule -DisplayName "WSL")

Output should be:

InterfaceAlias : vEthernet (WSL)

(Just to be sure I tested to connect to an open port on my PC from my phone, and indeed the created rule does not open the ports for my main network interface, it only opens the ports for the WSL interface.)


@kppullin mentioned:

I've found that this configuration does not persist across Windows reboots. Actually I think the rule does persist, it just stops working and I have to create another copy of the rule. Is this a me problem or more general? Running the regular, non-insider 2004 build.

Yes, sadly after a reboot the rule doesn't work anymore:

Get-NetFirewallInterfaceFilter -AssociatedNetFirewallRule (Get-NetFirewallRule -DisplayName "WSL")

printed

InterfaceAlias : eb3a4260-024a-4a60-8f01-58c27bd975dd

after I rebooted.

The rule can be modified to work again after reboot, no need to recreate:

Get-NetFirewallInterfaceFilter -AssociatedNetFirewallRule (Get-NetFirewallRule -DisplayName 'WSL')|Set-NetFirewallInterfaceFilter -InterfaceAlias 'vEthernet (WSL)'
Automate adjusting of firewall rule (only works if you have admin rights): Create a task in the windows taskscheduler (taskschd.msc), that runs as your useraccount, "Run only when user is logged on", "Run with highest privileges":

The task doesn't need any triggers, and the action should be:
cmd /c start "" /min powershell -WindowStyle hidden -c Get-NetFirewallInterfaceFilter -AssociatedNetFirewallRule (Get-NetFirewallRule -DisplayName 'WSL')^|Set-NetFirewallInterfaceFilter -InterfaceAlias 'vEthernet (WSL)'
The command uses cmd /c start "" /min to avoid a flashing window. Note the carret (^) before the pipe to ensure that cmd doesn't interpret the pipe for itself and instead sends it to powershell.
After this preparation add
schtasks.exe /run /tn "\\name of your task"
to your ~/.bashrc to run the task at each execution of WSL.

If even after creating the rule a connection can't be established, ensure that no blocking rules accidentally exist.

If an application tries to open a port, you typically get a message like this (sorry for the german localization of Windows πŸ€·β€β™‚οΈ):
firewall question
After accepting that dialog, Windows will not only create allow rules for the selected profiles, but also block rules for the not selected profiles:
firewall result
You need to delete those created block rules (in wf.msc), otherwise the connection is refused because these block rules are more important than our created "WSL" allow rule.

Note: even if you pressed "Cancel" in the firewall question dialog, the block rules will be created...

Any processing ? It causes this #5211

I found the following to work for me:
Open windows firewall settings, and remove the vEthernet (WSL) connection for each of the Domain, Private, and Public profiles:
image

This needs to be bumped because I spent way too long spelunking for a fix for this and this was it.

Agree though that ability to set vEthernet (WSL) to Private net connection profile would be the ideal workaround/real fix...

FWIW I'm on a Windows Hello for Business machine (non-domain-joined - Azure AD joined only w/ Intune etc. -- so it's not using Group Policy) and I was able to adjust the Group Policy setting for merging local firewall policies alone to get things working. I've rebooted the machine and it's persisted and still working.

I realize this may not apply for everyone if they're domain-joined and a scheduled Group Policy enforcement swings around and explicitly resets this to "No," but wanted to throw it out there. You may be surprised and find out that it's not explicitly set to "No" by Group Policy and that it's actually set to "Not Configured," so you may be able to set it explicitly, if not through the Group Policy UI then perhaps through the registry directly.

This is the registry key and property:

Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\WindowsFirewall\PublicProfile

AllowLocalPolicyMerge: 1

To set via PowerShell:

$path = 'HKLM:\SOFTWARE\Policies\Microsoft\WindowsFirewall\PublicProfile'
if (-not (Test-Path -Path $path)) {
    New-Item -Path $path
}

New-ItemProperty -Path $path -Name AllowLocalPolicyMerge -Value 1

At the very least if that doesn't fix it entirely, it should at least open up the ability to add a local firewall rule to do so. (As a side note: I wonder if fully opening up the firewall is necessary or if you just need select ports -- really port 53 UDP was the issue for me for DNS resolution which is mentioned in other issues.)

image

image

Everything is OK if I disable the firewall for the public network.

However, I tried both New-NetFirewallRule -DisplayName "WSL" -Direction Inbound -InterfaceAlias "vEthernet (WSL)" -Action Allow and @rmja 's solution, none of them work.
Get-NetFirewallInterfaceFilter -AssociatedNetFirewallRule (Get-NetFirewallRule -DisplayName "WSL") gives me InterfaceAlias : vEthernet (WSL)

Do you have any suggestions?

@meijieru Suggest you turn on the firewall log within Windows Defender Firewall for packets being dropped, that will allow you to see what is being blocked.

Chaz6 commented

Windows firewall ultimately makes me less secure. I cannot apply a rule that applies only to the WSL network adapter, which means the only way to make this work is either manually check and add the specific ipv4 /32 (why no IPv6 support?), or create a general rule for 172.19.240.0/20 applied to networks of type public (and hope that when I am roaming that the foreign LAN does not use those addresses, otherwise I am left vulnerable), and interface type local area network. It would be much more useful if I could apply a rule that applied to the specific WSL network adapter.

rlnt commented

I found the following to work for me: Open windows firewall settings, and remove the vEthernet (WSL) connection for each of the Domain, Private, and Public profiles: image

I am also using this as the working solution but this will result in Windows yelling at you that you no longer use the recommended firewall configuration. Anyone with a solution for that?
Also this does not save across reboots.

FWIW I'm on a Windows Hello for Business machine (non-domain-joined - Azure AD joined only w/ Intune etc. -- so it's not using Group Policy) and I was able to adjust the Group Policy setting for merging local firewall policies alone to get things working. I've rebooted the machine and it's persisted and still working.

I realize this may not apply for everyone if they're domain-joined and a scheduled Group Policy enforcement swings around and explicitly resets this to "No," but wanted to throw it out there. You may be surprised and find out that it's not explicitly set to "No" by Group Policy and that it's actually set to "Not Configured," so you may be able to set it explicitly, if not through the Group Policy UI then perhaps through the registry directly.

This is the registry key and property:

Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\WindowsFirewall\PublicProfile

AllowLocalPolicyMerge: 1

To set via PowerShell:

$path = 'HKLM:\SOFTWARE\Policies\Microsoft\WindowsFirewall\PublicProfile'
if (-not (Test-Path -Path $path)) {
    New-Item -Path $path
}

New-ItemProperty -Path $path -Name AllowLocalPolicyMerge -Value 1

At the very least if that doesn't fix it entirely, it should at least open up the ability to add a local firewall rule to do so. (As a side note: I wonder if fully opening up the firewall is necessary or if you just need select ports -- really port 53 UDP was the issue for me for DNS resolution which is mentioned in other issues.)

image

image

I improved upon your script so it also checks whether the value exists or not, also after allowing local rules merging 'default' dns started working so no longer need to add dns servers to resolv.conf..

# Powershell as admin
$path = 'HKLM:\SOFTWARE\Policies\Microsoft\WindowsFirewall\PublicProfile'
if (-not (Test-Path -Path $path)) {
    New-Item -Path $path
}
if ((Get-ItemProperty $path).PSObject.Properties.Name -contains "AllowLocalPolicyMerge") {
    Set-ItemProperty -Path $path -Name AllowLocalPolicyMerge -Value 1
} else {
    New-ItemProperty -Path $path -Name AllowLocalPolicyMerge -Value 1
}
# I had to reboot to apply changes in registry

As mentioned this only works for PCs not using GPO, therefore as an alternative there is also this piece of code to create a task to disable FW on the WSL interface altogether, however, as mentioned above, this comes with a side effect of notification that fw is disabled.

# CMD.exe/powershell as admin
schtasks /create /tn "WSL disable FW" /sc onlogon /delay 0000:15 /rl highest /ru system /tr "C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe -Command 'Set-NetFirewallProfile -DisabledInterfaceAliases ''vEthernet (WSL)'''"

Edit: seems it's not persistent even this way.. needs to be re-run manually, unlucky.

FWIW I'm on a Windows Hello for Business machine (non-domain-joined - Azure AD joined only w/ Intune etc. -- so it's not using Group Policy) and I was able to adjust the Group Policy setting for merging local firewall policies alone to get things working. I've rebooted the machine and it's persisted and still working.
I realize this may not apply for everyone if they're domain-joined and a scheduled Group Policy enforcement swings around and explicitly resets this to "No," but wanted to throw it out there. You may be surprised and find out that it's not explicitly set to "No" by Group Policy and that it's actually set to "Not Configured," so you may be able to set it explicitly, if not through the Group Policy UI then perhaps through the registry directly.
This is the registry key and property:
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\WindowsFirewall\PublicProfile
AllowLocalPolicyMerge: 1
To set via PowerShell:

$path = 'HKLM:\SOFTWARE\Policies\Microsoft\WindowsFirewall\PublicProfile'
if (-not (Test-Path -Path $path)) {
    New-Item -Path $path
}

New-ItemProperty -Path $path -Name AllowLocalPolicyMerge -Value 1

At the very least if that doesn't fix it entirely, it should at least open up the ability to add a local firewall rule to do so. (As a side note: I wonder if fully opening up the firewall is necessary or if you just need select ports -- really port 53 UDP was the issue for me for DNS resolution which is mentioned in other issues.)
image
image

I improved upon your script so it also checks whether the value exists or not, also after allowing local rules merging 'default' dns started working so no longer need to add dns servers to resolv.conf..

# Powershell as admin
$path = 'HKLM:\SOFTWARE\Policies\Microsoft\WindowsFirewall\PublicProfile'
if (-not (Test-Path -Path $path)) {
    New-Item -Path $path
}
if ((Get-ItemProperty $path).PSObject.Properties.Name -contains "AllowLocalPolicyMerge") {
    Set-ItemProperty -Path $path -Name AllowLocalPolicyMerge -Value 1
} else {
    New-ItemProperty -Path $path -Name AllowLocalPolicyMerge -Value 1
}
# I had to reboot to apply changes in registry

As mentioned this only works for PCs not using GPO, therefore as an alternative there is also this piece of code to create a task to disable FW on the WSL interface altogether, however, as mentioned above, this comes with a side effect of notification that fw is disabled.

# CMD.exe/powershell as admin
schtasks /create /tn "WSL disable FW" /sc onlogon /delay 0000:15 /rl highest /ru system /tr "C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe -Command 'Set-NetFirewallProfile -DisabledInterfaceAliases ''vEthernet (WSL)'''"

Edit: seems it's not persistent even this way.. needs to be re-run manually, unlucky.

I created automated solution to this it seems.. creating a run-as-admin shortcut that disables the FW for WSL interface and this shortcut is run when opening WSL console.

# powershell as admin
$linkPath = "$env:SystemDrive\WSL_FW.lnk"
$psPath = "$env:WINDIR\System32\WindowsPowerShell\v1.0\powershell.exe"
$WScriptShell = New-Object -ComObject WScript.Shell
$Shortcut = $WScriptShell.CreateShortcut($linkPath)
$Shortcut.TargetPath = $psPath
$Shortcut.Arguments  = '-WindowStyle Hidden -Command "Set-NetFirewallProfile -DisabledInterfaceAliases """vEthernet (WSL)""""'
$Shortcut.Save()
$bytes = [System.IO.File]::ReadAllBytes($linkPath)
$bytes[0x15] = $bytes[0x15] -bor 0x20 #set byte 21 (0x15) bit 6 (0x20) ON
[System.IO.File]::WriteAllBytes($linkPath, $bytes)

# Add this to .bashrc/.zshrc
# Disable FW for WSL Interface
[[ $(ls /dev/pts/  | wc -l) -le 3 ]] && cmd.exe /c "%HOMEDRIVE%\WSL_FW.lnk" 2>/dev/null

I found the following to work for me: Open windows firewall settings, and remove the vEthernet (WSL) connection for each of the Domain, Private, and Public profiles: image

I am also using this as the working solution but this will result in Windows yelling at you that you no longer use the recommended firewall configuration. Anyone with a solution for that? Also this does not save across reboots.

Wakaka, you are the ONE. Thx.

I also have a version of this problem with some insteresting symptoms.

I have 2 users on the same machine, each with their own WSL2 instance. User 1 can make TCP from linux to windows via the 127.0.0.1 address without disabling the firewall, and user 2 (me!) cannot, even if I use the machinename.local DNS.

One option was disabling the firewall on the Public profile (BAD!).

My GPOs stop me changing adapter specific settings on the default firewall profile so the solution described above was not working for me.

However I was allowed to change the protected network connections on just the Public profile for user 2, and that made it work without opening everything up. Cannot explain why 2 users on the same machine have different behaviour but at least now both can work.

In summary - you only need to modify the public profile, not all/default profiles for WSL to be unblocked

image

@rmja and @avzero07, is it not the same as Set-NetFirewallProfile -DisabledInterfaceAliases "vEthernet (WSL)" from above in this thread?

Between this and New-NetFirewallRule -DisplayName "WSL" -Direction Inbound -InterfaceAlias "vEthernet (WSL)" -Action Allow (also from this thread) I'd pick the latter because it doesn't result in the alerted Windows Firewall icon in the systray.

@noseratio

The latter won't work if you have additional rules.

I have a similar problem with XDebug and PhpStorm: The "WSL" firewall rule works. Unfortunately PhpStorm creates additional rules that block all connections to PhpStorm for the public profile. I don't want to deactivate that rule. So I have no other choice but to remove the WSL adapter from the public profile.

Instead of talking about all kinds of workarounds, why couldn't WSL2 just fix this (by providing some way to mark the wsl-host network as private)?

I've struggling to understand why this is still an issue after 3 years of being open. What the hell is going on at Microsoft? My company is now telling me that I can't use WSL2 precisely because they want to enforce a policy of not allowing Public domain firewalls to be disabled. I'm sure I'm not the only person in that boat.

Can we have some kind of update please. @craigloewen-msft - Is there anybody else that could be added to this issue to get some traction?

My missing piece was the firewall Public Profile Firewall State Inbound Connections was set to "Block all connections". After changing this to "Block (default)" adding the rules below using PowerShell as Administrator allowed WSL connections in and out.

New-NetFirewallRule -DisplayName "WSL" -Direction Inbound -InterfaceAlias "vEthernet (WSL)" -Action Allow
New-NetFirewallRule -DisplayName "WSL" -Direction Outbound -InterfaceAlias "vEthernet (WSL)" -Action Allow

image

EDIT: Note that this basically turns off the firewall for WSL - use with caution! For more granular access you can define the specific ports you want to allow in and out with the New-NetFirewallRule PowerShell cmdlet.

LMRW commented

Same issue here. Have to not use the block all incoming firewall setting on public networks, otherwise WSL2 is broken when accessing the internet.

Microsoft: please let us designate WSL2 as private.

Same issue here. Have to not use the block all incoming firewall setting on public networks, otherwise WSL2 is broken when accessing the internet.

Microsoft: please let us designate WSL2 as private.

Just found a workaround that seems to allow this.

First, install Hyper-V Manager if necessary. This is purely to get access to the PowerShell tools it provides to manage VM switches.

Run Set-VmSwitch "WSL" -SwitchType Internal. This converts the switch from a private VM switch to an internal one. It also makes it appear in Network Connections in Control Panel, as well as appearing when you run Get-NetConnectionProfile in PowerShell. You'll see that for vEthernet (WSL) NetworkCategory is listed as Public.

Manually assign an IP to the adapter via Control Panel, something in the 172.XX.XX.1 range, and make sure that your WSL install is on the same subnet.

Run Set-NetConnectionProfile -InterfaceAlias "vEthernet (WSL)" -NetworkCategory Private. You should now be able to ping the host machine from inside the VM without needing to modify any firewall rules.

Slight disclaimer: I've literally only just discovered that this works, so haven't tested it extensively, but it seems to be able to reliably access the Internet and the host machine.

EDIT: Unfortunately I've just found that it doesn't survive a reboot. Ah well.

This is insanely dumb. Why on earth would they choose to set a PURELY INTERNAL NETWORK as "Public" on the firewall settings?? This network has the same level of trust as starbucks wifi. It should be a "Private" network BY DEFAULT. ughh

ipcjs commented

WSL2 already supports systemd and can start the sshd service, so we can use the port forwarding function of ssh to let WSL2 access the host port.
like this:

# In WSL2, you can access port 1080 of the host through port 1081
ssh.exe -f -N -R 1081:127.0.0.1:1080 js@localhost &

Ridiculous. Going back to WSL1. Can't it talk directly to the networking devices anyway?

WSL1 isn't a win neither.. (in terms of previously discussed DNS issues)
WSL1 uses direct entries for DNS servers provided by system in /etc/resolv.conf
But when I connect to VPN it does NOT update resolv.conf automatically, only during wsl restart it seems.
I made a minor script that I put in to the .zshrc (since I use ZSH, in case of bash use .bashrc) file that does update the resolv conf automatically (should work for WSL2 as well)

# AutoUpdate DNS
ps -ef | egrep -i "(sl[e]ep 10|pow[e]rshell)" >/dev/null 2>&1 || (while true;do sudo bash -c "for i in $(powershell.exe 'Get-DnsClientServerAddress | Where-Object AddressFamily -Like 2 | Select-Object –ExpandProperty ServerAddresses' | sort -u | tr '\r\n' ' ');do echo nameserver \$i;done > /etc/resolv.conf && echo -e 'options timeout:1\noptions attempts:1' >> /etc/resolv.conf"; sleep 10;done &)
luxzg commented

Since I just got bumped on email about this issue, I'd like to point everyone to the fact that vSwitch can now be used to directly connect WSL2 distro, officially, no hacks, using "networkingMode=bridged". You do need W11 Pro, which shouldn't be an issue. I've compiled a nice big tutorial couple of days ago as a comment in main networking thread:
#4150 (comment)

Likewise added it to my GitHub:
https://github.com/luxzg/WSL2-fixes

I went through W10 to W11 upgrade (linked instructions for those with "unsupported" hardware), WSL2 Preview, creation of vSwitch, configuration of a bridge, and as a bonus systemd configuration on Ubuntu with complete systemd based networking setup. It should be doable for both newbies and experienced users. Btw, I can now tear up and setup new WSL2 instance with proper networking and full apt upgrades and all in less than 10 minutes, easy-peasy.

For those of you that cannot for whatever reason install Windows 11, its now possible to run WSLg (https://github.com/microsoft/wslg) in WSL2 on Windows 10 builds that have a UBR>= 2311. So, if you are reading this issue because you are trying to run Linux GUIs in Windows using an X-11 server like VcxSrv installed in Windows, then one alternative is to use WSLg instead.

This is solved all the problems I was personally having as I now do not have to disable the Defender firewall for the WSL2 connection in order to get the GUI processes in WSL2 to be able to connect to the X-11 port running in Windows. That in turn allows me to connect to my corporate VPN (which otherwise blocked dues to security policies related to firewall settings).

If you don't have the .2311 build of Windows 10, then install all the latest updates from Windows Update. You need to be updated to Version 22H2. I took the advice from here - https://superuser.com/questions/1754138/running-wsl-that-was-installed-from-the-microsoft-store-results-in-windows-vers. Note if that doesn't get you to UBR 2311, then you may need the preview update https://support.microsoft.com/en-gb/topic/november-15-2022-kb5020030-os-builds-19042-2311-19043-2311-19044-2311-and-19045-2311-preview-237a9048-f853-4e29-a3a2-62efdbea95e2.

I actually couldn't get that via Windows Update - probably because it's a preview release, but I found I could install it manually by downloading from https://www.catalog.update.microsoft.com/Search.aspx?q=KB5020030. Do this at your own risk though - it's a preview release. People seem to think it will be out of preview in a few months, so you might want to wait and use Windows Update.

After that - I rebooted and ensured my DISPLAY env variable setting was set to :0, and WAYLAND_DISPLAY was set to wayland-0 (the required values for WSLg) and WSLg started serving my Linux GUIs!!

Hope you find this helpful!

I wasn't sure if the New-NetFirewallRule command mentioned above might allow external traffic in, so I added -RemoteAddress LocalSubnet:

New-NetFirewallRule -DisplayName "WSL2toHost" -Direction Inbound -InterfaceAlias "vEthernet (WSL)" -Action Allow -RemoteAddress LocalSubnet

My understanding is that this will allow only traffic from the local subnet. I'm not sure if it's strictly needed though. Can anyone confirm one way or the other?

kkm000 commented

@therealkenc This has had the status "investigation required" for 2.5 years. How is... the investigation going? Any chance this is fixable? Is WSL2 fundamentally incompatible with Windows networking? There are dozens of cross-referencing issues, this is a real problem for so many people.

I believe that indicating the network as Private could resolve the issue, at least partially, if that's a possibility at all. The VM switch adapter connection profile is not exposed through WMI, so changing its profile the "normal" way, with Set-NetConnectionProfile, is impossible. Other Internal VM switches are visible, only not the WSL's one.

> Get-NetConnectionProfile -InterfaceAlias 'vEthernet (WSL)'
Get-NetConnectionProfile: No MSFT_NetConnectionProfile objects found with property 'InterfaceAlias' equal to 'vEthernet (WSL)'.  Verify the value of the property and retry.

> Get-NetConnectionProfile | ft InterfaceAlias,NetworkCategory,IPv4Connectivity

InterfaceAlias   NetworkCategory IPv4Connectivity
---------------- --------------- ----------------
Wi-Fi                    Private         Internet
vEthernet (buba)         Private     LocalNetwork

The second row is a Hyper-V internal switch, visible in Control Panel/Networking, but the WSL one isn't. It's interesting that both are visible in the long output of Get-VMSwitch | fl *, also returned through WMI(!); I compared them, no differences. The network interface is not visible in Device Manager either, although the Hyper-V switch is, as "Hyper-V Virtual Ethernet Adapter #2". I don't understand what is really going on.

kgonia commented

This one help me to to debug with PyCharm using enviroment in WSL 2

#4585 (comment)

z11k commented

Related to #4150

This is the script I use, run via Task Scheduler on login, sourced from #4150 :

$remoteip = wsl.exe /bin/bash -c "ip addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}'"
$found = $remoteip -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}';

if( !$found ){
  echo "The Script Exited, the ip address of WSL 2 cannot be found";
  exit;
}

#[Ports]

#All the ports you want to forward separated by comma
$ports=@(80,8080,443,10000,3000,5000);


#[Static ip]
#You can change the addr to your ip config to listen to a specific address
$addr='0.0.0.0';
$ports_a = $ports -join ",";


#Remove Firewall Exception Rules
iex "Remove-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' ";

#adding Exception Rules for inbound and outbound Rules
iex "New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Outbound -LocalPort $ports_a -Action Allow -Protocol TCP";
iex "New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Inbound -RemoteAddress $remoteip -Action Allow -Protocol TCP";

for( $i = 0; $i -lt $ports.length; $i++ ){
  $port = $ports[$i];
  iex "netsh interface portproxy delete v4tov4 listenport=$port listenaddress=$addr";
  iex "netsh interface portproxy add v4tov4 listenport=$port listenaddress=$addr connectport=$port connectaddress=$remoteip";
}

finally something what works also for me. yes it was need of rules for firewall... i will borrow it.. thx

My solution:
run_in_background.vbs:

Set WshShell = CreateObject("WScript.Shell") 
WshShell.Run "cmd /c <YOUR_ABSOLUTE_PATH>\disable-wsl-public-profile.bat",0

disable-wsl-public-profile.bat:

wsl exit && powershell -Command "Set-NetFirewallProfile -Profile Public -DisabledInterfaceAliases 'vEthernet (WSL)'"

image
image
image

My solution is to completely reinstall my WSL by: 1

  • removing any Windows Subsystem for Linux Update
  • then, disabling and enabling these two features (reboot after disabling the features):
    • Windows Subsystem for Linux
    • Virtual Machine Platform

By doing this, I assume that the WSL network interface has reconfigured.

Footnotes

  1. NotTheDr01ds, β€œAnswer to β€˜Completely reinstall WSL,’” Super User. Accessed: Dec. 24, 2023. [Online]. Available: https://superuser.com/a/1619435 ↩