Exploring the roots and future of Internet Relay Chat

Protection anti-flood sur IRC : mécanismes et configuration

La première fois que j'ai subi un flood sur IRC, c'était en 1998 sur un channel d'Undernet. Un type avec une douzaine de clones a bombardé le channel de messages à une vitesse que mon modem 56k ne pouvait pas suivre. Mon client mIRC a gelé, j'ai été déconnecté, et quand je suis revenu trois minutes plus tard, le channel était vide. Bienvenue sur IRC. Depuis, j'ai passé des années à configurer et affiner des protections anti-flood sur différents serveurs. Voici ce que j'ai appris.

Anatomie d'une attaque flood

Le flood IRC prend plusieurs formes, et les confondre mène à des protections inefficaces. Il faut distinguer au moins quatre types :

Le message flood : un utilisateur envoie des centaines de PRIVMSG ou NOTICE en quelques secondes. C'est le plus visible et le plus facile à contrer. Un simple compteur de messages par seconde suffit à le détecter.

Le CTCP flood : des requêtes CTCP VERSION, PING, ou FINGER envoyées en masse. Chaque requête déclenche une réponse automatique du client cible, ce qui peut saturer la connexion de la victime avec ses propres réponses. C'est un flood par amplification.

Le connection flood : des centaines de connexions TCP simultanées depuis la même IP ou le même sous-réseau. L'objectif n'est pas de communiquer mais de saturer les slots de connexion du serveur. Chaque connexion TCP consomme de la mémoire et un descripteur de fichier.

Le join/part flood : un bot rejoint et quitte un channel en boucle, générant des notifications chez tous les membres. Avec 50 clones qui font ça simultanément, le channel devient illisible.

; Exemple de trafic pendant un message flood
; (vue côté serveur, log brut)
:flooder!user@host PRIVMSG #target :AAAAAAAAAAAAAAA
:flooder!user@host PRIVMSG #target :BBBBBBBBBBBBBBB
:flooder!user@host PRIVMSG #target :CCCCCCCCCCCCCCC
:flooder!user@host PRIVMSG #target :DDDDDDDDDDDDDDD
; ... x200 en moins d'une seconde

Chacun de ces types nécessite une réponse différente. Un rate-limiter sur les messages ne protège pas contre un connection flood. Une limitation du nombre de connexions par IP ne stoppe pas un flood distribué depuis un botnet. La protection anti-flood efficace est multicouche.

Protections côté serveur

Les serveurs IRC modernes — UnrealIRCd, InspIRCd, Ergo — intègrent des mécanismes anti-flood configurables. Voici les principaux.

La file d'attente de réception (RecvQ) : chaque connexion client a un buffer de réception limité. Quand un client envoie plus vite que le serveur ne traite, le buffer se remplit. Quand il déborde, le client est déconnecté avec un message "RecvQ exceeded". C'est la protection la plus basique et la plus ancienne.

La file d'attente d'envoi (SendQ) : même principe, mais dans l'autre sens. Si le serveur doit envoyer plus de données au client que celui-ci ne peut recevoir (connexion lente), le SendQ se remplit et le client est déconnecté. Cela protège le serveur contre les "slow clients" qui consomment de la mémoire en accumulant des messages non lus.

# UnrealIRCd — Configuration anti-flood dans unrealircd.conf
set {
    anti-flood {
        connect-flood 3:60;          # Max 3 connexions par 60s par IP
        nick-flood 3:60;             # Max 3 changements de nick par 60s
        away-flood 4:120;            # Max 4 changements d'away par 120s
        join-flood 4:60;             # Max 4 joins par 60s par user
        invite-flood 4:60;
        knock-flood 4:60;
        max-concurrent-conversations 10; # Max 10 conversations privées simultanées
    };
};

# Classes de connexion avec limites SendQ/RecvQ
class clients {
    pingfreq 120;
    maxclients 1000;
    sendq 100000;     # 100 Ko max en file d'envoi
    recvq 8000;       # 8 Ko max en file de réception
};
Conseil : Commencez avec des valeurs conservatrices et relâchez-les si vos utilisateurs se plaignent de faux positifs. Il vaut mieux déconnecter un floodeur trop agressivement que de laisser un channel entier devenir inutilisable. Les utilisateurs légitimes génèrent rarement plus de 5 messages par seconde.

Le système de penalty

Le penalty est un mécanisme élégant utilisé par plusieurs serveurs IRC (notamment ircu, le serveur d'Undernet). Au lieu de compter les messages par seconde de façon rigide, le serveur attribue un "coût" à chaque commande. Plus une commande est coûteuse pour le serveur, plus le penalty est élevé.

; Penalties typiques (en secondes)
PRIVMSG/NOTICE : 2s
JOIN            : 2s
PART            : 0s (on veut que les gens puissent partir)
WHO             : 2-5s (selon la taille du résultat)
WHOIS           : 2s
LIST            : 10s (requête coûteuse)
NICK            : 3s
MODE            : 2s
TOPIC           : 2s
INVITE          : 2s

; Le penalty s'accumule. Si un utilisateur envoie :
; PRIVMSG (2s) + PRIVMSG (2s) + JOIN (2s) + NICK (3s) = 9s de penalty
; Le serveur retardera ses messages de 9 secondes avant de les traiter.

Le mécanisme fonctionne comme un seau qui fuit (leaky bucket). Chaque commande ajoute du penalty. Le penalty diminue de 1 seconde par seconde réelle. Si le penalty accumulé dépasse un seuil (typiquement 10-15 secondes), le serveur peut déconnecter le client avec "Excess flood".

Ce système est auto-régulateur. Un utilisateur normal, qui tape un message toutes les quelques secondes, ne remarque jamais le penalty — il s'écoule entre les messages. Un script qui envoie 50 messages par seconde accumule 100 secondes de penalty et se fait déconnecter presque instantanément.

Throttling des connexions

Le throttling de connexion est la première ligne de défense contre les botnets et les clones. Il limite le nombre de connexions TCP que le serveur accepte depuis une même source dans une fenêtre de temps donnée.

# InspIRCd — Module de connexion throttle
<module name="connflood">
<connflood bootwait="10"
           maxconns="3"
           seconds="30"
           timeout="30"
           quitmsg="Throttled">

# Ergo — Configuration dans le fichier YAML
server:
    ip-limits:
        count: true
        max-per-ip: 5              # Max 5 connexions par IP
        max-per-subnet: 20         # Max 20 par /24
    connection-limits:
        enabled: true
        max-connections-per-window: 12
        window: 1m
    connection-throttling:
        enabled: true
        duration: 1m
        max-connections: 12
        ban-duration: 10m
        ban-message: Trop de connexions. Réessayez dans 10 minutes.

Le throttling par sous-réseau (/24 ou /48 pour IPv6) est particulièrement utile contre les attaques depuis des blocs d'IP adjacentes. Les hébergeurs cloud attribuent souvent des IP dans le même sous-réseau, donc un attaquant qui loue plusieurs VPS chez le même fournisseur sera limité par cette règle.

Attention : Si votre serveur IRC est derrière un bouncer (BNC) ou un proxy web, toutes les connexions client sembleront venir de la même IP (celle du proxy). Configurez le mécanisme PROXY protocol ou WEBIRC pour transmettre l'IP réelle du client au serveur IRC, sinon le throttling par IP bloquera tous vos utilisateurs dès que la limite sera atteinte.

Protections côté client et bot

Côté opérateur de channel, les bots de protection restent un complément utile aux mécanismes serveur. Un bot peut réagir plus intelligemment qu'un compteur brut : analyser le contenu des messages, détecter les patterns de spam, bannir automatiquement les récidivistes.

# Exemple simplifié de bot anti-flood en Python
import time
from collections import defaultdict

class FloodProtector:
    def __init__(self, max_msgs=5, window=10, ban_duration=300):
        self.max_msgs = max_msgs
        self.window = window
        self.ban_duration = ban_duration
        self.msg_log = defaultdict(list)
        self.bans = {}

    def check(self, nick, hostmask):
        now = time.time()

        # Vérifier si déjà banni
        if hostmask in self.bans:
            if now < self.bans[hostmask]:
                return "banned"
            del self.bans[hostmask]

        # Nettoyer les anciens messages
        self.msg_log[hostmask] = [
            t for t in self.msg_log[hostmask]
            if now - t < self.window
        ]

        # Ajouter le message courant
        self.msg_log[hostmask].append(now)

        # Vérifier la limite
        if len(self.msg_log[hostmask]) > self.max_msgs:
            self.bans[hostmask] = now + self.ban_duration
            return "flood_detected"

        return "ok"

Ce type de protection fonctionne bien pour les petits channels. Pour les gros channels (500+ utilisateurs), le bot lui-même peut devenir un goulot d'étranglement s'il doit traiter chaque message. Dans ce cas, les protections côté serveur doivent faire le gros du travail.

Les modes de channel IRC offrent aussi des protections basiques mais efficaces :

/mode #canal +m          ; Channel modéré : seuls les +v peuvent parler
/mode #canal +R          ; Seuls les utilisateurs enregistrés peuvent joindre
/mode #canal +j 5:30     ; Max 5 joins par 30 secondes
/mode #canal +f 10:5     ; Max 10 messages par 5 secondes, sinon kick
/mode #canal +N          ; Pas de changement de nick dans le channel

Configuration pratique

Voici une configuration anti-flood complète pour UnrealIRCd que j'utilise en production. Elle est le résultat de plusieurs années d'ajustements :

# unrealircd.conf — Section anti-flood complète
set {
    anti-flood {
        # Flood de connexion
        connect-flood 3:60;

        # Flood de commandes par type
        nick-flood 3:60;
        join-flood 4:60;
        away-flood 4:120;
        invite-flood 4:60;
        knock-flood 4:60;
        target-flood {
            channel-privmsg 8:5;    # 8 msg par 5s sur un channel
            channel-notice 4:5;
            channel-tagmsg 4:5;
            private-privmsg 6:5;    # 6 msg privés par 5s
            private-notice 6:5;
            private-tagmsg 4:5;
        };

        # Conversations privées simultanées
        max-concurrent-conversations {
            users 10;
            new-user-every 15;      # 1 nouveau destinataire toutes les 15s
        };
    };

    # Limites de connexion par IP
    max-unknown-connections-per-ip 3;
    handshake-timeout 30;
    handshake-delay 0;
};

# Classe de connexion utilisateurs standard
class clients {
    pingfreq 120;
    maxclients 5000;
    sendq 100000;
    recvq 8000;
    connfreq 15;                   # 1 connexion toutes les 15s
};

# Classe pour les utilisateurs de confiance (plus de marge)
class trusted {
    pingfreq 120;
    maxclients 100;
    sendq 200000;
    recvq 16000;
};

Ces valeurs sont des points de départ. Chaque réseau a ses propres patterns d'utilisation. Un channel de gaming avec des messages courts et rapides nécessite des seuils plus élevés qu'un channel de support technique où les messages sont longs et espacés. Mesurez avant de configurer.

Questions fréquentes

Pourquoi mon client affiche "Excess Flood" alors que je ne floode pas ?

Ce message signifie que vous avez dépassé le seuil de penalty du serveur. Cela arrive souvent quand un script envoie plusieurs commandes rapidement (auto-join de nombreux channels, WHO automatique, etc.) ou quand vous collez un texte long qui est découpé en plusieurs messages. Réduisez le nombre de commandes automatiques ou ajoutez des délais entre elles.

Les protections anti-flood protègent-elles contre les DDoS ?

Les protections anti-flood IRC opèrent au niveau applicatif (couche 7). Elles ne protègent pas contre un DDoS volumétrique qui sature la bande passante du serveur avant même que les paquets n'atteignent le processus IRC. Pour cela, vous avez besoin d'une protection réseau (firewall, service anti-DDoS, filtrage chez l'hébergeur).

Comment tester mes protections anti-flood sans perturber les utilisateurs ?

Montez un serveur IRC de test isolé avec la même configuration que votre serveur de production. Utilisez un script qui simule différents types de flood (message, connexion, join/part) et vérifiez que les seuils se déclenchent correctement. Ne testez jamais sur un serveur en production — vos utilisateurs ne vous le pardonneront pas.