scala 通过JSch SSH隧道与远程进程/服务器通信

k2fxgqgv  于 2023-04-30  发布在  Scala
关注(0)|答案(1)|浏览(198)

我试图在JSch中以编程方式完成在Bash中工作良好的工作。我建立了一个SSH隧道,然后通过隧道进行通信。我应该每隔10秒左右发送一个身份验证字符串,作为回报,我将从远程主机获得稳定的行流。在JSch中,我已经建立了到远程主机的连接,但是当我尝试使用direct-tcpip选项设置通道,阅读和写入通道的getInputStreamgetOutputStream时,它抛出了一个异常failed to initialize the channel。在阅读了人们在其他SO回答中关于JSch的内容后,我在尝试写入outputStream之前做了channel.connect()。这就是Bash的工作原理:
在一个shell中:

ssh -l username -L LOCALPORT:127.0.0.1:REMOTEPORT REMOTEHOST

另一个shell:

ID='{ "id": 1234, "auth": "abcdefhijklmnopqrstuvwxyz" }'
while true; do echo $ID; sleep 10; done | nc localhost LOCALPORT

下面是一些Scala调用JSch的测试代码。我知道这很艰难。我只是想让JSch为我工作

import com.jcraft.jsch._

object Main extends Log4JLogging {
  def main(args: Array[String]): Unit = {
    // $ ssh -l username -L LOCALPORT:127.0.0.1:REMOTEPORT REMOTEHOST
    // $ ID='{ "id": 1234, "auth": "abcdefghijklmnopqrstuvwxyz" }'
    // $ while true; do echo $ID; sleep 10; done | nc localhost LOCALPORT

    val remoteIpaddr = "123.45.54.321"
    val localhost = "127.0.0.1"
    val sshPort = 22
    val tunnelLocalPort = LOCALPORT
    val tunnelRemotePort = REMOTEPORT

    val usernameAtRemoteHost = "username"
    val privateKeyForRemoteHost = "ssh/for-remotehost/id_rsa"

    val auth = "{ \"id\": 1234, \"auth\": \"abcdefghijklmnopqrstuvwxyz\" }\n"
    try {
      val currentWorkingDirectory: String = System.getProperty("user.dir")
      val pathPrivateKeyForRemoteHost: String = s"$currentWorkingDirectory/$privateKeyForRemoteHost"
      JSch.setConfig("server_host_key", JSch.getConfig("server_host_key") + ",ssh-rsa")
      JSch.setConfig("PubkeyAcceptedAlgorithms", JSch.getConfig("PubkeyAcceptedAlgorithms") + ",ssh-rsa")
      val tunnelJSch = new JSch()
      tunnelJSch.addIdentity(pathPrivateKeyForRemoteHost)
      val tunnelSessionPort = sshPort
      val tunnelSession = tunnelJSch.getSession(usernameAtRemoteHost, remoteIpaddr, tunnelSessionPort)
      tunnelSession.setConfig("StrictHostKeyChecking", "no") // yes I know this is bad, will change once things work
      tunnelSession.setPortForwardingL(tunnelLocalPort, localhost, tunnelRemotePort)
      tunnelSession.connect()

      val tunnelChannel = tunnelSession.openChannel("direct-tcpip")
      val input = tunnelChannel.getInputStream()
      val output = tunnelChannel.getOutputStream()
      tunnelChannel.connect()
//      tunnelChannel.setInputStream(System.in)
//      tunnelChannel.setOutputStream(System.out)
      output.write(auth.getBytes(StandardCharsets.UTF_8))
      val buffer = new Array[Byte](1024)
      var n = input.read(buffer)
      while (n > 0) {
        n = input.read(buffer)
      }
//      val dataJsch = new JSch()
//      dataJsch.addIdentity(pathPrivateKeyForRemoteHost)
//      val dataSession = dataJsch.getSession(usernameAtRemoteHost, localhost, tunnelLocalPort)
//      dataSession.setConfig("StrictHostKeyChecking", "no") // yes I know this is bad, will change once things work
//
//      val dataChannel = dataSession.openChannel("forwarded-tcpip")
//      dataChannel.setInputStream(System.in)
//      dataChannel.setOutputStream(System.out)
//      dataChannel.connect()
//
//      val input = dataChannel.getInputStream()
//      val output = dataChannel.getOutputStream()
//      output.write(auth.getBytes(StandardCharsets.UTF_8))
//      val buffer = new Array[Byte](1024)
//      var n = input.read(buffer)
//      while (n > 0) {
//        n = input.read(buffer)
//      }
//      dataChannel.disconnect()
      tunnelSession.disconnect()
    } catch {
      case e: Exception =>
        logStackTrace(e)
    System.exit(1)
    }
  }
}
643ylb08

643ylb081#

看起来您希望direct-tcpip以某种方式神奇地连接到setPortForwardingL。我很确定不会的。你基本上是在尝试两次同样的事情,但在这两种情况下,你都做了所有需要做的事情。
或者:

  • Socket连接到localhost:tunnelLocalPort,并通过它与远程端通话。这有点夸张,但也许更容易实现。
  • 或正确设置tunnelChannel(通过调用setHostsetPort)。或者更确切地说,使用Session.getStreamForwarder就可以做到这一点。

相关问题