mirror of git://git.acid.vegas/unrealircd.git
188 lines
5.1 KiB
C
188 lines
5.1 KiB
C
/*
|
|
* Extended ban to exempt from +f/+F checking.
|
|
* Eg: +e ~flood:*:~account:TrustedBot
|
|
* (C) Copyright 2023-.. Bram Matthys (Syzop) and the UnrealIRCd team
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 1, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
#include "unrealircd.h"
|
|
|
|
ModuleHeader MOD_HEADER
|
|
= {
|
|
"extbans/flood",
|
|
"1.0",
|
|
"Extban ~flood - exempt from +f/+F checks",
|
|
"UnrealIRCd Team",
|
|
"unrealircd-6",
|
|
};
|
|
|
|
/** Maximum length of the ~flood ban exemption */
|
|
#define MAX_FLOODBAN_LENGTH 128
|
|
|
|
/* Forward declarations */
|
|
int extban_flood_is_banned(BanContext *b);
|
|
int flood_extban_is_ok(BanContext *b);
|
|
const char *flood_extban_conv_param(BanContext *b, Extban *extban);
|
|
|
|
/** Called upon module init */
|
|
MOD_INIT()
|
|
{
|
|
ExtbanInfo req;
|
|
|
|
memset(&req, 0, sizeof(req));
|
|
req.letter = 'F';
|
|
req.name = "flood";
|
|
req.is_ok = flood_extban_is_ok;
|
|
req.conv_param = flood_extban_conv_param;
|
|
req.options = EXTBOPT_ACTMODIFIER;
|
|
if (!ExtbanAdd(modinfo->handle, req))
|
|
{
|
|
config_error("could not register extended ban type 'flood'");
|
|
return MOD_FAILED;
|
|
}
|
|
|
|
MARK_AS_OFFICIAL_MODULE(modinfo);
|
|
|
|
return MOD_SUCCESS;
|
|
}
|
|
|
|
/** Called upon module load */
|
|
MOD_LOAD()
|
|
{
|
|
return MOD_SUCCESS;
|
|
}
|
|
|
|
/** Called upon unload */
|
|
MOD_UNLOAD()
|
|
{
|
|
return MOD_SUCCESS;
|
|
}
|
|
|
|
/** Check if letters in 'str' are valid flood-types.
|
|
* TODO: ideally this would call a function in chanmode +F module!!
|
|
*/
|
|
static int flood_type_ok(char *str)
|
|
{
|
|
char *p;
|
|
|
|
/* The * (asterisk) simply means ALL. */
|
|
if (!strcmp(str, "*"))
|
|
return 1;
|
|
|
|
for (p = str; *p; p++)
|
|
if (!strchr("cjkmntr", *p))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
const char *flood_extban_conv_param(BanContext *b, Extban *extban)
|
|
{
|
|
static char retbuf[MAX_FLOODBAN_LENGTH+1];
|
|
char para[MAX_FLOODBAN_LENGTH+1];
|
|
char tmpmask[MAX_FLOODBAN_LENGTH+1];
|
|
char *type; /**< Type(s), such as 'j' */
|
|
char *matchby; /**< Matching method, such as 'n!u@h' */
|
|
const char *newmask; /**< Cleaned matching method, such as 'n!u@h' */
|
|
|
|
strlcpy(para, b->banstr, sizeof(para)); /* work on a copy (and truncate it) */
|
|
|
|
/* ~flood:type:n!u@h for direct matching
|
|
* ~flood:type:~x:.... when calling another bantype
|
|
*/
|
|
|
|
type = para;
|
|
matchby = strchr(para, ':');
|
|
if (!matchby || !matchby[1])
|
|
return NULL;
|
|
*matchby++ = '\0';
|
|
|
|
/* don't verify type(s), already done in is_ok for local clients */
|
|
//if (!flood_type_ok(type))
|
|
// return NULL;
|
|
/* ... but limit them to a reasonable value :D */
|
|
if (strlen(type) > 16)
|
|
return NULL;
|
|
|
|
b->banstr = matchby;
|
|
newmask = extban_conv_param_nuh_or_extban(b, extban);
|
|
if (BadPtr(newmask))
|
|
return NULL;
|
|
|
|
snprintf(retbuf, sizeof(retbuf), "%s:%s", type, newmask);
|
|
return retbuf;
|
|
}
|
|
|
|
int flood_extban_syntax(Client *client, int checkt, char *reason)
|
|
{
|
|
if (MyUser(client) && (checkt == EXBCHK_PARAM))
|
|
{
|
|
sendnotice(client, "Error when setting ban exception: %s", reason);
|
|
sendnotice(client, " Syntax: +e ~flood:floodtype(s):mask");
|
|
sendnotice(client, "Example: +e ~flood:*:~account:TrustedUser");
|
|
sendnotice(client, "Valid flood types are: c, j, k, m, n, t, r, and * for all");
|
|
sendnotice(client, "Valid masks are: nick!user@host or another extban type such as ~account, ~certfp, etc.");
|
|
}
|
|
return 0; /* FAIL: ban rejected */
|
|
}
|
|
|
|
int flood_extban_is_ok(BanContext *b)
|
|
{
|
|
static char para[MAX_FLOODBAN_LENGTH+1];
|
|
char *type; /**< Type(s), such as 'j' */
|
|
char *matchby; /**< Matching method, such as 'n!u@h' */
|
|
char *newmask; /**< Cleaned matching method, such as 'n!u@h' */
|
|
|
|
/* Always permit deletion */
|
|
if (b->what == MODE_DEL)
|
|
return 1;
|
|
|
|
if (b->ban_type != EXBTYPE_EXCEPT)
|
|
{
|
|
if (b->is_ok_check == EXBCHK_PARAM)
|
|
sendnotice(b->client, "Ban type ~flood only works with exceptions (+e) and not with bans or invex (+b/+I)");
|
|
return 0; /* reject */
|
|
}
|
|
|
|
strlcpy(para, b->banstr, sizeof(para)); /* work on a copy (and truncate it) */
|
|
|
|
/* ~flood:type:n!u@h for direct matching
|
|
* ~flood:type:~x:.... when calling another bantype
|
|
*/
|
|
|
|
type = para;
|
|
matchby = strchr(para, ':');
|
|
if (!matchby || !matchby[1])
|
|
return flood_extban_syntax(b->client, b->is_ok_check, "Invalid syntax");
|
|
*matchby++ = '\0';
|
|
|
|
if (!flood_type_ok(type))
|
|
return flood_extban_syntax(b->client, b->is_ok_check, "Unknown flood type");
|
|
if (strlen(type) > 16)
|
|
return flood_extban_syntax(b->client, b->is_ok_check, "Too many flood types specified");
|
|
|
|
b->banstr = matchby;
|
|
if (extban_is_ok_nuh_extban(b) == 0)
|
|
{
|
|
/* This could be anything ranging from:
|
|
* invalid n!u@h syntax, unknown (sub)extbantype,
|
|
* disabled extban type in conf, too much recursion, etc.
|
|
*/
|
|
return flood_extban_syntax(b->client, b->is_ok_check, "Invalid matcher");
|
|
}
|
|
|
|
return 1; /* OK */
|
|
}
|