fsxNet Wiki

BBS Development & Resources

User Tools

Site Tools


tutorials:crystal_bbs:part_zero

Crystal BBS - Part Zero

Intro the the Telnet protocol

This is by no means an exhaustive intro to Telnet, but a few basic notions are needed. The reason we're going into Telnet at all is because at the time this is being written (March 2017) dial-up is not really a thing anymore, and of the remaining BBSs, the large majority is accessible via Telnet, with some featuring SSH as an option.

Now, a robust BBS package would be written in a way that decouples the transport interface from the rest of the system, so you can just add new transports and maintain functionality (you may want to add SSH and a Web transport in the future, for example) but since this is an entry-level tutorial, we'll focus on Telnet and not worry too much about architecture.

Telnet is these days an obsolete protocol, since it's insecure and bound to a set of archaic notions by today's standards. The initial purpose of Telnet was to allow “virtual terminal” access to remote systems, and it was wildly successful. First mentioned in RFC 97 all the way back in February 1971, it would be formalized in RFC 854 published in May 1983, along with some follow-up RFCs describing protocol extensions and negotiation options. Being a product of the 70s, security was not of huge importance to its design (same problem as SMTP and others). Bear this in mind - Telnet is not secure and quite vulnerable to so called “man-in-the-middle” attacks, and has no provision to safeguard against it.

So, the basic idea is that we get a character by character interface, just like a local Linux terminal emulator. Our inputs are sent to the server, and we get an update of the virtual terminal's layout sent back (or not, in case the keystroke does not change the state of the terminal).

Usually, network programming involves sending and receiving messages, but for purposes of manipulating this virtual terminal, we'll be sending and receiving more than just text - among the messages we will send (and receive) are things that are not shown in text, like sounding a bell or clearing the screen or moving the cursor to a specific line and column. These are ANSI Escape Codes and are not specific to Telnet - they govern the behaviour of any “modern” text terminal. You can avoid these, but your BBS would not look very nice without screen clearing and cursor positioning and so on.

Specific to Telnet, there are factors like terminal size and message flow and so on - negotiating these client capabilities with the server was necessary even back when Telnet was first created as many different terminals, with different features, were prominent in the 1970s and 80s. Examples are the famous VT100 and VT220 terminals by DEC.

You can see these protocol messages for yourself when connecting to a Mystic BBS. Let's try this by connecting to the main fsxNet hub, Agency BBS. Instead of connecting directly to the BBS, start telnet by itself:

$ telnet
telnet> 

On the telnet> prompt, type:

telnet> toggle options

You should now see Will show option processing as a result. This means that the normally suppressed feature negotiation messages will be shown on screen. Oh, and by the way, whenever you want to exit a Telnet connection that is hung or somehow unusable, press Ctrl-5 to get a telnet client prompt, and then you can just type quit to exit. Now, on to the Agency BBS:

telnet> open agency.bbs.geek.nz

You should see:

Trying 219.89.83.33...
Connected to agency.bbs.geek.nz.
Escape character is '^]'.
SENT DO SUPPRESS GO AHEAD
SENT WILL TERMINAL TYPE
SENT WILL NAWS
SENT WILL TSPEED
SENT WILL LFLOW
SENT WILL LINEMODE
SENT WILL NEW-ENVIRON
SENT DO STATUS
SENT WILL XDISPLOC
RCVD WILL ECHO
SENT DO ECHO
RCVD WILL SUPPRESS GO AHEAD
RCVD DO TERMINAL TYPE
RCVD DO BINARY
SENT WILL BINARY
RCVD IAC SB TERMINAL-TYPE SEND
SENT IAC SB TERMINAL-TYPE IS "XTERM-256COLOR"
RCVD DONT NAWS
RCVD DONT TSPEED
RCVD DONT LFLOW
RCVD DONT LINEMODE
RCVD DONT NEW-ENVIRON
RCVD WONT STATUS
RCVD DONT XDISPLOC

Mystic BBS v1.12 A31 for Windows Node 1
Copyright (C) 1997-2016 By James Coyle

Detecting terminal emulation: ANSI detected.

and then the BBS's main login screen. So, that's a lot of feature negotiation going back and forth! We won't go into detail (more on them in the next part of this tutorial) but let's go into just one of the features being negotiated called Go Ahead. You can see two debug messages related to it in the connection log:

SENT DO SUPPRESS GO AHEAD
...
RCVD WILL SUPPRESS GO AHEAD

Go Ahead was used in the old days of “half-duplex” connections, which means that only one channel was used for reception and transmission, and so the Go Ahead message was sent after each interaction as a form of “over and out” to liberate the channel for the other party to proceed. Nowadays, most connections are “full-duplex” which means that separate channels are used for reception and transmission, so there is no need to burden the connection with extra Go Ahead characters.

Every feature negotiation message, either from the client or the server, starts with the 0xff (255, in decimal) byte, which is known as the IAC byte. IAC stands for “interpret as command” and basically means the next few bytes are to be interpreted as terminal commands, and not output to be shown on screen.

Ruby's net/telnet documentation has a good rundown of the byte values used in Telnet command messages. Here's an excerpt (full file here):

    IAC   = 255.chr # "\377" # "\xff" # interpret as command
    DONT  = 254.chr # "\376" # "\xfe" # you are not to use option
    DO    = 253.chr # "\375" # "\xfd" # please, you use option
    WONT  = 252.chr # "\374" # "\xfc" # I won't use option
    WILL  = 251.chr # "\373" # "\xfb" # I will use option

    OPT_SGA = 3.chr # "\003" # "\x03" # Suppress Go Ahead

Using this table, we can figure out what was sent in those telnet client negotiation messages, and what was the server's reply. So, for SENT DO SUPPRESS GO AHEAD, the client sent three bytes:

  1. 255 (IAC, start of command message)
  2. 253 (DO, or “please, you use option”)
  3. 3 (Suppress Go Ahead)

And the server replied with three more bytes:

  1. 255 (IAC, start of command message)
  2. 251 (WILL, or “I will use option”)
  3. 3 (Suppress Go Ahead)

And just like that, both client and server agreed that the Go Ahead feature is not to be used in this connection! Other messages are being exchanged in the full sequence above regarding speed, input type (binary or text) and even NAWS (Negotiate About Window Size), which has an awesome name. All of these will be addressed as we need them for our BBS, most on the next part of the tutorial. But you can tell from the design of the protocol that clients can be quite flexible in how they interact with any Telnet server you write, if you reply to feature negotiation messages appropriately!

The one problem with this setup is that there is no definitive “end” marker to the negotiation step of the connection, since at any time you can receive or send one of these messages to turn features on and off.

So this is Telnet in a nutshell - a text-oriented protocol that has special command messages mixed in.

Again, Telnet IAC messages should not be confused for ANSI Escape Codes that affect the terminal like \e[2J that clears the screen and so on. You might be familiar with them if you ever customized a Bash prompt, but they are related to the ANSI standard, not Telnet.

In the next part of the tutorial, we will create a basic TCP server that will use some of what we now know about Telnet to negotiate basic features with clients.

tutorials/crystal_bbs/part_zero.txt · Last modified: 2017/03/20 00:16 by sardaukar