diff --git a/doc/conf/help/help.conf b/doc/conf/help/help.conf index 3d66cc687..1056d0c47 100644 --- a/doc/conf/help/help.conf +++ b/doc/conf/help/help.conf @@ -1405,7 +1405,8 @@ help Spamfilter { " [type] specifies the target type, you can specify multiple targets:"; " 'c' channel msg, 'p' private msg, 'n' private notice,"; " 'N' channel notice, 'P' part msg, 'q' quit msg, 'd' dcc,"; - " 'a' away, 't' topic, 'u' user (nick!user@host:realname ban)"; + " 'a' away, 't' topic, 'T' message-tag (eg: +typing=active),", + " 'u' user (nick!user@host:realname ban)"; " [action] specifies the action to be taken (only 1 action can be specified):"; " 'kill', 'tempshun' (only shun current session), 'shun',"; " 'kline', 'gline', 'zline', 'gzline', 'block' (blocks the msg),"; diff --git a/include/h.h b/include/h.h index 83cfbb404..3fdc50eb2 100644 --- a/include/h.h +++ b/include/h.h @@ -723,7 +723,8 @@ extern MODVAR void (*tkl_stats)(Client *cptr, int type, char *para, int *cnt); extern MODVAR void (*tkl_sync)(Client *client); extern MODVAR void (*cmd_tkl)(Client *client, MessageTag *recv_mtags, int parc, char *parv[]); extern MODVAR int (*place_host_ban)(Client *client, BanAction action, char *reason, long duration); -extern MODVAR int (*match_spamfilter)(Client *client, char *str_in, int type, char *target, int flags, TKL **rettk); +extern MODVAR int (*match_spamfilter)(Client *client, char *str_in, int type, char *cmd, char *target, int flags, TKL **rettk); +extern MODVAR int (*match_spamfilter_mtags)(Client *client, MessageTag *mtags, char *cmd); extern MODVAR int (*join_viruschan)(Client *client, TKL *tk, int type); extern MODVAR unsigned char *(*StripColors)(unsigned char *text); extern MODVAR const char *(*StripControlCodes)(unsigned char *text); diff --git a/include/modules.h b/include/modules.h index 1a7b151ed..d887ccbfa 100644 --- a/include/modules.h +++ b/include/modules.h @@ -2260,6 +2260,7 @@ enum EfunctionType { EFUNC_CMD_TKL, EFUNC_PLACE_HOST_BAN, EFUNC_DOSPAMFILTER, + EFUNC_MATCH_SPAMFILTER_MTAGS, EFUNC_DOSPAMFILTER_VIRUSCHAN, EFUNC_FIND_TKLINE_MATCH_ZAP_EX, EFUNC_SEND_LIST, diff --git a/include/struct.h b/include/struct.h index 306cbb544..a1ece52d1 100644 --- a/include/struct.h +++ b/include/struct.h @@ -992,12 +992,13 @@ struct Secret { #define SPAMF_USERMSG 0x0002 /* p */ #define SPAMF_USERNOTICE 0x0004 /* n */ #define SPAMF_CHANNOTICE 0x0008 /* N */ -#define SPAMF_PART 0x0010 /* P */ -#define SPAMF_QUIT 0x0020 /* q */ -#define SPAMF_DCC 0x0040 /* d */ -#define SPAMF_USER 0x0080 /* u */ -#define SPAMF_AWAY 0x0100 /* a */ -#define SPAMF_TOPIC 0x0200 /* t */ +#define SPAMF_PART 0x0010 /* P */ +#define SPAMF_QUIT 0x0020 /* q */ +#define SPAMF_DCC 0x0040 /* d */ +#define SPAMF_USER 0x0080 /* u */ +#define SPAMF_AWAY 0x0100 /* a */ +#define SPAMF_TOPIC 0x0200 /* t */ +#define SPAMF_MTAG 0x0400 /* m */ /* Other flags only for function calls: */ #define SPAMFLAG_NOWARN 0x0001 diff --git a/src/aliases.c b/src/aliases.c index 860e95ba5..22f299b7d 100644 --- a/src/aliases.c +++ b/src/aliases.c @@ -66,7 +66,7 @@ void cmd_alias(Client *client, MessageTag *mtags, int parc, char *parv[], char * { if (SERVICES_NAME && (acptr = find_person(alias->nick, NULL))) { - if (alias->spamfilter && match_spamfilter(client, parv[1], SPAMF_USERMSG, alias->nick, 0, NULL)) + if (alias->spamfilter && match_spamfilter(client, parv[1], SPAMF_USERMSG, cmd, alias->nick, 0, NULL)) return; sendto_one(acptr, NULL, ":%s PRIVMSG %s@%s :%s", client->name, alias->nick, SERVICES_NAME, parv[1]); @@ -78,7 +78,7 @@ void cmd_alias(Client *client, MessageTag *mtags, int parc, char *parv[], char * { if (STATS_SERVER && (acptr = find_person(alias->nick, NULL))) { - if (alias->spamfilter && match_spamfilter(client, parv[1], SPAMF_USERMSG, alias->nick, 0, NULL)) + if (alias->spamfilter && match_spamfilter(client, parv[1], SPAMF_USERMSG, cmd, alias->nick, 0, NULL)) return; sendto_one(acptr, NULL, ":%s PRIVMSG %s@%s :%s", client->name, alias->nick, STATS_SERVER, parv[1]); @@ -90,7 +90,7 @@ void cmd_alias(Client *client, MessageTag *mtags, int parc, char *parv[], char * { if ((acptr = find_person(alias->nick, NULL))) { - if (alias->spamfilter && match_spamfilter(client, parv[1], SPAMF_USERMSG, alias->nick, 0, NULL)) + if (alias->spamfilter && match_spamfilter(client, parv[1], SPAMF_USERMSG, cmd, alias->nick, 0, NULL)) return; if (MyUser(acptr)) sendto_one(acptr, NULL, ":%s!%s@%s PRIVMSG %s :%s", client->name, @@ -112,7 +112,7 @@ void cmd_alias(Client *client, MessageTag *mtags, int parc, char *parv[], char * char *errmsg = NULL; if (can_send_to_channel(client, channel, &msg, &errmsg, 0)) { - if (alias->spamfilter && match_spamfilter(client, parv[1], SPAMF_CHANMSG, channel->chname, 0, NULL)) + if (alias->spamfilter && match_spamfilter(client, parv[1], SPAMF_CHANMSG, cmd, channel->chname, 0, NULL)) return; new_message(client, NULL, &mtags); sendto_channel(channel, client, client->direction, @@ -203,7 +203,7 @@ void cmd_alias(Client *client, MessageTag *mtags, int parc, char *parv[], char * { if (SERVICES_NAME && (acptr = find_person(format->nick, NULL))) { - if (alias->spamfilter && match_spamfilter(client, output, SPAMF_USERMSG, format->nick, 0, NULL)) + if (alias->spamfilter && match_spamfilter(client, output, SPAMF_USERMSG, cmd, format->nick, 0, NULL)) return; sendto_one(acptr, NULL, ":%s PRIVMSG %s@%s :%s", client->name, format->nick, SERVICES_NAME, output); @@ -214,7 +214,7 @@ void cmd_alias(Client *client, MessageTag *mtags, int parc, char *parv[], char * { if (STATS_SERVER && (acptr = find_person(format->nick, NULL))) { - if (alias->spamfilter && match_spamfilter(client, output, SPAMF_USERMSG, format->nick, 0, NULL)) + if (alias->spamfilter && match_spamfilter(client, output, SPAMF_USERMSG, cmd, format->nick, 0, NULL)) return; sendto_one(acptr, NULL, ":%s PRIVMSG %s@%s :%s", client->name, format->nick, STATS_SERVER, output); @@ -225,7 +225,7 @@ void cmd_alias(Client *client, MessageTag *mtags, int parc, char *parv[], char * { if ((acptr = find_person(format->nick, NULL))) { - if (alias->spamfilter && match_spamfilter(client, output, SPAMF_USERMSG, format->nick, 0, NULL)) + if (alias->spamfilter && match_spamfilter(client, output, SPAMF_USERMSG, cmd, format->nick, 0, NULL)) return; if (MyUser(acptr)) sendto_one(acptr, NULL, ":%s!%s@%s PRIVMSG %s :%s", client->name, @@ -247,7 +247,7 @@ void cmd_alias(Client *client, MessageTag *mtags, int parc, char *parv[], char * char *errmsg = NULL; if (!can_send_to_channel(client, channel, &msg, &errmsg, 0)) { - if (alias->spamfilter && match_spamfilter(client, output, SPAMF_CHANMSG, channel->chname, 0, NULL)) + if (alias->spamfilter && match_spamfilter(client, output, SPAMF_CHANMSG, cmd, channel->chname, 0, NULL)) return; new_message(client, NULL, &mtags); sendto_channel(channel, client, client->direction, diff --git a/src/api-efunctions.c b/src/api-efunctions.c index a739fb3f7..9ede41c11 100644 --- a/src/api-efunctions.c +++ b/src/api-efunctions.c @@ -67,7 +67,8 @@ void (*tkl_stats)(Client *client, int type, char *para, int *cnt); void (*tkl_sync)(Client *client); void (*cmd_tkl)(Client *client, MessageTag *mtags, int parc, char *parv[]); int (*place_host_ban)(Client *client, BanAction action, char *reason, long duration); -int (*match_spamfilter)(Client *client, char *str_in, int type, char *target, int flags, TKL **rettk); +int (*match_spamfilter)(Client *client, char *str_in, int type, char *cmd, char *target, int flags, TKL **rettk); +int (*match_spamfilter_mtags)(Client *client, MessageTag *mtags, char *cmd); int (*join_viruschan)(Client *client, TKL *tk, int type); unsigned char *(*StripColors)(unsigned char *text); const char *(*StripControlCodes)(unsigned char *text); @@ -307,6 +308,7 @@ void efunctions_init(void) efunc_init_function(EFUNC_CMD_TKL, cmd_tkl, NULL); efunc_init_function(EFUNC_PLACE_HOST_BAN, place_host_ban, NULL); efunc_init_function(EFUNC_DOSPAMFILTER, match_spamfilter, NULL); + efunc_init_function(EFUNC_MATCH_SPAMFILTER_MTAGS, match_spamfilter_mtags, NULL); efunc_init_function(EFUNC_DOSPAMFILTER_VIRUSCHAN, join_viruschan, NULL); efunc_init_function(EFUNC_STRIPCOLORS, StripColors, NULL); efunc_init_function(EFUNC_STRIPCONTROLCODES, StripControlCodes, NULL); diff --git a/src/ircd.c b/src/ircd.c index 32f307e9b..ed1e0d42b 100644 --- a/src/ircd.c +++ b/src/ircd.c @@ -370,7 +370,7 @@ int match_tkls(Client *client) if (loop.do_bancheck_spamf_away && IsUser(client) && client->user->away != NULL && - match_spamfilter(client, client->user->away, SPAMF_AWAY, NULL, SPAMFLAG_NOWARN, NULL)) + match_spamfilter(client, client->user->away, SPAMF_AWAY, "AWAY", NULL, SPAMFLAG_NOWARN, NULL)) { return 1; } diff --git a/src/misc.c b/src/misc.c index e5292f0e1..a7c1c7fb3 100644 --- a/src/misc.c +++ b/src/misc.c @@ -81,16 +81,17 @@ typedef struct { } SpamfilterTargetTable; SpamfilterTargetTable spamfiltertargettable[] = { - { SPAMF_CHANMSG, 'c', "channel", "PRIVMSG" }, - { SPAMF_USERMSG, 'p', "private", "PRIVMSG" }, + { SPAMF_CHANMSG, 'c', "channel", "PRIVMSG" }, + { SPAMF_USERMSG, 'p', "private", "PRIVMSG" }, { SPAMF_USERNOTICE, 'n', "private-notice", "NOTICE" }, { SPAMF_CHANNOTICE, 'N', "channel-notice", "NOTICE" }, - { SPAMF_PART, 'P', "part", "PART" }, - { SPAMF_QUIT, 'q', "quit", "QUIT" }, - { SPAMF_DCC, 'd', "dcc", "PRIVMSG" }, - { SPAMF_USER, 'u', "user", "NICK" }, - { SPAMF_AWAY, 'a', "away", "AWAY" }, - { SPAMF_TOPIC, 't', "topic", "TOPIC" }, + { SPAMF_PART, 'P', "part", "PART" }, + { SPAMF_QUIT, 'q', "quit", "QUIT" }, + { SPAMF_DCC, 'd', "dcc", "PRIVMSG" }, + { SPAMF_USER, 'u', "user", "NICK" }, + { SPAMF_AWAY, 'a', "away", "AWAY" }, + { SPAMF_TOPIC, 't', "topic", "TOPIC" }, + { SPAMF_MTAG, 'T', "message-tag", "message-tag" }, { 0, 0, 0, 0 } }; diff --git a/src/modules/away.c b/src/modules/away.c index 0f6cc18e4..3a741f505 100644 --- a/src/modules/away.c +++ b/src/modules/away.c @@ -86,7 +86,7 @@ CMD_FUNC(cmd_away) } /* Check spamfilters */ - if (MyUser(client) && match_spamfilter(client, new_reason, SPAMF_AWAY, NULL, 0, NULL)) + if (MyUser(client) && match_spamfilter(client, new_reason, SPAMF_AWAY, "AWAY", NULL, 0, NULL)) return; /* Check set::anti-flood::away-flood */ diff --git a/src/modules/dccdeny.c b/src/modules/dccdeny.c index 9aaf23e52..d27a9f7cd 100644 --- a/src/modules/dccdeny.c +++ b/src/modules/dccdeny.c @@ -639,7 +639,7 @@ static int can_dcc(Client *client, char *target, Client *targetcli, char *filena return 0; } - if (match_spamfilter(client, filename, SPAMF_DCC, target, 0, NULL)) + if (match_spamfilter(client, filename, SPAMF_DCC, "PRIVMSG", target, 0, NULL)) return 0; if ((fl = dcc_isforbidden(client, filename))) diff --git a/src/modules/message.c b/src/modules/message.c index 78e0c309d..e9c9c1994 100644 --- a/src/modules/message.c +++ b/src/modules/message.c @@ -117,8 +117,14 @@ int can_send_to_user(Client *client, Client *target, char **msgtext, char **errm } // Possible FIXME: make match_spamfilter also use errmsg, or via a wrapper? or use same numeric? - if (MyUser(client) && match_spamfilter(client, *msgtext, (sendtype == SEND_TYPE_NOTICE ? SPAMF_USERNOTICE : SPAMF_USERMSG), target->name, 0, NULL)) - return 0; + if (MyUser(client)) + { + int spamtype = (sendtype == SEND_TYPE_NOTICE ? SPAMF_USERNOTICE : SPAMF_USERMSG); + char *cmd = sendtype_to_cmd(sendtype); + + if (match_spamfilter(client, *msgtext, spamtype, cmd, target->name, 0, NULL)) + return 0; + } n = HOOK_CONTINUE; for (h = Hooks[HOOKTYPE_CAN_SEND_TO_USER]; h; h = h->next) @@ -379,8 +385,13 @@ void cmd_message(Client *client, MessageTag *recv_mtags, int parc, char *parv[], if ((*parv[2] == '\001') && strncmp(&parv[2][1], "ACTION ", 7)) sendflags |= SKIP_CTCP; - if (MyUser(client) && match_spamfilter(client, text, (sendtype == SEND_TYPE_NOTICE ? SPAMF_CHANNOTICE : SPAMF_CHANMSG), channel->chname, 0, NULL)) - return; + if (MyUser(client)) + { + int spamtype = (sendtype == SEND_TYPE_NOTICE ? SPAMF_USERNOTICE : SPAMF_USERMSG); + + if (match_spamfilter(client, text, spamtype, cmd, channel->chname, 0, NULL)) + return; + } new_message(client, recv_mtags, &mtags); diff --git a/src/modules/nick.c b/src/modules/nick.c index 680a8bf1b..f6364e239 100644 --- a/src/modules/nick.c +++ b/src/modules/nick.c @@ -298,7 +298,7 @@ CMD_FUNC(cmd_nick_local) { /* Local client changing nick: check spamfilter */ spamfilter_build_user_string(spamfilter_user, nick, client); - if (match_spamfilter(client, spamfilter_user, SPAMF_USER, NULL, 0, NULL)) + if (match_spamfilter(client, spamfilter_user, SPAMF_USER, "NICK", NULL, 0, NULL)) return; } @@ -883,7 +883,7 @@ int _register_user(Client *client, char *nick, char *username, char *umode, char find_shun(client); spamfilter_build_user_string(spamfilter_user, client->name, client); - if (match_spamfilter(client, spamfilter_user, SPAMF_USER, NULL, 0, &savetkl)) + if (match_spamfilter(client, spamfilter_user, SPAMF_USER, NULL, NULL, 0, &savetkl)) { if (savetkl && ((savetkl->ptr.spamfilter->action == BAN_ACT_VIRUSCHAN) || (savetkl->ptr.spamfilter->action == BAN_ACT_SOFT_VIRUSCHAN))) diff --git a/src/modules/part.c b/src/modules/part.c index efc86591f..937087a7e 100644 --- a/src/modules/part.c +++ b/src/modules/part.c @@ -89,7 +89,7 @@ CMD_FUNC(cmd_part) } if (commentx) { - if (match_spamfilter(client, commentx, SPAMF_PART, parv[1], 0, NULL)) + if (match_spamfilter(client, commentx, SPAMF_PART, "PART", parv[1], 0, NULL)) commentx = NULL; if (IsDead(client)) return; diff --git a/src/modules/quit.c b/src/modules/quit.c index 7af7a5250..8c59821a1 100644 --- a/src/modules/quit.c +++ b/src/modules/quit.c @@ -82,7 +82,7 @@ CMD_FUNC(cmd_quit) return; } - if (match_spamfilter(client, comment, SPAMF_QUIT, NULL, 0, NULL)) + if (match_spamfilter(client, comment, SPAMF_QUIT, "QUIT", NULL, 0, NULL)) { comment = client->name; if (IsDead(client)) diff --git a/src/modules/setname.c b/src/modules/setname.c index eb75a6be8..85ab9c3e5 100644 --- a/src/modules/setname.c +++ b/src/modules/setname.c @@ -89,7 +89,7 @@ CMD_FUNC(cmd_setname) /* set the new name before we check, but don't send to servers unless it is ok */ strcpy(client->info, parv[1]); spamfilter_build_user_string(spamfilter_user, client->name, client); - if (match_spamfilter(client, spamfilter_user, SPAMF_USER, NULL, 0, NULL)) + if (match_spamfilter(client, spamfilter_user, SPAMF_USER, "SETNAME", NULL, 0, NULL)) { /* Was rejected by spamfilter, restore the realname */ strcpy(client->info, tmpinfo); diff --git a/src/modules/tkl.c b/src/modules/tkl.c index 94ee581a4..ff1cc93c0 100644 --- a/src/modules/tkl.c +++ b/src/modules/tkl.c @@ -82,7 +82,9 @@ void _tkl_stats(Client *client, int type, char *para, int *cnt); void _tkl_sync(Client *client); CMD_FUNC(_cmd_tkl); int _place_host_ban(Client *client, BanAction action, char *reason, long duration); -int _match_spamfilter(Client *client, char *str_in, int type, char *target, int flags, TKL **rettk); +int _match_spamfilter(Client *client, char *str_in, int type, char *cmd, char *target, int flags, TKL **rettk); +int _match_spamfilter_mtags(Client *client, MessageTag *mtags, char *cmd); +int check_mtag_spamfilters_present(void); int _join_viruschan(Client *client, TKL *tk, int type); void _spamfilter_build_user_string(char *buf, char *nick, Client *client); int _match_user(char *rmask, Client *client, int options); @@ -146,6 +148,7 @@ TKLTypeTable tkl_types[] = { #define ALL_VALID_EXCEPTION_TYPES "kline, gline, zline, gzline, spamfilter, shun, qline, blacklist, connect-flood, handshake-data-flood, antirandom, antimixedutf8, ban-version" int max_stats_matches = 1000; +int mtag_spamfilters_present = 0; /**< Are any spamfilters with type SPAMF_MTAG present? */ MOD_TEST() { @@ -179,6 +182,7 @@ MOD_TEST() EfunctionAddVoid(modinfo->handle, EFUNC_CMD_TKL, _cmd_tkl); EfunctionAdd(modinfo->handle, EFUNC_PLACE_HOST_BAN, _place_host_ban); EfunctionAdd(modinfo->handle, EFUNC_DOSPAMFILTER, _match_spamfilter); + EfunctionAdd(modinfo->handle, EFUNC_MATCH_SPAMFILTER_MTAGS, _match_spamfilter_mtags); EfunctionAdd(modinfo->handle, EFUNC_DOSPAMFILTER_VIRUSCHAN, _join_viruschan); EfunctionAddVoid(modinfo->handle, EFUNC_SPAMFILTER_BUILD_USER_STRING, _spamfilter_build_user_string); EfunctionAdd(modinfo->handle, EFUNC_MATCH_USER, _match_user); @@ -213,6 +217,7 @@ MOD_INIT() MOD_LOAD() { + check_mtag_spamfilters_present(); EventAdd(modinfo->handle, "tklexpire", tkl_check_expire, NULL, 5000, 0); return MOD_SUCCESS; } @@ -2383,6 +2388,9 @@ TKL *_tkl_add_spamfilter(int type, unsigned short target, BanAction action, Matc index = tkl_hash(tkl_typetochar(type)); AddListItem(tkl, tklines[index]); + if (target & SPAMF_MTAG) + mtag_spamfilters_present = 1; + return tkl; } @@ -2653,6 +2661,7 @@ void _tkl_del_line(TKL *tkl) /* Finally, free the entry */ free_tkl(tkl); + check_mtag_spamfilters_present(); } /** Add some default ban exceptions - for localhost */ @@ -3130,7 +3139,7 @@ int _find_spamfilter_user(Client *client, int flags) return 0; spamfilter_build_user_string(spamfilter_user, client->name, client); - return match_spamfilter(client, spamfilter_user, SPAMF_USER, NULL, flags, NULL); + return match_spamfilter(client, spamfilter_user, SPAMF_USER, NULL, NULL, flags, NULL); } /** Check a spamfilter against all local users and print a message. @@ -4670,6 +4679,7 @@ int _join_viruschan(Client *client, TKL *tkl, int type) /** match_spamfilter: executes the spamfilter on the input string. * @param str The text (eg msg text, notice text, part text, quit text, etc * @param target The spamfilter target (SPAMF_*) + * @param cmd The command (eg: "PRIVMSG") * @param destination The destination as a text string (eg: "somenick", can be NULL.. eg for away) * @param flags Any flags (SPAMFLAG_*) * @param rettkl Pointer to an aTKLline struct, _used for special circumstances only_ @@ -4677,7 +4687,7 @@ int _join_viruschan(Client *client, TKL *tkl, int type) * 1 if spamfilter matched and it should be blocked (or client exited), 0 if not matched. * In case of 1, be sure to check IsDead(client).. */ -int _match_spamfilter(Client *client, char *str_in, int target, char *destination, int flags, TKL **rettkl) +int _match_spamfilter(Client *client, char *str_in, int target, char *cmd, char *destination, int flags, TKL **rettkl) { TKL *tkl; TKL *winner_tkl = NULL; @@ -4692,6 +4702,9 @@ int _match_spamfilter(Client *client, char *str_in, int target, char *destinatio if (rettkl) *rettkl = NULL; /* initialize to NULL */ + if (!cmd) + cmd = cmdname_by_spamftarget(target); + if (target == SPAMF_USER) str = str_in; else @@ -4771,7 +4784,7 @@ int _match_spamfilter(Client *client, char *str_in, int target, char *destinatio ircsnprintf(buf, sizeof(buf), "[Spamfilter] %s!%s@%s matches filter '%s': [%s%s: '%s'] [%s]", client->name, client->user->username, client->user->realhost, tkl->ptr.spamfilter->match->str, - cmdname_by_spamftarget(target), destinationbuf, str, + cmd, destinationbuf, str, unreal_decodespace(tkl->ptr.spamfilter->tkl_reason)); sendto_snomask_global(SNO_SPAMF, "%s", buf); @@ -4823,6 +4836,12 @@ int _match_spamfilter(Client *client, char *str_in, int target, char *destinatio me.name, client->name, destination, reason); break; } + case SPAMF_MTAG: + { + sendnumericfmt(client, ERR_CANNOTDOCOMMAND, "%s :Command blocked: %s", + cmd, reason); + break; + } case SPAMF_DCC: { char errmsg[512]; @@ -4853,7 +4872,7 @@ int _match_spamfilter(Client *client, char *str_in, int target, char *destinatio if ((tkl->ptr.spamfilter->action == BAN_ACT_WARN) || (tkl->ptr.spamfilter->action == BAN_ACT_SOFT_WARN)) { if ((target != SPAMF_USER) && (target != SPAMF_QUIT)) - sendnumeric(client, RPL_SPAMCMDFWD, cmdname_by_spamftarget(target), reason); + sendnumeric(client, RPL_SPAMCMDFWD, cmd, reason); return 0; } else if ((tkl->ptr.spamfilter->action == BAN_ACT_DCCBLOCK) || (tkl->ptr.spamfilter->action == BAN_ACT_SOFT_DCCBLOCK)) @@ -4891,6 +4910,60 @@ int _match_spamfilter(Client *client, char *str_in, int target, char *destinatio return 0; /* NOTREACHED */ } +/** Check message-tag spamfilters. + * @param client The client + * @param mtags Message tags sent by client + * @param cmd Command to be executed (can be NULL) + * @retval Return 1 to stop processing the command (ignore it) or 0 to allow/continue as normal + */ +int _match_spamfilter_mtags(Client *client, MessageTag *mtags, char *cmd) +{ + MessageTag *m; + char buf[4096]; + char *str; + + /* This is a shortcut: if there are no spamfilters present + * on message tags then we can return immediately. + * Saves a lot of CPU and it is quite likely too! + */ + if (mtag_spamfilters_present == 0) + return 0; + + for (m = mtags; m; m = m->next) + { + if (m->value) + { + snprintf(buf, sizeof(buf), "%s=%s", m->name, m->value); + str = buf; + } else { + str = m->name; + } + if (match_spamfilter(client, str, SPAMF_MTAG, cmd, NULL, 0, NULL)) + return 1; + } + return 0; +} + +/** Updates 'mtag_spamfilters_present' based on if any spamfilters + * are present with the SPAMF_MTAG target. + */ +int check_mtag_spamfilters_present(void) +{ + TKL *tkl; + + for (tkl = tklines[tkl_hash('F')]; tkl; tkl = tkl->next) + { + if (tkl->ptr.spamfilter->target & SPAMF_MTAG) + { + mtag_spamfilters_present = 1; + return 1; + } + } + + mtag_spamfilters_present = 0; + return 0; +} + /** CIDR function to compare the first 'mask' bits. * @author Taken from atheme * @returns 1 if equal, 0 if not. diff --git a/src/modules/topic.c b/src/modules/topic.c index 2aa170834..309de5d6d 100644 --- a/src/modules/topic.c +++ b/src/modules/topic.c @@ -242,7 +242,7 @@ CMD_FUNC(cmd_topic) Hook *tmphook; int n; - if (match_spamfilter(client, topic, SPAMF_TOPIC, channel->chname, 0, NULL)) + if (match_spamfilter(client, topic, SPAMF_TOPIC, "TOPIC", channel->chname, 0, NULL)) return; for (tmphook = Hooks[HOOKTYPE_PRE_LOCAL_TOPIC]; tmphook; tmphook = tmphook->next) { diff --git a/src/parse.c b/src/parse.c index 717ce1294..696695870 100644 --- a/src/parse.c +++ b/src/parse.c @@ -485,6 +485,11 @@ static void parse2(Client *cptr, Client **fromptr, MessageTag *mtags, char *ch) } } para[++i] = NULL; + + /* Check if one of the message tags are rejected by spamfilter */ + if (MyConnect(from) && !IsServer(from) && match_spamfilter_mtags(from, mtags, cmptr ? cmptr->cmd : NULL)) + return; + if (cmptr == NULL) { do_numeric(numeric, from, mtags, i, para); @@ -494,6 +499,7 @@ static void parse2(Client *cptr, Client **fromptr, MessageTag *mtags, char *ch) if (IsUser(cptr) && (cmptr->flags & CMD_RESETIDLE)) cptr->local->last = TStime(); + /* Now ready to execute the command */ #ifndef DEBUGMODE if (cmptr->flags & CMD_ALIAS) {