Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

一口气搞定 WSL2 的网络问题 #12

Open
hexh250786313 opened this issue Jan 31, 2021 · 12 comments
Open

一口气搞定 WSL2 的网络问题 #12

hexh250786313 opened this issue Jan 31, 2021 · 12 comments
Labels
post blog post type: POST

Comments

@hexh250786313
Copy link
Owner

hexh250786313 commented Jan 31, 2021

文章简介
博文置顶说明
本文介绍 wsl2 的端口转发、网络代理等问题,不会或者少量涉及 wsl2 的安装部署,因为安装教程很容易能找到。这里着重于端口转发、网络代理等容易遇到的坑

一、相关

二、关于 WSL2 的 IP

2.1. 要解决的问题

  1. 把 wsl2 的端口暴露给局域网

2.2. 端口转发

上述问题,可以通过端口转发的方式,让 windows 把 wsl2 的端口转发暴露给局域网,因此需要搞定三件事情:

  1. windows 需要能获取到子系统的模拟 ip 地址(不再需要获取子系统 ip,可以利用 localhost 来映射)
  2. windows 转发对应子系统端口
  3. 破除防火墙的限制

以上三个问题的对应方案如下:

2.2.1 获取子系统的虚拟 IP 地址(这一步已废弃,请直接看下文的 2.2.2)

============================
※ 注意,本第三节已经废弃,不再需要使用这种迂回的方式来映射子系统的 ip

※ 对于获取子系统 ip 不感兴趣的可以直接跳到文章第 2.2.2 小节端口转发

※ 本节不删除只用作存档,修改时间:2024/1/20
============================

  1. go-wsl2-host 下载该软件,这个脚本可以帮忙在 windows 系统中生成一个服务用来获得子系统的虚拟 ip 地址
  2. 在 powershell(后面的章节简写为 pwsh)中用管理员权限安装他:.\wsl2host.exe install
  3. 然后按照提示输入你当前的 windows 服务账号和密码,如果以前没有添加过服务账号,请看第 6 步的补充说明
  4. 重启电脑
  5. 检查服务有无启动成功:
    • 查看 windows 服务中有没有 wsl2host
    • 查看 hosts 文件中有没有多出一行类似于:192.168.82.59 ubuntu.wsl # managed by wsl2-host
    • 都没问题即说明这时候已经可以在 pwsh 脚本中用 ubuntu.wsl 来获取到子系统的虚拟 ip
  6. 补充说明:
    • 第三步的账号密码可以通过以下方式添加:windows 管理工具-本地安全策略-本地策略-用户分配权限-作为服务登录-添加当前登录的微软账号或本地账号(然后检查名称),然后 install 的时候用添加上去的那个账号名,例如你的微软账号可能是 123456789@qq.com,但是添加上去之后的账号名可能是 12345,所以以显示的账号(12345)为准
    • 如果你的系统上没有“本地安全策略”,那么说明你的 windows 版本如家庭版不支持这一操作。但别慌,可以用以下这段脚本下载“本地安全策略”到系统中(保存为 .bat 文件并以管理员权限打开):
      pushd "%~dp0"
      dir /b C:\Windows\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientExtensions-Package~3*.mum >List.txt
      dir /b C:\Windows\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientTools-Package~3*.mum >>List.txt
      for /f %%i in ('findstr /i . List.txt 2^>nul') do dism /online /norestart /add-package:"C:\Windows\servicing\Packages\%%i"
    • 家庭版有时候更新完系统后 wsl2host 服务会失灵,这时候重新 install 即可,重新 install 的时候可能会提示 keys already exist,这时候 remove 一下即可,remove 时会提示错误(不存在 wsl2host 服务),不用在意,只需要知道这时候已经移除了帐号了就行
    • 有的朋友可能会遇到死活无法安装上 wsl2host 服务的情况, 那也有个麻烦点的做法, 就是使用 .\wsl2host.exe debug 指令, 这样也可以手动给 hosts 添加上新的 ip, 这样需要每次开机都手动调下指令 (原因是每次开机宿主机 ip 都不一样), 挺麻烦的

2.2.2. 端口转发

  1. pwsh 中执行:notepad $profile 打开 pwsh 的配置文件,接下来要写两段脚本

  2. 在配置文件中添加如下代码并保存。另外下面的脚本中有 sudo 指令,这个要求你的 pwsh 要事先安装了 sudo 插件,这个是用来获取管理员权限的,请自行搜索安装方法。对于脚本里面的 192.168.10.68 就是你需要映射的端口,一般就是你的宿主机的内网 ip,自行修改,下面是代码:

    function setWslNetsh {
        param (
            $Port
        )
        sudo netsh interface portproxy add v4tov4 listenport=$Port connectaddress=localhost connectport=$Port listenaddress=192.168.10.68 protocol=tcp
        Write-Output "✔ Port($Port) now is out!"
    }
    
    function unsetWslNetsh {
        param (
            $Port
        )
        sudo netsh interface portproxy delete v4tov4 listenport=$Port listenaddress=192.168.10.68 protocol=tcp
        Write-Output "✔ Port($Port) now is not out!"
    }
    
    Set-Alias wsl-netsh-set setWslNetsh
    Set-Alias wsl-netsh-unset unsetWslNetsh
  3. 上面这段代码就是实现端口转发的主要脚本,这时候在 pwsh 中执行:wsl-netsh-set <port> 就能让 windows 把子系统的端口转发出去。例如:wsl-netsh-set 8000 就能把子系统中端口号为 8000 的进程转发出去

  4. 同样的 wsl-netsh-unset <port> 则是取消转发

  5. 另外还可以在子系统中去执行这个指令:pwsh wsl-netsh-set <port>pwsh wsl-netsh-unset <port>

  6. 原理补充:wsl2 的流量转发原理就是会把 wsl2 中的使用到的端口通过 localhost 转发的宿主机,例如你在子系统起了一个 http://localhost:8000 的服务,那么你不需要做任何事情,就可以在宿主机通过 http://localhost:8000 访问到这个服务,而这个脚本就是基于这个原理,通过 netsh 进行流量转发,把特定的 <ip>:<port> 的访问流量转发到 localhost:<port>,这样就能把子系统的端口暴露给局域网了

  7. ipv6 说明,上面的脚本是针对使用了 ipv4 的服务的,从 v4tov4 你就可以看出来,如果你子系统使用的是 ivp6 服务,那么你也可以这样来设置转发和取消转发,你可以自行调整 v4tov6 这一处,看你的宿主机是想用什么 ip 协议来访问这个子系统端口

    sudo netsh interface portproxy delete v4tov6 listenport=8000 listenaddress=192.168.10.68
    sudo netsh interface portproxy add v4tov6 listenport=8000 listenaddress=192.168.10.68 connectport=8000 connectaddress=::1
    
  8. 每次宿主机开机以后你会发现明明上一次开机已经进行过端口映射了,但是为什么这次开机后不生效,这是预料之中的事情,你只需要每次开机完毕后都用 wsl-netsh-unset <port> 取消转发,然后再重新设置一下转发就行了,你可以通过 netsh interface portproxy show all 看到当前有哪些进行了流量转发的地址和端口

2.2.3. 破除防火墙限制

最简单的做法其实就是在防火墙中添加出站和入站规则,添加一下需要暴露到局域网的端口即可。当然也可以把这个写成脚本,需要暴露什么端口直接执行脚本就行,同样在 pwsh 的配置文件中添加代码:

function setFWPort {
    param (
        $Port
    )
    $Port4WSL = "Port4WSL-" + $Port
    $NetFirewallRule = Get-NetFirewallRule
    if (-not $NetFirewallRule.DisplayName.Contains($Port4WSL)) {
        # sudo Remove-NetFireWallRule -DisplayName $Port4WSL
        sudo New-NetFireWallRule -DisplayName $Port4WSL -Direction Outbound -LocalPort $Port -Action Allow -Protocol TCP
        sudo New-NetFireWallRule -DisplayName $Port4WSL -Direction Inbound -LocalPort $Port -Action Allow -Protocol TCP
        Write-Output "✔ New rule for WSL(Port: $Port)!"
    }
    else {
        Write-Output "✔ Rule for WSL(Port: $Port) exists!"
    }
}

function unsetFWPort {
    param (
        $Port
    )
    $Port4WSL = "Port4WSL-" + $Port
    $NetFirewallRule = Get-NetFirewallRule
    if (-not $NetFirewallRule.DisplayName.Contains($Port4WSL)) {
        Write-Output "✔ Rule for WSL(Port: $Port) not exists!"
    }
    else {
        sudo Remove-NetFireWallRule -DisplayName $Port4WSL
        Write-Output "✔ Rule for WSL(Port: $Port) removed!"
    }
}

Set-Alias fw-port-set setFWPort
Set-Alias fw-port-unset unsetFWPort

然后就能用 fw-port-set <port> 来创建新的出入站规则,用 fw-port-unset <port> 移除规则。规则名称定为了 Port4WSL-<port>,可以自行修改

完成上述步骤,就可以把子系统的进程端口暴露到局域网了,例如我在子系统起了一个服务,端口为 8000,windows 在局域网的地址为 192.168.1.215,那么局域网下的其他设备就能通过访问 http://192.168.1.215:8000 访问我子系统下的服务

@hexh250786313 hexh250786313 added the post blog post type: POST label Jan 31, 2021
@GundamDr1ver
Copy link

微软账户该怎么输入密码呢 当时装完系统直接用微软账号登录了 但是输入微软账号的密码却不行

@hexh250786313
Copy link
Owner Author

@WP999 哎?不对,你说的输入密码应该是 .\wsl2host.exe install 时输入的密码吧,这个要以前添加过服务账户才行,具体看第 6 步,因为我刚刚试了下用微软账号应该是可以添加上的

@GundamDr1ver
Copy link

策略组添加微软账号是加上了 然后安装的时候账号密码输入微软账号邮箱加微软账号的密码然后重启电脑 ,就提示无法启动密码错误

@hexh250786313
Copy link
Owner Author

@WP999 试试密码用进入系统时的pin而不要用微软密码。再不行的话那只好用当前用户名试试了,策略组添加当前用户名

@GundamDr1ver
Copy link

放了几天 今天搞定了 ,一直用验证器登录 密码改过一次我给忘记了哈哈😂

@hexh250786313 hexh250786313 reopened this May 8, 2021
Repository owner locked and limited conversation to collaborators May 8, 2021
Repository owner unlocked this conversation May 8, 2021
@LittFlower
Copy link

问题:【输入 ubuntu.wsl 提示不存在这样的程序或命令】重启之后 windows 服务里有 wsl2host ,但是 hosts 文件中没有类似于 192.168.82.59 ubuntu.wsl # managed by wsl2-host 的一行,也无法使用 ubuntu.wsl 这个命令。

我已经尝试过:重启电脑;卸载 wsl2host 后重新安装。

@hexh250786313
Copy link
Owner Author

hexh250786313 commented Jul 29, 2022

@JiuLER 我也发现了, 我明儿有时间研究下, 连 debug 指令也写入不了, 不确定是否 go-host-wsl2 的原因

另外 ubuntu.wsl 不是指令, 是指 host 中的 ip 的解析域名, 例如 hosts 文件中有一行: 10.10.1.47 hello.world 那么你可以用 ping hello.world 看到是 ping 到 10.10.1.47 去了, ubuntu.wsl 同理

所以这个服务的原理其实就是在 wsl 初始化的时候, 把本系统相对于子系统的 ip 找出来再通过写入 host 转发到 ubuntu.wsl 这个域名来实现转发的

@LittFlower
Copy link

@hexh250786313 您说的对。我已经解决 WSL2 的网络问题了,,,通过重装电脑 /捂脸。

但是我的 Vmware Ubuntu1804 还是不能正常联网,在网上试了一些方法,但没有用。

不知道您有没有什么解决方法。

@hexh250786313
Copy link
Owner Author

@JiuLER 关于 vmware 我遇到过的问题不多, 网络的话一般是在 vmware 虚拟机的网络设置里换成桥接模式就可以上网了

以前我也遇到一次过不行的情况, 解决办法是: 左上角编辑按钮 > 虚拟网络编辑器 > 找到对应的虚拟机的的网口 ( 一般是第一个 ) > 选择桥接模式同时把桥接的 "自动" 改为你主机对应的网口

如果不确定哪个是对应的虚拟机的网口, 你可以在对应虚拟机设置的网络设置里的自定义那里看得到

@LittFlower
Copy link

@hexh250786313 我失败了。

@WWz33
Copy link

WWz33 commented Mar 16, 2023

我的情况仅供参考
sudo rm /etc/apt/apt.conf/porxy.conf

@abel533
Copy link

abel533 commented Apr 24, 2023

参考本文脚本和其他资料写了一篇完整的文章,由于是定时发布,需要在北京时间2023-4-24日19:30以后才能访问:

https://blog.csdn.net/isea533/article/details/130334713

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
post blog post type: POST
Projects
None yet
Development

No branches or pull requests

5 participants