I am attempting to use Apache SSHD to start local port forwarding and then read data from the local port in Java.
I can do this without Apache SSHD by using OpenSSH to start local port forwarding and then just create and read from a Socket in Java. This works as expected.
When I try to replicate this with Apache SSHD instead of using OpenSSH, I get no errors but cannot read from the Socket. Why can't I read from the Socket in the same way I can when using OpenSSH? Am I missing something with Apache SSHD?
Example using OpenSSH:
ssh -i keyfile -l username -L 12345:127.0.0.1:20130 sshServerAddress
Then leave that connection open and run some simple Socket reading code in Java:
Socket socket = new Socket("127.0.0.1", 12345);
socket.setSoTimeout(0);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new BUfferedInputStream(socket.getInputStream())))) {
String line = reader.readLine();
System.out.println(line);
}
When I do this, it prints the expected data being delivered over the tunnel.
I then tried to replicate this in Apache SSHD, and the connection completed without error, but when I try to read from the socket, it just returns null. Does anyone have any clues as to what is missing?
SshClient sshClient = SshClient.setUpDefaultClient();
sshClient.setForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
sshClient.start();
ClientSession session = sshClient.connect(username, sshServerAddress, 22).verify(10000, TimeUnit.MILLISECONDS).getSession();
FileKeyPairProvider keyPairProvider = new FileKeyPairProvider(keyfile.toPath());
keyPairProvider.setPasswordFinder(FilePasswordProvider.of(passphrase));
clientSession.setKeyIdentityProvider(keyPairProvider);
clientSession.setUsername(username); // is this redundant?
clientSession.auth().verify(10000, TimeUnit.MILLISECONDS);
SshdSocketAddress sshdSocketAddress = clientSession.startLocalPortForwarding(12345, new SshdSocketAddress("127.0.0.1", 20130));
Socket socket = new Socket("127.0.0.1", 12345);
socket.setSoTimeout(0);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new BUfferedInputStream(socket.getInputStream())))) {
String line = reader.readLine();
System.out.println(line);
}
So Apache SSHD didn't throw any errors. It authenticated and executed the port forwarding code. But why can't I then read from the local port?
For reference, I ran this test using org.apache.sshd sshd-core and sshd-common artifacts version 2.7.0.
UPDATE: I discovered that if I also open a shell channel, I can see the same output I would see if I were instead starting the port forwarding with OpenSSH, and I can also then read data on the forwarded port. But I still need to determine how to set this up properly. Example (I put this code prior to starting local port forwarding):
ChannelShell cshell = clientSession.createShellChannel();
cshell.setOut(new NoCloseOutputStream(System.out));
cshell.setErr(new NoCloseOutputStream(System.err));
cshell.open().verify(10000, TimeUnit.MILLISECONDS);
It's possible the server wouldn't actually fully initialize until I had accepted it's output. Now I need to figure out how to implement this in a proper way. I don't really care about the shell, I really just want to ignore it and consume data from the local port that port forwarding was set up for.