I have a reasonably simple requirement: I need to open a SSH connection to a Remote server from my Java server using JSCH. I don't have direct access, so I need to do it via a Jump server.
First I tested it out using basic SSH port forwarding commands. I logged into the Jump server and ran the following command: (port 34567 has no significance, just a random port)
raddaya@jumpserver> ssh -L *:34567:RemoteServer.com:22 [user]@JumpServer.com
After this, I logged into my Java server and saw if it worked:
raddaya@javaserver> ssh [user]@JumpServer.com -p 34567
As expected, it logged me into the Remote Server! So far, so good.
I wrote some Java code that looked roughly like this: [can't directly copy/paste the code, so please excuse typos]
Session jumpSession = jSch.getSession(jumpServerUsername,jumpServerAddress,22);
jumpSession.setPassword(jumpServerpw);
jumpSession.setConfig(STRICTHOSTKEYCHECKING,"no");
jumpSession.connect();
//now forward the port
int forwardedPort = jumpSession.setPortForwardingL("*",0,remoteServerAddress,22);
System.out.println("Port forwarding rules: " + Arrays.toString(jumpSession.getPortForwardingL()));
Session remoteSession = jSch.getSession(jumpServerUsername,jumpServerAddress,forwardedPort);
remoteSession.setPassword(jumpServerpw);
remoteSession.setConfig(STRICTHOSTKEYCHECKING,"no");
remoteSession.connect();
The port forwarding rule was properly printed here, it would pick a random port between ~30,000 to ~50,000 and forward the port. But to my surprise, I got a "Connection Refused" error when the remote session tried to connect to whatever port was forwarded. I was stuck here for quite some time, because this was pretty much exactly the same code to replicate the SSH commands that worked perfectly. Eventually, a colleague helped me out by showing me the code that worked:
Session jumpSession = jSch.getSession(jumpServerUsername,jumpServerAddress,22);
jumpSession.setPassword(jumpServerpw);
jumpSession.setConfig(STRICTHOSTKEYCHECKING,"no");
jumpSession.connect();
//if you don't give the first argument, it defaults to only allowing loopback forwarding
//i.e you can only connect via localhost!
int forwardedPort = jumpSession.setPortForwardingL(0,remoteServerAddress,22);
System.out.println("Port forwarding rules: " + Arrays.toString(jumpSession.getPortForwardingL()));
//Now we connect to localhost??
Session remoteSession = jSch.getSession(jumpServerUsername,"127.0.0.1",forwardedPort);
remoteSession.setPassword(jumpServerpw);
remoteSession.setConfig(STRICTHOSTKEYCHECKING,"no");
remoteSession.connect();
This does work and successfully connects. But I am completely baffled at the logic of this and even my colleague admits he doesn't know why this works. Is the second getSession somehow running from the jump server instead of the java server? But even in that case, why would I get a Connection Refused the first time? I really don't want to just use this code without understanding it, so I hope someone can explain.