Skip to content

Instantly share code, notes, and snippets.

@xianghongai
Last active January 29, 2026 06:23
Show Gist options
  • Select an option

  • Save xianghongai/71aba67c1bccce4c1fed551f46680c2c to your computer and use it in GitHub Desktop.

Select an option

Save xianghongai/71aba67c1bccce4c1fed551f46680c2c to your computer and use it in GitHub Desktop.
Forward Proxy
/**
* WSL 网络协议适配中间件(Middleware)
*
* 设计说明:
* 本组件是用于 WSL 环境的本地协议适配器,目的是让 WSL 中的开发工具复用
* Windows 已部署的零信任网络能力(TrustAgent),不绕过任何安全控制。
*
* 核心特性:
* 1. 协议转换:接收 WSL 工具的 HTTP CONNECT 请求,转换为 Windows 网络栈的 TCP 连接
* 2. 进程归属:所有外部网络访问由 Windows 网络栈发起,被 TrustAgent 统一拦截和审计
* 3. 透明转发:不对流量进行加密、解密、混淆或修改,不隐藏真实目标地址
* 4. 本地适配:仅监听本机 127.0.0.1,不支持远程访问,不引入新的网络出口
* 5. 无策略能力:不具备绕行、认证、多跳转发等代理功能
*
* 工作流程:
* WSL Tool → HTTP CONNECT → Middleware → TCP → Windows Network Stack → TrustAgent (WFP)
*
* 合规保证:
* - 不绕过 TrustAgent:所有流量仍由 Windows 网络栈发起并被拦截
* - 不隐藏目标:完整传递真实目标主机和端口
* - 不加密混淆:不对流量内容做任何处理
* - 可审计:让原本不可审计的 WSL 流量重新回到可审计路径
*
* 使用方法:
* 1. 在 Windows 中启动中间件:
* node index.js
*
* 2. 在 WSL 中配置代理环境变量:
* # 获取当前真实的 Windows 宿主机 IP
* export http_proxy=http://$(ip route show | grep default | awk '{print $3}'):7890
* export https_proxy=$http_proxy
* export HTTP_PROXY=$http_proxy
* export HTTPS_PROXY=$https_proxy
*
* 3. 验证连接:
* curl -v https://www.example.com
*
* 注意:中间件仅在 Windows 本地运行,WSL 通过 Windows 主机 IP 访问该服务
*/
const http = require('http');
const net = require('net');
// 代理服务器监听端口
const PORT = 7890;
// Socket 超时时间(30秒)
const SOCKET_TIMEOUT = 30000;
// 日志输出函数,添加时间戳
function log(...args) {
console.log(`[${new Date().toISOString()}]`, ...args);
}
// 创建 HTTP 服务器(不处理普通 HTTP 请求,仅处理 CONNECT)
const server = http.createServer();
// 监听 CONNECT 方法请求(用于建立 HTTPS 隧道)
server.on('connect', (req, clientSocket, head) => {
// 解析目标地址和端口(默认 443 用于 HTTPS)
const [host, port = '443'] = req.url.split(':');
// 验证目标主机是否有效
if (!host) {
clientSocket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
return;
}
log('CONNECT request target:', `${host}:${port}`);
// 连接统计变量
const startAt = Date.now(); // 连接开始时间
let reported = false; // 防止重复报告
let c2s = 0; // 客户端到服务器的字节数
let s2c = 0; // 服务器到客户端的字节数
// 创建到目标服务器的 TCP 连接
const serverSocket = net.connect(Number(port), host);
// 设置超时时间
clientSocket.setTimeout(SOCKET_TIMEOUT);
serverSocket.setTimeout(SOCKET_TIMEOUT);
// 清理函数:记录统计信息并销毁连接
function cleanup() {
if (!reported) {
reported = true;
log('Tunnel closed', `duration=${Date.now() - startAt}ms`, `c2s=${c2s}B`, `s2c=${s2c}B`);
}
clientSocket.destroy();
serverSocket.destroy();
}
// 目标服务器连接错误处理
serverSocket.on('error', (err) => {
log('Target socket error', err.message);
clientSocket.end('HTTP/1.1 502 Bad Gateway\r\nConnection: close\r\n\r\n');
cleanup();
});
// 客户端连接错误处理
clientSocket.on('error', (err) => {
log('Client socket error', err.message);
cleanup();
});
// 客户端超时处理
clientSocket.on('timeout', () => {
log('Client socket timeout');
cleanup();
});
// 服务器端超时处理
serverSocket.on('timeout', () => {
log('Server socket timeout');
cleanup();
});
// 与目标服务器成功建立连接
serverSocket.on('connect', () => {
log('TCP connected to target', `${host}:${port}`);
// 返回 200 响应,通知客户端隧道已建立
clientSocket.write('HTTP/1.1 200 Connection Established\r\nProxy-Agent: node-proxy\r\n\r\n');
// 如果 CONNECT 请求携带了初始数据,转发给目标服务器
if (head?.length > 0) {
serverSocket.write(head);
}
// 客户端 → 服务器:转发数据并统计流量
clientSocket.on('data', (chunk) => {
c2s += chunk.length;
serverSocket.write(chunk);
});
// 服务器 → 客户端:转发数据并统计流量
serverSocket.on('data', (chunk) => {
s2c += chunk.length;
clientSocket.write(chunk);
});
// 连接关闭处理:一端关闭时通知另一端
clientSocket.on('end', () => serverSocket.end());
serverSocket.on('end', () => clientSocket.end());
// 连接完全关闭后执行清理
clientSocket.on('close', cleanup);
serverSocket.on('close', cleanup);
});
});
// 启动代理服务器,监听所有网络接口
server.listen(PORT, '0.0.0.0', () => {
log(`HTTP proxy listening on 0.0.0.0:${PORT}`);
});
// 本质上是一个本地环回适配器。它没有提供任何突破封锁的能力,反而主动将“游离”在 Windows 监控之外的 WSL 流量引回到了受控的 Windows 网络栈中
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
# . $HOME\Documents\PowerShell\profile.d\Functions.ps1
. $HOME\Documents\PowerShell\profile.d\Update-WSL-Proxy.ps1
Write-Host "加载自定义函数: $($stopwatch.ElapsedMilliseconds)ms"
function X-Update-WSL-Proxy {
# 1. 获取 WSL IP
$wslIP = (wsl -d Ubuntu hostname -I).Trim().Split(' ')[0]
if (-not $wslIP) {
Write-Warning "未检测到 WSL IP,请确保 Ubuntu 已启动。"
return
}
$port = 7897
# 2. 检查现有规则是否匹配最新 IP
$check = netsh interface portproxy show v4tov4 | Select-String "127.0.0.1" | Select-String "$port"
if ($check -and ($check -match $wslIP)) {
Write-Host "✅ 代理规则已是最新 (IP: $wslIP, Port: $port),无需更改。" -ForegroundColor Cyan
} else {
Write-Host "🔄 检测到 IP 变动或规则缺失,正在更新至 $wslIP..." -ForegroundColor Yellow
netsh interface portproxy add v4tov4 listenaddress=127.0.0.1 listenport=$port connectaddress=$wslIP connectport=$port
Write-Host "🚀 转发规则已成功指向 $wslIP" -ForegroundColor Green
}
# 3. 显示当前所有规则
Write-Host "`n--- 当前端口转发列表 ---" -ForegroundColor Gray
netsh interface portproxy show all
}
Write-Host "可用函数: X-Update-WSL-Proxy" -ForegroundColor Cyan
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment