Exploring the roots and future of Internet Relay Chat

Regex para operadores IRC: bans, CIDR, hostmasks y anti-spam

Hay dos tipos de operadores IRC: los que saben regex y los que van baneando IPs una por una a las 4 de la mañana mientras un bot flood ataca con direcciones rotantes. Yo fui del segundo tipo durante mis primeros años. No cometas mi error.

Las expresiones regulares son la herramienta más potente que tiene un operador IRC para gestionar abusos a escala. Un solo regex ban puede bloquear un rango de IPs, un patrón de nicks de botnet, o un mensaje de spam que se repite con variaciones. Este artículo es la guía que me hubiera gustado tener en 2002.

¿Por qué regex en IRC?

El sistema de bans tradicional de IRC funciona con wildcards simples: * y ?. Esto cubre los casos básicos:

# Ban por nick pattern (wildcard)
/mode #canal +b troll*!*@*
# Banea: troll1, troll2, troll_xyz

# Ban por host
/mode #canal +b *!*@*.abuse-isp.com

# Ban por IP parcial
/mode #canal +b *!*@192.168.1.*

Pero los wildcards se quedan cortos rápido:

  • No puedes expresar "nicks que contengan 3+ dígitos seguidos"
  • No puedes matchear un rango de IPs que no sea un simple /24
  • No puedes filtrar mensajes que contengan URLs con patrones específicos
  • No puedes distinguir entre variaciones de un patrón de spam

Con regex, puedes. Y los IRCds modernos (UnrealIRCd, InspIRCd, Charybdis) soportan regex nativamente para bans y filtros.

Hostmasks: lo básico antes del regex

Antes de meternos en regex, repasemos las hostmasks porque son la base:

# Formato de una hostmask IRC:
# nick!usuario@host
#
# Ejemplos reales:
# marco!marco@irc6.net
# guest123!~guest@cpe-192-168-1-100.cable.isp.com
# spammer!spam@2001:db8::1

# Wildcards estándar:
# *     = cualquier cadena (incluyendo vacía)
# ?     = un solo carácter

# Ejemplos de bans con wildcards:
/mode #canal +b *!*@*.evil-isp.net         # Todo el ISP
/mode #canal +b *!*@10.0.0.*               # Subred /24
/mode #canal +b guest???!*@*                # guest + 3 chars exactos
/mode #canal +b *!~*@*                      # Usuarios con ~ (sin identd)

Los wildcards cubren quizás el 70% de los casos. El otro 30% necesita regex o CIDR.

Regex bans en la práctica

UnrealIRCd

UnrealIRCd soporta bans extendidos con la notación ~R: para regex sobre la máscara completa del usuario:

# Cargar el módulo regex (en unrealircd.conf)
loadmodule "extbans/regex";

# Sintaxis: /mode #canal +b ~R:patron_regex

# Ban: nicks que empiecen con "flood" seguido de 2-5 dígitos
/mode #canal +b ~R:flood[0-9]{2,5}!.*@.*

# Ban: cualquier usuario cuyo host contenga "tor" o "vpn"
/mode #canal +b ~R:.*!.*@.*(tor|vpn).*

# Ban: nicks con caracteres repetidos (aaaa, xxxxx, etc.)
/mode #canal +b ~R:(.)(\1){3,}.*!.*@.*

# KLINE con regex (nivel servidor, no canal):
/kline ~R:.*!.*@.*\.botnet\.example\.com
# O via la config:
ban nick {
    mask "~R:^[a-z]{3}[0-9]{6}$";
    reason "Patrón de botnet detectado";
}

InspIRCd

InspIRCd usa el módulo regex_pcre o regex_posix:

# inspircd.conf



# RLINE: ban regex a nivel de servidor
# Sintaxis: /rline patron duración :razón

# Ban nicks tipo botnet (3 letras + 5-8 números)
/rline ^[a-z]{3}\d{5,8}$ 7d :Patrón de nick de botnet

# Ban usuarios con realname sospechoso
# InspIRCd matchea contra nick!user@host\sreaname
/rline .*\sfree\s(bitcoin|crypto|money).* 30d :Spam en realname

# Ban temporal (1 hora) por patrón de host
/rline .*@.*\.dynamic\.suspect-isp\.net$ 1h :ISP problemático
Advertencia: Los regex bans se evalúan contra CADA conexión entrante y CADA cambio de nick. Un regex mal escrito (con backtracking excesivo) puede degradar el rendimiento de tu IRCd. Nunca uses .*.*.* ni patrones con cuantificadores anidados como (a+)+. Prueba tus regex en regex101.com antes de aplicarlos en producción.

Notación CIDR para bans por IP

CIDR (Classless Inter-Domain Routing) te permite banear rangos de IPs con precisión. Es más eficiente y preciso que los wildcards para rangos que no caen en límites /8, /16, /24.

# Repaso rápido de CIDR:
# /32 = 1 IP exacta            (255.255.255.255)
# /24 = 256 IPs                (255.255.255.0)   = *.*.*.0-255
# /16 = 65,536 IPs             (255.255.0.0)     = *.*.0-255.0-255
# /8  = 16,777,216 IPs         (255.0.0.0)

# Ejemplos en UnrealIRCd:
/kline *@192.168.1.0/24         # Rango 192.168.1.0 - 192.168.1.255
/kline *@10.0.0.0/16            # Rango 10.0.0.0 - 10.0.255.255
/kline *@203.0.113.64/26        # Rango 203.0.113.64 - 203.0.113.127

# Para IPv6:
/kline *@2001:db8::/32          # Prefijo /32 de IPv6
/kline *@2001:db8:abcd::/48     # Más específico

# Calcular CIDR para un rango específico:
# Quiero banear 172.16.50.0 - 172.16.50.63
# 64 IPs = /26
# → /kline *@172.16.50.0/26

# Quiero banear 10.0.4.0 - 10.0.7.255
# 1024 IPs = /22
# → /kline *@10.0.4.0/22

Un truco que uso frecuentemente: cuando recibo un ataque de una botnet que usa IPs de un mismo ASN, busco los rangos CIDR asignados a ese ASN y hago un kline del rango completo.

# Encontrar los rangos CIDR de un ASN:
# Usando whois:
whois -h whois.radb.net '!gAS15169'   # Google como ejemplo

# O usando bgp.tools:
curl -s https://bgp.tools/table.txt | grep 'AS15169'

# En la práctica, para una IP de atacante:
whois 203.0.113.45
# Busca el campo "route:" o "CIDR:" en la respuesta
# route: 203.0.113.0/24
# → /kline *@203.0.113.0/24

Filtros anti-spam con regex

Los spambots en IRC envían mensajes con variaciones para evadir filtros simples. Regex te permite matchear patrones a pesar de las variaciones.

UnrealIRCd spamfilter

# Sintaxis:
# /spamfilter add [tipo] [acción] [destino] [duración] [razón] [regex]

# Bloquear URLs de spam con variaciones:
/spamfilter add cpn kill - 0 "Spam URL" .*https?://(www\.)?free-(bitcoin|crypto|money)\..*/i

# Explicación:
# c = channel message
# p = private message  
# n = notice
# kill = desconectar al usuario
# El /i al final = case insensitive

# Bloquear invitaciones masivas a canales de spam:
/spamfilter add pi gline - 3600 "Spam invite" .*join\s+#(free|cheap|buy|sell)-.*/i
# pi = private + invite
# gline con duración 3600s (1 hora)

# Bloquear variaciones de "discord.gg" con caracteres unicode:
/spamfilter add cpn block - 0 "Discord spam" .*d[i1!]sc[o0]rd[\.\.](gg|com)\/.*/i

# Bloquear mensajes repetitivos (misma línea 3+ veces):
# Esto requiere el módulo antimixedutf8 o un bot externo
# ya que los spamfilters operan por mensaje individual

InspIRCd con m_filter

# inspircd.conf



# En el archivo de filtros:




# flags: c=channel, p=private, n=notice, N=channel notice
# action: kill, gline, zline, block, warn
Consejo: Mantén un log de tus spamfilters con la fecha en que los creaste y el contexto. Después de un par de meses, tendrás decenas de filtros y no recordarás por qué añadiste cada uno. Los filtros obsoletos que ya no matchean nada son peso muerto que ralentiza la evaluación de mensajes. Haz limpieza trimestral.

Biblioteca de patrones comunes

# === PATRONES DE NICK ===

# Botnet genérica: 2-3 letras + 5-9 dígitos
^[a-zA-Z]{2,3}[0-9]{5,9}$

# Variante: nombre_random + pipe/underscore + dígitos
^[a-z]+[_|][0-9]{3,}$

# Nick con solo caracteres especiales mezclados
^[\[\]\{\}\|\\^`_]{3,}$

# === PATRONES DE HOST ===

# Hosts de tor exit nodes (genérico)
.*\.tor-exit\..*
.*\.onion\..*

# VPN/proxy genéricos
.*(vpn|proxy|hide|anon).*\.(com|net|org)

# === PATRONES DE SPAM ===

# URLs acortadas sospechosas
https?://(bit\.ly|tinyurl|is\.gd|v\.gd|t\.co)/[a-zA-Z0-9]+

# Telegram/Discord invitations masivas
(t\.me|discord\.gg|discord\.com/invite)/[a-zA-Z0-9]+

# Crypto spam con variaciones unicode
(b[i1!]tc[o0][i1!]n|[e3]th[e3]r|cr[y¥]pt[o0])

# Repetición de caracteres (flood visual)
(.)\1{10,}

# === PATRONES DE EVASIÓN ===

# Espacios invisibles (zero-width, etc.)
[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]

# Mezcla de scripts unicode para evadir filtros
# (cirílico mezclado con latino, etc.)
# Esto requiere soporte Unicode en el motor regex del IRCd

Errores que te costarán caro

1. El regex que banea todo

# NUNCA hagas esto:
/spamfilter add cpn kill - 0 "test" .*
# Esto matchea CUALQUIER mensaje. Felicidades, acabas de silenciar tu red entera.

# Tampoco esto:
/mode #canal +b ~R:.*@.*
# Esto banea a todos. Literalmente todos.

2. Olvidar anclar el regex

# Quieres banear el nick "spammer" pero escribes:
/mode #canal +b ~R:spammer!.*@.*
# Esto también banea: nospammer, superspammer, spammer123

# Correcto:
/mode #canal +b ~R:^spammer$!.*@.*
# Los anclas ^ y $ limitan al nick exacto

3. Regex case-sensitive por defecto

# Este filtro no va a catchear "FREE BITCOIN":
/spamfilter add cpn kill - 0 "test" .*free bitcoin.*

# Necesitas el flag case-insensitive:
/spamfilter add cpn kill - 0 "test" .*free bitcoin.*/i
# O usar character classes:
/spamfilter add cpn kill - 0 "test" .*[fF][rR][eE]{2}\s+[bB][iI][tT].*

4. Catastrophic backtracking

# PELIGROSO - puede bloquear tu IRCd:
(a+)+b
(.*)(.*)(.*)
([a-z]+)*@

# Estos patrones causan backtracking exponencial con ciertos inputs.
# Un atacante puede enviar un mensaje diseñado para que tu regex
# consuma toda la CPU del IRCd durante segundos.
# Esto se llama ReDoS (Regular Expression Denial of Service).

# SEGURO - equivalentes sin backtracking:
a+b
.*@
[a-z]+@

Preguntas frecuentes

¿Qué motor de regex usan los IRCds?

Depende del IRCd y la compilación. UnrealIRCd usa PCRE2 (Perl Compatible Regular Expressions) por defecto, que es el motor más potente y con más features. InspIRCd soporta PCRE, POSIX y TRE como módulos intercambiables — puedes elegir cuál cargar. Charybdis usa PCRE. La diferencia práctica: PCRE soporta lookahead, lookbehind y backreferences; POSIX es más limitado. Si no estás seguro, asume PCRE y tu regex funcionará en la mayoría de IRCds modernos.

¿Los regex bans afectan al rendimiento del IRCd?

Sí, pero en la práctica es insignificante si tus regex son razonables. Un IRCd con 50 regex bans bien escritos no va a notar diferencia. El problema viene con regex mal escritos que causan backtracking, o con cientos de spamfilters que se evalúan en cada mensaje. Como regla general: si tienes más de 100 spamfilters activos, revisa si algunos se pueden consolidar en patrones más amplios o si hay filtros obsoletos que eliminar.

¿Puedo usar regex en bans de canal normales?

Solo si tu IRCd lo soporta mediante extended bans. En UnrealIRCd, la notación ~R: activa regex en bans de canal. En InspIRCd, necesitas el módulo regex cargado y funciona a través de RLINE (nivel servidor) más que en bans de canal individuales. En la mayoría de IRCds, los bans de canal estándar (+b) solo aceptan wildcards. Para regex, generalmente necesitas ser IRCop o usar los mecanismos de servidor.

¿Existe alguna herramienta para probar regex IRC antes de aplicarlos?

regex101.com es tu mejor amigo. Selecciona el sabor PCRE2, escribe tu patrón, y pega ejemplos de hostmasks o mensajes en el campo de test. Verás en tiempo real qué matchea y qué no, con explicación paso a paso. Para probar en un entorno IRC real sin afectar producción, monta un IRCd de test local y aplica los filtros ahí primero.