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出力されます。


コメント