Exploring the roots and future of Internet Relay Chat

InspIRCd Module System: Extending Your IRC Server

The first time I looked at InspIRCd's source code, I was struck by how little the core actually does. Channel modes? Modules. User modes? Modules. WHOIS output? Module. Even basic IRC commands like PRIVMSG are technically modules — though they're always loaded by default. This radical modularity is InspIRCd's defining characteristic, and understanding it is key to running the server effectively.

Architecture: Everything Is a Module

InspIRCd (currently at version 4.x) is built around a minimal core that handles TCP connections, the module loader, and basic data structures for users, channels, and servers. Almost all IRC functionality is implemented in dynamically loadable modules (shared libraries — .so files on Linux).

This approach has several advantages:

  • Customization: You can load exactly the features you need and nothing more. Running a simple chat server? Don't load the XLINE module. Need custom authentication? Write a module for your auth backend.
  • Isolation: A buggy module can be unloaded without restarting the server. In production, this is invaluable — you can diagnose and remove a problematic module without disconnecting users.
  • Experimentation: You can develop and test new features as modules without touching the core code. Load, test, unload. No recompilation of the entire server needed.
  • Security: Features you don't load can't have vulnerabilities. The attack surface is exactly what you choose it to be.

The downside is complexity. UnrealIRCd's monolithic approach — everything in one binary with a single config file — is simpler to understand and configure. InspIRCd requires understanding which modules provide which features, and a misconfigured module list can result in a server that connects but doesn't do what you expect.

Built-in Module Categories

InspIRCd ships with over 100 modules, organized into several categories:

Channel modes: m_banexception, m_inviteexception, m_redirect, m_stripcolor, m_topiclock, m_delayjoin, and many more. Each module adds one or more channel modes that operators can set.

User modes: m_callerid (server-side ignore), m_deaf (ignore channel messages), m_hidechans (hide channel list from WHOIS). These let users control their own IRC experience.

Commands: m_knock (request invite to a +i channel), m_namesx (extended NAMES reply), m_watch (server-side friend list). Commands that extend the basic IRC command set.

Authentication: m_password_hash, m_ldap, m_sql_auth, m_httpd_acl. Backends for user authentication against various data sources.

Connection control: m_connectban, m_dnsbl, m_connflood, m_cgiirc. Modules that control who can connect and how.

Anti-abuse: m_anticaps, m_blockhighlight, m_muteban, m_repeat. Tools for channel operators to manage disruptive behavior.

Loading and Configuring Modules

Modules are loaded in InspIRCd's configuration file (inspircd.conf):

<module name="banexception">
<module name="cloaking">
<module name="conn_umodes">
<module name="dnsbl">
<module name="password_hash">
<module name="sha256">

Module configuration is done through XML-style blocks in the same config file:

<cloaking mode="full"
         key="change-this-to-a-random-string"
         prefix="user/">

<dnsbl name="DroneBL"
       type="record"
       domain="dnsbl.dronebl.org"
       records="3,5,6,7,8,9,10,11,13,14,15"
       action="ZLINE"
       duration="7d"
       reason="Your IP is listed in DroneBL. Visit https://dronebl.org/lookup for more info.">

<connectban threshold="3"
             duration="10m"
             banduration="6h"
             ipv4cidr="32"
             ipv6cidr="128">

You can load and unload modules at runtime using IRC operator commands:

/LOADMODULE m_stripcolor
/UNLOADMODULE m_stripcolor
/RELOADMODULE m_stripcolor

This is one of InspIRCd's strongest operational features. If a module is causing problems, you can unload it immediately without any downtime. On a busy server, this can be the difference between a quick fix and a disruptive restart.

Essential Modules for Production

For a production server, here's what I'd consider the minimum module set:

<!-- Security -->
<module name="cloaking">        <!-- Hide user IPs -->
<module name="password_hash">   <!-- Hashed oper passwords -->
<module name="sha256">          <!-- SHA-256 hash provider -->
<module name="sslinfo">         <!-- TLS connection info -->

<!-- Anti-abuse -->
<module name="dnsbl">           <!-- DNS blacklist checking -->
<module name="connectban">      <!-- Rate limit connections -->
<module name="connflood">       <!-- Flood protection -->
<module name="banexception">    <!-- +e ban exceptions -->
<module name="inviteexception"> <!-- +I invite exceptions -->

<!-- Channel management -->
<module name="chanprotect">     <!-- Channel founder mode -->
<module name="delayjoin">       <!-- Hide joins until speech -->
<module name="redirect">        <!-- Redirect from full channels -->
<module name="topiclock">       <!-- Only ops change topic -->

<!-- User experience -->
<module name="callerid">        <!-- Server-side ignore -->
<module name="chghost">         <!-- Change displayed hostname -->
<module name="setname">         <!-- Change display name -->

Writing a Custom Module

InspIRCd modules are written in C++. A minimal module looks like this:

#include "inspircd.h"

class ModuleHello : public Module
{
public:
    ModuleHello()
    {
    }

    void init() override
    {
        ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT,
            "Hello module loaded!");
    }

    Version GetVersion() override
    {
        return Version("Says hello when loaded", VF_NONE);
    }
};

MODULE_INIT(ModuleHello)

Compile it against the InspIRCd headers:

cd /path/to/inspircd/src/modules/
cp hello.cpp .
cd ../..
make install

A more practical example — a module that logs all channel messages to a file:

#include "inspircd.h"

class ModuleChanLog : public Module
{
    std::ofstream logfile;

public:
    ModuleChanLog()
    {
        logfile.open("/var/log/ircd/channels.log",
            std::ios::app);
    }

    ~ModuleChanLog()
    {
        logfile.close();
    }

    ModResult OnUserPreMessage(User* user,
        MessageTarget& target,
        MessageDetails& details) override
    {
        if (target.type == MessageTarget::TYPE_CHANNEL)
        {
            Channel* chan = target.Get<Channel>();
            logfile << time(nullptr) << " "
                    << chan->name << " <"
                    << user->nick << "> "
                    << details.text << std::endl;
        }
        return MOD_RES_PASSTHRU;
    }

    Version GetVersion() override
    {
        return Version("Logs channel messages", VF_NONE);
    }
};

MODULE_INIT(ModuleChanLog)

The Hook System

InspIRCd's module API provides hooks for virtually every server event. The most commonly used hooks include:

  • OnUserConnect — Fired when a user completes registration
  • OnUserPreMessage — Before a message is sent (can block it)
  • OnUserPostMessage — After a message is sent
  • OnUserJoin — When a user joins a channel
  • OnUserPart — When a user leaves a channel
  • OnUserQuit — When a user disconnects
  • OnPreCommand — Before any IRC command is processed
  • OnMode — When channel or user modes change
  • OnCheckBan — When checking if a user matches a ban

Modules return MOD_RES_PASSTHRU to allow the event to continue, MOD_RES_ALLOW to explicitly allow it (overriding other checks), or MOD_RES_DENY to block it. This allows multiple modules to cooperate on the same event — one module might check a ban list, another might check a whitelist, and a third might log the result.

Debugging Modules

When a module doesn't behave as expected:

  • Check the log: InspIRCd's log file (usually data/ircd.log) shows module load/unload messages and any errors.
  • Use REHASH: Many configuration issues become visible after a /REHASH command, which reloads the config without restarting.
  • Enable debug logging: Set <log method="file" type="*" level="debug"> temporarily to get detailed output.
  • Test in isolation: If you suspect a module conflict, unload all non-essential modules and test with only the one you're debugging.
  • Use GDB: For C++ modules that crash, attaching GDB to the running process and getting a backtrace is often the fastest diagnostic method.

InspIRCd's modular architecture makes it one of the most flexible IRC servers available. The learning curve is steeper than UnrealIRCd's all-in-one approach, but for operators who want precise control over their server's behavior, the investment pays off. Every feature is a conscious choice, not a default you have to live with.

Frequently Asked Questions

Can I use InspIRCd modules with UnrealIRCd?

No. The module APIs are completely different. Modules must be written specifically for one server or the other. However, many features are available in both — they just have different module names and configuration syntax.

How many modules can InspIRCd load simultaneously?

There's no hard limit. In practice, production servers commonly run 50-80 modules without performance issues. The overhead of each module depends on what it does — a simple mode module has negligible impact, while a complex authentication module that queries external databases will have measurable latency.

Is InspIRCd harder to configure than UnrealIRCd?

Somewhat, yes. InspIRCd's configuration is spread across more conceptual layers — you need to understand which modules provide which features and configure each one. UnrealIRCd's single config file with built-in features is more straightforward for simple deployments. For complex deployments, InspIRCd's modularity can actually simplify configuration by allowing you to focus only on the features you're using.

What language are InspIRCd modules written in?

C++. InspIRCd 4.x uses C++17 features. There's no scripting interface like Eggdrop's Tcl or UnrealIRCd's (experimental) Lua support. This means module development requires C++ knowledge and compilation, but the resulting modules are fast and have full access to the server's internals.

FAQ

What makes InspIRCd different from UnrealIRCd?

InspIRCd has a fully modular architecture where almost every feature (including core protocol elements) is implemented as a loadable module. This gives operators fine-grained control over which features are available.

Can InspIRCd link with other IRCd types?

InspIRCd uses its own server-to-server protocol (spanning tree). It cannot directly link with UnrealIRCd or other IRCd types, but services packages like Anope work with both.

Is InspIRCd actively maintained?

Yes. InspIRCd v4 is the current major version, actively developed on GitHub. The project has a smaller community than UnrealIRCd but is well-regarded for its clean codebase.