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.

8
  • To clarify, are you wanting to send something like CTRL-Z to an ssh session programmatically, ie from a script?
    – 111---
    Commented Oct 18, 2019 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. Commented Oct 18, 2019 at 21:17
  • 1
    Possible duplicate of How to send ^D / EOT character to stdin of a shell process? Commented Oct 19, 2019 at 13:29
  • 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
    Commented Oct 20, 2019 at 3:04
  • 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. Commented Jul 31, 2020 at 16:13

3 Answers 3

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
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.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .