Commands and option negotiation

Read IAC commands

Decode Telnet control sequences that interrupt, erase, synchronize, or negotiate behavior inside the shared byte stream.

Every Telnet command begins with IAC, byte 255. A simple command uses two bytes: IAC followed by the command code.

These commands map to things a person at a terminal wants to do. Stop the running program. Check whether the far end is still alive. Undo the last typed character.

255 244  -> IAC IP   (Interrupt Process)
255 245  -> IAC AO   (Abort Output)
255 246  -> IAC AYT  (Are You There)
255 247  -> IAC EC   (Erase Character)
255 248  -> IAC EL   (Erase Line)

Why send IAC EC instead of a plain backspace character? Because these are protocol-level representations. One system erases characters with backspace, another with delete. The NVT command is neutral. Each end translates it into whatever its local system means by “erase one character”.

Send AYT by hand

IAC AYT is worth sending yourself. Most Telnet clients let you do it from command mode. Press the escape character, then type:

telnet> send ayt

A responding server prints something visible to prove the connection is alive. Historically that was a message like [Yes]. It is a tiny liveness check built into the protocol, decades before health-check endpoints.

Notice what happens if you send it to the lab server you will build later in this course. That server does not understand Telnet commands, so the bytes fff6 show up in its hex log as if they were data. That is a useful reminder: the command only means something if the other side speaks Telnet.

The command codes 251 through 254 are WILL, WONT, DO, and DONT. Those are three bytes rather than two, because they carry an option code. They get the next lesson to themselves.

Parse the stream, not the packets

Do not search each TCP packet on its own for these pairs. A packet may end right after IAC, with the command byte arriving in the next packet. From TCP’s point of view that is completely legal. It promised you a byte stream, not tidy packages.

Parse the continuous stream instead. A correct reader consumes bytes in order. When it sees 255, it waits for the next byte before deciding anything, even if that byte has not arrived yet.

Getting this wrong is nasty. A parser that misses a split IAC treats the command byte as data. Byte 244 is not printable ASCII, so garbage lands in the session, and the interrupt you meant to send never happens. Everything looks fine until packet boundaries fall in the wrong place, which on a real network they eventually will.

Lesson completed