IRC Is an Insanely Simple Protocol

This is where I’d usually make some joke about “if you remember, back in the day…” but… given how Freenode and Libera have been in the news recently for Freenode’s rather hostile takeover (and suicide), You probably know what IRC is. So. IRC, or Internet Relay Chat, is a really old (as in, 1988) protocol for text-based communications between users on a network. And the cool part is, it’s so simple that it’s almost funny. Like, let’s take a look. You could actually, with only a few minutes of reading, just enter raw IRC protocol lines by hand and have a perfectly valid and functional session.

For the record, IRC is technically still being worked on. The IRCv3 Working Group is what’s responsible for this. But regardless, let’s get into things.

The Basics

IRC takes place between a client and a server, sending lines of ASCII text between each other. Multiple servers can be joined together into a network, where servers will share activity from their users to other servers, allowing for everything on the network to send the same messages to all clients, using as few messages as possible. There’s no real difference between the client-client protocol and the server-server protocol, except that server-server communications usually require some authentication, encryption (TLS), and contain an identifier of where the message originated from. Servers can connect to other servers in an arbitrary spanning tree manner, meaning there is only one link from client A to client B through the server network. Nothing is specific to any given server, a server just relays messages from the rest of the network to its clients, and messages from its clients to any of its connected servers, thus repeating the cycle, until every client has received the message, using as few actual point-to-point messages as possible.1

All communication on IRC happens within a channel, to separate out conversations (though, direct client-to-client messaging is also possible between exactly two clients). Channels can have certain flags (called modes), so can users. Channels have a name, a topic string, a list of users with certain levels of power (operators), and, well, you get the idea. Users can join a channel, and then proceed to speak in it. All users in a channel are sent messages within that channel.

Clients are identified on the network by their chosen nickname (nick), which must be unique, but in addition, their machine username (user) and connecting IP / hostname (host) are also visible (with some exceptions that aren’t covered here, like +x mode on some IRC servers). Traditionally, this is displayed in the form nick!user@host when required. Nicks can be freely changed on the network, users cannot without a disconnect / reconnect cycle (or protocol extensions), and hosts generally cannot be changed by the client, but may be changed by the server (again, +x mode where available).

The Protocol

As mentioned, before, IRC is a text-based line-oriented protocol, and there’s basically only two types of lines:

  • Command lines, with commands like JOIN, PART, QUIT, PRIVMSG, etc.
  • Numeric lines, which are lines prefixed with a three-digit code to indicate what they are.

Command lines are usually sent in response to a client’s command, but can be sent spuriously. For example, messages in a channel are sent to all clients with a server-to-client PRIVMSG line. Numeric lines are for extra detail, such as when joining the server or a channel, with each number having a designated meaning.

Each line has four parts:

  • The prefix, where it came from (optional)
  • The command or numeric
  • Arguments
  • The “trailer”, which is other text

Arguments are space separated, meaning any text that contains spaces needs to be in the trailer. This format looks like this:

:prefix cmd/numeric arg1 arg2 :trailer

Of which, here’s some examples:

NICK Teknikal_Domain 265 Teknikal_Domain 1 2 :Current local users 1, max 2
:Teknikal_Domain MODE Teknikal_Domain :+wx
PRIVMSG #channel :Hey channel!
:[email protected] PRIVMSG #channel :Hey, tek!

Two of these lines do not contain prefixes. One line contains the prefix of the server itself, and the others contain the prefixes of the sending nicks. In server-to-server communication, the prefix is always used, but a client doesn’t need to use one when it sends, since the source of obvious — that client.

That’s it. Besides commands, numeric responses, and some protocol extensions, that’s all there is to it. Again, you’re more than capable of pulling up nc or telnet and typing in these commands by hand. This is… so simple it’s ridiculous. No, it’s so simple it’s Beautiful. It’s just barely enough structure to make something much more powerful than you’d expect. Yes, some parts can get complex, the channel modes, IRC operators, channel operators, bots, CTCP, DCC, but, that’s not what I’m focusing on. The actual wire protocol is basically just an identifier of who, and the message.

After reading that part of the specification, it goes into which mode letters are defined, what commands exist, and what numerics exist.

Honestly, after reading that, I was… well, I thought there had to be more. That there’s no way that it’s this simple. I was wrong. IRC is just that simple.

  1. With one exception: Within the spec, it’s mentioned that some channels can be server-local if prefixed with an & instead of a #, the channel does not get sent to other servers, and only clients on the local server can talk. Not all servers implement this though. ↩︎