0

The goal is to establish the reverse ssh connection from machine-a to machine-b, so I could ssh connect from machine-b to machine-a after the reverse connection is established.

After importing os module I go ahead and use os.system to ssh connect to a remote server using ssh -R 2210:localhost:22 me@80.54.0.107 & command. Please note that the command line ends with & character because I want to place the ssh process in the background:

import os 
result = os.system("ssh -R 2210:localhost:22 me@80.54.0.107 &")
print("...started ssh connection", result)

But I am getting the error and as a result the ssh connection is not established:

Pseudo-terminal will not be allocated because stdin is not a terminal.

I have tried to run it with subprocess hoping it will work:

import subprocess
cmd = ["ssh", "-R", "2210:localhost:22", "me@80.54.0.107", "&"]
result = subprocess.Popen(cmd, shell=False)

but it throws another error:

bash: -c: line 0: syntax error near unexpected token `&'

Is there a way to run ssh connection from Python placing it at the background?

alphanumeric
  • 17,967
  • 64
  • 244
  • 392
  • Do not use `os.system`. Never. Not under any circumstances. The limitations it adds to `subprocess.Popen` are all for the worse: can't use `shell=False` to avoid injection attacks, can't pass arguments out-of-band from code to run, can't configure file descriptor initialization -- and those limitations _actively prevent_ good security practices from being followed. – Charles Duffy Jul 29 '21 at 16:15
  • Anyhow, you don't need `&` on a `subprocess.Popen` command, because Python _already_ starts your process in the background (which is to say, without an implicit `wait`). If you wanted a foreground process you'd have to use something like `subprocess.call()` instead, or explicitly invoke a blocking function like `communicate()` or `wait()` on the returned object. – Charles Duffy Jul 29 '21 at 16:15
  • So the `&` command is parsed and recognized by the shell before running the actual process. As you can see, this doesn't work when invoking a subprocess in Python (it likely calls something lower than the shell, such as `execv`). Regardless, Popen technically already opens the process in the background. You can check on the process status with `result` in your case. – h0r53 Jul 29 '21 at 16:15
  • That said, if you're starting `ssh user@host` with no further arguments, keeping it in the background, and not redirecting its stdin/stdout/stderr away from inherited file descriptors, I really need to wonder about the context in which that's a sensible operation. You don't want your Python process and your ssh process to fight over who controls the TTY's stdin. – Charles Duffy Jul 29 '21 at 16:21
  • What would be a proper way to initiate the ssh connection from Python? – alphanumeric Jul 29 '21 at 16:31
  • @alphanumeric, err, a ssh connection _for what purpose_? To run a specific piece of software? To have an interactive shell you can hand off to the user? Something else? – Charles Duffy Jul 29 '21 at 16:48
  • For example: If you're running a specific command on the other host, then `['ssh', f'{remoteuser}@{remotehost}', 'remotecommand']` will do. If you want to run _several different_ commands on the same remote machine over the same transport, OTOH, you'd be better off using the paramiko library. – Charles Duffy Jul 29 '21 at 16:49
  • Or if you want to write a script that runs an interactive command built to accept human user input on the remote machine but simulates that input, then you're better off with [`pxssh`](https://pexpect.readthedocs.io/en/stable/api/pxssh.html). – Charles Duffy Jul 29 '21 at 16:54
  • But when you just run `subprocess.Popen(['ssh', 'somehost'])` with no further arguments, that copy of ssh is set up to read _from stdin_. Having something reading from stdin in the background is usually not a good idea (not just in python, in shell languages and pretty much everywhere else as well). – Charles Duffy Jul 29 '21 at 16:55
  • The purpose to start the ssh connection is to set up the reverse ssh. I need this reverse ssh to be running at the background so I could ssh to this machine from another computer with which the reverse ssh connection was established. I am editing my original post with more details – alphanumeric Jul 29 '21 at 17:00
  • In that case, you probably want the `-N` argument to ssh. `['ssh', '-N', '-R', f'{localfwdport}:{fwdhost}:{fwdport}', remotehost]` makes sense (since it's not trying to read from stdin), whereas `['ssh', 'remotehost']` doesn't. – Charles Duffy Jul 29 '21 at 17:02
  • That said, you might be better off running just _one_ copy of ssh with the `ProxyJump` option used, so it does the work of starting the second copy of ssh on your behalf. – Charles Duffy Jul 29 '21 at 17:04
  • @CharlesDuffy Please post your response as the answer so we could up vote it. – alphanumeric Jul 29 '21 at 17:05
  • 2
    Can't post answers, the question is closed. – Charles Duffy Jul 29 '21 at 17:05
  • 1
    Also, we have a lot of duplicates already in the knowledgebase that cover this ground, and cover it better than I could whipping something out in 30 seconds. I've added a few of them to the duplicate list now that you clarified the question to make it clear that it's about setting up port forwarding; both the ones I added have both answers showing how to do this with OpenSSH (using the `-N` argument), _and_ ones that show how to do it with paramiko. – Charles Duffy Jul 29 '21 at 17:09

0 Answers0