Build a local Telnet lab
Observe option negotiation bytes
Make the local server request a Telnet option and decode the client response as protocol bytes instead of printable text.
So far the lab server has only received data you typed. Now let’s make it speak the Telnet protocol itself, and watch how the client reacts.
Add this line right after the server accepts a connection, before the Welcome write:
socket.write(Buffer.from([255, 253, 31]))
Those three bytes mean IAC DO NAWS. Byte 255 is IAC, 253 is DO, and 31 is the option code for Negotiate About Window Size, defined in RFC 1073. In plain words, the server is asking the client: “please tell me how big your window is”.
A client that supports the option answers IAC WILL NAWS, then sends a NAWS subnegotiation with its dimensions.
Restart the server, reconnect with the Telnet client, then look at the hex log. You should see something like:
fffb1f
fffa1f00500018fff0
Let’s decode it byte pair by byte pair.
The first line, fffb1f, is IAC WILL NAWS. ff is 255, fb is 251 (WILL), 1f is 31 (NAWS). The client accepted.
The second line, starting fffa1f, is the NAWS subnegotiation. fa is 250, the SB command. Then come four data bytes: width and height, two bytes each. Here 0050 is 80 columns and 0018 is 24 rows. The fff0 at the end is IAC SE, closing the subnegotiation.
Now resize your terminal window while connected. A well-behaved client sends a fresh fffa1f sequence with the new dimensions. Make it wider and watch the width bytes grow. You are watching live option traffic in your own log.
When the client says no
Client behavior varies. A refusal starting fffc1f is also a valid result: IAC WONT NAWS. The client is saying “I don’t do that”, and the protocol is fine with it.
Netcat will not answer at all. It is not a Telnet client, so it treats your three bytes as ordinary data and dumps them to your terminal, where they show up as a stray character or nothing at all. Try it, and compare with what the Telnet client did.
Record what actually happened instead of assuming every client implements the same options. That habit is the whole point of this lab. Negotiation is a conversation, and you only know its outcome by reading the real bytes.
One more thing to notice. None of these bytes appeared on the client’s screen. The client consumed them as protocol traffic and showed you only Welcome. Data and commands share the stream, and this is what that looks like in practice.
Lesson completed