1 /* Copyright (C) 2010-2012 Trend Micro Inc.
4 * This program is a free software; you can redistribute it
5 * and/or modify it under the terms of the GNU General Public
6 * License (version 2) as published by the FSF - Free Software
11 * Responsible for correlation and log decoding
15 #define ARGV0 "ossec-analysisd"
19 #include "alerts/alerts.h"
20 #include "alerts/getloglocation.h"
21 #include "os_execd/execd.h"
22 #include "os_regex/os_regex.h"
23 #include "os_net/os_net.h"
24 #include "active-response.h"
28 #include "eventinfo.h"
29 #include "accumulator.h"
30 #include "analysisd.h"
32 #include "cleanevent.h"
34 #include "output/jsonout.h"
36 #ifdef PRELUDE_OUTPUT_ENABLED
37 #include "output/prelude.h"
40 #ifdef ZEROMQ_OUTPUT_ENABLED
41 #include "output/zeromq.h"
45 #include "syscheck-sqlite.h"
49 void OS_ReadMSG(int m_queue);
50 RuleInfo *OS_CheckIfRuleMatch(Eventinfo *lf, RuleNode *curr_node);
51 static void LoopRule(RuleNode *curr_node, FILE *flog);
54 void DecodeEvent(Eventinfo *lf);
55 int DecodeSyscheck(Eventinfo *lf);
56 int DecodeRootcheck(Eventinfo *lf);
57 int DecodeHostinfo(Eventinfo *lf);
60 static void DumpLogstats(void);
62 /** Global definitions **/
71 OSDecoderInfo *NULL_Decoder;
74 static int execdq = 0;
76 /* Active response queue */
79 static int hourly_alerts;
80 static int hourly_events;
81 static int hourly_syscheck;
82 static int hourly_firewall;
85 /* Print help statement */
86 __attribute__((noreturn))
87 static void help_analysisd(void)
90 print_out(" %s: -[Vhdtf] [-u user] [-g group] [-c config] [-D dir]", ARGV0);
91 print_out(" -V Version and license message");
92 print_out(" -h This help message");
93 print_out(" -d Execute in debug mode. This parameter");
94 print_out(" can be specified multiple times");
95 print_out(" to increase the debug level.");
96 print_out(" -t Test configuration");
97 print_out(" -f Run in foreground");
98 print_out(" -u <user> User to run as (default: %s)", USER);
99 print_out(" -g <group> Group to run as (default: %s)", GROUPGLOBAL);
100 print_out(" -c <config> Configuration file to use (default: %s)", DEFAULTCPATH);
101 print_out(" -D <dir> Directory to chroot into (default: %s)", DEFAULTDIR);
107 int main(int argc, char **argv)
109 __attribute__((noreturn))
110 int main_analysisd(int argc, char **argv)
113 int c = 0, m_queue = 0, test_config = 0, run_foreground = 0;
115 const char *dir = DEFAULTDIR;
116 const char *user = USER;
117 const char *group = GROUPGLOBAL;
121 const char *cfg = DEFAULTCPATH;
129 memset(prev_month, '\0', 4);
135 #ifdef LIBGEOIP_ENABLED
140 while ((c = getopt(argc, argv, "Vtdhfu:g:D:c:")) != -1) {
157 ErrorExit("%s: -u needs an argument", ARGV0);
163 ErrorExit("%s: -g needs an argument", ARGV0);
169 ErrorExit("%s: -D needs an argument", ARGV0);
175 ErrorExit("%s: -c needs an argument", ARGV0);
189 /* Check current debug_level
190 * Command line setting takes precedence
192 if (debug_level == 0) {
193 /* Get debug level */
194 debug_level = getDefine_Int("analysisd", "debug", 0, 2);
195 while (debug_level != 0) {
202 debug1(STARTED_MSG, ARGV0);
203 DEBUG_MSG("%s: DEBUG: Starting on debug mode - %d ", ARGV0, (int)time(0));
205 /* Check if the user/group given are valid */
206 uid = Privsep_GetUser(user);
207 gid = Privsep_GetGroup(group);
208 if (uid == (uid_t) - 1 || gid == (gid_t) - 1) {
209 ErrorExit(USER_ERROR, ARGV0, user, group);
213 debug1(FOUND_USER, ARGV0);
215 /* Initialize Active response */
217 if (AR_ReadConfig(cfg) < 0) {
218 ErrorExit(CONFIG_ERROR, ARGV0, cfg);
220 debug1(ASINIT, ARGV0);
222 /* Read configuration file */
223 if (GlobalConf(cfg) < 0) {
224 ErrorExit(CONFIG_ERROR, ARGV0, cfg);
227 debug1(READ_CONFIG, ARGV0);
230 #ifdef LIBGEOIP_ENABLED
231 Config.geoip_jsonout = getDefine_Int("analysisd", "geoip_jsonout", 0, 1);
233 /* Opening GeoIP DB */
234 if(Config.geoipdb_file) {
235 geoipdb = GeoIP_open(Config.geoipdb_file, GEOIP_INDEX_CACHE);
238 merror("%s: ERROR: Unable to open GeoIP database from: %s (disabling GeoIP).", ARGV0, Config.geoipdb_file);
247 if (Config.ar == -1) {
251 /* Get server's hostname */
252 memset(__shost, '\0', 512);
253 if (gethostname(__shost, 512 - 1) != 0) {
254 strncpy(__shost, OSSEC_SERVER, 512 - 1);
258 /* Remove domain part if available */
259 _ltmp = strchr(__shost, '.');
265 /* Continuing in Daemon mode */
266 if (!test_config && !run_foreground) {
271 #ifdef PRELUDE_OUTPUT_ENABLED
273 if (Config.prelude) {
274 prelude_start(Config.prelude_profile, argc, argv);
278 #ifdef ZEROMQ_OUTPUT_ENABLED
280 if (Config.zeromq_output) {
281 #if CZMQ_VERSION_MAJOR == 2
282 zeromq_output_start(Config.zeromq_output_uri);
283 #elif CZMQ_VERSION_MAJOR >= 3
284 zeromq_output_start(Config.zeromq_output_uri, Config.zeromq_output_client_cert, Config.zeromq_output_server_cert);
290 if (Privsep_SetGroup(gid) < 0) {
291 ErrorExit(SETGID_ERROR, ARGV0, group, errno, strerror(errno));
295 if (Privsep_Chroot(dir) < 0) {
296 ErrorExit(CHROOT_ERROR, ARGV0, dir, errno, strerror(errno));
300 Config.decoder_order_size = (size_t)getDefine_Int("analysisd", "decoder_order_size", 8, MAX_DECODER_ORDER_SIZE);
304 * Anonymous Section: Load rules, decoders, and lists
306 * As lists require two-pass loading of rules that makes use of lists, lookups
307 * are created with blank database structs, and need to be filled in after
308 * completion of all rules and lists.
312 /* Initialize the decoders list */
313 OS_CreateOSDecoderList();
315 if (!Config.decoders) {
318 if (!ReadDecodeXML(XML_DECODER)) {
319 ErrorExit(CONFIG_ERROR, ARGV0, XML_DECODER);
322 /* Read local ones */
323 c = ReadDecodeXML(XML_LDECODER);
326 ErrorExit(CONFIG_ERROR, ARGV0, XML_LDECODER);
330 verbose("%s: INFO: Reading local decoder file.", ARGV0);
334 /* New loaded based on file speified in ossec.conf */
335 char **decodersfiles;
336 decodersfiles = Config.decoders;
337 while ( decodersfiles && *decodersfiles) {
339 verbose("%s: INFO: Reading decoder file %s.", ARGV0, *decodersfiles);
341 if (!ReadDecodeXML(*decodersfiles)) {
342 ErrorExit(CONFIG_ERROR, ARGV0, *decodersfiles);
345 free(*decodersfiles);
355 /* Initialize the lists of list struct */
356 Lists_OP_CreateLists();
357 /* Load each list into list struct */
360 listfiles = Config.lists;
361 while (listfiles && *listfiles) {
363 verbose("%s: INFO: Reading loading the lists file: '%s'", ARGV0, *listfiles);
365 if (Lists_OP_LoadList(*listfiles) < 0) {
366 ErrorExit(LISTS_ERROR, ARGV0, *listfiles);
378 /* Create the rules list */
379 Rules_OP_CreateRules();
384 rulesfiles = Config.includes;
385 while (rulesfiles && *rulesfiles) {
387 verbose("%s: INFO: Reading rules file: '%s'", ARGV0, *rulesfiles);
389 if (Rules_OP_ReadRules(*rulesfiles) < 0) {
390 ErrorExit(RULES_ERROR, ARGV0, *rulesfiles);
397 free(Config.includes);
398 Config.includes = NULL;
401 /* Find all rules that require list lookups and attache the the
402 * correct list struct to the rule. This keeps rules from having to
403 * search thought the list of lists for the correct file during
410 /* Fix the levels/accuracy */
413 RuleNode *tmp_node = OS_GetFirstRule();
415 total_rules = _setlevels(tmp_node, 0);
417 verbose("%s: INFO: Total rules enabled: '%d'", ARGV0, total_rules);
421 /* Create a rules hash (for reading alerts from other servers) */
423 RuleNode *tmp_node = OS_GetFirstRule();
424 Config.g_rules_hash = OSHash_Create();
425 if (!Config.g_rules_hash) {
426 ErrorExit(MEM_ERROR, ARGV0, errno, strerror(errno));
428 AddHash_Rule(tmp_node);
431 /* Ignored files on syscheck */
434 files = Config.syscheck_ignore;
435 while (files && *files) {
437 verbose("%s: INFO: Ignoring file: '%s'", ARGV0, *files);
443 /* Check if log_fw is enabled */
444 Config.logfw = (u_int8_t) getDefine_Int("analysisd",
448 /* Success on the configuration test */
453 /* Verbose message */
454 debug1(CHROOT_MSG, ARGV0, dir);
455 debug1(PRIVSEP_MSG, ARGV0, user);
457 /* Signal manipulation */
461 if (Privsep_SetUser(uid) < 0) {
462 ErrorExit(SETUID_ERROR, ARGV0, user, errno, strerror(errno));
465 /* Create the PID file */
466 if (CreatePID(ARGV0, getpid()) < 0) {
467 ErrorExit(PID_ERROR, ARGV0);
471 if ((m_queue = StartMQ(DEFAULTQUEUE, READ)) < 0) {
472 ErrorExit(QUEUE_ERROR, ARGV0, DEFAULTQUEUE, strerror(errno));
476 if (Config.allow_list == NULL) {
478 verbose("%s: INFO: No IP in the allow list for active response.", ARGV0);
484 wl = Config.allow_list;
486 verbose("%s: INFO: Allow listing IP: '%s'", ARGV0, (*wl)->ip);
490 verbose("%s: INFO: %d IPs in the allow list for active response.",
495 /* Hostname allowlist */
496 if (Config.hostname_allow_list == NULL) {
498 verbose("%s: INFO: No Hostname in the allow list for active response.",
505 wl = Config.hostname_allow_list;
507 verbose("%s: INFO: Allow listing Hostname: '%s'", ARGV0, *wl);
511 verbose("%s: INFO: %d Hostname(s) in the allow list for active response.",
516 /* Startup message */
517 verbose(STARTUP_MSG, ARGV0, (int)getpid());
519 /* Going to main loop */
525 /* Main function. Receives the messages(events) and analyze them all */
527 __attribute__((noreturn))
528 void OS_ReadMSG(int m_queue)
530 __attribute__((noreturn))
531 void OS_ReadMSG_analysisd(int m_queue)
535 char msg[OS_MAXSTR + 1];
538 RuleInfo *stats_rule = NULL;
540 /* Null to global currently pointers */
541 currently_rule = NULL;
543 /* Initialize the logs */
546 /* Initialize the integrity database */
549 /* Initialize Rootcheck */
552 /* Initialize host info */
555 /* Create the event list */
556 OS_CreateEventList(Config.memorysize);
558 /* Initiate the FTS list */
560 ErrorExit(FTS_LIST_ERROR, ARGV0);
563 /* Initialize the Accumulator */
564 if (!Accumulate_Init()) {
565 merror("accumulator: ERROR: Initialization failed");
569 /* Start the active response queues */
571 /* Waiting the ARQ to settle */
575 if (Config.ar & REMOTE_AR) {
576 if ((arq = StartMQ(ARQUEUE, WRITE)) < 0) {
577 merror(ARQ_ERROR, ARGV0);
579 /* If LOCAL_AR is set, keep it there */
580 if (Config.ar & LOCAL_AR) {
582 Config.ar |= LOCAL_AR;
587 verbose(CONN_TO, ARGV0, ARQUEUE, "active-response");
591 /* Only for LOCAL_ONLY installs */
592 if (Config.ar & REMOTE_AR) {
593 if (Config.ar & LOCAL_AR) {
595 Config.ar |= LOCAL_AR;
602 if (Config.ar & LOCAL_AR) {
603 if ((execdq = StartMQ(EXECQUEUE, WRITE)) < 0) {
604 merror(ARQ_ERROR, ARGV0);
606 /* If REMOTE_AR is set, keep it there */
607 if (Config.ar & REMOTE_AR) {
609 Config.ar |= REMOTE_AR;
614 verbose(CONN_TO, ARGV0, EXECQUEUE, "exec");
618 debug1("%s: DEBUG: Active response Init completed.", ARGV0);
620 /* Get current time before starting */
623 /* Start the hourly/weekly stats */
624 if (Start_Hour() < 0) {
627 /* Initialize stats rules */
628 stats_rule = zerorulemember(
634 ErrorExit(MEM_ERROR, ARGV0, errno, strerror(errno));
636 stats_rule->group = "stats,";
637 stats_rule->comment = "Excessive number of events (above normal).";
640 /* Do some cleanup */
641 memset(msg, '\0', OS_MAXSTR + 1);
643 /* Initialize the logs */
645 lf = (Eventinfo *)calloc(1, sizeof(Eventinfo));
647 ErrorExit(MEM_ERROR, ARGV0, errno, strerror(errno));
649 os_calloc(Config.decoder_order_size, sizeof(char*), lf->fields);
650 lf->year = prev_year;
651 strncpy(lf->mon, prev_month, 3);
654 if (OS_GetLogLocation(lf) < 0) {
655 ErrorExit("%s: Error allocating log files", ARGV0);
661 #ifdef SQLITE_ENABLED
662 /* Open the sqlite db */
663 extern sqlite3 *conn;
665 if (Config.md5_allowlist) {
666 debug2("Opening md5_allowlist: %s", Config.md5_allowlist);
667 if((s_error = sqlite3_open(Config.md5_allowlist, &conn))) {
668 merror(INVALID_IGNORE_MD5DB, ARGV0, Config.md5_allowlist);
674 debug1("%s: DEBUG: Startup completed. Waiting for new messages..", ARGV0);
676 if (Config.custom_alert_output) {
677 debug1("%s: INFO: Custom output found.!", ARGV0);
682 lf = (Eventinfo *)calloc(1, sizeof(Eventinfo));
683 os_calloc(Config.decoder_order_size, sizeof(char*), lf->fields);
685 /* This shouldn't happen */
687 ErrorExit(MEM_ERROR, ARGV0, errno, strerror(errno));
690 DEBUG_MSG("%s: DEBUG: Waiting for msgs - %d ", ARGV0, (int)time(0));
692 /* Receive message from queue */
693 if ((i = OS_RecvUnix(m_queue, OS_MAXSTR, msg))) {
694 RuleNode *rulenode_pt;
696 /* Get the time we received the event */
699 /* Default values for the log info */
702 /* Check for a valid message */
704 merror(IMSG_ERROR, ARGV0, msg);
709 /* Message before extracting header */
710 DEBUG_MSG("%s: DEBUG: Received msg: %s ", ARGV0, msg);
712 /* Clean the msg appropriately */
713 if (OS_CleanMSG(msg, lf) < 0) {
714 merror(IMSG_ERROR, ARGV0, msg);
720 DEBUG_MSG("%s: DEBUG: Msg cleanup: %s ", ARGV0, lf->log);
722 /* Current rule must be null in here */
723 currently_rule = NULL;
725 /** Check the date/hour changes **/
727 /* Update the hour */
728 if (thishour != __crt_hour) {
729 /* Search all the rules and print the number
730 * of alerts that each one fired
733 thishour = __crt_hour;
735 /* Check if the date has changed */
736 if (today != lf->day) {
738 /* Update the hourly stats (done daily) */
742 if (OS_GetLogLocation(lf) < 0) {
743 ErrorExit("%s: Error allocating log files", ARGV0);
747 strncpy(prev_month, lf->mon, 3);
748 prev_year = lf->year;
753 /* Increment number of events received */
756 /*** Run decoders ***/
758 /* Integrity check from syscheck */
759 if (msg[0] == SYSCHECK_MQ) {
762 if (!DecodeSyscheck(lf)) {
763 /* We don't process syscheck events further */
768 lf->size = strlen(lf->log);
771 /* Rootcheck decoding */
772 else if (msg[0] == ROOTCHECK_MQ) {
773 if (!DecodeRootcheck(lf)) {
774 /* We don't process rootcheck events further */
777 lf->size = strlen(lf->log);
780 /* Host information special decoder */
781 else if (msg[0] == HOSTINFO_MQ) {
782 if (!DecodeHostinfo(lf)) {
783 /* We don't process hostinfo events further */
786 lf->size = strlen(lf->log);
789 /* Run the general Decoders */
792 lf->size = strlen(lf->log);
797 /* Run accumulator */
798 if ( lf->decoder_info->accumulate == 1 ) {
803 if (lf->decoder_info->type == FIREWALL) {
804 /* If we could not get any information from
805 * the log, just ignore it
815 /* We only check if the last message is
816 * duplicated on syslog
818 else if (lf->decoder_info->type == SYSLOG) {
819 /* Check if the message is duplicated */
820 if (LastMsg_Stats(lf->full_log) == 1) {
823 LastMsg_Change(lf->full_log);
829 if (Check_Hour() == 1) {
830 RuleInfo *saved_rule = lf->generated_rule;
833 /* Save previous log */
834 saved_log = lf->full_log;
836 lf->generated_rule = stats_rule;
837 lf->full_log = __stats_comment;
839 /* Alert for statistical analysis */
840 if (stats_rule->alert_opts & DO_LOGALERT) {
841 __crt_ftell = ftell(_aflog);
842 if (Config.custom_alert_output) {
843 OS_CustomLog(lf, Config.custom_alert_output_format);
847 /* Log to json file */
848 if (Config.jsonout_output) {
849 jsonout_output_event(lf);
854 /* Set lf to the old values */
855 lf->generated_rule = saved_rule;
856 lf->full_log = saved_log;
860 /* Check the rules */
861 DEBUG_MSG("%s: DEBUG: Checking the rules - %d ",
862 ARGV0, lf->decoder_info->type);
864 /* Loop over all the rules */
865 rulenode_pt = OS_GetFirstRule();
867 ErrorExit("%s: Rules in an inconsistent state. Exiting.",
872 if (lf->decoder_info->type == OSSEC_ALERT) {
873 if (!lf->generated_rule) {
877 /* Process the alert */
878 currently_rule = lf->generated_rule;
881 /* Categories must match */
882 else if (rulenode_pt->ruleinfo->category !=
883 lf->decoder_info->type) {
887 /* Check each rule */
888 else if ((currently_rule = OS_CheckIfRuleMatch(lf, rulenode_pt))
894 if (currently_rule->level == 0) {
898 /* Check ignore time */
899 if (currently_rule->ignore_time) {
900 if (currently_rule->time_ignored == 0) {
901 currently_rule->time_ignored = lf->time;
903 /* If the current time - the time the rule was ignored
904 * is less than the time it should be ignored,
905 * leave (do not alert again)
907 else if ((lf->time - currently_rule->time_ignored)
908 < currently_rule->ignore_time) {
911 currently_rule->time_ignored = lf->time;
915 /* Pointer to the rule that generated it */
916 lf->generated_rule = currently_rule;
918 /* Check if we should ignore it */
919 if (currently_rule->ckignore && IGnore(lf)) {
921 lf->generated_rule = NULL;
925 /* Check if we need to add to ignore list */
926 if (currently_rule->ignore) {
930 /* Log the alert if configured to */
931 if (currently_rule->alert_opts & DO_LOGALERT) {
932 __crt_ftell = ftell(_aflog);
934 if (Config.custom_alert_output) {
935 OS_CustomLog(lf, Config.custom_alert_output_format);
939 /* Log to json file */
940 if (Config.jsonout_output) {
941 jsonout_output_event(lf);
945 #ifdef PRELUDE_OUTPUT_ENABLED
947 if (Config.prelude) {
948 if (Config.prelude_log_level <= currently_rule->level) {
954 #ifdef ZEROMQ_OUTPUT_ENABLED
956 if (Config.zeromq_output) {
957 zeromq_output_event(lf);
962 /* Execute an active response */
963 if (currently_rule->ar) {
965 active_response **rule_ar;
967 rule_ar = currently_rule->ar;
971 if ((*rule_ar)->ar_cmd->expect & USERNAME) {
973 !OS_PRegex(lf->dstuser, "^[a-zA-Z._0-9@?-]*$")) {
975 merror(CRAFTED_USER, ARGV0, lf->dstuser);
980 if ((*rule_ar)->ar_cmd->expect & SRCIP) {
982 !OS_PRegex(lf->srcip, "^[a-zA-Z.:_0-9-]*$")) {
984 merror(CRAFTED_IP, ARGV0, lf->srcip);
989 if ((*rule_ar)->ar_cmd->expect & FILENAME) {
995 if (do_ar && execdq > 0) {
996 OS_Exec(execdq, arq, lf, *rule_ar);
1002 /* Copy the structure to the state memory of if_matched_sid */
1003 if (currently_rule->sid_prev_matched) {
1004 if (!OSList_AddData(currently_rule->sid_prev_matched, lf)) {
1005 merror("%s: Unable to add data to sig list.", ARGV0);
1007 lf->sid_node_to_delete =
1008 currently_rule->sid_prev_matched->last_node;
1012 else if (currently_rule->group_prev_matched) {
1015 while (j < currently_rule->group_prev_matched_sz) {
1016 if (!OSList_AddData(
1017 currently_rule->group_prev_matched[j],
1019 merror("%s: Unable to add data to grp list.", ARGV0);
1029 } while ((rulenode_pt = rulenode_pt->next) != NULL);
1031 /* If configured to log all, do it */
1034 if (Config.logall_json)
1035 jsonout_output_archive(lf);
1038 /** Cleaning the memory **/
1040 /* Only clear the memory if the eventinfo was not
1041 * added to the stateful memory
1042 * -- message is free inside clean event --
1044 if (lf->generated_rule == NULL) {
1053 /* Checks if the current_rule matches the event information */
1054 RuleInfo *OS_CheckIfRuleMatch(Eventinfo *lf, RuleNode *curr_node)
1059 * word match (fast regex),
1074 RuleInfo *rule = curr_node->ruleinfo;
1079 merror("%s: Inconsistent state. currently rule NULL", ARGV0);
1084 if (full_output && !alert_only)
1085 print_out(" Trying rule: %d - %s", rule->sigid,
1089 /* Check if any decoder pre-matched here */
1090 if (rule->decoded_as &&
1091 rule->decoded_as != lf->decoder_info->id) {
1095 /* Check program name */
1096 if (rule->program_name) {
1097 if (!lf->program_name) {
1101 if (!OSMatch_Execute(lf->program_name,
1103 rule->program_name)) {
1107 else if (rule->program_name_pcre2) {
1108 if (!lf->program_name) {
1112 if (!OSPcre2_Execute(lf->program_name,
1113 rule->program_name_pcre2)) {
1118 /* Check for the ID */
1124 if (!OSMatch_Execute(lf->id,
1130 else if (rule->id_pcre2) {
1135 if (!OSPcre2_Execute(lf->id,
1141 /* Check if any word to match exists */
1143 if (!OSMatch_Execute(lf->log, lf->size, rule->match)) {
1147 else if (rule->match_pcre2) {
1148 if (!OSPcre2_Execute(lf->log, rule->match_pcre2)) {
1153 /* Check if exist any regex for this rule */
1155 if (!OSRegex_Execute(lf->log, rule->regex)) {
1159 else if (rule->pcre2) {
1160 if (!OSPcre2_Execute(lf->log, rule->pcre2)) {
1165 /* Check for actions */
1171 if (strcmp(rule->action, lf->action) != 0) {
1176 /* Checking for the URL */
1182 if (!OSMatch_Execute(lf->url, strlen(lf->url), rule->url)) {
1186 if (rule->url_pcre2) {
1191 if (!OSPcre2_Execute(lf->url, rule->url_pcre2)) {
1196 /* Check for dynamic fields */
1198 for (i = 0; i < Config.decoder_order_size && rule->fields[i]; i++) {
1201 for (j = 0; j < Config.decoder_order_size; j++)
1202 if (lf->decoder_info->fields[j])
1203 if (strcasecmp(lf->decoder_info->fields[j], rule->fields[i]->name) == 0)
1206 if (j == Config.decoder_order_size)
1210 if (!OSRegex_Execute(lf->fields[j], rule->fields[i]->regex))
1215 /* Get TCP/IP packet information */
1216 if (rule->alert_opts & DO_PACKETINFO) {
1217 /* Check for the srcip */
1223 if (!OS_IPFoundList(lf->srcip, rule->srcip)) {
1228 /* Check for the dstip */
1234 if (!OS_IPFoundList(lf->dstip, rule->dstip)) {
1239 if (rule->srcport) {
1244 if (!OSMatch_Execute(lf->srcport,
1245 strlen(lf->srcport),
1250 else if (rule->srcport_pcre2) {
1255 if (!OSPcre2_Execute(lf->srcport,
1256 rule->srcport_pcre2)) {
1260 if (rule->dstport) {
1265 if (!OSMatch_Execute(lf->dstport,
1266 strlen(lf->dstport),
1271 else if (rule->dstport_pcre2) {
1276 if (!OSPcre2_Execute(lf->dstport,
1277 rule->dstport_pcre2)) {
1281 } /* END PACKET_INFO */
1283 /* Extra information from event */
1284 if (rule->alert_opts & DO_EXTRAINFO) {
1285 /* Check compiled rule */
1286 if (rule->compiled_rule) {
1287 if (!rule->compiled_rule(lf)) {
1292 /* Checking if exist any user to match */
1295 if (!OSMatch_Execute(lf->dstuser,
1296 strlen(lf->dstuser),
1300 } else if (lf->srcuser) {
1301 if (!OSMatch_Execute(lf->srcuser,
1302 strlen(lf->srcuser),
1311 else if (rule->user_pcre2) {
1313 if (!OSPcre2_Execute(lf->dstuser,
1314 rule->user_pcre2)) {
1317 } else if (lf->srcuser) {
1318 if (!OSPcre2_Execute(lf->srcuser,
1319 rule->user_pcre2)) {
1328 /* Adding checks for geoip. */
1329 if(rule->srcgeoip) {
1331 if(!OSMatch_Execute(lf->srcgeoip,
1332 strlen(lf->srcgeoip),
1339 else if(rule->srcgeoip_pcre2) {
1341 if(!OSPcre2_Execute(lf->srcgeoip,
1342 rule->srcgeoip_pcre2))
1350 if(rule->dstgeoip) {
1352 if(!OSMatch_Execute(lf->dstgeoip,
1353 strlen(lf->dstgeoip),
1360 else if(rule->dstgeoip_pcre2) {
1362 if(!OSPcre2_Execute(lf->dstgeoip,
1363 rule->dstgeoip_pcre2))
1371 /* Check if any rule related to the size exist */
1372 if (rule->maxsize) {
1373 if (lf->size < rule->maxsize) {
1378 /* Check if we are in the right time */
1379 if (rule->day_time) {
1380 if (!OS_IsonTime(lf->hour, rule->day_time)) {
1385 /* Check week day */
1386 if (rule->week_day) {
1387 if (!OS_IsonDay(__crt_wday, rule->week_day)) {
1392 /* Get extra data */
1393 if (rule->extra_data) {
1398 if (!OSMatch_Execute(lf->data,
1400 rule->extra_data)) {
1404 else if (rule->extra_data_pcre2) {
1409 if (!OSPcre2_Execute(lf->data,
1410 rule->extra_data_pcre2)) {
1415 /* Check hostname */
1416 if (rule->hostname) {
1417 if (!lf->hostname) {
1421 if (!OSMatch_Execute(lf->hostname,
1422 strlen(lf->hostname),
1427 else if (rule->hostname_pcre2) {
1428 if (!lf->hostname) {
1432 if (!OSPcre2_Execute(lf->hostname,
1433 rule->hostname_pcre2)) {
1438 /* Check for status */
1444 if (!OSMatch_Execute(lf->status,
1450 else if (rule->status_pcre2) {
1455 if (!OSPcre2_Execute(lf->status,
1456 rule->status_pcre2)) {
1463 if (rule->context_opts & SAME_DODIFF) {
1464 if (!doDiff(rule, lf)) {
1470 /* Check for the FTS flag */
1471 if (rule->alert_opts & DO_FTS) {
1473 if (lf->decoder_info->fts) {
1474 if (lf->decoder_info->fts & FTS_DONE) {
1475 /* We already did the fts in here */
1476 } else if (!FTS(lf)) {
1485 if (rule->lists != NULL) {
1486 ListRule *list_holder = rule->lists;
1487 while (list_holder) {
1488 switch (list_holder->field) {
1493 if (!OS_DBSearch(list_holder, lf->srcip)) {
1501 if (!OS_DBSearch(list_holder, lf->srcport)) {
1509 if (!OS_DBSearch(list_holder, lf->dstip)) {
1517 if (!OS_DBSearch(list_holder, lf->dstport)) {
1523 if (!OS_DBSearch(list_holder, lf->srcuser)) {
1526 } else if (lf->dstuser) {
1527 if (!OS_DBSearch(list_holder, lf->dstuser)) {
1538 if (!OS_DBSearch(list_holder, lf->url)) {
1546 if (!OS_DBSearch(list_holder, lf->id)) {
1551 if (!lf->hostname) {
1554 if (!OS_DBSearch(list_holder, lf->hostname)) {
1558 case RULE_PROGRAM_NAME:
1559 if (!lf->program_name) {
1562 if (!OS_DBSearch(list_holder, lf->program_name)) {
1570 if (!OS_DBSearch(list_holder, lf->status)) {
1578 if (!OS_DBSearch(list_holder, lf->action)) {
1586 list_holder = list_holder->next;
1590 /* If it is a context rule, search for it */
1591 if (rule->context == 1) {
1592 if (!(rule->context_opts & SAME_DODIFF)) {
1593 if (rule->event_search) {
1594 if (!rule->event_search(lf, rule)) {
1602 if (full_output && !alert_only) {
1603 print_out(" *Rule %d matched.", rule->sigid);
1607 /* Search for dependent rules */
1608 if (curr_node->child) {
1609 RuleNode *child_node = curr_node->child;
1610 RuleInfo *child_rule = NULL;
1613 if (full_output && !alert_only) {
1614 print_out(" *Trying child rules.");
1618 while (child_node) {
1619 child_rule = OS_CheckIfRuleMatch(lf, child_node);
1620 if (child_rule != NULL) {
1621 return (child_rule);
1624 child_node = child_node->next;
1628 /* If we are set to no alert, keep going */
1629 if (rule->alert_opts & NO_ALERT) {
1636 return (rule); /* Matched */
1639 /* Update each rule and print it to the logs */
1640 static void LoopRule(RuleNode *curr_node, FILE *flog)
1642 if (curr_node->ruleinfo->firedtimes) {
1643 fprintf(flog, "%d-%d-%d-%d\n",
1645 curr_node->ruleinfo->sigid,
1646 curr_node->ruleinfo->level,
1647 curr_node->ruleinfo->firedtimes);
1648 curr_node->ruleinfo->firedtimes = 0;
1651 if (curr_node->child) {
1652 RuleNode *child_node = curr_node->child;
1654 while (child_node) {
1655 LoopRule(child_node, flog);
1656 child_node = child_node->next;
1662 /* Dump the hourly stats about each rule */
1663 static void DumpLogstats()
1665 RuleNode *rulenode_pt;
1666 char logfile[OS_FLSIZE + 1];
1670 snprintf(logfile, OS_FLSIZE, "%s/%d/", STATSAVED, prev_year);
1671 if (IsDir(logfile) == -1)
1672 if (mkdir(logfile, 0770) == -1) {
1673 merror(MKDIR_ERROR, ARGV0, logfile, errno, strerror(errno));
1677 snprintf(logfile, OS_FLSIZE, "%s/%d/%s", STATSAVED, prev_year, prev_month);
1679 if (IsDir(logfile) == -1)
1680 if (mkdir(logfile, 0770) == -1) {
1681 merror(MKDIR_ERROR, ARGV0, logfile, errno, strerror(errno));
1686 /* Creat the logfile name */
1687 snprintf(logfile, OS_FLSIZE, "%s/%d/%s/ossec-%s-%02d.log",
1694 flog = fopen(logfile, "a");
1696 merror(FOPEN_ERROR, ARGV0, logfile, errno, strerror(errno));
1700 rulenode_pt = OS_GetFirstRule();
1703 ErrorExit("%s: Rules in an inconsistent state. Exiting.",
1707 /* Loop over all the rules and print their stats */
1709 LoopRule(rulenode_pt, flog);
1710 } while ((rulenode_pt = rulenode_pt->next) != NULL);
1713 /* Print total for the hour */
1714 fprintf(flog, "%d--%d--%d--%d--%d\n\n",
1716 hourly_alerts, hourly_events, hourly_syscheck, hourly_firewall);
1719 hourly_syscheck = 0;
1720 hourly_firewall = 0;