ircd flood control algorithm

I have written this document in June 2002 after having been asked questions about a piece of knowledge that I acquired a long time ago: flood control in ircds.

A little history and context

From 1996 until 1998, I developed with Etienne Bernard an IRC bot, the bobot.

At the end of 1996, I had the idea of managing the output of the bot with a queue, ordering the commands by priorities (at the time, IRC was a jungle, and keeping the op on a channel was a priority) and making the bot talk at the maximum speed the IRC server would process them.

I asked on the ircd development list if queuing in the server was documented anywhere, and having received a negative answer, I read the code of the ircd for a good while since the information was scattered all over the place to get an algorithm which seemed to work.

Disclaimer

I am documenting some work I did more than 5 years ago. The ircd code might have changed, especially with all the different flavors. However, the algorithm did work at the time, so it probably is a good start for some IRC flood control work. The IRCNet network should have a behavior pretty close to what is described here.

I will use from now on the present tense assuming that things are unchanged (there is no such guarantee), and details are excerpted from the bobot source code.

The algorithm: how flood control works

I have divided this section into two subsections: the general overview and the specifics with some figures.

General idea

The ircd has for each connection a buffer for commands sent by the client and waiting to be processed. In order to make IRC friendlier (avoid channel hijacking, flooding, etc), commands are processed one by one, not too many at a time.

If the buffer is filled, the client will be disconnected for excess flood. The trick is therefore to keep the buffer on the server to the minimum, i.e. have the buffering done on the client side. The question is thus to know what the delays for command processing are.

For each client connection, there is a penalty count. As long as it is positive, commands are processed. When it is negative, commands are kept until it is positive again.

Each second, the penalty count is increased, but cannot go over a maximum.

Details

Thinking about this again, I am not sure about the numbers at all.

Different commands have different cost: WHO is more expensive than a simple PRIVMSG for example. Also, the longer the line sent the higher the penalty.

Here is the get_penalty() function from bobot:

int get_penalty(struct line *l) {
  int answer;

  answer=1+(strlen(l->command)+strlen(l->params)+1)/100;
  if (!strcmp(l->command,"NICK"))
    return(answer+1);
  if (!strcmp(l->command,"JOIN"))
    return(answer+1);
  if (!strcmp(l->command,"PART"))
    return(answer+1);
  if (!strcmp(l->command,"TOPIC"))
    return(answer+2);
  if (!strcmp(l->command,"NOTICE"))
    return(answer);
  if (!strcmp(l->command,"PING"))
    return(answer+1);
  if (!strcmp(l->command,"WHO"))
    return(answer+3);
  if (!strcmp(l->command,"USERHOST"))
    return(answer+1);
  if (!strcmp(l->command,"KICK"))
    return(answer+2);
  if (!strcmp(l->command,"MODE"))
    return(answer+2);
  return(answer);
}

If I remember correctly (I couldn't find that from the code... I guess it would be possible, but ), the maximum for the penalty counter is 10, which is the beginning value, and is increased by 1 every second until it reaches that value.

Every time a line is processed by the server, its penalty is decreased to that counter.

Optimizations: reordering and grouping

Since the queue is managed on the client side, there are some optimizations possible instead of using a FIFO.

For example, some commands might be more important than others: MODE is more important than NICK for a bot keeping the op on a channel. bobot was using the following values for the queue scheduling:

/* Priorities */

#define SERVER_MODE_PRIORITY    0
#define OP_MODE_PRIORITY        1
#define BAN_MODE_PRIORITY       2
#define CHANNEL_MODE_PRIORITY   5
#define KICK_PRIORITY           10
#define PONG_PRIORITY           20
#define TOPIC_PRIORITY          30
#define PART_PRIORITY           40
#define JOIN_PRIORITY           50
#define USERHOST_PRIORITY       60
#define WHO_PRIORITY            70
#define WHOIS_PRIORITY          80
#define NICK_PRIORITY           90
#define PING_PRIORITY           100
#define URGENT_NOTICE_PRIORITY  120
#define MSG_PRIORITY            121
#define DEFAULT_NOTICE_PRIORITY 122
#define QUIT_PRIORITY           0

#define IMPORTANT_PRIORITY      19

Also, it may be cost-effective to group commands. For example, it costs more to send to MODE commands to give operator privileges to two different people rather than sending only one with two arguments. bobot merges MODE and KICK commands.

Comments

Please send comments about this document to hugo@larve.net. I am unlikely to keep this document up-to-date, but I will document errors; I am sure that there are some.


Hugo Haas