2

I start socat on a terminal by executing socat - UNIX-listen:/tmp/sock

Then I go to another terminal and start a program (by python) in such a way, that it appears to run in the first terminal, here is an example:

s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect("/tmp/sock")
proc=subprocess.Popen(['prg'], stdin=s, stdout=s, stderr=s, shell=False)
proc.wait()

Programs with simple input/output like "cat" for example are working fine, but more complex ones (like "vim" or "bash") are not very happy, obviously. Beside of that, when I hit Cntrl-C on the first terminal, the socat is killed, while I would prefer the keyboard interrupt to be delivered to the prg program (started in the python code above).

My question is: if it's possible and how to tell it to socat to behave like the prg is the terminal owner and not socat itself.

PS. It might appear that this question is a duplicate of this one, but it's not the case, because in that question the prg is called directly by socat, so it is possible to use EXEC options.

ilya
  • 145

1 Answers1

2

Signals nor tty ownership cannot be 'magically' carried over a socket.

Over AF_UNIX, you could send the tty file descriptor itself (using sendmsg and recvmsg) and have the receiving side use it (and not the socket) as the subprocess' stdout/stderr. This cannot be done with plain socat, but this method is used internally by e.g. the tmux tool.


With plain socat, the most you can do is make it send a literal 0x03 byte (^C) when Ctrl+C is pressed (that's what telnet and ssh do). You can test this by pressing Ctrl+VCtrl+C to send it once, or by running stty raw before socat to enter "raw mode" permanently.

That won't be enough to make the receiving end actually understand the keypress, though. The most basic method would be to check each byte manually – send a SIGINT when it sees 0x03; write it to the subprocess' stdin otherwise.

What telnetd and sshd do, however, is add a 'pseudo-tty' in between the socket and the subprocess – in Python you can create one using os.openpty(); the 'slave' side needs to be given as the subprocess' stdout/stderr, and your script will need to run in a loop copying data between the socket and the 'master' side.

That's still not quite enough – a full-featured terminal login protocol, such as SSH or Telnet, would also have messages to update the pty's dimensions, and react to termios setting changes (e.g. the "local echo" setting and others seen in stty).

It would be useful to read the source code of the telnet client & telnetd server, e.g. from GNU inetutils, as they do exactly that.

grawity
  • 501,077