前言

最近有使用WSL的需求WSL2,在实现网络互通时出现了些问题,默认的网络模式是 NAT,虽然这样隔离得很干净,但也带来了一丢丢小麻烦——比如从外部网络访问 WSL 的时候,直接用宿主机 IP + 端口是行不通的喔 (´;ω;)。于是雨晴翻了翻微软官方文档,帮大家在不使用 mirror 网络模式的 Windows 10 上,整理出了一套轻松实现网络互访的小妙招~

先导

动手之前,咱们先来瞄一眼 WSL2 的网络拓扑,这样理解起来会更清晰喵~
WSL 与 Windows 的网络拓扑长这样:

1
WSL -NAT> Windows -> Ethernet

一眼就能看出来叭:当外部网络想访问 WSL 的时候,宿主机并不会自动把请求里的目标地址转换成 WSL 的 IP 地址,所以从外面直接连进来就变得不那么方便啦 (๑•́ω•̀๑)

而且呢,因为 WSL 和 Windows 主机是走一块虚拟网卡来聊天的,所以想在 Windows 上直接用 localhost 去访问 WSL 里跑的服务,也是不行的哦!

那怎么办呢?嘿嘿,其实超简单的——我们只需要找一个”小帮手”,把发到主机上的请求乖乖地转发到 WSL 上就好啦~

Netsh 配置转发

为了方便大家,雨晴手搓了一个 PowerShell 脚本,几秒钟就能搞定端口转发,超省心的说~(≧▽≦)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#Requires -RunAsAdministrator

function Get-WSLIP {
try {
$ip = (wsl hostname -I).Trim().Split(' ')[0]
if ($ip -match '^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$') {
return $ip
} else {
Write-Host "[错误] 无法解析 WSL2 IP 地址,请确认 WSL2 正在运行。" -ForegroundColor Red
return $null
}
} catch {
Write-Host "[错误] 获取 WSL2 IP 失败: $_" -ForegroundColor Red
return $null
}
}

function Show-CurrentRules {
Write-Host "`n========== 当前 v4tov4 端口转发规则 ==========" -ForegroundColor Cyan
$rules = netsh interface portproxy show v4tov4
if ($rules -and $rules.Count -gt 1) {
$rules | ForEach-Object { Write-Host $_ }
} else {
Write-Host "(无转发规则)" -ForegroundColor Yellow
}
Write-Host "==============================================`n" -ForegroundColor Cyan
}

function Add-PortProxy {
param([string]$ListenPort, [string]$ConnectAddress)

$result = netsh interface portproxy add v4tov4 `
listenport=$ListenPort `
listenaddress=0.0.0.0 `
connectport=$ListenPort `
connectaddress=$ConnectAddress 2>&1

if ($LASTEXITCODE -eq 0) {
Write-Host "[成功] 已添加转发: 0.0.0.0:$ListenPort -> $ConnectAddress`:$ListenPort" -ForegroundColor Green
} else {
Write-Host "[失败] 添加转发规则出错: $result" -ForegroundColor Red
}
}

function Remove-PortProxy {
param([string]$ListenPort)

$result = netsh interface portproxy delete v4tov4 `
listenport=$ListenPort `
listenaddress=0.0.0.0 2>&1

if ($LASTEXITCODE -eq 0) {
Write-Host "[成功] 已删除转发规则: 0.0.0.0:$ListenPort" -ForegroundColor Green
} else {
Write-Host "[失败] 删除转发规则出错: $result" -ForegroundColor Red
}
}

# ==================== 主程序 ====================
while ($true) {
Show-CurrentRules

Write-Host "请选择操作:" -ForegroundColor White
Write-Host " 1 - 添加端口转发" -ForegroundColor Green
Write-Host " 2 - 解除端口转发" -ForegroundColor Yellow
Write-Host " 0 - 退出脚本" -ForegroundColor Gray
$choice = Read-Host "`n请输入选项 (1/2/0)"

switch ($choice) {
'1' {
$wslIp = Get-WSLIP
if (-not $wslIp) { continue }

$port = Read-Host "请输入要转发的端口号"
if ($port -notmatch '^\d+$' -or [int]$port -lt 1 -or [int]$port -gt 65535) {
Write-Host "[错误] 无效的端口号: $port" -ForegroundColor Red
continue
}

Write-Host "检测到 WSL2 IP: $wslIp" -ForegroundColor Cyan
Add-PortProxy -ListenPort $port -ConnectAddress $wslIp
}
'2' {
$port = Read-Host "请输入要解除转发的端口号"
if ($port -notmatch '^\d+$' -or [int]$port -lt 1 -or [int]$port -gt 65535) {
Write-Host "[错误] 无效的端口号: $port" -ForegroundColor Red
continue
}
Remove-PortProxy -ListenPort $port
}
'0' {
Write-Host "再见!" -ForegroundColor Gray
break
}
default {
Write-Host "[提示] 无效选项,请输入 1、2 或 0" -ForegroundColor Yellow
}
}

Start-Sleep -Milliseconds 500
}

把它复制下来,新建一个 .ps1文件,粘贴进去,保存,然后以管理员身份运行就能进入程序主界面啦~

脚本使用方法

假设我们在 WSL 上跑了一个监听 0.0.0.0:8080 的服务,平时呢需要拿 WSL 虚拟网卡的 IP + 端口才能连上。但有了脚本之后,只需要使用本机ip+8080 端口,发送到本机 8080 端口的请求就会被自动转发到 WSL 的 8080 端口上,就像这样:

1
外部请求 -> 本机 -Netsh规则-> WSL

使用例

雨晴在 WSL 上开了一个监听 1256418443 端口的 Cobalt Strike Team Server,然后逐个把它们添加进转发规则里~
img

试着用 127.0.0.1 连接一下:
img

嘿嘿,成功连上啦!本地的 beacon 也乖乖上线了~
img