So, I want to create my own SSH Client, not just sending commands but a full on ssh client for me to use like you would use PuTTy or mobaxterm, can someone here point me in the right direction.
Things I tried / thought of:
- Using Jsch to send and execute commands (If its possible I would love to know if this is able to be done without using Jsch).
SSH is a protocol that is defined to run on top of TCP, and you can make TCP connections in java using the java.net.Socket class.
So, yes, it can be done.
You'd have to implement the protocol yourself (or use JSch to do it, but given that all these tools already exist, and it's security, where in general relying on widely used tools is orders of magnitude more intelligent than relying on hand-written stuff, given that a security bug is very hard to test for – I assume this is some sort of exercise in sheer dogged arrogance, or, more likely, a learning exercise, which'd mean that you wouldn't want to use jsch here).
ssh works by sending any number of streams across the network, encrypted. By default, there is one stream (a two-way stream), with the user's shell being on one end (so, the /bin/bash executable, for example), and a terminal (where what you type forms the input, and any output is echoed to the terminal window) on the other.
ssh does NOT wait for you type a command then run it; that's /bin/bash doing this. This is basic linux info and has no direct bearing on ssh (the protocol), that's just what you're used to, because sshd (the linux executable that forms an ssh server) by default hooks your terminal up to the target server's shell executable. Usually bash.
Given that you know nothing of this, this sounds like a project that's a bit too far fetched as a starter experiment, but I'm going by incomplete information to make this assessment.
I'd start by making a trivial telnet client and server. telnet is at this point extremely outdated but it is basically ssh without the multiplexing of streams nor the encryption. If you can't write a telnet client, you can't write an ssh client either. And you can still start telnet servers on linux machines for testing purposes.
Once you've got that down, start figuring out the crypto and the multiplexing*.
*) With ssh you can, whilst having a shell open, also port forward and such; check out the -R and -L and -D options in standard ssh. Each such option allows for another stream to be sent along. (whilst you're sending shell commands and seeing their results, at the same time, over the same ssh connection, you are, say, sending a print job to a printer in the network of the other machine). Sending multiple streams through a single connection is called 'multiplexing', and it is part of the ssh specification.
Related
I'm currently trying to create an automated test using Java that runs some commands in a remote server the problem is that this remote server has a firewall. Manually I can ssh into the first server (firewall) using putty. Then I enter the details to the Server I wish to execute the commands. I've seen some article with code that mention how to use java code (jsch.jar) that I can ssh into a remote client but I haven't found a good enough explanation when a firewall is present. Can someone give me an explanation of what I should be trying to do and with some code snippet if possible
Not a complete answer, just an idea.
OpenSSH has a feature called ProxyCommand. It allows one to automatically issue a command on a target system, presumably another ssh.
So I have several entries of this sort in my .ssh/config:
Host the.private.host.behind.firewall.net
Hostname 10.0.100.106
User username_on_the_private_host
Compression yes
ProxyCommand ssh the.firewall.net nc -q 1 %h %p
Now I can issue ssh the.private.host.behind.firewall.net and first get to the SSH authentication on the.firewall.net, and then to the second authentication on the target host.
Likely Java implements SSH protocol on its own, but perhaps you could create a construction like this one.
Scenario
I'm in a Java project where we have to communicate with the CLIs of other machines. Unfortunately, we can't connect to these other machines directly and another bad luck is that they only support telnet. So we have the following setup, which is carved in stone (of course):
application <---- telnet or ssh ----> gateway <---- telnet ----> machine_001
(10.0.0.1) (192.168.1.1) (192.168.2.1)
(192.168.2.2)
( ... )
It's possible to connect via SSH or telnet to the gateway manually (e.g. using PuTTY), telnet from this shell to one of the machines and work with its CLI. As we want the communication to happen automatically, the application must be able to talk to the machines by itself; so I need a programmatic solution.
What I've tried so far
After some research on the internet I've found a library called JSch which looked promising, but I've encountered an evil problem. When the applications connects to the gateway, the telnet command and therefore the whole CLI of the target machine is one single command from application's viewpoint. So I'd have to struggle with a non-terminating InputStream, unsynchronized OutputStream and Threads if necessary.
The next try was to establish a SSH tunnel from L127.0.0.1:1234 to 192.168.2.1:23 (via the gateway), but with this configuration it's not possible to telnet to 127.0.0.1:1234 (neither programmatically nor manually).
The actual question
How can I get my application to talk to the machines via the gateway using telnet?
I'm writing a program in Java using the sockets to communicate with a Telnet server which allows the users to access the file directory in an UNIX OS.
When using Putty to communicate with this server, it prompts me for my username and password, but using my sockets there is nothing from the server except for a string which states that it uses SSH 2.0 - I think.
I'm sure that this has to do with the Telnet protocol, but how do I get the server to ask me for my username and password. What set of commands would I need to give the server in order to access the file directory in an UNIX environment?
Correction:
I figured that it's actually using SSH on port 22. It can be accessed using Putty or Microsoft Windows' Telnet program, but it doesn't actually use the Telnet protocol but the SSH protocol.
SSH isn't telnet. SSH is a protocol that is a lot like telnet, but is encrypted and has a slew of other features. So it looks like youre expecting a plain-text exchange, but what you're getting is the ssh protocol trying to do a handshake.
Telnet runs on port 23, SSH on 22. I imagine you want to use 23. Note: Telnet is old and unencrypetd and dangerous to use over the internet (unless youre going over a VPN or something that encrypts the session).
There is really nothing to the Telnet protocol for most uses...see this page for details. If the server on the other end is trying to negotiate a SSL connection, which is by far the most likely thing these days, try using a java.net.ssl.SSLSocket instead of a bare TCP socket.
Once you negotiate the connection (see the docs linked above) you should essentially print UNIX CLI commands to the socket and read (& parse) the results. If you just want to access files, maybe use FTP instead. Most modern servers are going to support SFTP.
Edit
With a little poking I found that using SSLSocket directly to connect to a SSH server is cumbersome at best because SSH has its own protocol. You probably don't want to reinvent the wheel on that one. Check out the answers to this question for some pure Java SSH client libraries. You can probably use at least one of these to solve your problem more directly than sending text commands over SSH.
Would it be a telnet server, it would be simple.
But what you have is a ssh server, and that is good as it is. telnet is heavily deprecated, as it is not encrypted.
You now have two options: Either use a ssh library or access the ssh command line client (or under Windows: the plink program) via its stdio.
I spent a lot of time developing an application that would use JSch and connect to a remote machine thru ssh to perform some command-line operations. However I learned that these operations can be performed at the localhost as well (my app is running on localhost). Now... I am too lazy to rewrite all the code and honestly I feel bad since I got really attached to JSch. Is there a way to trick JSch to connect to localhost instead or tell it in some way to just use localhost even though the code says otherwise? :)
P.S. in case it's not possible, how come the regular Proccess class doesnt support setOutputStream and setErrStream like JSch does, but only getInputStream and getErrorStream ??
As long as your local machine has an SSH server running (and your application has the necessary login credentials), you can use JSch to connect to your local machine, too - simply indicate localhost (or 127.0.0.1) as the host name for the connection.
This will have some overhead, though, since you are encrypting and decrypting all the data, which is not really necessary to execute some command locally. (On the other hand, this would allow you to run the commands as another user, for which you otherwise would need something like sudo or su, or RunAs under Windows.)
JSch implements the setOutputStream and setErrStream on top of the corresponding get... methods - it uses something similar to a PipedInputStream internally and a separate thread which shovels the data between those streams.
As JSch is open source, you can simply look how this is done (in the Channel class, if I remember right), and copy the relevant methods to your class which does the same things for a Process.
Is there a way to tell JSch not to encrypt the data?
You can use the none cipher, e.g. no encryption. This is by default disabled in all general-purpose clients and servers (as it defeats half of the purpose of SSH), but with the right configuration you can enable it. In JSch you can use
session.setConfig("cipher.s2c", "none,..."); // server to client
session.setConfig("cipher.c2s", "none,..."); // client to server
(This configuration option is the list of all options the client supports - see the documentation of setConfig for all supported values. The server will normally select the first one of this list that it also supports. To force no encryption (or canceling the connection), list only none.)
I don't know how to enable this in the SSH server - read your server's documentation. (And enable it only for localhost, if possible.)
The recommended way of using it is to switch to the none cipher only after authentication (so the authentication is still encrypted), but for localhost this might not be necessary. (You can use session.rekey() to switch the cipher (and key) after changing the configuration.)
i'm trying to execute a shell script from a j2ee application (made with flash builder 3, spring, apache cxf) et get the result of its execution in my flex interface.
the problem is my application is on a windows 7 station and i don't know how i can execute the script on a distant unix server & get back the result.
i know that ssh apis can help but i've no idea how to get back the result.
any help will be welcome.
thanx
If you have ssh installed on your windows machine, you should be able to execute a command like
ssh user#remote_host ipconfig
This will execute ipconfig on the remote_host as user "user". You will need to do a bit of research into ssh so that you can make it so you can log in without using a password, but google will help with that.
Alternatively you could look in to a java implementation of ssh - jssh for example, although I confess that I have no experience of using that package.
To execute program from windows to unix you really need ssh or telnet.
SSH is more secure. You can do this without running external process. Use one of available pure java SSH libraries (e.g. javassh.org).
See examples. If you use this library your task is trivial. Just call appropriate API.
About the only reasonable and reasonably secure answer I could come up with is to configure ssh on both machines.
*nix boxes usually have ssh server installed by default.
Putty terminal emulation for windows comes with neat ssh client command line utility called plink which can execute shell commands on a remote unix box in a secure manner.