Exploring the roots and future of Internet Relay Chat

Regex pour opérateurs IRC : bans, CIDR, hostmasks et anti-spam

J'ai appris les expressions régulières en bannissant des spammeurs sur EFnet en 2001. Rien de tel qu'une vague de spam à 3h du matin pour vous motiver à comprendre la différence entre .* et .+. Vingt-deux ans plus tard, les regex restent l'arme principale des opérateurs IRC contre le spam, les floods et les comportements abusifs. Voici un guide pratique, orienté IRC.

Pourquoi les regex sont indispensables sur IRC

IRC utilise des patterns de matching à deux niveaux. Le premier niveau, historique, est le glob matching des hostmasks : *!*@*.example.com. C'est simple, mais limité — vous ne pouvez pas matcher un motif dans un message, ni faire des conditions complexes sur les hostnames.

Le deuxième niveau, ce sont les expressions régulières (regex). Les IRCd modernes les utilisent pour :

Usages des regex sur IRC :
- Spamfilter : bloquer des messages par contenu
- Extended bans : bannir par regex sur nick/ident/host/realname
- KLINE/GLINE : bannir par pattern sur les connexions
- Filtres de nick : interdire certains pseudonymes
- Filtres de canal : interdire certains noms de canaux

Si vous opérez un serveur ou un réseau IRC sans maîtriser les regex, vous travaillez avec un bras attaché dans le dos.

Hostmasks : anatomie et patterns

Avant d'attaquer les regex, révisons les hostmasks. Un hostmask IRC a le format :

nick!ident@host

Exemples :
Marco!marco@unaffiliated/marco
Spammer42!~spam@203.0.113.42
Bot|service!bot@services.example.net

Structure :
├── nick    : le pseudonyme (peut changer)
├── ident   : le username (~prefixe si non vérifié)
└── host    : hostname ou IP (cloaké ou réel)

Les bans IRC classiques utilisent le glob matching (wildcards) :

# Bannir une IP spécifique
/mode #canal +b *!*@203.0.113.42

# Bannir un sous-réseau (glob)
/mode #canal +b *!*@203.0.113.*

# Bannir par ident
/mode #canal +b *!~spam@*

# Bannir par hostname partiel
/mode #canal +b *!*@*.tor-exit-node.example.net

# Bannir un nick pattern
/mode #canal +b Spammer*!*@*

Le glob matching est rapide et suffisant pour 80% des cas. Ses limites : pas de groupes, pas d'alternatives (ceci|cela), pas de quantificateurs précis. C'est là que les regex prennent le relais.

Bans CIDR : bloquer des plages IP

CIDR (Classless Inter-Domain Routing) est la notation standard pour désigner des plages d'adresses IP. Sur IRC, les bans CIDR sont plus précis que les wildcards :

# Wildcard : bannit 203.0.113.0 à 203.0.113.255
/mode #canal +b *!*@203.0.113.*

# CIDR équivalent : /24 = les 256 adresses
/mode #canal +b *!*@203.0.113.0/24

# CIDR plus fin : /28 = 16 adresses (203.0.113.0 à .15)
/mode #canal +b *!*@203.0.113.0/28

# CIDR /32 = une seule IP
/mode #canal +b *!*@203.0.113.42/32

Rappel des masques CIDR courants :

/32  = 1 adresse       (un seul utilisateur)
/28  = 16 adresses     (petit bloc)
/24  = 256 adresses    (sous-réseau classique)
/16  = 65 536 adresses (réseau de FAI)
/8   = 16 777 216      (à éviter — trop large)

IPv6 :
/128 = 1 adresse
/64  = sous-réseau standard (attribution typique par FAI)
/48  = site allocation
Attention : Un ban /16 bloque 65 536 adresses IP. Sur un FAI résidentiel, cela peut toucher des milliers d'utilisateurs innocents. Utilisez le masque le plus étroit possible. En cas de doute, commencez par /24 et élargissez uniquement si le spammeur utilise des IP dispersées dans le bloc.

Les klines/glines côté serveur utilisent aussi le CIDR :

# UnrealIRCd — kline sur un /24
/kline +d 203.0.113.0/24 :Spam (plage bloquée)

# InspIRCd
/gline *@203.0.113.0/24 3600 :Spam réseau
#                         ^durée en secondes

Spamfilter : regex appliquées au contenu

Le spamfilter d'UnrealIRCd est l'outil anti-spam le plus puissant disponible sur un IRCd. Il applique des regex PCRE (Perl Compatible Regular Expressions) aux messages, notices, parts, quits, et même aux away messages.

# Syntaxe UnrealIRCd
/spamfilter add [cible] [action] [durée] [raison] [regex]

# Cibles :
# p = message privé
# c = message canal
# n = notice
# q = quit message
# d = DCC
# u = part message
# t = topic
# a = away message

# Actions :
# warn    = log seulement
# block   = bloquer le message
# kill    = déconnecter l'utilisateur
# gline   = bannir du réseau
# shun    = silence (l'utilisateur peut lire mais pas écrire)

Exemple concret — bloquer les liens de phishing :

# Bloquer les liens steam/discord phishing
/spamfilter add cp block 0 "Phishing link detected" (?i)https?://(steam|disc[o0]rd|nitro)[-.]?(?!steampowered\.com|discord\.com)[a-z0-9]+\.[a-z]{2,}

# Décortiquons cette regex :
# (?i)                    → insensible à la casse
# https?://               → http ou https
# (steam|disc[o0]rd|nitro) → mots-clés de phishing
# [-.]?                   → séparateur optionnel
# (?!steampowered\.com|discord\.com)  → exclure les vrais domaines
# [a-z0-9]+\.[a-z]{2,}   → domaine quelconque

Pour InspIRCd, le filtrage regex passe par les modules m_filter et m_regex_stdlib :

# inspircd.conf



# filter.conf


# flags: p=privmsg, n=notice, c=channel, etc.

Exemples de filtres anti-spam courants

Voici une collection de filtres que j'utilise en production. Chaque regex a été testée et affinée au fil des mois :

# 1. Spam crypto / bitcoin scam
(?i)(free|earn|claim)\s+(btc|bitcoin|ethereum|crypto).*https?://

# 2. Mass-highlight (mention de 5+ nicks en un message)
# Pas faisable en regex pure — utiliser un module IRCd dédié
# UnrealIRCd : set::anti-flood::max-targets-per-command

# 3. Texte répétitif (aaaaaaa, hahahahaha)
(.)\1{15,}
# Match : un caractère répété 16+ fois

# 4. Majuscules excessives (80%+ du message en caps)
# Difficile en regex — utiliser un bot avec logique programmatique

# 5. Liens raccourcis suspects
(?i)https?://(bit\.ly|tinyurl\.com|t\.co|goo\.gl|is\.gd)/[a-zA-Z0-9]+

# 6. Spam d'invitation de canal
(?i)/?(join|invite)\s+#[a-z0-9_-]+\s+(free|girls|money|hack)

# 7. Numéros de téléphone (format international)
\+?[0-9]{1,3}[-. ]?\(?[0-9]{1,4}\)?[-. ]?[0-9]{3,4}[-. ]?[0-9]{3,4}

# 8. Flood de caractères Unicode exotiques (souvent du spam)
[\x{0600}-\x{06FF}]{20,}|[\x{0900}-\x{097F}]{20,}
# 20+ caractères arabes ou devanagari d'affilée
Conseil : Commencez toujours par l'action warn (log sans bloquer) pendant quelques jours. Analysez les faux positifs dans les logs. Passez en block ou kill seulement quand vous êtes sûr que la regex ne touche pas les messages légitimes.

Un filtre qui bloque des messages légitimes est pire que pas de filtre du tout. Vos utilisateurs perdront confiance et partiront. J'ai appris cette leçon en 2006 quand un filtre trop agressif bloquait toute phrase contenant le mot "free" — y compris "free software".

Optimisation et pièges des regex sur IRC

Catastrophic backtracking. Le danger numéro un avec les regex en production. Une regex mal écrite peut consommer 100% du CPU du serveur sur un seul message.

# DANGEREUX — backtracking exponentiel
(a+)+b
# Sur l'entrée "aaaaaaaaaaaaaaac", cette regex explose

# CORRIGÉ
a+b
# Même résultat, pas de backtracking

Règles pour éviter le backtracking catastrophique :

1. Évitez les quantificateurs imbriqués : (a+)+ , (a*)*
2. Utilisez les quantificateurs possessifs quand disponibles : a++ au lieu de a+
3. Utilisez les atomic groups : (?>a+) au lieu de (a+)
4. Testez avec des entrées adversariales avant mise en production
5. Configurez un timeout sur le moteur regex (si supporté)

Performance sur un réseau chargé. Chaque message qui transite par le serveur est testé contre chaque spamfilter actif. Avec 50 filtres et 1000 messages/seconde, cela fait 50 000 évaluations regex par seconde. Les regex complexes avec des lookahead/lookbehind sont plus coûteuses.

# Lent — lookahead complexe
(?=.*free)(?=.*nitro)(?=.*https?://).*

# Rapide — séquence simple
(?i)free\s+.*nitro\s+.*https?://
# ou mieux, si l'ordre est connu :
(?i)free\s+nitro\s+https?://

Encodage. Les messages IRC sont encodés en UTF-8 (en théorie — en pratique, c'est le Far West). Une regex qui matche des caractères ASCII peut rater des variantes Unicode. Le spam moderne utilise des homoglyphes Unicode pour contourner les filtres :

# Le spam écrit "frее" avec des "e" cyrilliques (U+0435)
# au lieu des "e" latins (U+0065)
# Votre filtre sur "free" ne matchera pas

# Solution : normaliser le texte avant filtrage (côté bot)
# ou matcher les deux variantes :
(?i)fr[eе][eе]

Outils pour tester vos regex

Ne testez jamais une regex directement en production. Utilisez ces outils :

# regex101.com — testeur en ligne avec explication pas à pas
# Sélectionnez le moteur PCRE2 (celui qu'utilisent les IRCd)

# En ligne de commande avec grep
echo "free nitro https://fakesite.com" | grep -P '(?i)free\s+nitro\s+https?://'

# Python pour des tests en lot
import re

pattern = re.compile(r'(?i)free\s+nitro\s+https?://')

test_messages = [
    "Free nitro https://fakesite.com",     # doit matcher
    "Feel free to try nitro",               # ne doit PAS matcher
    "FREE NITRO https://scam.xyz",          # doit matcher
    "The software is free under MIT",       # ne doit PAS matcher
]

for msg in test_messages:
    result = "MATCH" if pattern.search(msg) else "NO MATCH"
    print(f"{result}: {msg}")

Après les tests unitaires, déployez en mode warn pendant au moins 48 heures. Analysez les logs pour détecter les faux positifs. Puis passez en block.

Questions fréquentes

Quel moteur regex utilisent les IRCd ?

UnrealIRCd utilise PCRE2. InspIRCd supporte plusieurs moteurs via des modules : regex_stdlib (C++ std::regex), regex_pcre (PCRE), regex_posix (POSIX ERE). Charybdis/Solanum utilisent PCRE. Vérifiez la documentation de votre IRCd pour connaître la syntaxe supportée.

Un filtre regex peut-il ralentir mon serveur IRC ?

Oui, si la regex est mal écrite (backtracking catastrophique) ou si vous avez trop de filtres complexes. En pratique, 20-30 filtres bien écrits n'ont aucun impact mesurable sur un serveur moderne. Au-delà de 100 filtres, commencez à surveiller le CPU. UnrealIRCd affiche des warnings si un spamfilter prend trop de temps.

Comment bannir les connexions Tor sur mon réseau ?

Plutôt que de maintenir une liste d'IP Tor (qui change constamment), utilisez un DNSBL spécialisé. UnrealIRCd supporte les blacklists DNS nativement : configurez dronebl.org ou efnetrbl.org dans votre bloc blacklist {}. Ces listes incluent les nœuds de sortie Tor et sont mises à jour automatiquement.