Node.JS SSH2.js multihop 多段SSH方法

ssh2.jsを使って簡単に多段ポート転送する方法です。 このサンプルで何段でもSSH可能です。 この例は、まずconn1(踏み台サーバー)をRaspberry Piにして、conn2が最終接続するサーバーです。 今回もconn2はエックスサーバーです。

サンプルプログラム

説明は下に書いています。

const fs = require('fs');
const {Client} = require('ssh2')
const conn1 = new Client()
const conn2 = new Client()

const main = async ()=>{
  conn1.on('ready', () => {
    console.log("conn1 connection ready");
    conn1.forwardOut('127.0.0.1', 62345, 'hostname.xserver.jp', 10022, (err, stream) => {
      if (err) {
        console.log('conn1 :: forwardOut error: ' + err);
        return conn1.end();
      }
      conn2.connect({
        sock: stream,
        username: 'username',
        privateKey: fs.readFileSync('fullpath','utf8'),
        passphrase: '<your passphrase>'
      });
    })
  });
  
  conn1.connect({
    host: '192.168.11.4',
    port:22,
    username: 'pi',
    privateKey: fs.readFileSync('<full_path>','utf8'),
    passphrase: '<your passphrase>'
    //password: '<your password' //if you are using paasword instead of private key for SSH
  })
  
  conn2.on('ready', () => {
    console.log('conn2:: connection ready');
    conn2.exec('pwd', (err, stream) => {
      if (err) {
        console.log('conn2:: exec error: ' + err);
        return conn1.end(); // 親のconn1を終了したら、conn2も終了する
      }
      stream.on('close', () => {
        conn1.end(); // 親のconn1を終了したら、conn2も終了する
      }).on('data', (data) => {
        console.log(data.toString());
      });
    });
  });
}

main();

説明

私が分かりにくかった事を中心に書いています。

  • conn1.forwardOutはconn1(=Raspberry pi)でポート転送をする事です。
  • なので、conn1.forwardOutの127.0.01(localhost)はRaspberry Pi自身の内部のIPアドレスです。
  • conn1.forwardOutの62345はRaspberry Piの127.0.0.1の使っていないポート番号です。 6万番台で適当に使いました。 (nmap 127.0.01で使用ポート番号を確認できます。)
  • Raspberry Pi の127.0.0.1:62345をエックスサーバに転送すると記述しています。
  • hostname.xserver.jpには転送先(conn2)のIPアドレスかホスト名で置き換えてください。
  • 10022には転送先のSSHのポート番号で置き換えてください。 エックスサーバのSSHポート番号は10022で固定なので10022を入れています。
  • Raspberry Piは鍵でのSSH通信設定しているので、privateKeyとpassphraseを設定しています。 パスワード(初期設定)の場合は、privateKeyとpassphraseは不要で、その代わりpassword;”あなたのパスワード”を使う必要があります。
  • privateKeyにはfs.readFileSyncを使っています。 node-sshの場合はfs.readFileSyncは不要でした。
  • conn1.forwardOutのcallbackで設定しているstreamでの通信とするので、conn2.connectのsockにstreamを渡しています。
  • これで、conn2からレスポンスがあったら、stream.on(‘data’,(data)=>{})で受取っています。
  • 上記の例では、conn2.exeでLinuxのpwdコマンドを送信し、conn2のエックスサーバーから、現在ディレクトリ名が、stream.on(‘data’, (data)=>{})に届いて、文字列としてconsole出力されます。

コメント