You are here: Home > Modules > Umod4

How to install UnrealIRCd 4 Modules

How to install 3rd party modules?

In UnrealIRCd 4 you should place the .c file in your src/modules/third/ directory of the UnrealIRCd source directory.

cp somemodule.c /home/irc/unrealircd-4.0.0/src/modules/third

Then from your UnrealIRCd source directory you just run make and make install:

cd /home/irc/unrealircd-4.x
make install

UnrealIRCd will automatically detect any .c files in the src/modules/third directory and compile them.

You should no longer use make custommodule, use the method described above instead!

The method from above ensures that when you reconfigure or recompile UnrealIRCd the third party modules will be recompiled as well. Also when you upgrade to a new version, UnrealIRCd 4 will automatically copy the 3rd party modules from your previous UnrealIRCd installation (based on your input of the 1st ./Config question)

All modules should be loaded on all servers, unless otherwise specified

Click HERE to go to the modules download page

Module Description

All modules should be loaded on all servers, unless explicitly specified otherwise

The shown config block snippets are just examples of the structure, it's up to you to integrate it properly with your existing config

Module compilation

Since Windows users can (and pr0lly should) use the above .zip archives created through AppVeyor, these instructions apply to *nix users only. I'm assuming you know at least a little bit about the OS you're using.

I personally clone this git repo and symlink modules into the Unreal 3rd party directory, meaning I can simply pull the changes and re-run make. So:

cd /home/unreal
mkdir build # Or whatever folder you want
cd build
git clone
cd ../unrealircd-4.0.18/src/modules/third # This is your Unreal source directory
ln -s /home/unreal/build/unrealircd_mods/u4/m_autovhost.c m_autovhost.c
ln -s /home/unreal/build/unrealircd_mods/u4/m_rmtkl.c m_rmtkl.c
# More links here: ln -s <target> <link name>
cd ../../../ # Back to the source tree's root
make && make install # Or the custom make command needed for like m_confprot

After that just add the relevant loadmodule "third/m_modname"; line(s) to unrealircd.conf. =] When I've updated one or more module(s), you can simply do:

cd /home/unreal/build/unrealircd_mods
git pull
cd /home/unreal/unrealircd-4.0.18
make && make install

Repo structure

  • skrip: Some miscellaneous scripts that might be of use (see readme in the dir for deetz) ;]
  • u4: Modules for Unreal 4.x obviously
  • uncommon: Quite specialised/complex modules, doubt you'll care about them ;3
  • templates: Muh templ8s for Unreal m0ds m8, everything is explained inside the .c files there
  • spec: Specifically written for someone by request, as such it's tailored to them/their network and is probably not very useful to you (see readme in the dir for deetz)
  • malv: Specifically written for Malvager; move along, nothing to see here =]
  • br0ken: Modules I started working on but which don't quite work (see the readme in the dir for details)

This README contains all modules and their descriptions/usage info (ordered from new to old). Modules that have PORTED behind their name tell you that I've ported them. If it says UNC (uncommon) or has no tag at all, that means I wrote it from scratch fam. There will be others but they should be self-explanatory. =]

Module Description
m_needauthjoin (UNC) Require authentication with services before users are able to join channels (with exceptions, chmode +A)
m_pubnetinfo (UNC) Display public network/server information such as SSL/TLS links
m_noghosts Keep channels clear of "ghosts" of opers
m_rehashgem (UNC) Implements an additional rehash flag -gem (global except me)
m_block_masshighlight Prevent mass highlights network-wide
m_timedbans Adds extban ~t for auto-expiring bans
m_rtkl Allows privileged opers to remove remote servers' local K/Z:Lines
m_autojoin_byport Auto-join channels on connect based on connection port
m_blocknossl (UNC) Allows privileged opers to temporarily block new, non-SSL user connections
m_nick_minlen Impose a minimum nick length
m_debug (UNC) Allows privileged opers to easily view internal (configuration) data
m_extwarn Enables additional configuration error checking
m_allowctcp_opers Allows opers to override someone's umode +T (noctcp)
m_plainusers Allows opers to list all users NOT connected over SSL/TLS
m_uniquemsg Implements chmode +U to prevent people from repeating messages
m_pmlist Implements umode +P to only allow only certain people to privately message you
m_sacmds Implements SA* commands for privileged opers as well as an accompanying snomask +A
m_storetkl Store TKL entries persistently across IRCd restarts
m_auditorium Channel mode +u to show channel events/messages to/from people with +o/+a/+q only
m_uline_nickhost Requires people to address services like [email protected]
m_websocket_restrict Impose restrictions on websocket connections
m_listrestrict Impose certain restrictions on /LIST usage
m_pmdelay Disallow new clients trying to send private messages until exceeding a certain timeout
m_noinvite Adds umode +N to block invites
m_textshun (UNC) Drop messages based on nick and body
m_tklexcept Implements an E:Line to set TKL exceptions at runtime
m_kickjoindelay Chanmode +j to prevent people from rejoining too fast after a kick
m_commandsno (PORTED) Adds snomask +C: lets IRC operators see command usages
m_clones (PORTED) Adds a command /CLONES to list all users having the same IP address matching the given options
m_operpasswd (PORTED) Snomask for failed OPER attempts with the ability to kill
m_netadmins (PORTED) Implements KILL and X:Line protection for privileged opers
m_securequery (PORTED) Adds umode +Z to prevent SSL users and non-SSL ones privately messaging each other
m_chansno (PORTED) Allows you to assign channels for specific server notifications (sort of like snomasks)
m_fantasy Implements custom fantasy channel !cmds
m_denyban Deny specific ban masks network-wide
m_portsifresi (PORTED) Protect specific ports with a password
m_anticaps Block/lowercase messages that contain a configurable amount of capital letters
m_joinmute (PORTED) Adds +J chmode: Mute newly joined people for +J X seconds
m_anti_amsg Drop messages originating from /amsg
m_autovhost Apply vhosts at connect time based on users' raw nick formats or IPs
m_message_commonchans Adds umode +c to prevent people who aren't in a common channel with you from messaging you
m_bancheck_access (UNC) Prevents people who have +o or higher from getting banned, unless done by people with +a/+q or opers
m_fixhop (UNC) The +h access mode seems to be a little borked/limited, this module implements some tweaks for it
floodprot (UNC, MOD) Channel Mode +f
m_repeatprot (UNC) G(Z):Line/kill users (or block their messages) who spam through CTCP, INVITE, OPER, NOTICE and/or PRIVMSG
m_md5fjert (UNC, LEAF-ONLY) Custom FJERT command lol, required in conjunction with m_confprot
m_confprot (UNC, HUB-ONLY) Verifies leaf configs by checking their remotely included confs etc
m_getlegitusers (PORTED) Command /getlegitusers to show user/bot count across the network
m_clearlist Adds /CLEARLIST <channel> <types> <mask> command to clear out banlists etc
m_banfix_voice +v overrides +b and +b ~q: for some reason, this module aims to correct that
m_rmtkl (PORTED) Adds /rmtkl command to easily remove *:Lines in bulk
m_git Install/Update third-party mods easily on (possibly) all servers through git
m_forward (PORTED) Robust channel forwarding system

m_report (MALV)

Adds a /report command which does nothing at all. [=[==[==[=[

m_needauthjoin (UNC)

Requested by Paul DK, prevent unidentified/unregistered users from creating new channels or joining existing ones. You can exempt them from this restriction on a per-channel basis by using the new channel mode +A (we runnin' out of chmodes lol). It doesn't take arguments as that would needlessly complicate things, so think of +A as an inverse of +R. ;] As always, opers/U:Lines/servers are not restricted. =]

Users trying to join will get the dankass numeric reply 477: You need a registered nick to join that channel

m_pubnetinfo (UNC)

Another request/proposal by PeGaSuS, this module displays information for every server that is allowed to be publicly available. Right now it'll simply show if a server is linked over localhost and if it's using SSL/TLS to communicate with the other end. Simply execute /pubnetinfo and check the server notices sent to you. ;]

Example output: [pubnetinfo] Link localhost connection = no -- SSL = yes [pubnetinfo] Link localhost connection = no -- SSL = yes [pubnetinfo] Link localhost connection = yes -- SSL = no

So in this case I ran the command on someleaf, which only has information about the hub it's linked to. For the other servers this leaf asks its hub for the information instead (otherwise we can't tell if it's using SSL or nah). The hub has info on 2 additional servers; another leaf and the services node.

You can get similar information by using /stats C, but: 1) it only outputs shit for directly attached servers 2) it requires you to remove C from set::oper-only-stats for making it publicly usable 3) it displays the server connection port too. ;]


Originally proposed by PeGaSuS, this module makes IRC opers part +O channels once they oper down. I've kept the "ghosts" thing for lack of a better term, deal w/ it. =]

Config block:

noghosts {
    message "g h o s t b u s t e r s";
    flags "O";
    channels {
        "#opers"; // Don't forget the "" to make sure Unreal doesn't interpret it as a comment ;]

All configurables are optional; the default message is simply Opered down and if no channels are specified it'll check all +O ones the opered-down oper is in. I may extend flags to contain more flags at some point, which would also affect the message (prolly). =]

m_rehashgem (UNC)

Implements an additional rehashing flag -gem (global except me). Since m_confprot requires you to set allowunknown to 1 when making config changes, it would cause a triple rehash on the hub which is really not necessary. =] I doubt anyone is actively using m_confprot so this mod is really just for me. =]

Soooooo, when you do /rehash -gem, all other servers will rehash everything (appends -all flag by default). You can also rehash just MOTDs, SSL-related stuff, etc by appending their respective flags to -gem:

  • /rehash -gemssl
  • /rehash -gemmotd
  • Any other "sub" flag Unreal already supports (/helpop rehash should show these)

If you're running a mixed U3/U4 network this prolly won't work out of the box. In that case you'll have to change the source; find the line saying #define BACK_COMPAT 0 and change it to 1 instead, then recompile. ;]

m_mshun (MALV)

Enables privileged 0pers to add shuns that only affect PRIVMSG, NOTICE, KNOCK and INVITE (M:Lines lmao), except when sending to U:Lines (NiqqServ etc). Only opers with the new operpriv mshun will be able to use it, although all others will get the notices since these M:Lines are netwerk wide bruh. Servers, U:Lines and opers are exempt for obvious raisins.

Expiring shuns is done with an EVENT thingy in Unreal, which is set to run every 10 seconds. This means if you set a shun for 5 seconds (why would you anyways?) it may not expire after eggzacktly 5 seconds. ;] When no expiration is specified the value in set::default-bantime is used. Every server checks the expirations themselves. =] Also, they store it in a ModData struct so it persists through a rehash without the need for a .db fiel. ;] Furthermore, they sync their known M:Lines upon server linkage. =]] Other lines such as G:Lines, Z:Lines are also stored in memory and get resynced during a link so these are pretty similar aye.

Config block:

operclass netadmin-mshun {
    parent netadmin;
    privileges {

MSHUN [-]<ident@host> [expire] <reason>

Also supports the alias MLINE. The first argument may also be an online nickname, this will be resolved to their full mask. =] Wildcards * and ? are also supp0rted.


  • MSHUN guest*@* 0 nope => All...
  • MLINE guest*@* 0 nope => ...of...
  • MLINE -guest*@* => ...these add/delete the same M:Line, with no expiration
  • MSHUN guest*@* 3600 ain't gonna happen => Add an M:Line that expires in an hour =]
  • MSHUN guest*@* 1h ain't gonna happen => Ditto ;];]
  • MSHUN => Show all M:Lines
  • MLINE halp => Show built-in halp

The hostmask is matched against user@realhost only. The timestring shit like 1h supports up to weeks (so you can't do 1y).


This shit can halp you prevent highlight spam on your entire network. =] It keeps track of a user's messages on a per-channel basis and checks if they highlight one person too many times or too many different persons at once. Opers and U:Lines are exempt (as per usual), but also those with list modes +a and +q. ;3 When someone hits the threshold, opers with the snomask EYES will get a server notice through the module (enable that shit with /mode <nick> +s +e etc ;]).

Updated shit:

  • Don't count duplicate nicks on the same line as separate highlights
  • Added chanmode +H to exempt a channel from all mass highlight checks, which mite b useful for quiz channels
  • Added conf directives (and message handling for) allow_accessmode, percent, show_opers_origmsg
  • Added conf directive allow_authed (see bel0w bruh)
  • Added action viruschan
  • Added conf directive multiline imo tbh fambi (see below for m0ar inf0)

Config block:
The module doesn't necessarily require any configuration, it uses the following block as defaults

block_masshighlight {
    maxnicks 5;
    delimiters "     ,.-_/\:;";
    action gline;
    duration 7d;
    reason "No mass highlighting allowed";
    snotice 1;
    banident 1;
    multiline 0;
    allow_authed 0;
    //allow_accessmode o; // k4be
    percent 1; // k4be
    show_opers_origmsg 1; // k4be
  • maxnicks: Maximum amount of highlighted nicks (going over this number results in action setting in) -- works in conjunction with percent
  • delimiters: List of characters to split a sentence by (don't forget the surrounding quotes lol) -- any char not in the default list may prevent highlights anyways
  • action: Action to take, must be one of: drop (drop silently [for the offender]), notice (drop, but do show notice to them), gline, zline, shun, tempshun, kill, viruschan
  • duration: How long to gline, zline or shun for, is a "timestring" like 7d, 1h5m20s, etc
  • reason: Reason to show to the user, must be at least 4 chars long
  • snotice: Whether to send snomask notices when users cross the highlight threshold, must be 0 or 1
  • banident: When set to 1 it will ban ident@iphost, otherwise *@iphost (useful for shared ZNCs etc)
  • multiline: When set to 1 it will keep counting highlights until it encounters a line without one
  • allow_authed: When set to 1 it will let logged-in users bypass this shit
  • allow_accessmode: Must be one of vhoaq (or omitted entirely for no exceptions [the default]), exempts everyone with at minimum the specified mode from highlight checks (e.g. a includes people with +q)
  • percent: Threshold for the amount of characters belonging to highlights, not counting delimiters (e.g. hi nick would be 67%) -- works in conjunction with maxnicks
  • show_opers_origmsg: Display the message that was dropped to opers with the SNO_EYES snomask set

If you omit a directive which is required for a certain action, you'll get a warning and it will proceed to use the default. It should be pretty clear what directives are required in what cases imo tbh famalam. ;];]


A much requested feature. =] Allows you to give channel bans (+b etc) an expiration time, using qt3.14 extbans. ;] Since it's integr8ed w/ channel mode +b, you need halfops or higher to be able to use this shit. The resolution for the expiration time is 1 minute; less than that seems useless to me anyways. Also, the module doesn't check for expirations every second (does every 15 though). It unsets as many bans per "line" as possible (either 8 masks or a total char length of >= 200).

I tested this across 30 channels with 48 bans for each, it walks through them in less than a second. ;];];]

Protip: This module (or a variation of it) will be included in Unreal 4.0.17 onwards so you're better off using that to track updates more easily.

Simply do /mode #chan +b ~t:<EXPIRATION>:<BANMASK>

The banmask is your regular wildcard-enabled nick!user@host mask. Expiration is a "timestring" (see bel0w). Also, if you add a banmask which Unreal already knows it will emit an error. I'm not replacing bans simply because a person (and not some code ;]) should decide which expiration time should be active.


  • /mode #ham +b ~t:60:Guest*!*@*
  • /mode #ham +b ~t:1h5m:Guest*!*@*
  • /mode #ham +b ~t:3d4h1m:Guest*!*@*

Bans the same people, but with different expirations.


Allows privileged opers to remove remote servers' local K/Z:Lines. The required privileges are tkl:kline and tkl:zline, which the "netadmin" operclass should carry by default. The syntax is mostly the same as for regular K/Z:Lines, with the addition of one in the very front to indicate the target server. After some checks it will simply pass on a KLINE or ZLINE command to that server, so any further error handling is done by that module. ;]

RKLINE <server> <[-]identmask@hostmask> {duration} {reason} => Add/Delete a local K:Line on server for the specified usermask (duration and reason are ignored for deletions)
RZLINE <server> <[-]identmask@ipmask> {duration} {reason} => Add/Delete a local Z:Line on server for the specified usermask (duration and reason are ignored for deletions)


  • RKLINE myleaf.dom.tld * 0 lolnope => Adds a permanent K:Line on myleaf.dom.tld for everyone connecting from
  • RKLINE myleaf.dom.tld -* 0 lolnope => Deletes this same K:Line
  • RZLINE myleaf.dom.tld *@123.123.123.* 60 lolnope => Adds a one-minute Z:Line on myleaf.dom.tld for everyone connecting from 123.123.123.*

Since the snomask notices on the target server are only sent to local opers, I had to hack some hook bs to get the executing oper to see that shit. =]

Protip: I didn't include a method for listing the remote server's X:Lines, you can already use /stats K myleaf.dom.tld for that fam. ;]


Similar to set::auto-join, this forces users to join one/multiple channels on connect, based on the p0rt they're using.

Config block:

autojoin_byport {
    6667 "#plain";
    6697 "#ssl,#ssl2";

Should be pretty clear how that works. ;] Currently it doesn't check for duplicates or max channels, so bnice. It does check for valid channel names/lengths and port ranges. =]

m_blocknossl (UNC)

Allows privileged opers to temporarily block new, non-SSL (actually TLS but w/e) user connections network-wide. ;3 There's a new operpriv, which if set, allows an oper of that class to both block and unblock non-SSL connections. Keep in mind that rehashing the IRCd also reset the blocking flag for that server. ;] Opers with snomask SNO_KILLS (/umode +s +k etc) will see notices about disallowed connections.

Updated shit:

  • Also notice opers of blocked connections =]

Config block:

operclass netadmin-blocknossl {
    parent netadmin;
    privileges {


Both commands do not take any arguments and are broadcasted to other servers. =]


Imposes a minimum require length for nicknames. Opers are exempt as they can do SANICK or possibly /os SVSNICK anyways. ;]

Updated shit:

  • Also checks the nick on connect now xd

Simply load the module and throw a directive in the set { } block.

Config block:

set {
    // Rest of your set block goes here
    nick-min-length 5;

That means only nicks of 5 chars and longer are allowed (obviously). ;]

m_otkl (MALV)

Allows privileged opers to set one-time G/GZ:Lines. Local Z:Lines are not supported because they seem fairly useless imo tbh famlamlm. =] The rules for hostmasks etc are the same as for regular G/GZ:Lines. These "OTKLines" persist through a rehash, plus servers will sync everything they know at link-time too. ;]

If any online users match a newly added OTKLine, they will be killed first (with the well-known G:Line message about being permanently b&). Then once they reconnect, they'll get killed one more time before the OTKLine is removed from all servers. ez pz.

Updated shit:

  • Updates an OTKLine if a match for the mask is already found (instead of doing fuck all yo)
  • Uses a default reason no reason if none specified =]
  • Now also works on users who changed their ident thru HostServ or /chgident by een oper ;];]

Simply OGLINE or OZLINE => List current OG/OZ:Lines (they're 2 different lists yo)
OGLINE halp and OZLINE halp => View built-in halp ;3
OGLINE <[-]identmask@hostmask> {reason} => Set/remove an OG:Line (reason is required for adding, ignored when deleting)
OZLINE <[-]identmask@ipmask> {reason} => Set/remove an OZ:Line (ditto for reason)


  • OGLINE *@some.domain.* not gonna happen => Sets a host-based ban
  • OZLINE *@123.123.* nope => Sets an IP-based ban
  • OZLINE -*@123.123.* nope => Removes an IP-based ban

m_debug (UNC)

Allows privileged opers to easily view internal (configuration) data. I know you can do some of it with a /STATS command, but this shit displays different info than that. ;]

Currently it allows opers with the operpriv m_debug to view configured oper and operclass information. By default it asks the server to which you're connected, but since it may differ across servers (local O:Lines etc), you can also ask another server directly. =]

Config block:

operclass netadmin-debug {
    parent netadmin;
    privileges {

DBG <datatype> [server]
I went with DBG and not DEBUG cuz a bunch of clients probably nick the /debug command, get at me. ;];]


  • DBG opers => Get a list of known opers from the server you're on
  • DBG operclasses ayy.check.em => Asks the leaf ayy.check.em about the operclasses it knows


Enables additional error checking of the IRCd configuration. I originally wrote it to (temporarily?) work around a bug (although it may be by design) where you don't get a warning about using non-existent operclasses during rehash/init. So it currently only checks for that, but I may extend it to include other things later. =]

The module only throws warnings, so it allows the rehash etc to continue normally. This way it won't break any functionality. ;];]


Allows opers to override someone's umode +T (noctcp), which basically means opers can do CTCPs regardless of the usermode.

Updated shit:

  • Oper to oper is always allowed
  • If oper had +T also, they wouldn't see the reply in some cases


A simple module to list all users not connected over SSL/TLS. Just run /PUSERS or /PLAINUSERS to get a nice lil' list. ;] It attempts to cram as many nicks on one line as it can, to avoid spamming the fuck out of you. Only opers can use it obviously. =]


A request by PeGaSuS to implement a channel mode +U to prevent people from repeating messages. Like if you said ayy checkem and I try it too, it won't be allowed. There has to be another unique message first. =] Requires +a or +q to set (or opers with OperOverride obv). Anyone with +o or up will be excluded from the check (opers are not exempt).


Sort of a hybrid between umode +D (don't allow private messages at all) and +R (allow registered users only), this module allows you to keep a whitelist of people allowed to send you private messages. =] Their UID is stored so it persists through nickchanges too, but the module only shows you the original whitelisted nick in lists etc.

Updated shit:

  • PMHELP command to always show the halp shit =]
  • OPENPM nao accepts -persist to make the module not purge the entry when it becomes stale (instead, check if they're regged and authed on next reconnect)
  • Opers no longer need to be whitelisted (similar to U:Lines etc)

Load the module and set umode +P on yourself (anyone can (un)set the umode). You can't set up a list without it but if you do have one and then unset the umode, it will be kept. Only when you disconnect will it be cleared (so it even persists through rehashes). Also, if you have +P and message someone else, they will automatically be added to the list. If UIDs go stale (relevant user disconnects) the entry will also be removed if it's not persistent. See below (Syntax) for how2manage da whitelist. ;3

There are also a few configuration directives for netadmins to tweak that shit.

Config block:

pmlist {
    noticetarget 0; // Default is 0
    noticedelay 60; // Seconds only
  • noticetarget => Whether to notice the target instead, if the source is a regged and logged in user
  • noticedelay => How many seconds have to pass before a user will receive another notice

OPENPM <nick> [-persist] => Allow messages from the given user (the argument must be an actual, existing nick)
CLOSEPM <nickmask> => Clear matching entries from your list; supports wildcard matches too (* and ?)
PMLIST => Display your current whitelist
PMHELP => Display built-in halp info

OPENPM guest8 => Allow guest8 to message you
OPENPM muhb0i -persist => Allow muhb0i, persistently
CLOSEPM guest* => Remove all entries matching this mask (guest8, guestxxxx, etc)
CLOSEPM * => Remove all entries (saves you a disconnect lol)

Now this is what happens when a non-whitelisted user tries to message you:

  • For users who haven't logged into services or if noticetarget is set to 0, they will get a notice saying you don't accept private messages from them. It also instructs them to tell you to do /openpm for them, like in a common channel.
  • For users who have logged into services and if noticetarget is set to 1 you will get a single notice asking you to do /openpm (the notice also includes their message).
  • These notices only happen once in a certain time period (based on the config directive noticedelay). After the first one, everything else will be silently discarded until enough time passes.


This module used to be called m_sanick, so remove that one entirely and replace it with this to avoid conflicts

I've gotten multiple requests to have a module to implement SA* commands (like SANICK, SAUMODE) within the IRCd instead of through services (usually /os SVSNICK etc). Right now it allows privileged opers to forcibly change someone's nickname and/or their usermodes. =] You cannot use any of these commands on U:Lined users, raisins should b fairly obvious.

This m0d also implements a snomask +A to indicate who can see the related server notices. I had to pick A (ykno, like Admin?) cuz all of cCnNsS are already taken, so rip. There are also operprivs for every "subcommand" to indicate who can use which. You also gotta have one of the operprivs to set the snomask. ;] The target user won't get a visual cue at all for umode changes, unlike when using services. This means no notice, no <nick> sets mode <modestr> in their console, etc.

Config blocks:
First, make sure an operclass has one or more of the operprivs:

operclass netadmin-sacmds {
    parent netadmin;
    privileges {

And assign it to one or more oper(s). Then (optionally), to easily and automatically enable the snomask for them, append the A flag to your current set::snomask-on-oper:

set {
    // Rest of your set block goes here
    snomask-on-oper "cfkevGqsSoA";

This won't set the snomask for opers w/o the privilege, as the IRCd executes the on-oper thingy on behalf/in name of the oper. As such, operprivs are verified beforehand. ;]

SANICK <fromnick> <tonick>
SAUMODE <nick> <umodes>

SANICK ayy bastem => Changes the nick ayy to bastem
SAUMODE bastem -x+Z => Removes bastem's virtual host and enables the m_securequery restriction


Even though servers sync all X:Lines (G:Line, Z:Line, GZ:Line, Shun (S:Line), spamfilter (F:Line), ...) upon linkage, some people may want to keep them stored in a .db file local to every server. An example use case would be storing Q:Lines in case services are down and the IRCd was rebooted/had crashed/whatever; people could use nicks like NickServ until services are back to re-add their own Q:Lines.

This module re-adds all X:Lines at IRCd boot only, inside MOD_INIT (so before it has fully booted), as long as they shouldn't expire at the time of booting. It also skips spamfilters added through config files entirely, as there's really no need to keep track of those. ;] The DB file is refreshed everytime someone adds/removes an X:Line (this includes using RMTKL if you have version >= 1.22 of that), when they expire and if they should expire when "cold" booting the IRCd.

Module output can be seen through the Unreal user's shell session as the IRCd boots (it's logged to LOG_ERROR which only becomes the actual ircd.log file once Unreal has forked off):

$ /home/unreal/ircd/unrealircd start
Starting UnrealIRCd
Loading IRCd configuration..
[storetkl] Reading stored X:Lines from '/home/unreal/ircd/data/tkl.db'
[storetkl] Not re-adding G:Line 'ham@*' [AYYYY LMAO] because it should be expired
[storetkl] Not re-adding G:Line 'hueaj@*' [AYYYY LMAO] because it should be expired
[storetkl] Not re-adding G:Line 'hue@*' [AYYYY LMAO] because it should be expired
[storetkl] Re-added 15 X:Lines
[storetkl] Rewriting DB file due to 3 skipped/expired X:Lines
Configuration loaded without any problems.
UnrealIRCd started.


The good ol' channel mode +u from Unreal 3.x. =] Since a bunch of stuff for this mode was hardcoded in U3's core sauce, I've made a few adjustments to maximise its usability. I've never used +u myself back then, so I'm not 100% sure if the features match (it was basically guesswork based on the dirty U3 sauce).

Once the channel mode is set, the following restrictions apply:

Everyone with +o/+a/+q:

  • Can see the full user list and all channel events (joins, quits, etc)
  • Will see messages from anyone, even those without a list access mode

People without +o/+a/+q:

  • Can only see users with any of those 3 modes
  • Will also only see messages from such users

IRCOpers only:

  • If they have the proper override (which afaik is override:see:who:onchannel) they can also see everyone, but not their messages if they don't have the proper list modes

The channel mode can only be set by people with +a or +q (and opers with OperOverride obv). When the mode is unset or someone gets chanops, they won't immediately see the other users "joining". Instead, people have to do /names #chan (this is how it worked in U3 too). OR if you have +D active as well, that module will take care of the rest. ;]


You're probably familiar with the idea of having to do /msg [email protected] as opposed to just /msg NickServ. This can be helpful to counter bots that try to auto-reg their nicks to join channels with +R set. ;]

Simply load the module and everyone will have to address all U:Lines with the above format. So if your services link's name is you'll have to use /msg [email protected]. This goes for both PRIVMSG and NOTICE (also includes CTCP as that's just PRIVMSG wrapped in special characters).


Some people may wanna impose some restrictions on websocket-connected users, one of deez nuts things could be limiting the ports they can use. Read more about Unreal's websocket support right here.

Since websocket support for non-SSL ports works right out of the box, you're going to need a new listen block for non-SSL connections from websocket users. I used port 8080 for the keks but you can really use as many as you want.

Updated shit:

  • Added channels block to restrict websocket users to certain channels too =]

Config block:

listen {
    ip *;
    port 8080;
    options {
websocket_restrict {
    port 8080;
    //port 8443; // If you have an SSL listen block too
    zlinetime 60;
    channels {
        "#chan1"; // Don't forget the "" to make sure Unreal doesn't interpret it as a comment ;]

Now, if any websocket users connect to a port that isn't 8080 their IP will get GZ:Lined for the amount of seconds specified with zlinetime (defaults to 60). The other way around is true as well; regular clients connecting to a websocket port will be awarded the same GZ:Line. I originally had to do that for websocket users cuz they aren't fully online yet, so the special frames wouldn't be formed and sent. This resulted in the client sending the GET / command about 5 times and that resulted in 5 snotices too. =] I did the same for regular clients to remain consistent.

The channels list is optional; if omitted there will be no channel restrictions, otherwise they can only join the specified ones. They also only apply to websocket users, so regular clients can join their channels too.

I may (will probs) add more possibilities for restrictions at some point. =]


This module used to be called m_listdelay, so remove that one entirely and replace it with this to avoid conflicts

Allows you to impose certain restrictions on /LIST usage, such as requiring clients to have been online for a certain period of time. Simply load the module and add a new block to your unrealircd.conf, for which see bel0w. Opers, servers and U:Lines are exempt for obvious reasons. ;]

Updated shit:

  • Added gline-on-join-fakechan functionality
  • Merged k4be's contributions regarding em fake channel listing
  • Default to no restrictions if no config block specified
  • Added exceptions block
  • Added the ability to require auth w/ services (in addition to the delay)
  • Moved config directives from the set block to its own listrestrict bl0cc
  • Renamed module since it has more functionalities nao

Config block:

listrestrict {
    connectdelay 60; // How long a client must have been online for
    needauth 1; // Besides connectdelay, also require authentication w/ services
    authisenough 1; // Don't check connectdelay if user is identified OR exempt from authentication entirely
    fakechans 1; // Send a fake channel list if connectdelay and/or needauth checks fail
    glinetime 7d; // For channels with gline set to 1, use 0 for permanent bans

    fakechannel {
        // Only the name is required
        name "#honeypot";
        //topic "ayy lmao"; // Defaults to "DO NOT JOIN"
        //users 50; // Defaults to 2 users, must be >= 1
        //gline 0; // Defaults to 0

    fakechannel {
        name "#fakelol";
        topic "top kek";
        users 10;
        gline 1; // G:Line won't kick in if connectdelay and needauth checks are satisfied, or if the user has a 'fakechans' exception

    exceptions {
        all "user@*";
        connect "[email protected]"; // Only require auth
        auth "*@123.123.123.*"; // Only require connectdelay
        fakechans "ayy@lmao"; // Don't send a fake channel list, just prevent sending of the legit one

        // You can also specify multiple types for the same mask:
        auth "need@moar";
        fakechans "need@moar";
        // This user would only need to wait <connectdelay> seconds and won't get a fake channel list at all

Omitting a directive entirely will make it default to off. If connectdelay is specified, the minimum required value is 10 as anything below seems pretty damn useless to me. =] The exceptions block should be pretty self explanatory. ;]

As usual with my mods, U:Lines, opers and servers are exempt from any restrictions.


Disallow phr3$ly connected clients trying to send private messages until exceeding a certain timeout, like butts connecting and immediately spamming actual users in private. Simply load the module and (optionally) add one directive to your unrealircd.conf, for which see bel0w. Messages from opers, servers and U:Lines are exempt for obvious reasons, also sending to U:Lines (m-muh /ns identify). ;]

Config block:

set {
    // Rest of the set block goes here obv, like kline-address, network-name, etc
    pmdelay 60;

Above example sets the delay to 60 seconds. The minimum required is 10 as anything below seems useless while having this module loaded. =]


Adds a new umode +N (as in Noinvite ;]) to prevent all invites. The only ones that can still invite you are 0pers obv. Simply l0ad the module and do like /umode +N for profits.

m_textshun (UNC)

Enables privileged 0pers to drop messages based on nick and body regexes (T:Lines), similar to badwords and spamfilter but more specific. It only supports (PCRE) regexes because regular wildcards seem ineffective to me, fucken deal w/ it. ;] Also, you can't have spaces (due to how IRC works) so you'll have to use \s and shit. Unreal creates a case-insensitive match so no worries there, it also tells you if you fucked up your regex (and what obv). Only opers with the new operpriv textshun will be able to use it, although all others will get the notices since these T:Lines are netwerk wide bruh. You'll also get a server notice for when a T:Line is matched. Servers, U:Lines and opers are exempt for obvious raisins.

Expiring shuns is done with an EVENT thingy in Unreal, which is set to run every 10 seconds. This means if you set a shun for 5 seconds (why would you anyways?) it may not expire after eggzacktly 5 seconds. ;] When no expiration is specified the value in set::default-bantime is used. Every server checks the expirations themselves. =] Also, they store it in a ModData struct so it persists through a rehash without the need for a .db fiel. ;] Furthermore, they sync their known T:Lines upon server linkage. =]] Other lines such as G:Lines, Z:Lines are also stored in memory and get resynced during a link so these are pretty similar aye.

Updated shit::

  • Default shun time is now based on set::default-bantime instead of being permanent xd
  • Expire shuns w/ EVENT handler
  • Show pretty setat timestamps during server sync phase as well as in /tline list
  • Send to snomask SNO_TKL instead of realops etc
  • Now supports timestrings like 1h instead of having to pass seconds =]

Config block:

operclass netadmin-textshun {
    parent netadmin;
    privileges {

TEXTSHUN <ADD/DEL> <nickrgx> <bodyrgx> [expire] <reason>

Also supports the aliases TS and TLINE. =]


  • TLINE add guest.+ h[o0]+m[o0]+ 0 nope => All...
  • TEXTSHUN add guest.+ h[o0]+m[o0]+ nope => ...of...
  • TS del guest.+ .+ => ...these add/delete the same T:Line, with no expiration
  • TLINE add guest.+ h[o0]+m[o0]+ 3600 ain't gonna happen => Add a T:Line that expires in an hour =]
  • TLINE add guest.+ h[o0]+m[o0]+ 1h ain't gonna happen => Ditto ;];]
  • TLINE => Show all T:Lines
  • TS halp => Show built-in halp

The nick regex is matched against both nick!user@realhost and nick!user@vhost masks. The timestring shit like 1h supports up to weeks (so you can't do 1y).


Allows privileged opers to set TKL exceptions at runtime (like except tkl). Since it's similar to that shit you should always pass it an ident@host mask. The host bit is the real hostname, or an IP in case of just a GZ:Line exception. These E:Lines persist through a rehash/restart as well cuz they're saved in data/tklexcept.db. Allow certain operclasses to use it by simply adding a top-level privilege eline.

Config block:

operclass netadmin-eline {
    parent netadmin;
    privileges {

ELINE <typeflags> <[-]mask>

The - is obviously there so you can remove them too. ;] You can also use just /eline to view the built-in halp and /stats E to view all exceptions (this was already there).

Typeflags list (they're the same as except tkl):

  • G => G:Line
  • Z => Global Z:Line
  • Q => Global Q:Line
  • s => Shun
  • q => Local Q:Line


  • ELINE GZQsq *@*.lan => Set an exception on all types for everyone on a LAN domain.
  • ELINE GZ *@*.lan => Set an exception on G(Z):Lines for everyone on a LAN domain.
  • ELINE * *@*.lan => Set an exception on all types for everyone on a LAN domain.
  • ELINE * -*@*.lan => Remove an exception for all types. The mask should be an exact match (i.e. it doesn't do a wildcard match).


Adds a chanmode +j <delay> to prevent people from rejoining too fast after a kick. You can set a delay of between 1 and 20 seconds, as anything higher might be a bit much lol. You gotta have at least +o to set this shit. Opers and U:Lines are exempt, as well as servers (cuz just in case lol).

Updated shit:

  • Store the ModData struct with the client instead of channel to preserve memory (muh lifetimes lol)

m_commandsno (PORTED)

Guess who originally wrote this one?
Adds a snomask +C for opers so they can see what commands people use. ;3 Specify what commands may be monitored in the config, then set the snomask with /mode <nick> +s +C (or extend set::snomask-on-oper).

Config block:
I've kept the "location" the same as the original one but I did rename the directive. It's simply a comma-delimited list of commands. ;]

set {
    // Rest of the set block goes here obv, like kline-address, network-name, etc
    commandsno "version,admin,module";

m_clones (PORTED)

Yay for AngryWolf. =]
Adds a command /CLONES to list all users having the same IP address matching the given options. Clones are listed by a nickname or by a minimal number of concurrent sessions connecting from the local or the given server.

I made one change, which is instead of having /helpop clones (which requires you to add a block to all servers' help.conf files) you can now view a built-in halp thingay. =]

CLONES <min-num-of-sessions|nickname> [server]

Some examples:

  • CLONES 2 => Lists local clones having 2 or more sessions
  • CLONES Loser => Lists local clones of Loser
  • CLONES 3 => Lists all clones with at least 3 sessions, which are connecting from
  • CLONES => View built-in halp

m_operpasswd (PORTED)

Another port of one of AngryWolf's modules. =]
This basically lets you see the username and password for a failed OPER attempt, you gotta set an extra snomask flag to see them though. You can do this wit /mode <nick> +s +O or just use it in set::snomask-on-oper.

I made some changes to this module as it relied on "netadmins" which Unreal 4.x doesn't have n0 m0ar. So I came up with a new operclass privilege to indicate who is able to set the snomask. You also had to explicitly enable the snomask in the 3.x version, but it's now enabled by default. ;]

Config blocks:

operclass netadmin-operpasswd {
    parent netadmin;
    privileges {

operpasswd {
    enable-global-notices 1;
    enable-logging 0;
    max-failed-operups 3;
    failop-kill-reason "Too many failed OPER attempts lol";

Since snomask notices are only sent to a server's local opers, you gotta use enable-global-notices to broadcast that shit to errone. Also, you have to specify something for max-failed-operups in order to get the kill to work, since the module sorta assumes 0 which means "disable that shit fam". The kill reason defaults to "Too many failed OPER attempts".

m_netadmins (PORTED)

My port of AngryWolf's module for Unreal 3.x.
Even though Unreal 4.x doesn't have a rank system, I've kept the name and will use part of the original terminology here.

This module prevents "netadmins" from getting killed/X:Lined by "lower" opers and optionally by everyone but servers and U:Lines. Since ranks are no more, I went with a few operclass flags to indicate "netadmins" and their protection level. ;3 Also, TEMPSHUN wasn't overridden before but it is nao. =]

Config block:

operclass netadmin-protected {
    parent netadmin;
    privileges {
        m_netadmins { partial; };

The innermost bit can be either partial or full. The first one means only other "netadmins" can fuck with you, the latter excludes those too. So people with full will still be able to kill the ones with partial. Anyone with either of those flags will count as a "netadmin".

m_securequery (PORTED)

Originally written by Stealth, this is quite a simple module. It adds a umode +Z so people who aren't connected wit SSL can't message you, und ditto for the other way around. Simply set it on yourself or enforce it through the config, whatever fl0ats ur b0at fam.

Protip: This module (or a variation of it) will be included in Unreal 4.0.12 onwards so you're better off using that to track updates more easily.

m_chansno (PORTED)

My port of AngryWolf's module for Unreal 3.x.
Allows you to assign different channels for different types of server notifications. It works like the snomask system, but instead of receiving notifications in your private server console thingy, you will get the messages in channels. ;] Simply load the module and get to unrealircd.conf, see below for halp.

Updated shit:

  • Added spamfilter-hits "snomask"

Config block:

chansno {
    msgtype privmsg;

    channel "#huehue" {
        server-connects; squits; oper-ups;

    channel "#kek" {
        mode-changes; topics; joins; parts; kicks;

The first directive, msgtype, can either be privmsg or notice. The first one dumps a plain message as if it were ein user, the second is a channel notice.

And here's a list of types you can use fam:

  • mode-changes => Mode changes inside channels
  • topics => Topic changes lol
  • joins => Join messages obv
  • parts => Part messages 0bv
  • kicks => Kick messages OBV
  • nickchanges => Nickname changes m8
  • connects => Local client connections
  • disconnects => Local client disconnections
  • server-connects => Local server connections
  • squits => Local server disconnections
  • unknown-users => Disconnections of unknown (local) clients
  • channel-creations => Channel creations (previously non-existent channels)
  • channel-destructions => Channel destructions (the last user parted from a channel), notify local users only (to prevent duplicates)
  • oper-ups => Successful oper-ups, displays opernick and opercla$$
  • spamfilter-hits => Notify whenever someone matches a spamfilter
  • tkl-add => Notify whenever a TKL is added (G:Line, K:Line, Z:Line, etc)

You may have noticed the term local a lot above. This means the underlying hook only triggers for clients connected directly to that particular server. So people on server A doing a chanmode change won't cause server B to pick up on it. In this case A will simply broadcast it so everyone gets notified. =] The exception on this are channel destructions; every server will see the event so they will only broadcast it to their local users. I added dis because fuck dupes. ;3


Fantasy commands may sound familiar if you're using Anope IRC services or have fucked with InspIRCd at some point. They're basically aliases for certain commands and are visible to other users, since they're generally called like !cmd dicks. Unreal provides aliases too but afaik that only works for /cmd dicks, which isn't visible to others. You can also change the command prefix to like ?cmd or \cmd or whatever you want (one character max), just not /cmd. ;] It also supports a few special inline variables, more on that bel0w.

Furthermore, these aliases are limited to channel messages. There's not much you can do in private messages anyways, besides maybe ACTION shit.

Keep in mind messages similar to !!cmd (like, more than one leading cmdchar) are ignored, as well as messages starting with any other character

Updated shit:

  • Removed $chan requirement kek
  • Allow multiple modeflags in the conf again, instead of trying to dynamically append shit
  • Special vars now go from 1 through 9 ;]
  • Special vars $1i and $2i
  • Added m0ar special vars $1h and $2h, see bel0 for an explanation fam

Special variables:
I'll put these before the config block so you'll have that info before you get to it. ;] You can use all the special variants for $1 through $9.

  • $chan => Will obv be replaced with the channel you dumped the command in
  • $1 => Will be replaced with the user's first argument
  • $1- => Becomes the first argument plus everything after it (greedy)
  • $1i => If the first arg is a nick, replace it with their ident/username
  • $1h => If the first arg is a nick, replace it with their hostname

You cannot use multiple greedy vars however, raisins should be obvious.

Config block:
Creating aliases might be a bit complex, so I'll just dump an example config right here and explain in-line with comments. =]

fantasy {
    // Change command prefix to \, so it becomes \dovoice etc
    //cmdchar \;

    // "!dovoice urmom" results in "/mode $chan +v urmom"
    dovoice     "MODE $chan +v $1";
    unvoice     "MODE $chan -v $1";

    // "!fgt urmom" is turned into "/kick $chan urmom :ayyyyy ur faget"
    fgt         "KICK $chan $1 :ayyyyy ur faget";

    // "!bitchnigga urmom dickface" results in a separate "/kick $chan $nick :nigga b0iiii" for both urmom and dickface
    bitchnigga  "KICK $chan $1- :nigga b0iiii";

    // "!ayylmao urmom u goddam fuckstick" becomes "/kick urmom :u goddam fuckstick"
    ayylmao     "KICK $chan $1 :$2-";

    // "!invex urmom" is majikked into "/mode $chan +I *!*@urmom.tld"
    invex       "MODE $chan +I *!*@$1h";
    uninvex     "MODE $chan -I *!*@$1h";

    // "!safe urmom" will become "/kick $chan urmom :$chan is a safe space lol m8 urmom"
    safe        "KICK $chan $1 :$chan is a safe space lol m8 $1";

    // It is also possible to have the same alias issue multiple commands ;]
    safe        "MODE $chan +b *!*@$1h";

    // You can also go through ChanServ, provided you have access with it
    n           "PRIVMSG ChanServ :KICK $chan $1 change your nick and rejoin lol";

As you may have noticed there are some colons in there. These are required, because otherwise there's no telling where the target arg stops and the message begins. Also, in case you do !devoice (so without ne args) it will try and voice the user who issued it. Permissions for using the resulting command are eventually checked by the do_cmd() call I have in hur. ;3


In the event of a netsplit, if someone tries to be funny by setting +b *!*@* on the main channel, nobody will be able to join until opers come in and fix it. This module allows you to deny such bans. =] Optionally, specify if opers are allowed to override it and if offenders should get a notice. I even went a bit further and also applied these restrictions to SAMODE. ;]

Config block:

denyban {
    allowopers 0;
    denynotice 1;
    reason "ayy ur faget lol (stripped $num masks)";
    mask BAN_ALL;
    mask *!*@*;

The mask *!*@* is kinda special, so you'll have to specify BAN_ALL to prevent people from doing MODE #chan +b *!*@* etc. For anything else it will do a wildcard match, as is usual. The directives allowopers and denynotice should be pretty clear. They default to 1 and 0, respectively.

For the reason directive you can use $num, which will be replaced with the actual amount of stripped masks. ;] No masks means they'll see the default message.

I went with denyban over deny ban (notice the space) as I'm not sure if the latter will conflict with any of Unreal's internals (like deny dcc { } etc).

m_portsifresi (PORTED)

Using this module you can specify a different password for every port. This might be useful if you have like backup servers only certain people should be able to connect to. Or if you want a totally priv8 netw3rk. I think it was originally written by Sky-Dancer. The code seems to indicate the maximum password is 32 chars, so keep that in mind.

Config block:
I've kept the original format mostly, with the exception of stripping the required trailing :. ;]

psifre {
    pass "6667:hams";
    pass "6697:turds";

So any client connecting to port 6667 will first have to send a PASS hams command. People who use 6697 have to do PASS turds.


Some people may often type in caps which is annoying af really. So this module allows you to block these messages by means of an anticaps { } configuration block. It works for both channel and user private messages. ;] It disregards colour codes and control characters as well spaces while counting caps. U:Lines and opers are once again exempt.

Updated shit:

  • Now also ignores ACTION and CTCP related shit =]
  • Allow for lowercasing of the message instead of bl0cking
  • Also limit the caps in NOTICE lol (tfw forgot about it xd)

Config block:

anticaps {
    capslimit 10;
    minlength 10;
    lowercase_it 1;

Above example would set a limit of 10% capital letters, with a minimum message length of 10. In other words, if the message is less than 10 characters it won't even bother checking. You can also set it to 0 to effectively disable it. They default to 50% and 30 chars respectively.

Set lowercase_it to 1 to lowercase the entire (plaintext) message instead of downright bl0cking it. ;]

m_joinmute (PORTED)

Originally written by Dvlpr, this module prevents people who just joined a channel from speaking for a set amount of seconds. It works with a new channel mode: +J <seconds>, for which you need to be chanop or higher to set. Furthermore, opers, U:Lines and anyone with any access mode (one or more of +vhoaq) will be able to talk right away. U:Lines are exempt since some services may join a channel, do something and part. =]


Some clients implement a command like /amsg <message>, which sends that message to all active tabs (both channels and private queries). This can get really spammy, so the module will allow the first message to go through and block the others for a short period of time. It will also strip colours and control codes, in case some people have edgy scripts for different markup across tabs. The offender will get an in-channel notice if the target is a channel and in the server console if otherwise.


Apply vhosts at connect time based on users' raw nick formats or IP addresses. The vhosts are entered in unrealircd.conf and they must be at least 5 chars in length. Furthermore, you can only enter the host part (so not ident@host).

Updated shit:

  • Added $ident dynamic variable
  • Return silently Notify opers with SNO_EYES when a connecting user's vhost would be illegal (can't do this earlier due to $nick and $ident ;])
  • Added $nick dynamic variable which gets replaced at runtime with the connecting user's nickname (0bv)
  • Throw error if you try to configure an ident bit
  • Now displays a warning if you forgot to configure some vhost entries =]

Add a config block that looks like this:

autovhost {
    *!* $nick.big.heks;
    192.168.* premium.lan;

So everyone connecting from a typical LAN IP will get the vhost premium.lan, for example. It replaces both cloakedhost and virthost, so that when you do /umode +x after a -x at some point, it will re-use this vhost. ;];] Also, keep in mind that Anope's HostServ for example will override this vhost as HS sets it after us.


Adds a umode +c so you can prevent fucktards who don't share a channel with you from messaging you privately. Simply load it and do /mode <your_nick> +c. ;3 Opers and U:Lines are exempt from this (i.e. they can always send private messages), the reason why should be obvious imo tbh fam.

Updated shit:

  • Added BACKPORT thing for pre-4.0.10 IRCds cuz need to define muh own static int has_common_channels in that case
  • Allow sending to ulines imo tbh (in case of modes-on-connect "+c")

m_saprivmsg (MALV)

Inspired by SAJOIN and friends, this "forces" a PRIVMSG from a certain user. =] It comes with a new top-level operclass privilege saprivmsg. I wrote this just for lelz so bnice lmao.

Updated shit:

  • Allow the target to be a U:Lined user
  • No longer check for can_send(), seems a bit retarded for /sa* commands xd

SAPRIVMSG <target channel/nick> <victim> <msg>

There's also the shorter command SASAY. ;3 The module checks if the target exists (obv), as well if victim is even in there. If the target is a nick it must be U:Lined. ;] Opers and U:Lines are protected from being a victim to this shit anyways.

m_bancheck_access (UNC)

This one was mostly written for keks. It prevents chanops/hops from banning anyone who has +o, +a and/or +q. The module will check every banmask against people who have any of those access modes, using both their vhost and cloaked host. Opers can ban anyone regardless, but they can also still be affected by other bans if they don't have a high enough access mode. This is done to maintain fairness in the channel, but opers may sometimes need to set wide-ass and/or insane channel bans. Similar to m_fixhop, this mod will simply strip the affected masks and let the IRCd handle further error processing.

Note: Afaik Unreal is unable to "ask" your NickServ flavour about access lists from within a module. So if you have Anope and did /cs access #chan add <nick> 10 it will auto-op that person when they authenticate, but Unreal knows fuck all about this list. As such, it simply checks if they have the proper access mode right now.

Updated shit:

  • Reset conf defaults on rehash lol
  • Display in-channel notice in case certain masks are stripped (configurable), only the one user will see it obv

To enable above mentioned notices, simply slam this in the config somewhere: bancheck_access_notif 1;

m_fixhop (UNC)

In my opinion the +h access mode (channel halfops yo) is a little b0rked. So I made a qt3.14 module that implements some tweaks which you can enable at will in da config. ;3

Updated shit:

  • Also prevent them from changing certain channel modes like -t, -f etc
  • Reset conf defaults on rehash lol
  • Show config warning if widemask_notif is enabled but disallow_widemasks is not
  • Display in-channel notice in case certain masks are stripped (configurable), only the one user will see it obv
  • Don't blindly allow ulines anymore, as hops would be able to do /cs mode #chan +b <mask> for any mask lel

Just compile that shit, load it and add the tweaks you want to a top-level config block (disable one by simply removing/leaving out the directive):

fixhop {
    disallow_chmodes "ft";
  • allow_invite => Apparently when a chan is +i halfops can't invite people, this overrides that
  • disallow_widemasks => Hops can normally set a ban/exemption/invex for shit like *!*@*, this disallows that by stripping those masks
  • widemask_notif => Enable the in-channel notice
  • disallow_chmodes => Will strip the given channel modes in either direction, ne arguments should be taken into account
  • chmode_notif => Enable in-channel n0tice for dis

floodprot (UNC, MOD)

Some people have requested some additional features for chanmode +f. I contemplated implementing those with another module, but there aren't any proper mode flags available. xd So I just edited this shit instead. =] Remove the line that mentions loadmodule "chanmodes/floodprot" from ur modules.default.conf and add loadmodule "third/floodprot" instead. Since that file will be overwritten with the next upgrade, move it to a separate include and use that for your servers (you better be using remote includes lol)

Since I'm not gonna rehash Syzop's documentation, refer to that shit for the current arguments. My modification implements the f0ll0wing:

  • An action D to just drop the message (I thought about using B but since there's also b this might get confuzzling)
  • A floodtype r that catches repeated messages (sort of like m_repeatprot but channel-bound instead of netwerk wide =])

An example m0dd could be: /mode #dicktits +f [2r#D]:15 (1r don't werk cuz that wouldn't be a repeat =]), so people using the same line twice in 15 seconds will be flagged. The third one will be dropped and a slightly cryptic message is shown to the spammer. Similar to m_repeatprot it will catch alternated messages. ;3

The new floodtype will detect repeats in channel notices/CTCP/messages/ACTIONs interchangeably, meaning one of each will trigger above example mode after the message. It currently only works with actions D and b (drop and kickban), but I may change that if people need moar. =]

Updated shit:

  • Improved the logic for determining whether something is repeated or simply text spam
  • Is now also markup/colour agnostic (i.e. bold/underline/etc and colours will be stripped before matching)

m_holidays (MALV)

Do some string replacements based on wat holiday it is atm. =]

m_repeatprot (UNC)

This module used to be called m_noticeprot, so remove that one entirely and replace it with this to avoid conflicts

Sometimes there are faggots who spam the shit out of you, either through NOTICE, PRIVMSG, CTCP, INVITE or OPER commands. This module will GZ:Line/kill/block their ass if they do. Other than specifying the triggers and exceptions, you can tweak the action a lil' bit:

  • action <block/kill/gzline> -- what action to take upon detecting a spammer, default is gzline
  • showblocked <0/1> -- display the ban message to the spammer when action == block, default = 0
  • banmsg <string> -- zline message obviously, default = Nice spam m8
  • tkltime <timestr> -- how long to zline for, format is like 60, 1h5m, etc; default = 60 (seconds)
  • threshold <int> -- after how many identical messages the action kicks in, default = 3

The module will keep track of people's last and first to last messages, so it will still catch people who alternate their spam. =] Also, channels are excluded as they probably have something better in place (like +C to disable CTCP in general).

Updated shit:

  • Improved the logic for determining if something is spammerino or n0
  • Exceptions are also checked against nick!ident@IP nao (instead of just [email protected]) xd
  • Sends a snomask notice to SNO_EYES (/umode +s +e) about the flood (includes trigger type, nick, body and action))
  • Reset conf defaults on rehash lol
  • Added new config directive timespan so you can "expire" the counters (simply don't specify it to never expire 'em)
  • Added trigger for INVITE spam
  • Added another action gline
  • Added trigger for CTCP yo
  • Is now also markup/colour agnostic (i.e. bold/underline/etc and colours will be stripped before matching)
  • Added detection for repeated OPER messages, will exclude the first one since that is usually legitimate (it only checks for duplicate OPER <user> too)
  • Also exempted sending to U:Lines as people sometimes fuck up their NickServ passwerds etc
  • Added exception block
  • Renamed some variables/directives
  • Added showblocked directive
  • Added multiple actions, as well as the ability to choose between 'em
  • Renamed this shit to m_repeatprot lol
  • Moved everything into an encapsulating repeatprot { } block, with triggers { } one inside for the actual triggers

Config block example:

repeatprot {
    triggers {
    exceptions {

    timespan 2m;
    action block;
    //action kill;
    //action gzline;
    //action gline;
    banmsg "Nice spam m8";
    showblocked 1;
    //tkltime 60;
    threshold 3;

You need at least one trigger obviously. The exception masks must match *!*@*, so should be a full nick mask m9. The hostname used should match the realhost as well and not a cloaked one.

m_md5fjert (UNC, LEAF-ONLY)

Probably doesn't work with Wind0ngs

m_confprot's counterpart. Requires no additional configuration, but requires to be built with (from the Unreal sauce dir):
export EXLIBS='-DFJERT=\"${INCLUDEDIR}\"'; make

Updated shit:

  • Resend the digest if the hub seems to have split

m_confprot (UNC, HUB-ONLY)

Probably doesn't work with Wind0ngs

This module allows the hub of a network to verify the leaves' configs (if remotely included, libcURL etc). It requires a configuration block confprot { } to be added and also supports a few additional options. If it encounters an error of any kind, it will block the leaf's IP of which opers will be notified. You can also optionally verify m_md5fjert itself.

Compile flags:
This shit requires a few custom flags to compile succesfully, but they depend heavily on the Unreal version. In all cases should you run the following from the Unreal sauce dir.

If you're on anything before 4.0.10, you should use:

export EXLIBS="-L<Unreal homedir>/curl/lib -lcurl -L<Unreal source dir>/extras/c-ares/lib <Unreal source dir>/extras/c-ares/lib/libcares.a"

If your version is 4.0.10 or greater, use:

export EXLIBS="-L<Unreal install dir>/lib -lcurl -L<Unreal install dir>/lib <Unreal install dir>/lib/"

It also assumes you're using a few sort-of-best practices:

  • You're only working with remote includes
  • Split network and hub/leaf configs (so unrealircd.conf contains just 2 include "httpx://..." lines) -- network comes before hub/leaf
  • Includes aren't nested more than once (top ones go in unrealircd.conf, those may contain only includes that don't include shit themselves)

Updated shit:

  • Added oper privilege cline
  • Renamed zlinetime to clinetime
  • Added a command /CLINE (see bel0w)
  • Now uses a custom so-called C:Line to prevent server connections (since some ZNC providers may get (G)Z:Lined entirely otherwise xd, see below)
  • Reset conf defaults on rehash lol
  • Moved everything into an encapsulating confprot { } block, with protected { } one inside for the actual entries

The confprot::protected block should contain entries for every leaf and can optionally contain NETWORK and FJERT entries (duplicate entries will be ignored). Other than that, there are the following optionals for in confprot { } itself:

  • allowunknown <0/1> -- allow links to happen despite errors, default = 0
  • clinetime <timestr> -- format is like 60, 1h5m, etc; default = 60 (seconds)
  • sslverify <0/1> -- verify SSL cert shit for the FJERT entry, default = 1

Any server that's not in the list will be allowed/denied, as specified with the directive confprot::allowunknown. The default is to deny, except ulines for obvious raisins. =] If set to 1, the module will still run through the checks as much as it can so you can still see when shit goes down (basically a dry run y0).

PROTIP if allowunknown is disabled: When you change leaf configs one way or another (like changing a remote include) and you do /rehash -global, the hub may start C:Lining shit. To prevent this, set allowunknown 1, rehash the hub, wait for it to complete and do /rehash -global, then flip allowunknown back and rehash the hub once moar. ;]

Example config section (UPDATED):

confprot {
    protected {
        NETWORK "https://includes.domain.tld/network.conf";
        FJERT "https://includes.domain.tld/m_md5fjert.c";
        myleaf.domain.tld "https://includes.domain.tld/myleaf.conf";
        myleaf2.domain.tld "https://includes.domain.tld/myleaf2.conf";
    allowunknown 0;
    clinetime 60;
    sslverify 0;

CLINE shit:
So the updated version comes with a new command, which you can use to list and remove C:Lines. /cline * and /cline will both remove the C:Line on (i.e. it supports wildcard masks). You can't use it to prevent servers from connecting, just jupe it if that's wat u want. Also, simply do /cline ? or /cline help to view the built-in help.

I'm using C:Lines because (G)Z:Lines may result in ZNC providers who run an IRCd on the same box to get fukt entirely. If I didn't use any *:Line at all it would result it running the cURL-related checks every goddamn time (with accompanying link established, read error messages (and a bunch of others)), which ain't gonna happen fam. Also, there's no expiration notice on C:Lines; if you see another denied notice you can safely assume it expired (according to clinetime obv). They're also not really timed, they just expire on the next run. ;] They also get cleared if you rehash.

To allow opers to list/remove C:Lines, give them the cline privilege:

operclass muhclass {
    parent netadmin-with-override;
    privileges {

m_tkl (MALV, MOD)

A slight modification of Syzop's built-in module, it prevents showing a message like Message blocked when using spamfilters of the type block.

Updated shit:

  • Spamfilters are never checked when sending to U:Lined users (cuz spamfilters could normally affect /msg nickserv register etc)
  • Now also resolves /gline <nick> to a user@host mask instead of *@host so ZNC providers don't get glined en masse xd

m_getlegitusers (PORTED)

Originally written by darko, this module simply counts how many legitimate clients you have on your network. People who are on more than one channel are seen as legitimate, while ones in no channels are marked "unknown". It also accounts for services boats.

Just run /getlegitusers and check your server console. =]


This module is quite similar to m_rmtkl in that you can clear "ban" lists based on masks with wildcards. So you could use a mask of *!*@* or even just * to clear errythang, it's pretty straightforward imo tbh. =]

Updated shit:

  • Now also runs hooks for TKL_DEL (so m_storetkl is aware of that shit)
  • Apparently it didn't quite properly propagate removals of malformed masks, fixed that shit =]
  • Also removes all corrupted entries (like butthams@* instead of butthams!*@*), cuz most (if not all) clients and the IRCd won't let you remove those

CLEARLIST <channel> <types> <mask>

Types list:

  • b => Ban
  • e => Ban exception
  • I => Invite exception


  • CLEARLIST #bighek b *
  • CLEARLIST #ayylmao Ie guest*!*@*
  • CLEARLIST #hambutt * *


So apparently someone with +v can still talk if they're banned (+b) or mutebanned (+b ~q:). This seems counterintuitive to me and probably a bunch of others, so the module rectifies that. Keep in mind that people with at least +h or IRC operator status (as well as ulines) can still talk through it.

Also, when you're not even voiced but have +b on you and you /notice #chan, you don't see a "you are banned" message. So I fixed that too. =]

Just load it and g0. =]

m_rmtkl (PORTED)

My port of AngryWolf's module for Unreal 3.x.
Removes all TKLs (bans) matching the given conditions and having any types you specify. The removal is done locally or globally, depending on whether the ban is global or not. With this command you can easily get rid of a group of no longer necessary bans. Wildcards are supported.

Updated shit:

  • Since Unreal 4 uses the operclass stuff, I've leveraged the system to ensure the proper permissions are checked. Depending on your operclass blocks, they may already be included (e.g. top-level permissions like tkl { zline } would allow opers to remove both global and local Z:Lines.
  • Apparently spamfilters fall under TKL as well (flags f and F for local and gl0bal, respectively), added support for dis. It skips over the default spamfilters carried by Unreal.
  • Added extra parameter -skipperm to skip over permanent *:lines (since they're there for a raisin ;3).

Operclass permissions overview):

  • (Local) K:Line: tkl:kline:remove
  • (Local) Q:Line: tkl:qline:local:remove
  • (Local) Z:Line: tkl:zline:local:remove
  • (Local) Spamfilter: tkl:spamfilter:local:remove
  • G:Line: tkl:gline:remove
  • Q:Line: tkl:qline:remove
  • S:Line: tkl:shun:remove
  • Global Z:Line: tkl:zline:remove
  • Global Spamfilter: tkl:spamfilter:remove

RMTKL <types to remove> <user@host/ip mask> [reason mask]

Types list:

  • K => Local K:Line
  • q => Local Q:Line
  • z => Local Z:Line
  • f => Local Spamfilter
  • G => G:Line
  • Q => Global Q:Line
  • s => Global S:Line
  • Z => Global Z:Line
  • F => Global Spamfilter
  • * => Everything but Q:Lines and Spamfilters

Also take a look at the built-in help by issuing simply /rmtkl.


Probably doesn't work with Wind0ngs

This module allows easy installation and updating of modules from git through an IRC command. It requires access to a shell/pipe and the commands "make" and "git" (so may not work on Wind0ngs). The paths you can feed it may NOT start with a slash, and are always relative to $HOME. Also requires you to have the privilege git in yo opercla$$. =]

Oh yeah, it also throws a SNO_EYES snomask to notify IRC opers of the command usage. Every server it ran on returns one line of output regarding its success as well.

GIT INSTALL <Unreal source path> <build/tmp folder> <git clone URL> [-global]
GIT UPDATE <Unreal source path> <git module path> [-global]

Example: /git install build/unrealircd-4.0.5 build
This will clone the repo to the folder $HOME/build (of the server you are on) and copy .c files in there to $HOME/build/unrealircd-4.0.5/src/modules/third. It will then run make && make install.

Example 2: /git update build/unrealircd-4.0.5 build/somemodule -global
This will do a pull of the repo in $HOME/build/somemodule and again copies .c files to $HOME/build/unrealircd-4.0.5/src/modules/third before doing make && make install. Since -global is specified, all currently connected servers will do the same.

m_forward (PORTED)

Muh first attempt at porting ein module for UnrealIRCD 3.x to 4.x. =]
The original Unreal 3 mod can be found on the Unreal forums.

Updated shit:

  • Now also allows people with list mode +a to set chmode +F (instead of just +q) =]
  • While checking the target channel for +B there was a bug with casting a char * to void *, which fucked shit up xd
  • Channel mode +A is no longer known to UnrealIRCd it seems, so removed that shit =]
  • +b was checked last, seems to me it should be first in order to have the extended ~f: bantype override it
  • When checking for +B on target channel, it originally checked chptr (which is a pointer to the current channel's struct)
  • Cleaned up c0dd ein bit lel
  • better_override is now settable through unrealircd.conf, no need to recompile anymore (allows opers w/ OperOverride to simply /join restricted channels)

better_override defaults to 0/false so you can simply omit the configuration variable if you don't want this feature. Otherwise, add m_forward_override 1 to the global configuration.

I'll also include ze original readme sort of thing right here:
This module is based on the m_banlink module, but offers a more robust featureset. This module and the banlink module are incompatible with each other, so having both installed at once won't work (and why would you anyway?)

My module offers the following features:

  • +F <channel> channel mode to forward users that are unable to join to another channel (including invite only, keyed, etc. not just banned). Requires channel owner (+q) to set
  • +B channel mode to prevent users from being forwarded to your channel. Requires channel owner (+q) to set
  • +Q user mode to prevent yourself from being forwarded to other channels
  • ~f:#channel:nick!user@host extended bantype to forward specific users to another channel (overrides +F)
  • Users will only be forwarded once. If they cannot join the second channel, nothing will happen (even if the second channel is +F)
  • Users will be given a descriptive message as to why they are unable to join the first channel (e.g. "channel is invite only" or "you are banned")
  • (Optional) You may choose to allow Opers to be able to directly join a channel via OperOverride (e.g. normally an oper must /invite themselves into a +i channel, this would allow them to just join. Either way an OperOverride message is given and logged). To enable this, see the Config section [in the source]