Search code examples
pythonlinuxwindowsparamikossh-tunnel

Python paramiko/sshtunnel code works fine under linux but fails under Windows


I have successfully gotten the following python paramiko/sshtunnel code to work properly under linux to tunnel to a port on a remote machine via an SSH tunnel. However, running the exact, same python code under Windows 10 fails. This is Python 3.9.5 in both cases.

First, the code itself ...

import sys
import json
import time
import queue
import socket
import paramiko
import sshtunnel
from threading import Thread

remotehost = 'remote-host-blah-blah-blah.net'
remoteport = 9999
pkeyfile   = os.path.expanduser('~/.ssh/id_rsa')

def main():
    pkey = paramiko.RSAKey.from_private_key_file(pkeyfile)
    with sshtunnel.open_tunnel(
        (remotehost, 22),
        ssh_username='remoteusername',
        ssh_pkey=pkey,
        compression=True,
        remote_bind_address=('0.0.0.0', remoteport)
    ) as remote:
        connecthost = remote.local_bind_host
        connectport = remote.local_bind_port
        return runit(connecthost, connectport)
    return 1

def runit(connecthost, connectport):
    client = None

    while True:
        try:
            client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            client.connect((connecthost, connectport))
            output(f'\nconnected: {connecthost}:{connectport}')
            break
        except Exception as e:
            time.sleep(1.0)
            print(f'!!! retrying {connecthost}:{connectport} because of {e}')

    # If we made it here, we are properly connected through
    # the tunnel. This works under linux, but we never get
    # here under Windows 10. The code which follows is not
    # pertinent to this Stackoverflow question, so I have
    # left out the remaining code in this program.

And this is the error that keeps printing ...

!!! retrying 0.0.0.0:53906 because of [WinError 10049] The requested address is not valid in its context

The "53906" port is different each time I run this, of course.

Also, under Windows 10, I can go to Power Shell while this python program is running, and I can run the following, in which case I indeed get connected to the port and see the remote data ...

telnet localhost 53906

This seems to imply that there is something about the way that python is trying to connect to that socket which is causing the error.

Can anyone see what I might need to change in my python code to get this to work properly under Windows 10?

Thank you very much.


Solution

  • I figured out the problem and fixed it.

    These two lines return connecthost = '0.0.0.0' and a random value for connectport:

            connecthost = remote.local_bind_host
            connectport = remote.local_bind_port
    

    However, if I force connecthost to be '127.0.0.1' in the client.connect call, my code works fine.

    I'm guessing that Windows 10 must handle '0.0.0.0' differently from how linux handles it. If so, then perhaps sshtunnel.open_tunnel under Windows should be changed to return '127.0.0.1' instead of '0.0.0.0'.

    Anyway, this is working now.