Commands and option negotiation

Negotiate with WILL and DO

Read WILL, WONT, DO, and DONT as two independent conversations about who performs each Telnet option.

Telnet was built to connect wildly different systems. A 1970s mainframe and a modern laptop cannot assume the same terminal features. So options are negotiated, not assumed. Both sides start from the plain NVT and upgrade from there, one option at a time.

Four commands express offers, requests, refusals, and instructions to stop:

  • WILL option: I offer to perform this option
  • WONT option: I refuse, or I will stop performing it
  • DO option: please perform this option
  • DONT option: do not perform it, or stop performing it

On the wire, each is a three-byte sequence. IAC, then the command, then the option code:

255 251 opt   IAC WILL opt
255 252 opt   IAC WONT opt
255 253 opt   IAC DO   opt
255 254 opt   IAC DONT opt

Let’s see a full exchange. The server offers to echo, and the client agrees:

server: 255 251 1    IAC WILL ECHO
client: 255 253 1    IAC DO ECHO

A side that cannot support the offer answers DONT ECHO instead. The same works in reverse: you can request with DO, and the other side accepts with WILL or declines with WONT.

Refusal is always allowed. The rule from RFC 854 is that an option is only active once both sides have agreed. One side asking is never enough. This is why every implementation must handle a “no” gracefully: the plain NVT keeps working either way.

Two independent conversations

Each direction is negotiated separately. Supporting an option while sending does not mean the same option is active while receiving.

Take ECHO. WILL ECHO from the server means “I will echo what you send me”. Whether the client also echoes in the other direction is a completely separate negotiation. Think of every option as two switches, one per direction, and each switch needs agreement from both sides before it flips.

Avoid negotiation loops

Implementations must avoid negotiation loops, and this is the classic Telnet bug. Side A sends DO ECHO. Side B acknowledges with WILL ECHO. Side A treats the acknowledgment as a fresh offer and acknowledges back with another DO ECHO. Side B answers again. The two ping-pong forever and the connection fills up with negotiation bytes.

The fix is to track the current state of each option. If you receive a WILL for an option that is already on, do nothing. Only send a negotiation command when you want the state to change. Never acknowledge a state you are already in.

Lesson completed