I am trying to connect via SSH to a computer tunneling through another computer using paramiko in Python, but I am having some strange issues.
My config file in /.ssh/config looks like this:
Host remoteA
HostName 169.254.1.1
User root
IdentityFile ~/.ssh/id_dss.openssh.remoteA
ForwardX11 no
StrictHostKeyChecking no
ForwardAgent yes
UserKnownHostsFile /dev/null
Host remoteB
User root
IdentityFile ~/.ssh/id_dss.openssh.remoteB
ForwardX11 no
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
ProxyCommand ssh -W 169.254.1.2:22 remoteA
And my python code like this:
from paramiko import SSHClient,SSHConfig,SSHException
import getpass
import paramiko
def getSSHConnection(hostName):
config = SSHConfig()
user = getpass.getuser()
config.parse(open('C:/Users/' + user +'/.ssh/config'))
host=config.lookup(hostName)
# setup SSH client
client = SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
#Check for proxy settings
try:
print host ['proxycommand']
proxy = paramiko.ProxyCommand(host['proxycommand'])
except:
proxy = None
#Setup the SSH connection
try:
if (proxy is None):
client.connect(host['hostname'],22,username=host['user'],key_filename=host['identityfile'])
else:
client.connect(host['hostname'],22,username=host['user'], key_filename=host['identityfile'],sock=proxy)
except SSHException,ex:
print ex
return client
ssh_client = getSSHConnection('remoteA')
# run a command
print "\nRun a command"
cmd = 'ps aux'
stdin,stdout,stderr = ssh_client.exec_command(cmd)
print stdout.read()
ssh_client = getSSHConnection('remoteB')
# run a command
print "\nRun a command"
cmd = 'ps aux'
stdin,stdout,stderr = ssh_client.exec_command(cmd)
print stdout.read()
First when connecting to remoteA it works perfectly,but then when connecting to remoteB it crashes in the step: proxy = paramiko.ProxyCommand(host['proxycommand']).
File "C:\Python27\lib\site-packages\paramiko\client.py",line 291,in connect
for (family,socktype,proto,canonname,sockaddr) in socket.getaddrinfo(hostname,port, socket.AF_UNSPEC,socket.SOCK_STREAM):
socket.gaierror: [Errno 11004] getaddrinfo failed
Within Cygwin,I am able to connect using the command ssh remoteB so I know the config file should be ok.
If it makes any difference,I am running this on Windows 7.
I think you can stick to your first solution. Just you need to change your proxy command and make sure your jump host has got nc installed
I use a proxy command like this
proxy = paramiko.ProxyCommand("ssh -o StrictHostKeyChecking=no jumphostIP nc targethostIP 22")
I found this WiKi very useful
http://en.wikibooks.org/wiki/OpenSSH/Cookbook/Proxies_and_Jump_Hosts
Just use actual values instead of %h and %p as I have done.
So instead of using ProxyCommand I used port forwarding to solve my issue.
def getForwardedSSHPort(self, tunnnelHostName):
forwarderClient = self.getSSHConnection(tunnnelHostName, None)
transport = forwarderClient.get_transport()
dest_addr = ('169.254.1.2', 22)
local_addr = ('127.0.0.1', 10022)
channel = transport.open_channel('direct-tcpip', dest_addr, local_addr)
remoteClient = self.getSSHConnection( tunnnelHostName, channel)
Related
How to telnet network device via jump server(SSH) using paramiko or any other library
I am able to SSH jumpserver and able to SSH other device over it. But need solution to telnet from jumpserver.
Use SSH port forwarding.
Modifying the code from Nested SSH using Python Paramiko for telnet, you get a code like this:
# establish SSH tunnel
self.ssh = paramiko.SSHClient()
# ...
self.ssh.connect(hostname=ssh_host, username=ssh_user, password=ssh_password)
transport = ssh_client.get_transport()
dest_addr = (telnet_host, telnet_port)
local_unique_port = 4000 # any unused local port
local_host = 'localhost'
local_addr = (local_host, local_unique_port)
vmchannel = vmtransport.open_channel("direct-tcpip", dest_addr, local_addr)
tn = telnetlib.Telnet(local_host, local_unique_port)
in the terminal, the following works just fine:
> ssh me#host -p 22
but the following python code gives me a TimeoutError:
from paramiko import SSHClient
client = SSHClient()
client.connect(hostname='host', port=22, username='me', look_for_keys=True)
Any idea why that would be the case? The connection uses RSA keys for authentication, and I'm over a VPN. Seems like I'm missing some context I need to tell paramiko about, but I can't figure out what it is.
I usually connect to a remote server by adding an explicit link to my private key:
HOST = 'hostname'
USER = 'username'
PKEY = '/path/to/rsa_private_key'
PKEY_PASS = 'xxx'
k = paramiko.RSAKey.from_private_key_file(PKEY, PKEY_PASS)
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
print "connecting"
ssh.connect(HOST, username=USER, pkey=k)
connect_status = 'connected' if ssh else 'failed to connect'
print connect_status
I need to connect to SFTP server using proxy command.
I know how to connect to SFTP server directly:
paramiko's sshclient with sftp
I can open an SSH connection via proxy command using this code:
import paramiko
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
target_host = 'sftp.XXXXX.co'
target_port = 22
proxy = paramiko.proxy.ProxyCommand('/usr/bin/nc --proxy proxy_host:8080 %s %d' % (target_host, target_port) )
client.connect(hostname=target_host,username='username', port=target_port, password='XXXXXXXX', sock=proxy)
But I need to create SFTPClient, not SSHClient. But I do not know how to pass the ProxyCommand to the SFTPClient.
To connect to SFTP server using a "custom socket", do:
proxy = paramiko.proxy.ProxyCommand(...)
transport = paramiko.Transport(proxy)
transport.connect(username = username, password = password)
sftp = paramiko.SFTPClient.from_transport(transport)
I'm trying to do ssh through middle server with python.
I tried to work as written at this example : SSH to machine through a middle host
but when I'm running the code, I'm getting the following exception paramiko.ssh_exception.SSHException: Error reading SSH protocol banner
When I'm opens the terminal that executes the program password authentication is required in order to proceed
I also edited the ~/.ssh/config as follows:
Host cybnode13
ProxyCommand ssh root#cybhead1.lnx.biu.ac.il nc %h %p
My code is attached below
proxy_command = 'ssh -p %s %s#%s nc %s %s' % (password, proxy_user, proxy_host, host, 22)
proxy = paramiko.ProxyCommand(proxy_command)
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(host, username=proxy_user, password=password, sock=proxy)
stdin, stdout, stderr = client.exec_command('echo HELLO')
I am trying to ssh tunnel from PC --> server1 ---> server2 ----> switch1
This is possible through a regular terminal with a simple: ssh switch1 it references my ssh_config which reads:
Host server1
user bill
Hostname server1
ForwardAgent yes
IdentityFile ~/.ssh/id_rsa
ProxyCommand none
Host server2
user bill
Hostname server2
IdentityFile ~/.ssh/id_rsa
ProxyCommand ssh server1 /usr/bin/nc %h %p
Host switch1
user bill
Hostname %h.omniture.com
ProxyCommand ssh server2 /usr/bin/nc %h %p
Not a problem from regular terminal. But trying to build a python script to do it has proven to be difficult.
Script is as follows:
import paramiko
import subprocess
import getpass
import os
def ssh_command(ip, user, passwd, command):
client = paramiko.SSHClient()
client.load_host_keys('/Users/bill/.ssh/known_hosts')
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
config = paramiko.SSHConfig()
if os.path.exists('/etc/ssh/ssh_config'):
config.parse(open('/etc/ssh/ssh_config'))
if os.path.exists(os.path.expanduser('~/.ssh/config')):
config.parse(open(os.path.expanduser('~/.ssh/config')))
host = config.lookup(ip)
if 'proxycommand' in host:
proxy = paramiko.ProxyCommand(
subprocess.check_output(
[os.environ['SHELL'], '-c', 'echo %s' %
host['proxycommand']]
).strip()
)
else:
proxy = None
client.connect(host['hostname'], username='bill',
password=getpass.getpass(), sock=proxy)
ssh_session = client.get_transport().open_session()
if ssh_session.active:
ssh_session.exec_command(command)
print ssh_session.recv(1024)
return
ssh_command('sw-a-102.sin2', 'bill', getpass.getpass(), 'show ver')
The error I get is:
No handlers could be found for logger "paramiko.transport"
Traceback (most recent call last):
File "/Users/bill/git/tools/python/dns-check/proxy-test.py", line 34, in <module>
ssh_command('switch1', 'bill', getpass.getpass(), 'show ver')
File "/Users/bill/git/tools/python/dns-check/proxy-test.py", line 28, in ssh_command
client.connect(host['hostname'], username='bill', password=getpass.getpass(), sock=proxy)
File "/Library/Python/2.7/site-packages/paramiko/client.py", line 265, in connect
t.start_client()
File "/Library/Python/2.7/site-packages/paramiko/transport.py", line 406, in start_client
raise e
paramiko.ssh_exception.ProxyCommandFailure: ('ssh server2 /usr/bin/nc switch1 22', 'Broken pipe')
If I can get this to work using paramiko that would be great, if someone knows a better way, that would be good too. Thank you for your time.
There is a better way, still with Paramiko but without ProxyCommand configuration.
Reason being paramiko's proxy command support is buggy and prone to race conditions, which is the cause of the error above.
OTOH, SSH has native support for tunneling in the protocol itself and does not require external tools to achieve it.
import paramiko
# Make clients
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.MissingHostKeyPolicy())
server2_client = paramiko.SSHClient()
server2_client.set_missing_host_key_policy(paramiko.MissingHostKeyPolicy())
switch1_client = paramiko.SSHClient()
switch1_client.set_missing_host_key_policy(paramiko.MissingHostKeyPolicy())
# Connect to server1 normally
client.connect('server1')
# Make channel server1 -> server2
server2_chan = client.get_transport().open_channel('direct-tcpip', ('<server2 ip>', 22,), ('127.0.0.1', 0))
# Connect to server2 via server1's channel
server2_client.connect('<server2 ip>', sock=server1_chan)
# Make channel server2 -> switch1
switch1_chan = server2_client.get_transport().open_channel('direct-tcpip', ('<switch1 ip>', 22,), ('127.0.0.1', 0))
# Finally connect to switch1 via server2 channel
switch1_client.connect('switch1', sock=server2_chan)
switch1_client.exec_command(<command>)
Substitute server and switch names with their IP addresses.
See also a parallel SSH client based on paramiko with support for native SSH tunneling.