6

I am trying to figure out exactly what is sent to an SSH host when I press Ctrl+c in either PuTTY or OpenSSH. All I am trying to do is send control codes programmatically that are equivalent to when a user presses Ctrl+z for example. So far every time I send ^C or \cc or \003 it just prints it out. There must be some sort of additional information to let the terminal know it was ^C escaped?

I am programmatically sending characters to an SSH session that is already connected to an SSH host. I want to see the same effect as when I have OpenSSH client open and I press Ctrl+c on my keyboard.

noone392
  • 169
  • To clarify, are you wanting to send something like CTRL-Z to an ssh session programmatically, ie from a script? – 111--- Oct 18 '19 at 20:57
  • 1
    Ctrl/C and Ctrl/Z in this context are signals, not characters. You need to explain what you're trying to achieve rather than how to implement what you think needs to be done. – Chris Davies Oct 18 '19 at 21:17
  • 1
  • I am trying to send characters pragmatically to ssh clients that have an ssh session open to a host. – noone392 Oct 19 '19 at 21:04
  • 1
    It all depends on how specifically you want to send control-C to the SSH client, and what exactly that SSH client is. The question as asked, "what is sent to an SSH host when I press CTL-C in PuTTY" is simple: the character control-C, '\x03'. OpenSSH is a suite of utilities and libraries, not an SSH client, so it's meaningless to ask what happens when you "press CTL-C in OpenSSH". – AlexP Oct 20 '19 at 03:04
  • Thank you @AlexP. I am open to different ways how to do this. At the moment I am looking at modifying openssh to give me a hook write before encryption to inject bytes, or I have a mitm tool to modify packets in the tunnel if I provide the keys, but then I need to modify openssh to export them when the tunnel is formed. Open to easier ideas – noone392 Oct 21 '19 at 04:13
  • 1
    You need to explain what you're trying to achieve rather than how to implement what you think needs to be done. Also show (not explain) us what you have tried. – ctrl-alt-delor Jul 31 '20 at 16:13
  • I am trying to mimic a keyboard in a web session where the apache web server backend, ssh's into an ubuntu desktop VM and acts exactly like if you were on the ubuntu vm directly. – noone392 Jul 31 '20 at 16:56

3 Answers3

4

If Ctrl+c is sent over SSH, it's one byte: ^C i.e. hex 0x03 i.e. octal 003 i.e. ASCII ETX.
If Ctrl+z is sent over SSH, it's one byte: ^Z i.e. hex 0x1a i.e. octal 032 i.e. ASCII SUB.

I wrote "if" because Ctrl+c on the client side may or may not generate a byte that gets to the server side. And on the server side this byte may or may not get to whatever program was started by the SSH server.

I don't know how exactly PuTTY in Windows handles this, but I know the mechanics in Linux (i.e. Linux client + Linux server). My answer puts together information from several other answers:

Let's suppose you run ssh using a terminal emulator, then you press Ctrl+c. This is what happens:

  1. The terminal emulator generates ^C.

  2. There's a tty line discipline that may or may not intercept this byte and "convert" it to a signal.

    • If the line discipline is configured to trigger SIGINT upon ^C then it will send SIGINT to the current foreground process group. ssh, being in the foreground process group, will receive the signal and exit.

    • If the line discipline is configured not to treat ^C specially then it will send ^C like any "normal" byte (e.g. like a or 5), ssh will read it and send it to the remote side. And then…

  3. On the remote side there may or may not be a tty allocated.

    • If there is no tty then a program started by the SSH server will receive ^C on its stdin.

    • If there is a tty then there is a line discipline that in turn may or may not be configured to treat ^C specially. Similarly to what can happen locally, the remote line discipline will send SIGINT to the (remote) foreground process group xor pass ^C like any "normal" byte.

ssh started as ssh … some_command or ssh -T … does not allocate a tty on the remote side and does not make the local terminal stop treating ^C specially. In effect local Ctrl+c will terminate the local program (i.e. the ssh itself). But if you bypass the local line discipline by piping to ssh then you will be able to pass arbitrary data (including ^C byte) to some_command; on the remote side there will be no line discipline that could mangle the data.

ssh started without a command or with -t (-tt is needed in some circumstances) does allocate a tty on the remote side and does make the local terminal stop treating ^C specially. In effect local Ctrl+c won't terminate the local program (i.e. the ssh itself) but it will get as ^C to the remote side where the remote line discipline will handle it; so local Ctrl+c will possibly terminate the remote program. The remote line discipline won't be able to tell if ^C it gets comes from local Ctrl+c or (e.g.) from piping printf "\003" to ssh; it's the same byte. When a tty is allocated on the remote side, you cannot reliably send/receive arbitrary data by piping to/from ssh; the line discipline on the remote side will mangle the data. You can get some additional insight from this question of mine: ssh with separate stdin, stdout, stderr AND tty.

So far every time I send ^C or \cc or \003 it just prints it out.

Possibilities:

  • There is no tty on the remote side, so there is no line discipline that would "convert" ^C to SIGINT there; and the program "prints it out" in a form you can actually see (like cat -A).

  • Or there is a tty on the remote side, but the line discipline is configured not to treat ^C specially; and the terminal driver xor the program "prints it out" (it's easy to configure the terminal driver to echo (in caret notation) what it gets as input: stty ctlecho).

  • Or there is a tty on the remote side and the line discipline is configured to treat ^C specially; but the program traps SIGINT and instead of terminating itself "prints it out".

1

Something like this:

(echo ping google.com; sleep 3; printf "\003"; ) |
  ssh -tt localhost
Ole Tange
  • 35,514
0

I am trying to figure out exactly what is sent to an SSH host when I press CTRL-C in either putty or open ssh.

i don't know.

All I am trying to do is send control codes pragmatically that are equivalent to when a user presses CTRL-Z for example.

to send Ctrl+C programmatically, send a SIGINT to the ssh, for example:

killalll -s SIGINT ssh

will do the equivalent of pressing ctrl+C in all SSH sessions you have access to. likewise for Ctrl+Z use SIGTSTP:

killall -s SIGTSTP ssh

will press Ctrl+Z in all ssh terminals... and to send to just a specific ssh session, have its ssh PID and use kill

kill -s SIGTSTP PID

will send Ctrl+Z on the ssh session belonging to that PID.