使用ssh2建立SSH连接后端口转发失效问题排查
问题描述
建立SSH连接后,希望将其转发到指定端口,再通过代理传输全部数据流量。目前SSH连接已成功建立,但转发端口无法正常工作,无法传输流量,以下是我的代码:
const conn = new Client(); const sshConfig: ConnectConfig = { host: sshIp, port: sshPort, username: sshUsername, password: sshPassword, }; const StaticIP = "127.0.0.1"; conn.on("ready", () => { console.log("ssh connected!"); conn.forwardOut(StaticIP, 4567, sshIp, sshPort, (err, stream) => { if (err) { return; } connectToProxy(StaticIP, 4567); stream.on("data", (data) => { console.log(`received data: ${data}`); }); stream.on("close", () => { console.log("connection is closed!"); }); }); }); console.log("ssh connecting.."); conn.connect(sshConfig);
问题排查与修复方案
1. forwardOut 参数逻辑错误
forwardOut 的作用是创建从本地经SSH隧道到远程目标服务的连接,你的参数填错了:
- 第三个、第四个参数你填了SSH服务器的
sshIp和sshPort,相当于把流量又发回SSH服务器,这不是代理流量的正确逻辑,应该替换成你实际要访问的目标服务地址和端口。 - 第二个参数(本地发起请求的端口)填0即可,不需要指定固定值,系统会分配随机端口。
2. 缺少本地端口监听与双向数据转发
你没有在本地监听4567端口,也没建立本地端口和SSH隧道之间的双向数据通道——这是流量无法传输的核心问题。目前代码只创建了SSH流,但没有把本地端口的请求流量导入流,也没把流返回的数据回传给本地连接。
3. connectToProxy 调用时机错误
你在拿到SSH流后直接调用connectToProxy,但此时本地4567端口没有被监听,连接请求会直接失败,必须等本地端口监听成功后再调用。
修复后的示例代码
const conn = new Client(); const sshConfig: ConnectConfig = { host: sshIp, port: sshPort, username: sshUsername, password: sshPassword, }; const LOCAL_PROXY_PORT = 4567; // 替换成你实际要访问的目标服务地址和端口 const TARGET_SERVICE_HOST = "目标服务IP/域名"; const TARGET_SERVICE_PORT = 80; conn.on("ready", () => { console.log("ssh connected!"); // 监听本地4567端口,接收代理请求 const localProxyServer = require('net').createServer((localSocket) => { // 通过SSH隧道连接到目标服务 conn.forwardOut( '127.0.0.1', 0, TARGET_SERVICE_HOST, TARGET_SERVICE_PORT, (err, sshStream) => { if (err) { console.error("SSH隧道创建失败:", err); localSocket.end(); return; } // 双向转发数据:本地请求 ↔ SSH隧道 localSocket.pipe(sshStream); sshStream.pipe(localSocket); } ); }); // 启动本地代理端口 localProxyServer.listen(LOCAL_PROXY_PORT, '127.0.0.1', () => { console.log(`本地代理已启动:127.0.0.1:${LOCAL_PROXY_PORT}`); // 此时再发起代理连接 connectToProxy('127.0.0.1', LOCAL_PROXY_PORT); }); }); console.log("ssh connecting.."); conn.connect(sshConfig);
关键说明
- 用
net.createServer监听本地4567端口,每收到一个本地连接,就创建对应的SSH隧道到目标服务。 - 通过
pipe方法实现本地socket和SSH流的双向数据转发,这是流量能正常传输的核心。 - 确保
forwardOut指向正确的目标服务,而非SSH服务器本身。 - 等本地端口监听成功后再调用
connectToProxy,保证连接能被正常接收。
内容的提问来源于stack exchange,提问作者Abolfazl Almas
相关产品推荐
相关产品推荐

