How to log each SSH session packet with Paramiko? - python

I am working with Paramiko 2.7.1, using a simple client implementation for running commands on remote SSH servers.
On most of my hosts, it works great. Input commands go out, output (if exists) comes back.
One specific type of host (an IBM VIOS partition to be precise) is giving me headaches in that the commands execute, but the output is always empty.
I have used PuTTY in an interactive session to log all SSH packets and check for any differences and, at least during an interactive session, no differences present between a working and a non-working host.
I have enabled Paramiko logging with:
basicConfig(level=DEBUG)
logging.getLogger("paramiko").setLevel(logging.DEBUG)
log_to_file('ssh.log')
But the output doesn't dump each packet. I have done a search for any parameters or methods that would dump those packets but I've come up empty.
Wireshark is not an option since we are talking about an encrypted connection.
I would prefer to keep using exec_command instead of having to refactor everything and adapt to using an SSH shell.
So, in the end. Is there any way to dump the entire SSH session with Paramiko? I can handle either SSH packets or raw data.
Edit 1: I have remembered that PuTTY's plink.exe does ssh exec commands, so I used it to compare both SSH server's output and stumbled onto the solution to my base problem: https://www.ibm.com/support/pages/unable-execute-commands-remotely-vio-server-padmin-user-ssh
Still, I'd rather have captured the session with Paramiko, since I will not always be able to simulate with other tools...

In addition to enabling logging, call Transport.set_hexdump():
client.get_transport().set_hexdump(True)
Regarding your original problem, see also:
Command executed with Paramiko does not produce any output

Related

Combining interactive shell and recv_exit_status method using Paramiko

I am using paramiko for SSH with my remote devices.
and I am make communication with them using paramiko shell (invoke_shell() method) for interactivity.
The main problem with paramiko shell (as I've read in many answers here) is that there is no guarantee that paramiko SSHClient methods which indicates that the server finished writing such as recv_exit_status() and exit_status_ready() will behave as expected.
So I created mechanism that will read the last line of the output from the shell and determine if this line contains only shell's prompt in such case the command execution was finished.
This is works in case there is no changes in prompt.
Now I've read here Wait until task is completed on Remote Machine through Python that 'exec_command()' method return tuple 'stdin, stdout, stderr' and preforming stdout.channel.recv_exit_status() will block channel until it is done.
My question is if I will create such a tuple and will preform stdout.channel.recv_exit_status() with stdout that I will get when I am open on each interactive command (meaning I will do 'shell_chan.send('something')' and then will do stdout.channel.recv_exit_status()) will it do the job? will it return only when interactive command has finished?
SSHClient.recv_exit_status signals that the channel has closed.
The "shell" channel closes only when the shell closes. A "shell" is a black box with input and output. Nothing else. There's no way SSH, let alone Paramiko, will be able to tell anyhow, when individual commands in the shell have finished. The shell_chan.send('something') is not a signal to SSH to execute a command. It simply sends an arbitrary input to the "shell". Nothing else. It's totally at the shell disposition how the input is interpreted. All that the SSH/Paramiko gets back is an arbitrary unstructured output. Paramiko cannot interpret it anyhow for you.
If you need to be able to tell when a command has finished, you need to use "exec" channel (SSHClient.exec_command method in Paramiko). You should not use the "shell" channel, unless you are implementing an interactive SSH terminal client, like PuTTY (or in rare cases, when you talk to an limited SSH server that does not implement the "exec" channel, as it often the case with dedicated devices, such as routers, switches, etc).
For related questions, see:
Execute multiple dependent commands individually with Paramiko and find out when each command finishes
How to get each dependent command execution output using Paramiko exec_command
Use the same SSH object to issue "exec_command()" multiple times in Paramiko
Execute (sub)commands in secondary shell/command on SSH server in Paramiko
Invoke multiple commands inside a process in interactive ssh mode
Executing command using Paramiko exec_command on device is not working
What is the difference between exec_command and send with invoke_shell() on Paramiko?

Is it possible to use python to establish a putty ssh session and send some input?

Fist of all, due to Company Policy, Paramiko, or installing anything that requires administrative access to local machine it right out; otherwise I would have just done that.
All I have to work with is python with standard libraries & putty.
I am attempting to automate some tedious work that involves logging into a network device (usually Cisco, occasionally Alcatel-Lucent, or Juniper), running some show commands, and saving the data. (I am planning on using some other scripts to pull data from this file, parse it, and do other things, but that should be irrelevant to the task of retrieving the data.) I know this can be done with telnet, however I need to do this via ssh.
My thought is to use putty's logging ability to record output from a session to a file. I would like to use Python to establish a putty session, send scripted log-in and show commands, and then close the session. Before I set out on this crusade, does anyone know of any way to do this? The closest answers I have found to this all suggest to use Paramiko, or other python ssh library; I am looking for a way to do this given the constraints I am under.
The end-result would ideal be able to be used as a function, so that I can iterate through hundreds of devices from a list of ip addresses.
Thank you for your time and consideration.
If you can't use paramiko, and Putty is all you get so the correct tool is actually not Putty - it's his little brother Plink - you can download it here
Plink is the command line tool for Putty and you can your python script to call it using os.system("plink.exe [options] username#server.com [command])
See MAN Page here
Hope it will help,
Liron

Options to run a commnd remotely over ssh

I have numerous test servers. These test servers get re-imaged frequently, and they have the same user account and password after being re-imaged. I want to write a python script that runs a command remotely over ssh on one of these servers, without prompting user for a password, and gathers the output of the command. In some circumstance I want to run one command, get output, analyze the output. In other situation, I want to run several commands at a time (possibly run a script file). I read many postings about running commands remotely, using third party packages (e.g. paramiko). Is there a recommended way to achieve this task without using additional packages ? The server from which my script will be run might not have the package installed.
Or should I used pexpect ?
Ideally I would like to use subprocess and capture the output (providing password as an argument). Of course, my script has to handle the case when the client is logging for first time, and prompted to add ssh key to .ssh/knownhosts file.
Thank you,
Ahmed.
If host key security is not an issue (you are on a trusted network etc), you can bypass the host checking. And if you use key-based authentication there is no need for a password prompt:
ssh -oUserKnownHostsFile=/dev/null -oStrictHostKeyChecking=no -oPasswordAuthentication=no \
-n doctor#tardis some_cmd
This way you can just use subprocess as if you executed some_cmd locally.

How to easily create a local SSH tunnel using pure Python

I have a pretty simple task: using ssh, I want to create a tunnel that forwards traffic from my local machine to a specific port on a remote machine. I can do this from the command line:
ssh -N -L 123:127.0.0.1:456 user#remotehost
Then if I run:
telnet localhost 123
it's the equivalent of logging into remotehost and running
telnet 127.0.0.1 456
I've managed to do this with something along the lines of;
subprocess.Popen(['ssh', '-N', '-L', '%i:127.0.0.1:%i' % (new_port, old_port), ssh_user + '#' + ip_addr])
But now I want to move away from that and use only Python - no external processes.
I've tried using fabric.context_managers.remote_tunnel but unless I've misunderstood this is meant for creating a tunnel that starts at a remote location, not from the local machine. That is, it is the equivalent of SSHing into a remote machine and creating an SSH tunnel from there, which is silly for my purpose. I suppose I could set the remote host to actually be the local machine but this seems inefficient and honestly I don't even understand how to do that.
I've also tried forward.py on paramiko and it doesn't work because my private key is encrypted. I'd like to modify the script to handle that, and also just simplify it for my needs, but both the script and the paramiko library are daunting and I don't know how to begin.
Surely there's an easy way to do this? I seem to be so close yet so far.
What do you mean by "pure Python"? Subprocess is bundled with standard python installation.
Subprocess and Fabric are designed for such tasks, why would you want to move away from them?
If you have, minimal tasks to be performed remotely e.g. check memory, hostname, etc. you can go ahead with suprocess. However if you have some big requirements, I would suggest going with fabric.
For your purpose where you have to work on the same machine, why not use subprocess with check_call or Popen. As an alternative, you can change your code altogether so as to be able to get into Unix core to achieve what the Linux commands do.

using python commands within paramiko

I've been using Paramiko today to work with a Python SSH connection, and it is useful.
However one thing I'd really like to be able to do over the SSH is to utilise some Pythonic sugar. As far as I can tell I can only use the inbuilt Paramiko functions, and if I want to anything using Python on the remote side I would need to use a script which I have placed on there, and call it.
Is there a way I can send Python commands over the SSH connection rather than having to make do only with the limitations of the Paramiko SSH connection? Since I am running the SSH connection through Paramiko within a Python script, it would only seem right that I could, but I can't see a way to do so.
RPyC could be what you're looking for. It gives you access to another machine's Python environment directly from the local script.
>>> import rpyc
>>> conn = rpyc.classic.connect("someremotehost.com")
>>> conn.modules.sys.path
['D:\\projects\\rpyc\\servers', 'd:\\projects', .....]
To establish a connection over SSL or SSH, see:
http://rpyc.sourceforge.net/docs/secure-connection.html#ssl
Well, that is what SSH created for - to be a secure shell, and the commands are executed on the remote machine (you can think of it as if you were sitting at a remote computer itself, and that either doesn't mean you can execute Python commands in a shell, though you're physically interact with a machine).
You can't send Python commands simply because Python do not have commands, it executes Python scripts.
So everything you can do is a "thing" that will make next steps:
Wrap a piece of Python code into file.
scp it to the remote machine.
Execute it there.
Remove the script (or cache it for further execution).
Basically shell commands are remote machine's programs themselves, so you can think of those scripts like shell extensions (python programs with command-line parameters, e.g.).

Categories

Resources