SSH不同版本使用jsch问题处理

1.问题一2.问题二2.1 说明2.2 解决

3.问题三

1.问题一

# 1.系统

cat /etc/os-release

# 系统信息

NAME="openEuler"

VERSION="22.03 (LTS-SP1)"

ID="openEuler"

VERSION_ID="22.03"

PRETTY_NAME="openEuler 22.03 (LTS-SP1)"

ANSI_COLOR="0;31"

# 2.ssh

ssh -V

# ssh信息

OpenSSH_8.8p1, OpenSSL 1.1.1m 14 Dec 2021

# 1.Java报错

com.jcraft.jsch.JSchException: Algorithm negotiation fail

# 2.使用 systemctl status sshd 查看状态

Unable to negotiate with xxx.xxx.x.xxx port xxxxx: no matching host key type found.

Their offer: ssh-rsa,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha>

问题解决:

配置文件sshd_config的HostKeyAlgorithms添加算法ssh-rsa

HostKeyAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-256,rsa-sha2-512,ssh-rsa

2.问题二

2.1 说明

OpenSSH是从原本的OpenSSH_7.4p1, OpenSSL 1.0.2k-fips 26 Jan 2017升级到 OpenSSH_9.7p1, OpenSSL 3.2.0 23 Nov 2023,当前环境如下:

# 1.系统

CentOS Linux release 7.8.2003 (Core)

# 2.ssh -V

OpenSSH_9.7p1, OpenSSL 3.2.0 23 Nov 2023

# 1.密码错误时Java报错信息

cn.hutool.extra.ssh.JschRuntimeException: JSchException: Auth fail

# 密码修改正确后 systemctl status sshd 查看状态

Accepted password for root from 123.160.246.239 port 22838 ssh2

# 2.通过sftp上传文件时

cn.hutool.extra.ssh.JschRuntimeException: JSchException: channel is not opened.

# 过一会儿后 systemctl status sshd 查看状态

error: no more sessions

代码进行调试,发现报错的位置:

// 报错行

channelSftp.put(fs, directory, ChannelSftp.OVERWRITE);

// 报错信息

com.jcraft.jsch.SftpException: No such file

我一度认为是传输模式的问题,在ChannelSftp.put(InputStream src, String dst, int mode)方法中,mode参数用于指定文件传输模式,其可选值有:

ChannelSftp.OVERWRITE:这是默认的传输模式,它会完全覆盖目标服务器上的同名文件。如果目标文件不存在,则会创建一个新的文件。ChannelSftp.RESUME:这种模式下,如果传输被中断,那么在下次调用put方法时,会从上一次中断的地方继续传输,而不是重新开始传输整个文件。ChannelSftp.APPEND:此模式允许你将数据追加到目标服务器上的现有文件中,而不是覆盖它。如果目标文件不存在,则会创建一个新的文件。

换用其他模式依然报错。

2.2 解决

最终发现是代码的问题:

// 进行代码调试时发现远程登录耗时较久

SshClient.getInstance().sshRemoteCallLoginByTool(sshHost, sshPort, sshUserName, sshPassword);

// 导致创建目标目录时未执行

SshClient.getInstance().execCommandByTool("mkdir " + targetPath);

execCommandByTool方法的原始代码:

/**

* 执行命令

*

* @param command 命令

*/

public String execCommandByTool(String command) {

boolean isConnected = checkConnectionStatus();

if (isConnected) {

return JschUtil.exec(session, command, Charsets.UTF_8);

}

return null;

}

可以看出,如果登录较慢,checkConnectionStatus的状态是false则创建目录的命令未被执行,导致上传时的文件路径不存在,出现报错信息,改进如下:

/**

* 执行命令

*

* @param command 命令

*/

public String execCommandByTool(String command) {

boolean isConnected = checkConnectionStatus();

while (!isConnected) {

isConnected = checkConnectionStatus();

}

return JschUtil.exec(session, command, Charsets.UTF_8);

}

3.问题三

# 连接超时异常

com.jcraft.jsch.JSchException: Session.connect: java.net.SocketTimeoutException: Read timed out

# 包损坏

com.jcraft.jsch.JSchException: Packet corrupt

异常出现的位置及处理方案:

private boolean createSessionAndConnected() {

if (session == null) {

log.info("SSHClient createSessionAndConnected...");

session = JschUtil.createSession(this.sshHost, this.sshPort, this.sshUser, this.sshPass);

Properties config = new Properties();

config.put("StrictHostKeyChecking", "no");

session.setConfig(config);

try {

session.connect(8000);

// com.jcraft.jsch.JSchException: Session.connect: java.net.SocketTimeoutException: Read timed out

// 增加超时时间 session.connect(200000);

} catch (JSchException e) {

// com.jcraft.jsch.JSchException: Packet corrupt

// 使用同一个session对象再次进行连接时会报错

// 重新连接时使用新的session对象

session = null;

e.printStackTrace();

log.info("SSHClient createSessionAndConnected printStackTrace");

return false;

}

log.info("SSHClient createSessionAndConnected Success!");

}

return this.session.isConnected();

}

推荐阅读

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。