ssh2 accepts an already connected stream through its sock option. Let socksv5 establish the route to the SSH server, then hand that stream to 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 is the application's existing SSH configuration, including its account, key and hostVerifier policy. The SOCKS host and port identify the intermediary; sshConfig.host and port identify the final SSH service.

The example uses a SOCKS endpoint without authentication. For an SSH server reachable from the public internet, the SOCKS5 proxy list can supply candidates; each still needs to permit the SSH destination and port. For its username/password method, use socks.auth.UserPassword(proxyUser, proxyPassword) in auths. Those credentials do not replace the SSH account.

localDNS false passes the destination hostname to the SOCKS server, using proxy-side destination resolution. Without that explicit choice, socksv5's documented default tries local resolution.

The SOCKS callback runs after negotiation. Wait for ssh2's ready event before requesting SFTP. These are separate successful stages; neither a TCP connection to the proxy nor a SOCKS reply proves that SSH authentication or the SFTP subsystem succeeded.

متعلقہ مضامین