Recently, I was engaged in researching what solutions exist for implementing a web-ssh proxy server. The essence of the task is to enable users to connect to an arbitrary ssh-server via a web interface. Usually, web-ssh solutions are designed to connect to the server on which they are deployed, but as part of my task I wanted the user to specify the IP, port, username and password of the user (or key) and connect to an arbitrary server. I did not manage to find a similar solution on the move.
Actually, of course, there is Guacamole, but for my task, using this application was too costly both in terms of development resources and functions and their organization, so I refused to use Guacamole.
However, for the open shellinabox package, I found a solution on a blog in German, which I decided to bring to the level I needed. The result is a nice Docker container, which can be found on both GitHub and Dockerhub , which solves all the necessary tasks.
But the article is not about that, but about the accompanying Python code that I had to write. The fact is that I didn’t like that if the user opened web ssh and went somewhere, the session would hang endlessly, which in my opinion is unacceptable. This leads to the following negative consequences:
In general, I decided that I want to make sure that the shellinabox breaks the connection if the user does not write anything to the console (stdin) for a few minutes and does not receive data to stdout.
Long enough Google search showed me that goals can be achieved using the timeout and strace commands. The timeout command turned out to be new for me, its purpose is to ensure the interruption of the process upon reaching a certain timeout in the event that it did not end.
I use the strace command often, however, I usually use it to track the reason why some service or team is not working as expected. As part of my search for how to monitor activity on the stdin channels, the stdout process, I found that strace can also provide this:
strace -e write=1,2 -e trace=write -p <PID>
In general, these teams were what I needed to carry out my plans. The general scheme looks like this:
For those who want to immediately see how the whole script works, send it here . For the rest, further in parts.
Briefly, the code can be presented as follows.
monitor_daemon(inactivity_interval, identity_file) ... ... os.execv("/usr/bin/ssh", ["/usr/bin/ssh"] + identity_args + ["-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null", "-p", str(peer_port), "%s@%s" % (peer_login, peer_ip)])
The code is simple and self-evident. All magic is inside the monitor_daemon
function:
def monitor_daemon(inactivity_interval, identity_file): orig_pid = os.getpid() try: pid = os.fork() if pid > 0: return except OSError as e: print("Fork #1 failed: %d (%s)" % (e.errno, e.strerror)) sys.exit(1) os.chdir("/") os.setsid() os.umask(0) try: pid = os.fork() if pid > 0: sys.exit(0) except OSError as e: print("Fork #2 failed: %d (%s)" % (e.errno, e.strerror)) sys.exit(1) if identity_file != "": time.sleep(1) os.unlink(identity_file) try: while True: proc = subprocess.Popen('timeout %d strace -e write=1,2 -e trace=write -p %d' % (inactivity_interval, orig_pid), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc.poll() counter = 0 for line in proc.stderr.readlines(): counter += 1 if(counter <= 3): os.kill(orig_pid, signal.SIGKILL) sys.exit(0) except Exception as e: pass sys.exit(0)
where we are most interested in part:
while True: proc = subprocess.Popen('timeout %d strace -e write=1,2 -e trace=write -p %d' % (inactivity_interval, orig_pid), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc.poll() counter = 0 for line in proc.stderr.readlines(): counter += 1 if(counter <= 3): os.kill(orig_pid, signal.SIGKILL) sys.exit(0)
in which the monitoring starts in a cycle, which, after a specified waiting period, completes the ssh process, if required.
That's all. The solution was simple enough, but it took some time to study the available tools.
PS: I am not a professional python developer, the code is suboptimal.
PPS: If someone has a desire to improve the code, welcome to the repository , I will gladly accept PRs.
Source: https://habr.com/ru/post/332544/
All Articles