21

When I view the length and width of my terminal emulator with stty size then it is 271 characters long and 71 lines tall. When I log into another server over SSH and execute stty size, then it is also 271 characters long and 71 lines tall. I can even log into some Cisco IOS device and terminal is still 271 characters long and 71 lines tall:

C1841#show terminal | i Len|Wid
Length: 71 lines, Width: 271 columns
C1841#

Now if I resize my terminal emulator(Gnome terminal) window in local machine, both stty size in remote server and "show terminal" in IOS show different line length and number of lines. How are terminal length and width forwarded over SSH and telnet?

Martin
  • 7,516

3 Answers3

27

The telnet protocol, described in RFC 854, includes a way to send in-band commands, consisting of the IAC character, '\255', followed by several more bytes. These commands can do things like send an interrupt to the remote, but typically they're used to send options.

A detailed look at an exchange that sends the terminal type option can be found in Microsoft Q231866.

The window size option is described in RFC 1073. The client first sends its willingness to send an NAWS option. If the server replies DO NAWS, the client can then send the NAWS option data, which is comprised of two 16-bit values.

Example session, on a 47 row 80 column terminal:

telnet> set options
Will show option processing.
telnet> open localhost
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
SENT WILL NAWS
RCVD DO NAWS
SENT IAC SB NAWS 0 80 (80) 0 47 (47)

The ssh protocol is described in RFC 4254. It consists of a stream of messages. One such message is "pty-req", which requests a pseudo-terminal, and its parameters include the terminal height and width.

byte      SSH_MSG_CHANNEL_REQUEST
uint32    recipient channel
string    "pty-req"
boolean   want_reply
string    TERM environment variable value (e.g., vt100)
uint32    terminal width, characters (e.g., 80)
uint32    terminal height, rows (e.g., 24)
uint32    terminal width, pixels (e.g., 640)
uint32    terminal height, pixels (e.g., 480)
string    encoded terminal modes

The telnet and ssh clients will catch the SIGWINCH signal, so if you resize a terminal window during a session, they will send an appropriate message to the server with the new size. Ssh sends the Window Dimension Change Message:

byte      SSH_MSG_CHANNEL_REQUEST
uint32    recipient channel
string    "window-change"
boolean   FALSE
uint32    terminal width, columns
uint32    terminal height, rows
uint32    terminal width, pixels
uint32    terminal height, pixels
Mark Plotnick
  • 25,413
  • 3
  • 64
  • 82
  • Could you update with an example of the hex values you could use to actually send the Window Dimension Change Message? I cannot find an example of it anywhere. – MirroredFate Jul 12 '17 at 00:33
  • @MirroredFate The C code that sends that message is https://github.com/openssh/openssh-portable/blob/master/channels.c#L3859 . I don't know offhand how to see the raw bytes that are sent; you may have to add some logging to the openssh source code. – Mark Plotnick Jul 14 '17 at 16:19
2

I suspect that it's via the signal SIGWINCH --- probably delivered down the pipe.

From wikipedia:

SIGWINCH
    The SIGWINCH signal is sent to a process when its controlling
     terminal changes its size (a window change).

If I do a (in zsh):

[romano:~] 1 % TRAPWINCH() {echo hi;}

...and I modify the terminal size:

[romano:~] % stty size
35 99
[romano:~] % hi
[romano:~] % hi
[romano:~] % hi
[romano:~] % stty size
31 80
Rmano
  • 3,425
0

RFC 4254 Section 6.9 Message name "window-change" is sent with the new dimensions. On the client side it may be true the original SIGWINCH is caught, but it gets sent via that message I believe. https://www.ietf.org/rfc/rfc4254.txt

john
  • 1