Modular IRC security service for P10 (ircu-style) uplinks: DNSBL checks, flood controls, G-lines, channel enforcement, optional GeoIP (ipinfo), console whois / seen from the link cache (including away when the hub reports it on the link), and more. Written in Perl.
Lineage: the codebase shares roots with the public key2peace/defender project (Defender IRC service). You do not need a GitHub “Fork” of that repo to publish this tree: a standalone repository is fine. NetIRC Defender V3 is this project’s name and P10-focused evolution. Keep the GPL-2.0 license file and existing copyright headers in source files when you redistribute (see License).
- Perl 5.10+. Networking uses
SocketandIO::Socket, which ship with a normal Perl build as core modules (they are not separate CPAN installs when you use theperlpackage from your Linux distribution). - Linux (or similar) is assumed for production; P10 link to your hub.
- Config parsing: this tree bundles
Config::GeneralandTie::IxHashunderConfig/andTie/— you do not install those from CPAN. dnsblmodule: uses the same coreSockethelpers (gethostbyname/inet_ntoa) for RBL DNS lookups — noNet::DNSor other CPAN DNS stack. Lists and replies are read fromdnsbl.confin yourdatadir. Usednsbl.conf.examplein the repository as a template (copy todatadir/dnsbl.confand replace with zones you are allowed to query).
Install the perl (and on some distros perl-modules) package from your distribution; you do not need to compile Perl from source.
Socket / IO::Socket: these are part of perl-core. A stock apt install perl or dnf install perl pulls them in, so you do not run cpan / cpanm for the IRC uplink, dnsbl RBL checks, or other DNS-style lookups in this codebase.
Extra CPAN: not required for this tree — config helpers and related code are bundled.
Debian / Ubuntu
sudo apt update
sudo apt install -y perl perl-modules openssl ca-certificates
perl -v # confirm 5.10 or newerRocky Linux / AlmaLinux / Fedora / RHEL
sudo dnf install -y perl perl-IO-Socket-SSL openssl
perl -vThen continue with Quick start (clone, defender.conf, run).
-
Clone the repository.
-
Copy the sample config next to
defender.pland edit it (defender.confis always loaded from that directory, not fromdatadir):cp defender.conf.example defender.conf $EDITOR defender.confIf you add the
versionmodule tomodules=, add rules indatadir/deny_version.conf(seedatadirindefender.conf; it is often your clone/install directory):cp deny_version.conf.example /path/to/your/deny_version.conf $EDITOR /path/to/your/deny_version.confIf
dnsblis inmodules=, createdatadir/dnsbl.conf(Config::General; one block per RBL zone). You can start from the template:cp dnsbl.conf.example /path/to/your/dnsbl.conf $EDITOR /path/to/your/dnsbl.confOptional —
regexp_akill: not enabled in the defaultmodules=list indefender.conf.example. If you addregexp_akilltomodules=, createdatadir/regexp_akill.conf(the module logs if the file is missing). Template:cp regexp_akill.conf.example /path/to/your/regexp_akill.conf $EDITOR /path/to/your/regexp_akill.conf -
Run (foreground debug):
perl defender.pl --debug
Or daemon mode (default when not passing
--debug), perdefender.pl/Modules/Main.pm.
Use defender.sh for normal operator actions (same directory as defender.pl):
chmod +x defender.sh
./defender.sh start # daemon via defender.pl
./defender.sh stop # SIGINT, then SIGKILL if needed
./defender.sh restart
./defender.sh statuscheckD.sh is not a replacement for defender.sh: it is meant only for cron so the process comes back after reboot or crash (uses nohup + lock file). If you already start/stop by hand with defender.sh, keep using that; add checkD.sh on a timer if you want an automatic safety net.
chmod +x checkD.sh
# crontab -e — example:
* * * * * /path/to/defender-master/checkD.sh >/dev/null 2>&1See the top of checkD.sh for CHECKD_LOG, CHECKD_DEBUG, and CHECKD_LOG_EVERY_RUN.
defender.conf— hubserver/port/password,linktype=p10, service identity (servername,sid, …),channel(control channel for operator commands),modules=…, paths, thresholds. On connect,verbose+versionscan_userare always run before other modules (sodnsbldoes not delay “Signed on” or CTCP VERSION); on quit / join / part / kill / nick change,verboseruns before the rest soseen(disk) and other hooks do not delay “Signed off” and similar lines. Optionalcontrol_channel_line_delay_msspaces consecutive PRIVMSG to the control channel andglobopswhen sends are within ~1.5s; unset means no delay (older trees mistakenly reusedipinfo_line_delay_msfor that — it is not used byipinfohere). Automatic profile switch is controlled byattack_mode_auto,attack_mode_enter_conn_per_min,attack_mode_hold_sec. dnsbl readsdnsbl_cache_ttl,dnsbl_query_timeout_sec,dnsbl_cb_trigger_conn_per_min,dnsbl_cb_trigger_timeouts_per_min,dnsbl_cb_cooldown_sec,dnsbl_backlog_skip_ttl_secplusattack_...overrides. ipinfo readsipinfo_token,ipinfo_cache_ttl_sec,ipinfo_burst_limit,ipinfo_burst_window_sec,ipinfo_http_timeout_sec(seedefender.conf.example).defender.confis not committed (see.gitignore); usedefender.conf.exampleas the template.- Under
datadir(seedatadir=indefender.conf), usually not committed:dnsbl.conf,regexp_akill.conf,glines.conf,killchans.conf,deny_version.conf,defender_persistent_counters.v1,seen_state.sto(from the seen module). Besidedefender.pl:defender.conf,defender.pid, and (iflogto=Text) the file atlogpath— often the same folder asdatadir, but paths are independent. Templates:defender.conf.example→defender.confnext todefender.pl;deny_version.conf.example,dnsbl.conf.example,regexp_akill.conf.example→datadirwith the names above. A commentedcgiirc.confmay live at the project root in this tree; the running service reads$datadir/cgiirc.conf(create or copy there if you use the cgiirc module). Optional:seen_max_entriesindefender.conf(default 10000) limits last-seen records.
Commands below are sent on the control channel set in defender.conf as channel. Replace <botnick> with your configured bot nick. On the uplink, IRC operator status is required for most operator commands (message.pl and several modules call isoper).
| Command | Operator? | Description |
|---|---|---|
help |
yes | Short index; lists each loaded module’s cmd_help line. |
help <module> |
yes | Help for one scan module name (as in modules=). |
info |
yes | Short network snapshot counts (servers / users / channels seen on the link). |
info help |
yes | Longer explanation of info subcommands and related lookups. |
info servers |
yes | List of server names from the P10 cache. |
info users |
yes | User counts grouped by uplink server. |
info users list |
yes | Capped flat list of cached nicks. |
info chans |
yes | Per-server channel name statistics (JOIN-derived; rows overlap). |
info chans list / info channels list |
yes | Capped flat list of distinct channel names seen. |
status |
yes | Process start time, uptime, metrics, loaded modules, link capabilities. |
status all |
yes | Same metrics plus stats output for every loaded scan module. |
status <module> |
yes | stats for scan modules whose name matches (e.g. status dnsbl). |
<botnick> rehash |
yes | Reload defender.conf and rescan module list (SIGHUP-style). |
<botnick> shutdown |
yes | Shut down Defender. |
CTCP to the bot’s nick (VERSION, TIME, …) is answered in message.pl with rate limiting; not specific to scan modules.
Only modules listed in defender.conf are active. Names must match Modules/Scan/<name>.pm without .pm.
Order: for each new client, scan_user runs in list order until a module calls gline() (that increments an internal counter and skips remaining modules for that client). Keep conn_average (and any other always-on counters) before modules that may G-line from scan_user (dnsbl, regexp_akill, cgiirc, etc.) so connection-rate stats stay accurate.
| Module | What it does | Commands on the control channel |
|---|---|---|
| conn_average | Counts sign-ons per minute; if above conn_average_max, sends GLOBOPS; if conn_average_mirror_console is not 0, repeats the warning on the control channel. Can auto-enable global attack mode and (optionally) force emergency G-lines while attack mode is active. |
None (automatic). Use status conn_average if stats is defined. |
| dnsbl | Checks new users against RBL zones from dnsbl.conf in datadir. |
None (automatic). |
| version | CTCP VERSION fingerprinting / deny_version.conf rules (when version is in modules=). G-line duration for G rules is fixed in code (86400s). Global outbound CTCP limiting is configurable via version_ctcp_global_burst, version_ctcp_global_window_sec, version_ctcp_global_mute_sec (and attack_... overrides while attack mode is active). |
version ctcp-all — sends CTCP VERSION to $*.net; oper. Replies still filtered by deny_version.conf. |
| regexp_akill | On sign-on, matches nick!ident@host + realname against regexes; G-lines on match (~600s). Off by default — add regexp_akill to modules= and maintain regexp_akill.conf if you use it. |
regexp_akill add <pattern> <reason>, regexp_akill del <pattern>, regexp_akill list — oper; file regexp_akill.conf. |
| flood | Per-channel flood detection and temporary +f (and related) lock. |
None (automatic). |
| nickflood | Kills rapid nick changes (nickflood_limit). |
None (automatic). |
| killchan | G-lines non-opers who join listed channels after a grace period. | killchan add #channel reason, killchan del #channel, killchan list — oper; list stored in killchans.conf. |
| message | Logs private messages to the bot to the control channel and auto-replies once with support channel info. | No control-channel commands (PM-only behaviour). |
| verbose | Announces joins/parts/modes/KILLs/etc. on the control channel. | None (automatic). |
| gline | Manages G-lines (local cache + IRCd); syncs GL traffic from the link. | gline, gline help — help text. gline add …, gline del …, gline list, gline del all. Shorthand: gline <target> [time] [reason] (same as gline add). oper. |
| ipinfo | GeoIP / host info via ipinfo.io (token in defender.conf). |
ip or ip <target> (address, hostname, or nick) — oper. |
| whois | Snapshot from the P10 client cache (not the IRCd’s full /WHOIS): user/host, IP, account if known, sign-on, server, channels, privileges. The command also requests live IRCd WHOIS away (301), idle (317) and account (330) and prints them when received. |
whois <nick> or whois nick <nick> — oper. |
| seen | Last quit / kill for a nick, or online from the P10 cache (server/channels). For online users it can trigger live IRCd away lookup to correct stale pre-link away state. Changing nick removes the old nick from last-seen. | seen <nick> — oper; datadir/seen_state.sto (pruned, persisted). |
| cgiirc | Detects unauthorised CGI:IRC via VERSION notices; optional cgiirc.conf whitelist. |
None (automatic). |
To see the exact help string a module registers, use help <module> on the control channel (same text as in the bot output).
Away / live WHOIS data: away state in the P10 cache is accurate after relevant A lines have been seen while Defender is linked. Users already away before link-up can be stale; whois now asks IRCd live away (301) and seen can request live away for online users, so displayed state is corrected on demand. whois also asks for live idle (317) and account (330); if idle reply does not arrive within timeout, it reports n/a (IRCd timeout).
| Path | Role |
|---|---|
defender.pl |
Entry point |
message.pl |
PRIVMSG/NOTICE routing, CTCP, help text |
Modules/Main.pm |
Config load, module wiring |
Modules/Link/p10.pm |
P10 uplink |
Modules/Scan/* |
Scan / policy modules |
Modules/Log/Text.pm |
File logging (logto=Text) |
defender.sh |
Manual start / stop / restart / status |
checkD.sh |
Cron watchdog only (auto restart after reboot/crash) |
defender.conf.example |
Config template: copy to defender.conf in the same directory as defender.pl (not necessarily datadir; see datadir= for policy files) |
deny_version.conf.example |
Template for the version module’s deny_version.conf in datadir |
dnsbl.conf.example |
Template for dnsbl.conf (Config::General: RBL zones, duration, reason, <reply>) |
regexp_akill.conf.example |
Template for regexp_akill.conf (tab: regex, reason); use only if regexp_akill is in modules= |
This program is free software licensed under the GNU General Public License v2.0 — see the LICENSE file. Running perl defender.pl --help also references GPL v2.
Bundled third-party code (for example under Config/ and Tie/) retains its own copyright and license notices in the respective files.
Issues and pull requests are welcome. Do not commit secrets: keep defender.conf, API tokens, and hub passwords out of git (use defender.conf.example only for structure).
Defender is an IRC network tool: use it only on networks and systems you are allowed to administer.