How Telnet works

Data and commands share one stream

Distinguish ordinary terminal data from Telnet control sequences when both travel through the same TCP byte stream.

8 minute lesson

~~~

Telnet puts terminal data and protocol commands in the same TCP stream. There is no separate control connection. Compare this with FTP, which opens one connection for commands and another for file data. Telnet chose one stream for everything, so it needs a way to mark where data stops and a command begins.

The marker is the byte value 255. It means Interpret As Command, abbreviated IAC. The next byte tells the receiver which Telnet command follows. Option negotiation commands include one more byte naming the option.

Here is what a receiver might pull out of the stream:

104 101 108 108 111        five data bytes: "hello"
255 253 1                  IAC DO ECHO (a three-byte negotiation)
255 246                    IAC AYT (a two-byte command)
119 111 114 108 100        five more data bytes: "world"

Every byte below 255 that is not part of a command sequence is plain terminal data. The receiver reads along, and the moment it hits 255 it switches to command parsing.

Escaping byte 255

What happens if terminal data genuinely contains byte 255? The sender writes it twice. The receiver interprets 255 255 as one data byte instead of the start of a command:

sender wants to transmit:  200 255 13
sender actually writes:    200 255 255 13

This is the classic escaping trick. You see the same idea in \\ inside strings and %% in format strings. Any protocol that mixes data and control in one channel needs one.

TCP does not respect your boundaries

TCP does not preserve application message boundaries. One read may contain half a command, several commands, or commands mixed with data. A read can even end exactly after an IAC byte, with the command code arriving in the next read.

A Telnet implementation must keep parsing until every complete sequence is available. In practice that means buffering: if the stream ends mid-sequence, hold the partial bytes and wait for more.

A naive parser that assumes “one read equals one message” works fine on a fast loopback connection and then breaks on a real network. That is exactly the kind of bug this lesson exists to spare you.

Lesson completed

Take this course offline

Get every free book and course as PDF and EPUB files.

Get the download library →