summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAlexander Barton <alex@barton.de>2016-01-04 22:11:47 +0100
committerAlexander Barton <alex@barton.de>2016-01-04 22:15:46 +0100
commit49ab79d0e64c73d575dfe87edce40637b8f2adef (patch)
tree38b1712ada276efa8f659331a643bea71a532791 /src
parentcedba36965c3b89a5ab7222764bd751fd7fc88bf (diff)
downloadngircd-49ab79d0e64c73d575dfe87edce40637b8f2adef.tar.gz
ngircd-49ab79d0e64c73d575dfe87edce40637b8f2adef.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/ngircd/defines.h3
-rw-r--r--src/ngircd/irc.c30
-rw-r--r--src/ngircd/messages.h1
-rw-r--r--src/testsuite/message-test.e4
4 files changed, 30 insertions, 8 deletions
diff --git a/src/ngircd/defines.h b/src/ngircd/defines.h
index ff849bbe..6bea174e 100644
--- a/src/ngircd/defines.h
+++ b/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
 
diff --git a/src/ngircd/irc.c b/src/ngircd/irc.c
index bd741cbb..15bb90f7 100644
--- a/src/ngircd/irc.c
+++ b/src/ngircd/irc.c
@@ -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;
diff --git a/src/ngircd/messages.h b/src/ngircd/messages.h
index 818d83b9..90292a2b 100644
--- a/src/ngircd/messages.h
+++ b/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)"
diff --git a/src/testsuite/message-test.e b/src/testsuite/message-test.e
index 5dc325de..e4637863 100644
--- a/src/testsuite/message-test.e
+++ b/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"