JSch 实际使用中的问题

Abstract

这篇文章会介绍一些常见的使用JSch中的一些问题.  都是在实际客户运行环境中发现的问题.

JSch是一个用Java实现的与SSH服务器交互的库. 但是这个库本身已经很久没有更新了.

一般的测试代码:

import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Logger;
import com.jcraft.jsch.Session;

import java.io.InputStream;
import java.util.Date;

public class TestJSch {
    public static String host = "",
            user = "",
            pass = "";
    static int port = 22;
    public static void main(String[] args) throws Exception {
        if (args.length < 3) {
            System.out.println("Missing param. Run with  [host, user, pass]");
            return;
        } else {
            host = args[0];
            user = args[1];
            pass = args[2];
        }

        JSch.setLogger(new Logger() {
            @Override
            public boolean isEnabled(int i) {
                return true;
            }

            @Override
            public void log(int i, String s) {
                System.out.println(new Date() + " " + s);
            }
        });
        System.out.println("Connect " + host);

        try {
            String command = "cat /proc/diskstats";

            String command_output = runCommand(command);

            System.out.println(command_output);
        }
        catch (Exception e) {
            e.printStackTrace();
        }


    }

    static String runCommand(String input_command) throws Exception {
        Session session = null;
        try {
            // instantiate JSCH object.
            JSch jsch = new JSch();


            // create session.
            session = jsch.getSession(user, host, port);
            session.setPassword(pass);
            // given we are running non-interactively, we will automatically accept new host keys.
            session.setConfig("StrictHostKeyChecking", "no");

            // is host configured with a user & password?

            // connect
            session.connect();

            // execute command.
            ChannelExec channel = (ChannelExec) session.openChannel("exec");
            channel.setCommand(input_command);

            // collect command output.
            InputStream commandOutput = channel.getInputStream();
            channel.connect();
            StringBuffer s = new StringBuffer();
            byte[] buf = new byte[256];
            int n = -1;
            while ((n = commandOutput.read(buf)) > 0) {
                s.append(new String(buf, 0, n));
            }
            // disconnect
            channel.disconnect();

            return s.toString();
        }
        catch (Exception e) {
            e.printStackTrace();
            return "";
        }
        // ensure we disconnect the session.
        finally {
            if (session != null) {
                session.disconnect();
            }

        }
    }
}

Case 1 认证方式导致的失败

在连接某些客户端时,发现连接被一直卡住了. 并且没有任何输出.  系统自带ssh可以连接.

这个一般是因为jsch的认证方法有很多种, 而其中很多是需要UI交互操作的 而这在后台程序中就会出现问题.

默认的顺序:

            session.setConfig("PreferredAuthentications", "gssapi-with-mic,publickey,keyboard-interactive,password");

其中: gssapi-with-mic,keyboard-interactive 都是需要交互的.

所以可以按照如下设置:

           session.setConfig("PreferredAuthentications", "password,gssapi-with-mic,publickey,keyboard-interactive");

Case 2: jsch 升级导致的不工作

从JSch0.1.53 升级到 0.1.54的过程中导致的某些Cisco 设备不工作.

报错是:

java.io.IOException: failed to initialize the channel.
	at com.jcraft.jsch.Channel$1.init(Channel.java:242)
	at com.jcraft.jsch.Channel$1.write(Channel.java:253)
	at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
	at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
	at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:295)
	at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:141)
	at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:229)
	at java.io.BufferedWriter.flush(BufferedWriter.java:254)

查看Changelog 发现:

Changes since version 0.1.53:
- bugfix: fixed CVS-2016-5725
          Refer to following links,
            http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2016-5725
            https://github.com/tintinweb/pub/tree/master/pocs/cve-2016-5725
          Thanks a lot for tintinweb's contributions.
- bugfix: sftp-put may send the garbage data in some rare case.
- bugfix: fixed a deadlock bug in KnownHosts#getHostKey().
- bugfix: SftpProgressMonitor#init() was not invoked in sftp-put
          by using the output-stream.
- change: KnownHosts#setKnownHosts() should accept the non-existing file.
- change: excluding the user interaction time from the timeout value.
- change: addressing SFTP slow file transfer speed with Titan FTP.
- change: updating copyright messages; 2015 -> 2016

并没有看到哪里改了. 实际对比代码发现是因为packet size改变了 导致在老的设备上无法工作:

这个是我格式化后的代码(存储在我的github: https://github.com/gaoxingliang/JSch)

可以看到这个最大mac 长度改变了 导致对老设备的兼容性上出现了.

解决办法1: 使用我改过后的基于0.1.54 修改的版本 (https://github.com/gaoxingliang/JSch/releases)

2. 在我看了0.1.53和0.1.54之间的修改过后, 主要fix 了一个CVE问题, 然后我在0.1.53上也Fix了这个问题. 也可以在这里下载.

猜你喜欢

转载自blog.csdn.net/scugxl/article/details/85097670