diff --git a/CHANGES b/CHANGES index 54d5a5db68..06bf808292 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,8 @@ +2.4-278 | 2016-02-12 18:53:35 -0800 + + * Better multi-space separator handline. (Mark Taylor & Johanna Amann) + 2.4-276 | 2016-02-10 21:29:33 -0800 * Allow IRC commands to not have parameters. (Mark Taylor) diff --git a/VERSION b/VERSION index 834f974518..45f7a1f8c1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.4-276 +2.4-278 diff --git a/src/analyzer/protocol/irc/IRC.cc b/src/analyzer/protocol/irc/IRC.cc index 0a32588783..18426c0f7c 100644 --- a/src/analyzer/protocol/irc/IRC.cc +++ b/src/analyzer/protocol/irc/IRC.cc @@ -32,6 +32,15 @@ void IRC_Analyzer::Done() tcp::TCP_ApplicationAnalyzer::Done(); } +inline void IRC_Analyzer::SkipLeadingWhitespace(string& str) + { + const auto first_char = str.find_first_not_of(" "); + if ( first_char == string::npos ) + str = ""; + else + str = str.substr(first_char); + } + void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) { tcp::TCP_ApplicationAnalyzer::DeliverStream(length, line, orig); @@ -49,20 +58,21 @@ void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) return; } - if ( length < 2 ) + string myline = string((const char*) line, length); + SkipLeadingWhitespace(myline); + + if ( myline.length() < 3 ) { Weird("irc_line_too_short"); return; } - string myline = string((const char*) line, length); - // Check for prefix. string prefix = ""; - if ( line[0] == ':' ) + if ( myline[0] == ':' ) { // find end of prefix and extract it - unsigned int pos = myline.find(' '); - if ( pos > (unsigned int) length ) + auto pos = myline.find(' '); + if ( pos == string::npos ) { Weird("irc_invalid_line"); return; @@ -70,9 +80,9 @@ void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) prefix = myline.substr(1, pos - 1); myline = myline.substr(pos + 1); // remove prefix from line + SkipLeadingWhitespace(myline); } - if ( orig ) ProtocolConfirmation(); @@ -80,7 +90,8 @@ void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) string command = ""; // Check if line is long enough to include status code or command. - if ( myline.size() < 4 ) + // (shortest command with optional params is "WHO") + if ( myline.length() < 3 ) { Weird("irc_invalid_line"); ProtocolViolation("line too short"); @@ -106,20 +117,21 @@ void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) } else { // get command - unsigned int pos = myline.find(' '); + auto pos = myline.find(' '); // Not all commands require parameters - if ( pos > (unsigned int) length ) - pos = (unsigned int) length; + if ( pos == string::npos ) + pos = myline.length(); command = myline.substr(0, pos); for ( unsigned int i = 0; i < command.size(); ++i ) command[i] = toupper(command[i]); // Adjust for the no-parameter case - if ( pos == (unsigned int) length ) + if ( pos == myline.length() ) pos--; myline = myline.substr(pos + 1); + SkipLeadingWhitespace(myline); } // Extract parameters. @@ -149,7 +161,7 @@ void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) // // (### This seems not quite prudent to me - VP) if ( command == "SERVER" && prefix == "") - { + { orig_status = REGISTERED; } } @@ -157,7 +169,7 @@ void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) if ( ! orig && resp_status == WAIT_FOR_REGISTRATION ) { if ( command == "PASS" ) - { + { vector p = SplitWords(params,' '); if ( p.size() > 3 && (p[3].find('Z')<=p[3].size() || @@ -615,6 +627,7 @@ void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) string target = params.substr(0, pos); string message = params.substr(pos + 1); + SkipLeadingWhitespace(message); if ( message.size() > 0 && message[0] == ':' ) message = message.substr(1); @@ -689,6 +702,7 @@ void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) string target = params.substr(0, pos); string message = params.substr(pos + 1); + SkipLeadingWhitespace(message); if ( message[0] == ':' ) message = message.substr(1); @@ -713,6 +727,7 @@ void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) string target = params.substr(0, pos); string message = params.substr(pos + 1); + SkipLeadingWhitespace(message); if ( message[0] == ':' ) message = message.substr(1); @@ -938,7 +953,10 @@ void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) { channels = params.substr(0, pos); if ( params.size() > pos + 1 ) + { message = params.substr(pos + 1); + SkipLeadingWhitespace(message); + } if ( message[0] == ':' ) message = message.substr(1); } @@ -1009,7 +1027,7 @@ void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) else if ( irc_who_message && command == "WHO" ) { vector parts = SplitWords(params, ' '); - if ( parts.size() < 1 || parts.size() > 2 ) + if ( parts.size() > 2 ) { Weird("irc_invalid_who_message_format"); return; @@ -1020,13 +1038,16 @@ void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) oper = true; // Remove ":" from mask. - if ( parts[0].size() > 0 && parts[0][0] == ':' ) + if ( parts.size() > 0 && parts[0].size() > 0 && parts[0][0] == ':' ) parts[0] = parts[0].substr(1); val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); - vl->append(new StringVal(parts[0].c_str())); + if ( parts.size() > 0 ) + vl->append(new StringVal(parts[0].c_str())); + else + vl->append(new StringVal("")); vl->append(new Val(oper, TYPE_BOOL)); ConnectionEvent(irc_who_message, vl); @@ -1131,6 +1152,7 @@ void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) { server = params.substr(0, pos); message = params.substr(pos + 1); + SkipLeadingWhitespace(message); if ( message[0] == ':' ) message = message.substr(1); } diff --git a/src/analyzer/protocol/irc/IRC.h b/src/analyzer/protocol/irc/IRC.h index 82a97a4d4d..497225846d 100644 --- a/src/analyzer/protocol/irc/IRC.h +++ b/src/analyzer/protocol/irc/IRC.h @@ -22,7 +22,7 @@ public: /** * \brief Called when connection is closed. */ - virtual void Done(); + void Done() override; /** * \brief New input line in network stream. @@ -31,7 +31,7 @@ public: * \param data pointer to line start * \param orig was this data sent from connection originator? */ - virtual void DeliverStream(int len, const u_char* data, bool orig); + void DeliverStream(int len, const u_char* data, bool orig) override; static analyzer::Analyzer* Instantiate(Connection* conn) { @@ -47,6 +47,8 @@ protected: private: void StartTLS(); + inline void SkipLeadingWhitespace(string& str); + /** \brief counts number of invalid IRC messages */ int invalid_msg_count; diff --git a/testing/btest/Baseline/scripts.base.protocols.irc.events/out b/testing/btest/Baseline/scripts.base.protocols.irc.events/.stdout similarity index 50% rename from testing/btest/Baseline/scripts.base.protocols.irc.events/out rename to testing/btest/Baseline/scripts.base.protocols.irc.events/.stdout index 8ec1e7f95d..bc5df852c2 100644 --- a/testing/btest/Baseline/scripts.base.protocols.irc.events/out +++ b/testing/btest/Baseline/scripts.base.protocols.irc.events/.stdout @@ -11,21 +11,10 @@ thenagualII!~affreujoj@THENAGUAL.users.undernet.org -> #easymovies: \x0304,00DVD -> ladyvampress: list -> #easymovies: @ladyvampress gordon1`^!~allu0002@gordon2411.users.undernet.org -> #easymovies: \x0308\x02File Server Online\x02 \x0303Triggers:\xab\x0308\x0308/ctcp gordon1`^ /ctcp gordon1`^ /CTCP gordon1`^ Movies Galore\x0303\xbb Sends:\xab\x03081/30\x0303\xbb Queues:\xab\x03080/30\x0303\xbb Accessed:\xab\x03082556 times\x0303\xbb Online:\xab\x03080/4\x0303\xbb RCPS:\xab\x0308193.8 Kbs by MadDingo\x0303\xbb Served:\xab\x03081.14TB in 1118 files\x0303\xbb Current BW:\xab\x030818.7 Kbs\x0303\xbb AQT:\xab\x0308No Wait\x0303\xbb \x0f\x0303\x97\x0314I\x0303-\x0315n\x0303-\x0315v\x0303-\x0300i\x0303-\x0300s\x0303-\x0315i\x0303-\x0315o\x0303-\x0314n\x0303\x97\x0f -quit: () -thenagualII!~affreujoj@THENAGUAL.users.undernet.org -> #easymovies: \x02TDCC Server Online\x02 Desc:\xc2\xabjet li fong sai yuk 2 vostfr\xc2\xbb Trigger:\xc2\xabtrigger1\xc2\xbb Size:\xc2\xab699MB\xc2\xbb Sends:\xc2\xab0/2\xc2\xbb Queues:\xc2\xab0/10\xc2\xbb Record CPS:\xc2\xab0 cps by n/a\xc2\xbb Downloads:\xc2\xab0\xc2\xbb \x0f\x97I-n-v-i-s-i-o-n\x97 -thenagualII!~affreujoj@THENAGUAL.users.undernet.org -> #easymovies: \x02TDCC Server Online\x02 Desc:\xc2\xabarturo.brachetti.l.homme.aux.mille.songes.avi\xc2\xbb Trigger:\xc2\xabtriggerII\xc2\xbb Size:\xc2\xab698MB\xc2\xbb Sends:\xc2\xab0/2\xc2\xbb Queues:\xc2\xab0/10\xc2\xbb Record CPS:\xc2\xab0 cps by n/a\xc2\xbb Downloads:\xc2\xab0\xc2\xbb \x0f\x97I-n-v-i-s-i-o-n\x97 -thenagualII!~affreujoj@THENAGUAL.users.undernet.org -> #easymovies: \x02TDCC Server Online\x02 Desc:\xc2\xabnational geographic les hackers.avi\xc2\xbb Trigger:\xc2\xab!tdcc-3\xc2\xbb Size:\xc2\xab693MB\xc2\xbb Sends:\xc2\xab0/2\xc2\xbb Queues:\xc2\xab0/10\xc2\xbb Record CPS:\xc2\xab0 cps by n/a\xc2\xbb Downloads:\xc2\xab0\xc2\xbb \x0f\x97I-n-v-i-s-i-o-n\x97 -i-am-mojo!~morgana1@mojojo.users.undernet.org -> #easymovies: \x0308,01 Movies and music updated on the weekends........ \x0304,01Type:\x0308,01 @i-am-mojo \x0304,01For My List Of:\x0308,01 5,307 \x0304,01Files \x0302,01~ \x0304,01Slots:\x0308,01 3/4 \x0302,01~ \x0304,01Queued:\x0308,01 0 \x0302,01~ \x0304,01Speed:\x0308,01 26,007cps \x0302,01~ \x0304,01Next: \x0308,01NOW \x0302,01~ \x0304,01Served:\x0308,01 1,403 \x0302,01~ \x0304,01List: \x0308,01Jul 17th \x0302,01~ \x0304,01Search: \x0308,01ON \x0302,01~ \x0304,01Mode: \x0308,01Normal \x0302,01~ -i-am-mojo!~morgana1@mojojo.users.undernet.org -> #easymovies: SLOTS 4 3 NOW 0 999 64627 5307 341063215095 0 1310935138 105421 OmeNServE v2.51\x01 -ladyvampress!~who_cares@ladyvampress.users.undernet.org -> #easymovies: \x0313,01 \x0313,1Movies and Assorted TV shows \x0315,01Type:\x0313,01 @ladyvampress \x0315,01For My List Of:\x0313,01 3,311 \x0315,01Files \x0314,01- \x0315,01Slots:\x0313,01 0/2 \x0314,01- \x0315,01Queued:\x0313,01 8 \x0314,01- \x0315,01Speed:\x0313,01 79,921cps \x0314,01- \x0315,01Next: \x0313,0192m \x0314,01- \x0315,01Served:\x0313,01 6,990 \x0314,01- \x0315,01List: \x0313,01Jul 7th \x0314,01- \x0315,01Search: \x0313,01ON \x0314,01- \x0315,01Mode: \x0313,01Normal \x0314,01- - -> thenagualII: trigger1 -ladyvampress!~who_cares@ladyvampress.users.undernet.org -> #easymovies: SLOTS 2 0 92m 8 999 79921 3311 2111443703336 0 1310040328 107209 OmeNServE v2.52\x01 -zEmm!ExUser@zem122.users.undernet.org -> #easymovies: \x0308\xab\xab \x0307Server\x0308 \xbb\xbb \x0304Trigger\x0308~[\x0307/ctcp zEmm !!bizzniches!!\x0308]~ \x0304Used\x0308~[\x03070 cps\x0308]~ \x0304Next.Send\x0308~[\x0307Open\x0308]~ \x0304Stole\x0308~[\x0307142.93Gb in 143 files\x0308]~ \x0304Record\x0308~[\x0307174.2Kb/s by Pontius\x0308]~ \x0304Sends\x0308~[\x03070/2\x0308]~ \x0304Queues\x0308~[\x03070/10\x0308]~ \x0304Entered\x0308~[\x0307565 times\x0308]~ \x0304Note\x0308~[\x0307get the new...\x0308]~ \x0308\x02\xab\x02 \x0304\xcb\xd7\xc7\x0308\xfc\x0304\xae\xa7\xee\xf6\xf1 \x0308\x02\xbb\x02 -thenagualII!~affreujoj@THENAGUAL.users.undernet.org -> #easymovies: \x0304,00DVD DIVX ASS APPZ DOCU PHOTOS\x0314,00\x95 \x0301,00Type:\x0304,00 @thenagualII \x0301,00For My List Of:\x0304,00 69,157 \x0301,00Files \x0314,00\x95 \x0301,00Slots:\x0304,00 15/15 \x0314,00\x95 \x0301,00Queued:\x0304,00 0 \x0314,00\x95 \x0301,00Speed:\x0304,00 0cps \x0314,00\x95 \x0301,00Next: \x0304,00NOW \x0314,00\x95 \x0301,00Served:\x0304,00 853 \x0314,00\x95 \x0301,00List: \x0304,00Jul 19th \x0314,00\x95 \x0301,00Search: \x0304,00OFF \x0314,00\x95 \x0301,00Mode: \x0304,00Normal \x0314,00\x95 - -> ladyvampress: list - -> #easymovies: @ladyvampress -gordon1`^!~allu0002@gordon2411.users.undernet.org -> #easymovies: \x0308\x02File Server Online\x02 \x0303Triggers:\xab\x0308\x0308/ctcp gordon1`^ /ctcp gordon1`^ /CTCP gordon1`^ Movies Galore\x0303\xbb Sends:\xab\x03081/30\x0303\xbb Queues:\xab\x03080/30\x0303\xbb Accessed:\xab\x03082556 times\x0303\xbb Online:\xab\x03080/4\x0303\xbb RCPS:\xab\x0308193.8 Kbs by MadDingo\x0303\xbb Served:\xab\x03081.14TB in 1118 files\x0303\xbb Current BW:\xab\x030818.7 Kbs\x0303\xbb AQT:\xab\x0308No Wait\x0303\xbb \x0f\x0303\x97\x0314I\x0303-\x0315n\x0303-\x0315v\x0303-\x0300i\x0303-\x0300s\x0303-\x0315i\x0303-\x0315o\x0303-\x0314n\x0303\x97\x0f quit: () -> #brotest: test quit: (quitting) quit: brotest (Client Quit) + -> #BROTEST: test +quit: (quitting) +quit: brotest (Client Quit) diff --git a/testing/btest/Traces/irc-whitespace.trace b/testing/btest/Traces/irc-whitespace.trace new file mode 100644 index 0000000000..a99af06b5e Binary files /dev/null and b/testing/btest/Traces/irc-whitespace.trace differ diff --git a/testing/btest/scripts/base/protocols/irc/events.test b/testing/btest/scripts/base/protocols/irc/events.test index 0ca6c4020b..c5220b247b 100644 --- a/testing/btest/scripts/base/protocols/irc/events.test +++ b/testing/btest/scripts/base/protocols/irc/events.test @@ -1,10 +1,9 @@ # Test IRC events # @TEST-EXEC: bro -r $TRACES/irc-dcc-send.trace %INPUT -# @TEST-EXEC: cp .stdout out # @TEST-EXEC: bro -r $TRACES/irc-basic.trace %INPUT -# @TEST-EXEC: cat .stdout >>out -# @TEST-EXEC: btest-diff out +# @TEST-EXEC: bro -r $TRACES/irc-whitespace.trace %INPUT +# @TEST-EXEC: btest-diff .stdout event irc_privmsg_message(c: connection, is_orig: bool, source: string, target: string, message: string) {