WSL2想要连上宿主机Windows里设置的网络代理端口很是蛋疼。
前置条件
PS C:\Users\overlord> wsl -l -v
NAME STATE VERSION
* Ubuntu-20.04 Running 2
获取Host和WSL的ip
首先我们需要获取WSL2的动态IP,再每次Windows系统重启之后,它会动态给WSL2分配一个新IP。
所以可以写个脚本displayip.sh,来动态获取。
#!/bin/bash
echo "Host ip: $(cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }')"
echo "WSL client ip: $(hostname -I | awk '{print $1}')"
运行可查看当前Windows host主机ip、WSL的ip。
chmod +x displayip.sh
./displayip.sh
Host ip: 172.20.96.1
WSL client ip: 172.20.99.149
Windows使用的代理程序
我用的Clash for Windows支持http和socks5代理。
代理端口为1081。
错误尝试
Windows Defender 里新增入站规则
管理员权限ps运行:
New-NetFirewallRule -DisplayName "WSL" -Direction Inbound -InterfaceAlias "vEthernet (WSL)" -Action Allow
会在Windows Defender 防火墙里增加开启一条入站规则“WSL”。这条规则允许全部接口名为 vEthernet (WSL) ——也就是WSL2的入站连接。
在WSL的bash里ping宿主主机,测试连通:
ping 172.20.96.1 -c 4
PING 172.20.96.1 (172.20.96.1) 56(84) bytes of data.
64 bytes from 172.20.96.1: icmp_seq=1 ttl=128 time=0.373 ms
64 bytes from 172.20.96.1: icmp_seq=2 ttl=128 time=0.350 ms
64 bytes from 172.20.96.1: icmp_seq=3 ttl=128 time=0.398 ms
64 bytes from 172.20.96.1: icmp_seq=4 ttl=128 time=0.380 ms
--- 172.20.96.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3114ms
rtt min/avg/max/mdev = 0.350/0.375/0.398/0.017 ms
但是此时通过宿主机的ip并不能访问到代理软件使用的1081接口。用telnet测试接口可得如下结果。
telnet 172.20.96.1 1081
Trying 172.20.96.1...
对1081的连接请求会一直停留在尝试连接的步骤上。
入站规则的用处
增加入站规则其实可以用来让WSL2子系统访问Windows宿主机起的http服务。
例如我用node在Windows宿主机的5000端口起了一个node的server。
PS D:\Codes\nodejs16\tsrctutorial> pnpm preview
> [email protected] preview D:\Codes\nodejs16\tsrctutorial
> vite preview
> Network: http://172.24.0.1:5000/
> Network: http://192.168.56.1:5000/
> Network: http://192.168.3.130:5000/
> Local: http://localhost:5000/
> Network: http://172.20.96.1:5000/
WSL2内用telnet测试的结果就会变成:
telnet 172.20.96.1 5000
Trying 172.20.96.1...
Connected to 172.20.96.1.
Escape character is '^]'.
还可以用curl测试。
curl http://172.20.96.1:5000
...
从Windows宿主机访问WSL2起的服务
新版WSL2里系统已经映射,直接用localhost即可访问。
比如在WLS2里起个简单的node服务器,在Windows的浏览器中用 localhost:port 即可访问。
猜想
可能是Windows Defender的入站规则只对它认识的连接协议放行,而clash的混合http和socks5的协议不在它认识的范围内。
正确方案
配置 Windows Defender
在“高级安全 Windows Defender 防火墙” -- 属性,选项卡“公用配置文件”,状态组里“受保护的网络连接:”右边的“自定义”按钮,打开保护的网络连接窗口取消勾选“vEthernet (WSL)”复选框。
不过配置的缺点是每次重启必须重新配置。原因是vEthernet这个服务必须每次登录WSL2才会出现,Windows Defender 会默认将其纳入保护,我还没有找到Windows Defender默认不保护它的方法。
欢迎留言交流重启后也能生效的WSL和宿主访问的配置方法。
测试连接
telnet
telnet 172.20.96.1 1081
Trying 172.20.96.1...
Connected to 172.20.96.1.
Escape character is '^]'.
curl
curl -x "socks5://172.20.96.1:1081" https://www.google.com
302 Moved
302 Moved
The document has moved
here.
使用场景
先配置好Windows Defender的高级安全,再把宿主机的代理端口设置为WSL2系统代理,或者git的代理。
clash或者其他的代理程序需要开放局域网访问(Allow LAN)。
WSL2里设置系统代理部分,我使用一个bash脚本来做这样的配置。
socks5协议的proxy.sh脚本
#!/bin/bash
hostip=$(cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }')
wslip=$(hostname -I | awk '{print $1}')
port=1081
PROXY_SOCKS="socks5://${hostip}:${port}"
function display() {
echo "Host ip: ${hostip}"
echo "WSL client ip: ${wslip}"
echo "current PROXY: ${PROXY_SOCKS}"
}
function set_proxy() {
export http_proxy="${PROXY_SOCKS}"
export https_proxy="${PROXY_SOCKS}"
echo "env http/https proxy set."
}
function unset_proxy() {
unset http_proxy
unset https_proxy
echo "env proxy unset."
}
function set_git_proxy() {
git config --global http.proxy "${PROXY_SOCKS}"
git config --global https.proxy "${PROXY_SOCKS}"
echo "git config proxy set."
}
function unset_git_proxy() {
git config --global --unset http.proxy
git config --global --unset https.proxy
echo "git conffig proxy unset."
}
if [ "$1" = "display" ]; then
display
elif [ "$1" = "set" ]; then
set_proxy
elif [ "$1" = "unset" ]; then
unset_proxy
elif [ "$1" = "setgit" ]; then
set_git_proxy
elif [ "$1" = "ungit" ]; then
unset_git_proxy
else
echo "incorrect arguments."
fi
第4行port=你Windows代理程序设置的代理端口。
保存后记得chmod +x proxy.sh赋予执行权限。
用法
./proxy.sh display
Host ip: 172.20.96.1
WSL client ip: 172.20.99.149
current PROXY: socks5://172.20.96.1:1081
./proxy.sh set
env http/https proxy set.
./proxy.sh unset
env proxy unset.
./proxy.sh setgit
git config proxy set.
./proxy.sh ungit
git conffig proxy unset.
set之后可以curl或wget访问需要代理连上的地址;setgit之后拉github上连接不上的包。
参考资料
Windows Defender Firewall blocks access from WSL2 · Issue #4139 · microsoft/WSL
Add "allow" rule to Windows firewall for WSL2 network · Issue #4585 · microsoft/WSL
Protecting X410 Public Access for WSL2 via Windows Defender Firewall
[WSL 2] NIC Bridge mode (Has TCP Workaround) · Issue #4150 · microsoft/WSL