ssh2 通过 sock 选项接受一个已连接的流。让 socksv5 建立通往 SSH 服务器的路由,然后把该流交给 SSH:

const socks = require('socksv5');
const { Client } = require('ssh2');

const connection = socks.connect({
  host: sshConfig.host,
  port: sshConfig.port || 22,
  proxyHost: 'proxy.example',
  proxyPort: 1080,
  localDNS: false,
  auths: [socks.auth.None()],
}, socket => {
  const ssh = new Client();
  ssh.on('error', error => console.error(error.message));
  ssh.on('ready', () => {
    ssh.sftp((error, sftp) => {
      if (error) {
        console.error(error.message);
        ssh.end();
        return;
      }
      sftp.readdir('.', (error, entries) => {
        if (error) console.error(error.message);
        else console.log(entries);
        ssh.end();
      });
    });
  });
  ssh.connect({ ...sshConfig, sock: socket });
});
connection.on('error', error => console.error(error.message));

sshConfig 是应用现有的 SSH 配置,包括账号、密钥和 hostVerifier 策略。SOCKS 的主机和端口标识中间层;sshConfig.host 和 port 标识最终的 SSH 服务。

示例使用不带认证的 SOCKS 端点。对于可从公网访问的 SSH 服务器,SOCKS5 代理列表可以提供候选;每个候选仍需允许该 SSH 目标和端口。其用户名/密码方式要在 auths 中使用 socks.auth.UserPassword(proxyUser, proxyPassword)。这些凭据并不替代 SSH 账号。

localDNS false 会把目标主机名交给 SOCKS 服务器,即使用代理侧的目标解析。若不做这一明确选择,socksv5 文档所述的默认行为会尝试本地解析。

SOCKS 回调在协商之后运行。要等到 ssh2 的 ready 事件再请求 SFTP。这是两个各自成功的阶段;到代理的 TCP 连接和 SOCKS 应答都不能证明 SSH 认证或 SFTP 子系统已经成功。

相关文章