Limit the number of message targes, and suppress duplicates
authorAlexander Barton <alex@barton.de>
Mon, 4 Jan 2016 21:11:47 +0000 (22:11 +0100)
committerAlexander Barton <alex@barton.de>
Mon, 4 Jan 2016 21:15:46 +0000 (22:15 +0100)
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.

src/ngircd/defines.h
src/ngircd/irc.c
src/ngircd/messages.h
src/testsuite/message-test.e

index ff849bb..6bea174 100644 (file)
 /** 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
 
index bd741cb..15bb90f 100644 (file)
@@ -517,8 +517,10 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors)
        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 ForceType, bool SendErrors)
                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 <msgto> of form:
                 * RFC 2812 2.3.1:
                 *   msgto =  channel / ( user [ "%" host ] "@" servername )
@@ -725,9 +734,18 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors)
                }
 
        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;
index 818d83b..90292a2 100644 (file)
 #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)"
index 5dc325d..e463786 100644 (file)
@@ -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"