3

I am looking for a way to resize terminal when using telnetlib. I have achieved a similar effect on SSH with Paramiko's resize_pty, but I need to support telnet protocol too. Is this even possible (does telnet even have a control stream)?

Note that telnetlib is not a requirement - if there is a better library I would be happy to use it.

UPDATE (more background): I am building a web-based interface for connecting to networking devices. Frontend is built using JS/AJAX, it basically just sends keystrokes to backend and receives screen content from it. Backend is written in Python and takes care of opening a SSH/telnet session to a device, sends keystrokes to it and fetches an output stream, which is then passed through VT100 virtual terminal (pyte). The contents of virtual screen are then sent back to frontend. The problem arises when user wants to resize the terminal screen size in his browser. With SSH I just send resize_pty() through Paramiko and then also resize the pyte's virtual terminal screen size. But with telnet I was unable to find the appropriate resize function that would tell the device that it should resize its terminal. Is this possible?

johndodo
  • 17,247
  • 15
  • 96
  • 113
  • Could you elaborate more on what are you doing? Do you need telnetlib to handle some kind of pseudo-terminal with server output for you, or just send the resize terminal request to it? – Michał Górny Jul 30 '12 at 08:07
  • @MichałGórny: I have updated the question, I hope it makes more sense now... :) – johndodo Jul 30 '12 at 11:17
  • Thanks. I've did a bit of research and when the terminal is resized, telnetd debugs `td: recv suboption NAWS 0 97 (97) 0 26 (26)`. Sadly, I don't see any specific option in `telnetlib` to send suboptions but I'll have to take a closer look at the protocol. – Michał Górny Jul 30 '12 at 14:08

1 Answers1

4

Ok, I've been able to assemble the following masterpiece:

naws_command = struct.pack('!BBBHHBB',
        255, 250, 31, # IAC SB NAWS
        width, height,
        255, 240) # IAC SE
t.get_socket().send(naws_command)

Now a few words of explanation.

First of all, telnetlib does not support sending commands directly; it simply escapes them. Thus, to send the command we have to use the underlying socket directly. We do that using the get_socket() method of the Telnet object instance (t here).

The NAWS command assembled here is defined by RFC 1073. The width and height variables are regular Python integers which get packed into two 16-bit unsigned integers.

Note that this isn't a perfect solution and I'm not sure if it will actually work for you. Most importantly, during the capabilities negotiation, telnetlib will inform the server that it WON'T NAWS, so a particular server may actually ignore the commands.

If that's the case, you'd probably have to use set_option_negotiation_callback(). Sadly, that means you will have to handle all the options which normally telnetlib does for you. And AFAIK it has no conveniences for that.

Michał Górny
  • 18,713
  • 5
  • 53
  • 76
  • 1
    Thank you!!! I had to use `set_option_negotiation_callback()` to set `WILL NAWS` exactly as you described. It wasn't that much work either, I just studied telnetlib.py and replicated its handling of messages - just a few lines. It works perfectly now. :) – johndodo Jul 31 '12 at 06:52
  • 1
    Yes, the `telnetlib` seems pretty straightforward in code. And it has a few symbolic constants you could use as well; but I think you'd need to replace `B` with `c` in the `pack()` call. – Michał Górny Jul 31 '12 at 07:19