使用 SSHj 进行 SSH 端口转发

2023-12-04

我正在尝试创建一个隧道来使用防火墙后面支持 SSH 的服务。我想要一个完整的java解决方案,但我似乎无法让它工作。我找到了这个github 片段并基于此,我创建了以下代码来保留给我隧道的后台线程:

// property on surrounding class
// static final SSHClient sshclient = new SSHClient();

Thread thread = new Thread(new Runnable() {

    @Override
    public void run() {
        try {
            String host = "10.0.3.96";
            sshclient.useCompression();
            sshclient.addHostKeyVerifier("30:68:2a:20:21:9f:c8:e8:ac:b4:a7:fc:2d:a7:d0:26");
            sshclient.connect(host);
            sshclient.authPassword("messy", "messy");
            if (!sshclient.isAuthenticated()) {
                throw new RuntimeException(String.format("Unable to authenticate against '%s'", host));
            }
            Forward forward = new Forward(8111);
            InetSocketAddress addr = new InetSocketAddress("google.com", 80);
            SocketForwardingConnectListener listener = new SocketForwardingConnectListener(addr);

            sshclient.getRemotePortForwarder().bind(forward, listener);
            sshclient.getTransport().setHeartbeatInterval(30);

            HttpURLConnection con = (HttpURLConnection) new URL("http://localhost:8111").openConnection();
            con.setRequestMethod("GET");
            BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
            String line = null;
            while( (line = reader.readLine()) != null) {
                System.out.println(line);
            }

            sshclient.getTransport().join();

        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            if (sshclient != null && sshclient.isConnected()) {
                sshclient.disconnect();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
});
thread.setDaemon(true);
thread.start();

问题是,如果我连接到像“10.0.3.96”这样的远程 SSH 服务器,它就不起作用。如果我在本地主机上使用本地 SSH 服务器,它就会工作。我一直在尝试不同的配置并尝试调试,但我无法掌握 SSHj 包内部发生的情况。

现在它不一定是 SSHj 解决方案,但这将是首选,因为代码的其他部分已完全实现并使用 SSHj,而且我不想在一个项目中混合两个 SSH 包。

谢谢你的帮助。


尝试这样的事情。它接受要连接的服务器列表。它将通过隧道将每个中间连接连接到最后一个服务器。我还没有测试过 2 台以上的服务器,但它应该可以工作。这个答案改编自那边的项目并用 groovy 编写。您应该只需要导入即可使其在 groovyconsole 中工作。

@Grab(group='net.schmizz', module='sshj', version='0.8.1')
@Grab(group='org.bouncycastle', module='bcprov-jdk16', version='1.46')

//the sequence of hosts that the connections will be made through
def hosts = ["server1", "server2"]
//the starting port for local port forwarding
def startPort = 2222
//username for connecting to all servers
def username = 'user'
def pw = 'pass'

//--------------------------------------------------------------------------//

final TunnelPortManager PORT_MANAGER = new TunnelPortManager()

//list of all active port forwarders
List<PortForwarder> portForwarders = []

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

/**
 *  Established the actual port forwarder 
 */
class PortForwarder extends Thread implements Closeable {
    private final SSHClient sshClient;
    private final InetSocketAddress remoteAddress;
    private final ServerSocket localSocket;
    private CountDownLatch latch = new CountDownLatch(1);

    public PortForwarder(SSHClient sshClient, InetSocketAddress remoteAddress, ServerSocket localSocket) {
        this.sshClient = sshClient;
        this.remoteAddress = remoteAddress;
        this.localSocket = localSocket;
    }

    private static String buildName(InetSocketAddress remoteAddress, Integer localPort) {
        return "SSH local port forward thread [${localPort}:${remoteAddress.toString()}]"
    }

    @Override
    public void run() {
        LocalPortForwarder.Parameters params = new LocalPortForwarder.Parameters("127.0.0.1", localSocket.getLocalPort(),
                remoteAddress.getHostName(), remoteAddress.getPort());
        LocalPortForwarder forwarder = sshClient.newLocalPortForwarder(params, localSocket);
        try {
            latch.countDown();
            forwarder.listen();
        } catch (IOException ignore) {/* OK. */}
    }

    @Override
    public void close() throws IOException {
        localSocket.close();
        try {
            this.join();
        } catch (InterruptedException e) {/* OK.*/}
    }
}

/**
 *  Will hand out local ports available for port forwarding
 */
class TunnelPortManager {
    final int MAX_PORT = 65536

    Set<Integer> portsHandedOut = new HashSet()

    ServerSocket leaseNewPort(Integer startFrom) {
        for (int port = startFrom; port < MAX_PORT; port++) {
            if (isLeased(port)) {
                continue;
            }

            ServerSocket socket = tryBind(port);
            if (socket != null) {
                portsHandedOut.add(port);
                println "handing out port ${port} for local binding"
                return socket;
            }
        }
        throw new IllegalStateException("Could not find a single free port in the range [${startFrom}-${MAX_PORT}]...");
    }

    synchronized void returnPort(ServerSocket socket) {
        portsHandedOut.remove(socket.getLocalPort());
    }

    private boolean isLeased(int port) {
        return portsHandedOut.contains(port);
    }

    protected ServerSocket tryBind(int localPort) {
        try {
            ServerSocket ss = new ServerSocket();
            ss.setReuseAddress(true);
            ss.bind(new InetSocketAddress("localhost", localPort));
            return ss;
        } catch (IOException e) {
            return null;
        }
    }
}


PortForwarder startForwarder(PortForwarder forwarderThread) {
    forwarderThread.start();
    try {
        forwarderThread.latch.await();
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
    return forwarderThread;
}


SSHClient getSSHClient(username, pw, String hostname, int port=22){
    SSHClient client = new SSHClient()
    client.addHostKeyVerifier(new PromiscuousVerifier())
    client.connect(hostname, port)
    client.authPassword(username, pw)
    return client
}

int hostCount = hosts.size()
String hostname = hosts[0]

SSHClient client = getSSHClient(username, pw, hostname)
println "making initial connection to ${hostname}"

Session session

//create port forwards up until the final
for (int i=1; i<hostCount; i++){
    hostname = hosts[i]
    println "creating connection to ${hostname}"
    ServerSocket ss = PORT_MANAGER.leaseNewPort(startPort)
    InetSocketAddress remoteAddress = new InetSocketAddress(hostname, 22)

    PortForwarder forwarderThread = new PortForwarder(client, remoteAddress, ss)
    forwarderThread = startForwarder(forwarderThread)
    session = client.startSession()

    println "adding port forward from local port ${ss.getLocalPort()} to ${remoteAddress.toString()}"
    portForwarders.add(forwarderThread)

    client = getSSHClient(username, pw, "127.0.0.1", ss.getLocalPort())
}

session = client.startSession()

//shut down the running jboss using the script
Command cmd = session.exec("hostname")
String response = IOUtils.readFully(cmd.getInputStream()).toString()
cmd.join(5, TimeUnit.SECONDS)
println "response -> ${response}"

portForwarders.each { pf ->
    pf.close()
}

session.close()
client.disconnect()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 SSHj 进行 SSH 端口转发 的相关文章

  • Java 中等效的并行扩展

    我在 Net 开发中使用并行扩展有一些经验 但我正在考虑在 Java 中做一些工作 这些工作将受益于易于使用的并行库 JVM 是否提供任何与并行扩展类似的工具 您应该熟悉java util concurrent http java sun
  • 为什么 i++ 不是原子的?

    Why is i Java 中不是原子的 为了更深入地了解 Java 我尝试计算线程中循环的执行频率 所以我用了一个 private static int total 0 在主课中 我有两个线程 主题 1 打印System out prin
  • Java EE:如何获取我的应用程序的 URL?

    在 Java EE 中 如何动态检索应用程序的完整 URL 例如 如果 URL 是 localhost 8080 myapplication 我想要一个可以简单地将其作为字符串或其他形式返回给我的方法 我正在运行 GlassFish 作为应
  • 如何找到给定字符串的最长重复子串

    我是java新手 我被分配寻找字符串的最长子字符串 我在网上研究 似乎解决这个问题的好方法是实现后缀树 请告诉我如何做到这一点或者您是否有任何其他解决方案 请记住 这应该是在 Java 知识水平较低的情况下完成的 提前致谢 附 测试仪字符串
  • 给定两个 SSH2 密钥,我如何检查它们是否属于 Java 中的同一密钥对?

    我正在尝试找到一种方法来验证两个 SSH2 密钥 一个私有密钥和一个公共密钥 是否属于同一密钥对 我用过JSch http www jcraft com jsch 用于加载和解析私钥 更新 可以显示如何从私钥 SSH2 RSA 重新生成公钥
  • 制作一个交互式Windows服务

    我希望我的 Java 应用程序成为交互式 Windows 服务 用户登录时具有 GUI 的 Windows 服务 我搜索了这个 我发现这样做的方法是有两个程序 第一个是服务 第二个是 GUI 程序并使它们进行通信 服务将从 GUI 程序获取
  • Final字段的线程安全

    假设我有一个 JavaBeanUser这是从另一个线程更新的 如下所示 public class A private final User user public A User user this user user public void
  • Spark 1.3.1 上的 Apache Phoenix(4.3.1 和 4.4.0-HBase-0.98)ClassNotFoundException

    我正在尝试通过 Spark 连接到 Phoenix 并且在通过 JDBC 驱动程序打开连接时不断收到以下异常 为简洁起见 下面是完整的堆栈跟踪 Caused by java lang ClassNotFoundException org a
  • Liferay ClassNotFoundException:DLFileEntryImpl

    在我的 6 1 0 Portal 实例上 带有使用 ServiceBuilder 和 DL Api 的 6 1 0 SDK Portlet 这一行 DynamicQuery query DynamicQueryFactoryUtil for
  • 磁模拟

    假设我在 n m 像素的 2D 表面上有 p 个节点 我希望这些节点相互吸引 使得它们相距越远吸引力就越强 但是 如果两个节点之间的距离 比如 d A B 小于某个阈值 比如 k 那么它们就会开始排斥 谁能让我开始编写一些关于如何随时间更新
  • 如何在PreferenceActivity中添加工具栏

    我已经使用首选项创建了应用程序设置 但我注意到 我的 PreferenceActivity 中没有工具栏 如何将工具栏添加到我的 PreferenceActivity 中 My code 我的 pref xml
  • 如何为俚语和表情符号构建正则表达式 (regex)

    我需要构建一个正则表达式来匹配俚语 即 lol lmao imo 等 和表情符号 即 P 等 我按照以下示例进行操作http www coderanch com t 497238 java java Regular Expression D
  • 如何在 javadoc 中使用“<”和“>”而不进行格式化?

    如果我写
  • Java列表的线程安全

    我有一个列表 它将在线程安全上下文或非线程安全上下文中使用 究竟会是哪一个 无法提前确定 在这种特殊情况下 每当列表进入非线程安全上下文时 我都会使用它来包装它 Collections synchronizedList 但如果不进入非线程安
  • 玩!框架:运行“h2-browser”可以运行,但网页不可用

    当我运行命令时activator h2 browser它会使用以下 url 打开浏览器 192 168 1 17 8082 但我得到 使用 Chrome 此网页无法使用 奇怪的是它以前确实有效 从那时起我唯一改变的是JAVA OPTS以启用
  • 编译器抱怨“缺少返回语句”,即使不可能达到缺少返回语句的条件

    在下面的方法中 编译器抱怨缺少退货声明即使该方法只有一条路径 并且它包含一个return陈述 抑制错误需要另一个return陈述 public int foo if true return 5 鉴于Java编译器可以识别无限循环 https
  • 有没有办法为Java的字符集名称添加别名

    我收到一个异常 埋藏在第 3 方库中 消息如下 java io UnsupportedEncodingException BIG 5 我认为发生这种情况是因为 Java 没有定义这个名称java nio charset Charset Ch
  • JGit 检查分支是否已签出

    我正在使用 JGit 开发一个项目 我设法删除了一个分支 但我还想检查该分支是否已签出 我发现了一个变量CheckoutCommand但它是私有的 private boolean isCheckoutIndex return startCo
  • 将 List 转换为 JSON

    Hi guys 有人可以帮助我 如何将我的 HQL 查询结果转换为带有对象列表的 JSON 并通过休息服务获取它 这是我的服务方法 它返回查询结果列表 Override public List
  • Spring Boot @ConfigurationProperties 不从环境中检索属性

    我正在使用 Spring Boot 1 2 1 并尝试创建一个 ConfigurationProperties带有验证的bean 如下所示 package com sampleapp import java net URL import j

随机推荐