diff --git a/src/analyzer/protocol/irc/IRC.cc b/src/analyzer/protocol/irc/IRC.cc index a0b36b6c4b..ae9e446512 100644 --- a/src/analyzer/protocol/irc/IRC.cc +++ b/src/analyzer/protocol/irc/IRC.cc @@ -5,6 +5,7 @@ #include "zeek/analyzer/protocol/irc/IRC.h" #include +#include #include "zeek/Event.h" #include "zeek/NetVar.h" @@ -42,6 +43,18 @@ inline void IRC_Analyzer::SkipLeadingWhitespace(string& str) { str = str.substr(first_char); } +bool IRC_Analyzer::IsValidClientCommand(const std::string& command) { + static const std::unordered_set validCommands = + {"ADMIN", "AWAY", "CNOTICE", "CPRIVMSG", "CONNECT", "DIE", "ENCAP", "ERROR", "INFO", + "INVITE", "ISON", "JOIN", "KICK", "KILL", "KNOCK", "LINKS", "LIST", "LUSERS", + "MODE", "MOTD", "NAMES", "NICK", "NOTICE", "OPER", "PART", "PASS", "PING", + "PONG", "PRIVMSG", "QUIT", "REHASH", "RULES", "SERVER", "SERVICE", "SERVLIST", "SERVER", + "SETNAME", "SILENCE", "SQUERY", "SQUIT", "STATS", "SUMMON", "TIME", "TOPIC", "TRACE", + "USER", "USERHOST", "USERS", "VERSION", "WALLOPS", "WHO", "WHOIS", "WHOWAS", "STARTTLS"}; + + return validCommands.find(command) != validCommands.end(); +} + void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) { static auto irc_join_list = id::find_type("irc_join_list"); static auto irc_join_info = id::find_type("irc_join_info"); @@ -54,7 +67,8 @@ void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) { // check line size if ( length > 512 ) { - Weird("irc_line_size_exceeded"); + if ( AnalyzerConfirmed() ) + Weird("irc_line_size_exceeded"); return; } @@ -62,7 +76,8 @@ void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) { SkipLeadingWhitespace(myline); if ( myline.length() < 3 ) { - Weird("irc_line_too_short"); + if ( AnalyzerConfirmed() ) + Weird("irc_line_too_short"); return; } @@ -71,7 +86,8 @@ void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) { if ( myline[0] == ':' ) { // find end of prefix and extract it auto pos = myline.find(' '); if ( pos == string::npos ) { - Weird("irc_invalid_line"); + if ( AnalyzerConfirmed() ) + Weird("irc_invalid_line"); return; } @@ -80,16 +96,14 @@ void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) { SkipLeadingWhitespace(myline); } - if ( orig ) - AnalyzerConfirmation(); - int code = 0; string command = ""; // Check if line is long enough to include status code or command. // (shortest command with optional params is "WHO") if ( myline.length() < 3 ) { - Weird("irc_invalid_line"); + if ( AnalyzerConfirmed() ) + Weird("irc_invalid_line"); AnalyzerViolation("line too short"); return; } @@ -101,7 +115,8 @@ void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) { myline = myline.substr(4); } else { - Weird("irc_invalid_reply_number"); + if ( AnalyzerConfirmed() ) + Weird("irc_invalid_reply_number"); AnalyzerViolation("invalid reply number"); return; } @@ -127,6 +142,10 @@ void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) { // Extract parameters. string params = myline; + if ( ! AnalyzerConfirmed() && orig && IsValidClientCommand(command) ) { + AnalyzerConfirmation(); + } + // special case if ( command == "STARTTLS" ) return; diff --git a/src/analyzer/protocol/irc/IRC.h b/src/analyzer/protocol/irc/IRC.h index 7dc40178ee..fda8ac2d4e 100644 --- a/src/analyzer/protocol/irc/IRC.h +++ b/src/analyzer/protocol/irc/IRC.h @@ -75,6 +75,14 @@ private: */ std::vector SplitWords(const std::string& input, char split); + /** + * Checks if a passed string is a valid command for an IRC client. + * + * \param command command to check + * \return true if command is valid + */ + static bool IsValidClientCommand(const std::string& command); + analyzer::tcp::ContentLine_Analyzer* cl_orig; analyzer::tcp::ContentLine_Analyzer* cl_resp; bool starttls; // if true, connection has been upgraded to tls