There is a device that is running some proprietrary, undocumented ssh daemon, for which I need to write and ssh client that can send & execute commands from a file. Jsch turned out to be unsuitable for this particular project, so we went for plink.
The problem is, that after connecting to the device, the prompt is "halted" by the OS of the device, and it is only released after 2-3 seconds, when some welcome message and some alarms have been collected and displayed. But by the time this happens, plink already releases the session.
The command itself is nothing extraordinary: plink.exe -ssh user@host -pw password help
When I execute it on a standard linux server, it works flawlessly. But the device in question "swallows" the command, as the prompt is not ready when the connection is established.
As I came to understand, plink is a one-off kind of thing, meaning it will issue the command, wait for the response, then terminate the connection - but it has a -shareexists argument, that is supposed to search for existing connections to the same host, and use that to send the commands.
Using this, I'm trying to create a multi-threaded approach, where the login thread is created first, and while it is alive, the command execution thread should hook into it via -shareexists.
If I understood correctly, it should be used like this: plink.exe -shareexists -ssh user@host -pw password help
The result is half working, as I can see that the login thread is successful, and is supposedly alive when the command execution starts:
SSHConnectionHandler.main: starting ssh test
PLinkLoginThread.PLinkLoginThread: plink login thread created
PLinkLoginThread.PLinkLoginThread: Thread[Thread-0,5,main]
PLinkLoginThread.doLogin: starting login procedure
PLinkLoginThread.doLogin: plink.exe -ssh user@host -pw password
PLinkLoginThread.doLogin: login procedure finished
Welcome to Ubuntu 14.04.2 LTS (GNU/Linux 3.13.0-55-generic x86_64)
* Documentation: https://help.ubuntu.com/
System information as of Tue Dec 1 14:42:43 CET 2020
System load: 0.01 Processes: 201
Usage of /: 49.1% of 113.81GB Users logged in: 1
Memory usage: 36% IP address for eth0: x.x.x.x
Swap usage: 2%
=> /mnt/backup/dkcad2 is using 88.4% of 98.30GB
Graph this data and manage this system at:
https://landscape.canonical.com/
301 packages can be updated.
231 updates are security updates.
Last login: Tue Dec 1 14:16:52 2020 from y.y.y.y
$
PLink Thread is alive: true
SSHConnectionHandler.main: executing command while login thread is alive
SSHConnectionHandler.main: pLinkLoginThread is alive: true
SSHConnectionHandler.main: sehr gut, sehr gut
PLinkCommandExecutorThread.pLinkCommandExecutorThread: plink executor thread created
PLinkCommandExecutorThread.pLinkCommandExecutorThread: Thread[Thread-1,5,main]
PLinkCommandExecutorThread.run: executing command
plink.exe -shareexists -ssh user@host -pw password help
PLinkCommandExecutorThread.run: command executed
But for some reason, either the command is not sent to the login thread session, or the response is swallowed.
Here is the code of the thread execution:
public static void main(String[] args) {
String sshStream = null;
String command = "ls";
System.out.println("SSHConnectionHandler.main: starting ssh test");
pLinkLoginThread = new PLinkLoginThread(testHost, 22, testUser, testPassword);
try {
pLinkLoginThread.start();
} catch (Exception e) {
e.printStackTrace();
}
try {
while (pLinkLoginThread.isAlive()) {
System.out.println("SSHConnectionHandler.main: executing command while login thread is alive");
System.out.println("SSHConnectionHandler.main: pLinkLoginThread is alive: " + pLinkLoginThread.isAlive());
if (pLinkLoginThread.isAlive()) {
System.out.println("SSHConnectionHandler.main: sehr gut, sehr gut");
pLinkCommandExecutorThread = new PLinkCommandExecutorThread(command, testHost, 22, testUser, testPassword);
pLinkCommandExecutorThread.start();
pLinkCommandExecutorThread.join();
} else {
System.out.println("SSHConnectionHandler.main: das ist kein Kakao, Günther!");
}
}
} catch (Exception e) {
System.out.println("SSHConnectionHandler.main: exception during command execution");
e.printStackTrace();
}
}
And here are the two threads:
Login thread
public class PLinkLoginThread extends Thread {
PLinkLoginThread(String host, int port, String user, String password) {
System.out.println("PLinkLoginThread.PLinkLoginThread: plink login thread created");
System.out.println("PLinkLoginThread.PLinkLoginThread: " + this);
run(host, port, user, password);
}
public void run(String host, int port, String user, String password) {
Process process;
String login = "plink.exe -ssh " + user + "@" + host + " -pw " + password;
try {
Runtime r = Runtime.getRuntime();
System.out.println("PLinkLoginThread.doLogin: starting login procedure");
System.out.println("PLinkLoginThread.doLogin: " + login);
process = r.exec(login);
process.waitFor(3, TimeUnit.SECONDS);
System.out.println("PLinkLoginThread.doLogin: login procedure finished");
System.out.println(SSHConnectionHandler.readInputStream(process.getInputStream()));
System.out.println("PLink Thread is alive: " + process.isAlive());
} catch (Exception e) {
System.out.println("PLinkLoginThread.doLogin");
e.printStackTrace();
}
}
}
Command execution thread (this should hook into the already open connection):
public class PLinkCommandExecutorThread extends Thread {
PLinkCommandExecutorThread (String command, String host, int port, String user, String password) {
System.out.println("PLinkCommandExecutorThread.pLinkCommandExecutorThread: plink executor thread created");
System.out.println("PLinkCommandExecutorThread.pLinkCommandExecutorThread: " + this);
run(command, user, host, password);
}
public void run(String command, String user, String host, String password) {
Process process;
String commandToExecute = "plink.exe -shareexists -ssh " + user + "@" + host + " -pw " + password + command;
try {
Runtime r = Runtime.getRuntime();
System.out.println("PLinkCommandExecutorThread.run: executing command");
System.out.println(commandToExecute);
process = r.exec(commandToExecute);
process.waitFor(3, TimeUnit.SECONDS);
System.out.println("PLinkCommandExecutorThread.run: command executed");
System.out.println(SSHConnectionHandler.readInputStream(process.getInputStream()));
System.out.println(SSHConnectionHandler.readInputStream(process.getErrorStream()));
} catch (Exception e) {
System.out.println("PLinkCommandExecutorThread.run");
e.printStackTrace();
}
}
}
Using saved PuTTY sessions isn't an option either, as there are 300+ such devices and no naming convention for the sessions.
Is there anything else I could try?