How I built a self-organizing distributed network of IRC-bots for a good cause.
The bot called
Why did you create this IRC-bot?
For a couple of years I was given the task to handle the #dreamhack IRC-channel on quakenet. Between events it was quite a quiet place but during the early 2000s it became the largest channel on Quakenet for the days during the event.
The number of users in the channel naturally attracted people who wanted to spam their cs-servers, dc++ hubs or just be of nuisance so there was a small team of ops that monitored the channel and kick-banned the offenders.
Even if we had multiple ops online every hour of the day the size and amount of traffic in the channel was a problem. There is a limited amount of bans that a channel can have before the ban-list is full. One solution was to have a script in the irc-client of the op that kept an internal ban-list, so when someone was to be banned for 30 minutes the user was first banned in the channel, kicked and then shortly thereafter unbanned again. But if the user would rejoin before the ban-time was out, the script in the irc-client would kick+ban+unban again, until the time for the ban had lapsed.
This also came with some problems, what happens if the op goes offline, then all the state kept in their client is unavailable. So the solution was to create a IRC-bot that would work just like the script in each operators irc-client, but central. But to no one’s surprise this also had some problems.
The flood problem
As a standard user on Quakenet you could send about two commands per second before you were throttled by the server. This wasn’t as big of a problem when the commands that kicked+banned+unbanned was distributed among a handful of operators, but when it was a single bot we would hit the flood-wall instantly.
The naive solution is to add another bot and let half the ops use that one, and half the ops the other one. But not a fun or challenging solution. What I wanted was a bot that you could just drop on a host and it would join the channel, get opped and communicate with its peers without any hands on.
The bot that is called
Landlady was the last iteration of these ideas and it worked quite well.
The setup was that besides the main channel that was to be moderated there was two more channels (three if we count the debug channel). The first for bot-bot communication, and the seconds one for operator-bot communication.
The bot-bot channel, lets call it #botbot was only for the bots and was used for the bots to organize themselves. The steps was as follows
- When a bot joins #botbot it sends a message to the channel to announce that it wants to be part of the mesh. Appended to this message is a random number between 1 and <a lot>
- The bots already in the channel sees the message from the new bot they respond with a response message, also with a random number. All the messages are in plain view of every bot.
- Every bot creates a list of the bots in the channel, including themself, and their random number and sort the list. The bots own placement in the list is saved and used to figure out which commands should be acted on for each bot.
- When a command is issued in the operator-bot channel the target is hashed and the first byte of the hash is used to select which bit should issue the commands.
- This sequence was also triggered automatically when a bot in the bot-list left the channel.
Lets take an example: We have four bots in the channel Gandalf, Saruman, Radagast and Alatar. Each have sent a random number to the channel and ordered themselves in a list in the above order. 0 – Gandalf, 1 – Saruman, 2 – Radagast and 3 – Alatar. This means that Gandalf (0) takes care of all commands against targets whose first byte is in the range 0-63. Saruman handles 64-127, and so on.
The idea behind this is to let the bots autonomously divide the work evenly between themselves.
This channel was the interface between the operators and the bots, the reason for it to be a channel was two-fold. It is an easy way for the operators to send a message to all bots with one message, and also it allowed the other operators to see what already have been done.
It was a simple setup, just send “kb #channel [email protected]” to the #opbot channel and the bots would each hash the target and decide if it was their responsibility to take action.
Each bot saved the ban-mask for each kick-banned user, even if it didn’t match their hash. This was so that every time the same user was kick-banned the time they were banned increased logarithmically. So after a couple of bans you were out for the rest of the week.
Each bot also kept track of the unbans from the other bots and if an unban didn’t happen all the other bots had a timer to unban that was delayed a bit.
Unfortunately did the bots only get a few uses, the development didn’t go very fast and mostly occurred during the events which meant that when it was stable enough the use of IRC as main communication method had passed. Even for a nerdy community as Dreamhack. But it was a fun exercise in design and implementation.