当前位置: 首页 > 面试题库 >

通过JSch的SSH隧道

龚沛
2023-03-14
问题内容

我的目的是连接到位于防火墙后面的服务器(主机)。我可以通过连接到网络中的另一台服务器(隧道)然后通过SSH到该服务器来访问此服务器。但是,我无法通过JSch实现相同的方案。

我无法为此编写以下代码。如果我在这里做任何愚蠢的事情,请告诉我。

public class JschExecutor {

    public static void main(String[] args){
        JschExecutor t=new JschExecutor();
        try{
            t.go();
        } catch(Exception ex){
            ex.printStackTrace();
        }
    }
    public void go() throws Exception{

        StringBuilder outputBuffer = new StringBuilder();

        String host="xxx.xxx.xxx.xxx"; // The host to be connected finally
        String user="user";
        String password="passwrd";
        int port=22;

        String tunnelRemoteHost="xx.xx.xx.xx"; // The host from where the tunnel is created

        JSch jsch=new JSch();
        Session session=jsch.getSession(user, host, port);
        session.setPassword(password);
        localUserInfo lui=new localUserInfo();
        session.setUserInfo(lui);
        session.setConfig("StrictHostKeyChecking", "no");

        ProxySOCKS5 proxyTunnel = new ProxySOCKS5(tunnelRemoteHost, 22);
        proxyTunnel.setUserPasswd(user, password);
        session.setProxy(proxyTunnel);

        session.connect(30000);

        Channel channel=session.openChannel("exec");
        ((ChannelExec)channel).setCommand("hostname");

        channel.setInputStream(null);
        ((ChannelExec)channel).setErrStream(System.err);

        InputStream in=channel.getInputStream();
        BufferedReader ebr = new BufferedReader(new InputStreamReader(in));

        channel.connect();

        while (true) {
            byte[] tmpArray=new byte[1024];
            while(in.available()>0){
                int i=in.read(tmpArray, 0, 1024);
                if(i<0)break;
                outputBuffer.append(new String(tmpArray, 0, i)).append("\n");
             }
            if(channel.isClosed()){
                System.out.println("exit-status: "+channel.getExitStatus());
                break;
             }
        }
        ebr.close();

        channel.disconnect();

        session.disconnect();

        System.out.println(outputBuffer.toString());
    }

  class localUserInfo implements UserInfo{
    String passwd;
    public String getPassword(){ return passwd; }
    public boolean promptYesNo(String str){return true;}
    public String getPassphrase(){ return null; }
    public boolean promptPassphrase(String message){return true; }
    public boolean promptPassword(String message){return true;}
    public void showMessage(String message){}
  }

}

上面的代码session.connect(30000);在行中给出了以下异常。

com.jcraft.jsch.JSchException: ProxySOCKS5: com.jcraft.jsch.JSchException: fail in SOCKS5 proxy
    at com.jcraft.jsch.ProxySOCKS5.connect(ProxySOCKS5.java:317)
    at com.jcraft.jsch.Session.connect(Session.java:231)
    at com.ukris.main.JschExecutor.go(JschExecutor.java:50)
    at com.ukris.main.JschExecutor.main(JschExecutor.java:19)
Caused by: com.jcraft.jsch.JSchException: fail in SOCKS5 proxy
    at com.jcraft.jsch.ProxySOCKS5.connect(ProxySOCKS5.java:200)
    ... 3 more

问题答案:

SOCKSjsch上的代理设置允许您连接到远程端上 正在运行的 代理服务器。一个sshd在远程端将
被视为一个SOCKS代理。您需要做的是建立一个本地端口,该本地端口转发到您要隧道连接到的计算机上的ssh端口,然后使用api建立与此系统的辅助ssh连接。

我以您的示例为例,并对其进行了略微重写以实现此目的:

import com.jcraft.jsch.*;
import java.io.*;

public class JschExecutor2 {

    public static void main(String[] args){
        JschExecutor2 t=new JschExecutor2();
        try{
            t.go();
        } catch(Exception ex){
            ex.printStackTrace();
        }
    }

    public void go() throws Exception{

        StringBuilder outputBuffer = new StringBuilder();

        String host="firstsystem"; // First level target
        String user="username";
        String password="firstlevelpassword";
        String tunnelRemoteHost="secondlevelhost"; // The host of the second target
        String secondPassword="targetsystempassword";
        int port=22;


        JSch jsch=new JSch();
        Session session=jsch.getSession(user, host, port);
        session.setPassword(password);
        localUserInfo lui=new localUserInfo();
        session.setUserInfo(lui);
        session.setConfig("StrictHostKeyChecking", "no");
        // create port from 2233 on local system to port 22 on tunnelRemoteHost
        session.setPortForwardingL(2233, tunnelRemoteHost, 22);
        session.connect();
        session.openChannel("direct-tcpip");

        // create a session connected to port 2233 on the local host.
        Session secondSession = jsch.getSession(user, "localhost", 2233);
        secondSession.setPassword(secondPassword);
        secondSession.setUserInfo(lui);
        secondSession.setConfig("StrictHostKeyChecking", "no");

        secondSession.connect(); // now we're connected to the secondary system
        Channel channel=secondSession.openChannel("exec");
        ((ChannelExec)channel).setCommand("hostname");

        channel.setInputStream(null);

        InputStream stdout=channel.getInputStream();

        channel.connect();

        while (true) {
            byte[] tmpArray=new byte[1024];
            while(stdout.available() > 0){
                int i=stdout.read(tmpArray, 0, 1024);
                if(i<0)break;
                outputBuffer.append(new String(tmpArray, 0, i));
             }
            if(channel.isClosed()){
                System.out.println("exit-status: "+channel.getExitStatus());
                break;
             }
        }
        stdout.close();

        channel.disconnect();

        secondSession.disconnect();
        session.disconnect();

        System.out.print(outputBuffer.toString());
    }

  class localUserInfo implements UserInfo{
    String passwd;
    public String getPassword(){ return passwd; }
    public boolean promptYesNo(String str){return true;}
    public String getPassphrase(){ return null; }
    public boolean promptPassphrase(String message){return true; }
    public boolean promptPassword(String message){return true;}
    public void showMessage(String message){}
  }

}

这段代码的作用是创建一个本地端口,将其转发到目标系统上的ssh端口,然后通过它进行连接。hostname命令的运行表明它确实在转发的系统上运行。



 类似资料:
  • 我想使用RazorSQL连接到我的数据库,该数据库正在远程服务器上运行。我使用以下命令在本地主机上创建SSH隧道: 我通过RazorSQL的GUI配置连接,将本地主机指定为主机,将1111指定为端口。当我单击“Connect”(连接)时,出现以下错误消息: 其中是远程服务器的IP地址。 此外,我不允许更改我的pg_hba的内容。conf文件。这就是目前的情况: 是否可以使用我当前的设置,在不修改服

  • 但是现在要通过Java的JSch库来完成,怎么做呢?第一次尝试了portforwarding,但在终端上我没有这样做(没有在中设置参数)。 然后我遇到了一个问题,如何使用JSCH SSH到另一个SSH服务器后面的服务器?,但我不明白如何创建tcp隧道!

  • 问题内容: 我已经在两个服务器 A 和 B 之间建立了SSH隧道。 B 有MySQL服务器,这可行: 虽然这不是: 尽管my.cnf具有以下几行: 现在关于隧道。它连接以下内容: 但是当(在 A上 ,端口转发)时,我会 我懂了 当我这样做 我懂了 可能是什么原因?我究竟做错了什么? 问题答案: 这里有三个问题。 1-暂时忘记SSH隧道 您不能将MySQL绑定到多个特定IP。第一个子句被第二个子句覆

  • 我有两台机器:machine foo()运行redis服务器,而machine bar()运行通过Jedis连接到foo的java应用程序。当给jedis提供地址时,一切都很好。 但是我不信任foo和bar之间的路由器,redis也不支持SSL。因此,我设置了一个从bar到foo:的ssh隧道 现在,从bar中,我可以直接在或通过隧道在成功地telnet到foo上的redis。对于jedis,如果

  • 问题内容: 我最近开始学习Hibernate技术,不得不使用Hibernate从数据库中获取数据。问题是我只能通过SSH隧道连接到数据库。我可以在文件中使用任何属性来解决此问题吗?或者,您可以建议另一种新手可以理解的方式。 问题答案: 也许使用Jsch。一些示例可以为您提供解决之道。 另一种方法是使用HTTP代理处理程序和端口转发功能来实现自己的SSH SocketFactory。起点可以是: 您

  • 基本上,我有一个java程序,它使用JSch SSH库来控制两个不同的SSH连接。 我创建了一个名为SSHConnection的类,它是JSch库的包装器,并通过调用如下所示的构造函数初始化了两个副本: 但是,我发现,如果我已经打开了一个使用SHELL通道的会话,当我试图为第二个会话打开第一个通道时,我会得到一个错误,即“channel is not opened”(JSch异常)。 有没有一种方