commit 49ab79d0e64c73d575dfe87edce40637b8f2adef from: Alexander Barton date: Mon Jan 04 21:15:46 2016 UTC Limit the number of message targes, and suppress duplicates This prevents an user from flooding the server using commands like this: PRIVMSG nick1,nick1,nick1,... Duplicate targets are suppressed silently (channels and clients). In addition, the maximum number of targets per PRIVMSG/NOTICE/... command are limited to MAX_HNDL_TARGETS (25). If there are more, the daemon sends the new 407 (ERR_TOOMANYTARGETS_MSG) numeric, containing the first target that hasn't been handled any more. Closes #187. commit - cedba36965c3b89a5ab7222764bd751fd7fc88bf commit + 49ab79d0e64c73d575dfe87edce40637b8f2adef blob - ff849bbeacb2b157c1a747b6a3f0783bafe612b5 blob + 6bea174e2d46725bd36284973e4a6d630d94e810 --- src/ngircd/defines.h +++ src/ngircd/defines.h @@ -206,6 +206,9 @@ /** Max. number of channel modes with arguments per MODE command. */ #define MAX_HNDL_MODES_ARG 5 +/** Max. number of targets per PRIVMSG/NOTICE/... command. */ +#define MAX_HNDL_TARGETS 25 + /** Max. number of WHO replies. */ #define MAX_RPL_WHO 25 blob - bd741cbbad732df693a235ed17d3a6c89c7cd03c blob + 15bb90f73ced63e4d7134d5f49b56fb893debd2a --- src/ngircd/irc.c +++ src/ngircd/irc.c @@ -517,8 +517,10 @@ Send_Message(CLIENT * Client, REQUEST * Req, int Force CL2CHAN *cl2chan; CHANNEL *chan; char *currentTarget = Req->argv[0]; - char *lastCurrentTarget = NULL; + char *strtok_last = NULL; char *message = NULL; + char *targets[MAX_HNDL_TARGETS]; + int i, target_nr = 0; assert(Client != NULL); assert(Req != NULL); @@ -558,10 +560,17 @@ Send_Message(CLIENT * Client, REQUEST * Req, int Force message = Req->argv[1]; /* handle msgtarget = msgto *("," msgto) */ - currentTarget = strtok_r(currentTarget, ",", &lastCurrentTarget); + currentTarget = strtok_r(currentTarget, ",", &strtok_last); ngt_UpperStr(Req->command); - while (currentTarget) { + while (true) { + /* Make sure that there hasn't been such a target already: */ + targets[target_nr++] = currentTarget; + for(i = 0; i < target_nr - 1; i++) { + if (strcasecmp(currentTarget, targets[i]) == 0) + goto send_next_target; + } + /* Check for and handle valid of form: * RFC 2812 2.3.1: * msgto = channel / ( user [ "%" host ] "@" servername ) @@ -725,9 +734,18 @@ Send_Message(CLIENT * Client, REQUEST * Req, int Force } send_next_target: - currentTarget = strtok_r(NULL, ",", &lastCurrentTarget); - if (currentTarget) - Conn_SetPenalty(Client_Conn(Client), 1); + currentTarget = strtok_r(NULL, ",", &strtok_last); + if (!currentTarget) + break; + + Conn_SetPenalty(Client_Conn(Client), 1); + + if (target_nr >= MAX_HNDL_TARGETS) { + /* Too many targets given! */ + return IRC_WriteErrClient(Client, + ERR_TOOMANYTARGETS_MSG, + currentTarget); + } } return CONNECTED; blob - 818d83b9e594102fc46ed01b1b79452b1533c057 blob + 90292a2b3aae492020b77c7e6b68a7e61a09a7f3 --- src/ngircd/messages.h +++ src/ngircd/messages.h @@ -110,6 +110,7 @@ #define ERR_CANNOTSENDTOCHAN_MSG "404 %s %s :Cannot send to channel" #define ERR_TOOMANYCHANNELS_MSG "405 %s %s :You have joined too many channels" #define ERR_WASNOSUCHNICK_MSG "406 %s %s :There was no such nickname" +#define ERR_TOOMANYTARGETS_MSG "407 %s :Too many recipients" #define ERR_NOORIGIN_MSG "409 %s :No origin specified" #define ERR_INVALIDCAP_MSG "410 %s %s :Invalid CAP subcommand" #define ERR_NORECIPIENT_MSG "411 %s :No recipient given (%s)" blob - 5dc325ded807cd68807c8d05dc54a31451394cf0 blob + e46378637b8c2ff44df43a85d13911484809eeec --- src/testsuite/message-test.e +++ src/testsuite/message-test.e @@ -35,13 +35,13 @@ expect { send "privmsg nick,nick :test\r" expect { timeout { exit 1 } - "@* PRIVMSG nick :test\r*@* PRIVMSG nick :test" + "@* PRIVMSG nick :test" } send "privmsg Nick,#testChannel,nick :test\r" expect { timeout { exit 1 } - "@* PRIVMSG nick :test\r*401*@* PRIVMSG nick :test" + "@* PRIVMSG nick :test\r*401" } send "privmsg doesnotexist :test\r"