wazuh 日志收集原理分析

wazuh 默认安装到 /var/ossec目录下。

我基于manager端进行分析,和agent一样。默认启动ossec-logcollector进程去搜集日志:比如 snort日志、auditd日志、syslog日志等。

入口函数代码在src/logcollector/main.c中。

int main(int argc, char **argv)
{

    /* 初始化处理: 命令行解析、权限限制、 消息队列哈希表、加载配置*/
    ...

    /* 初始化消息队列, 用来将数据通过队列顺序处理, 后面的w_create_input_threads和
       w_create_output_threads创建线程组来处理日志队列 */
    w_msg_hash_queues_init();

    /* 这里会初始化logsk,这个会涉及到后面创建out thread的数量 */
    if (LogCollectorConfig(cfg) < 0) {
        merror_exit(CONFIG_ERROR, cfg);
    }
    ...
    /* 默认在ossec.conf中没有定义socket配置,所以走下面的代码,logsk只有两个元素并且name为空。
     * 后面在w_msg_hash_queues_add_entry函数中往msg_queues_table中写入一个元素,
       只有一个out thread
     */
    if (logsk == NULL) {
        os_calloc(2, sizeof(logsocket), logsk);
        logsk[0].name = NULL;
        logsk[0].location = NULL;
        logsk[0].mode = 0;
        logsk[0].prefix = NULL;
        logsk[1].name = NULL;
        logsk[1].location = NULL;
        logsk[1].mode = 0;
        logsk[1].prefix = NULL;
    }

    /* 主要处理入口*/
    LogCollectorStart();
}

LogCollectorConfig的实现:

/* Read the config file (the localfiles) */
int LogCollectorConfig(const char *cfgfile)
{
    int modules = 0;
    logreader_config log_config;

    modules |= CLOCALFILE;
    modules |= CSOCKET;

    log_config.config = NULL;
    log_config.globs = NULL;
    log_config.socket_list = NULL;
    log_config.agent_cfg = 0;
    accept_remote = getDefine_Int("logcollector", "remote_commands", 0, 1);
    log_config.accept_remote = accept_remote;

    /* 这里读取internal_options.conf和local_internal_options.conf的配置信息 */
    loop_timeout = getDefine_Int("logcollector", "loop_timeout", 1, 120);
    open_file_attempts = getDefine_Int("logcollector", "open_attempts", 0, 998);
    vcheck_files = getDefine_Int("logcollector", "vcheck_files", 0, 1024);
    maximum_lines = getDefine_Int("logcollector", "max_lines", 0, 1000000);
    maximum_files = getDefine_Int("logcollector", "max_files", 1, 100000);
    sock_fail_time = getDefine_Int("logcollector", "sock_fail_time", 1, 3600);
    sample_log_length = getDefine_Int("logcollector", "sample_log_length", 1, 4096);
    force_reload = getDefine_Int("logcollector", "force_reload", 0, 1);
    reload_interval = getDefine_Int("logcollector", "reload_interval", 1, 86400);
    reload_delay = getDefine_Int("logcollector", "reload_delay", 0, 30000);
    free_excluded_files_interval = getDefine_Int("logcollector", "exclude_files_interval", 1, 172800);
    
    // 读取配置文件ossec.conf的入口,ReadConfig函数通过调用
       read_main_elements=>Read_Socket最终往log_config.socket_list添加元素
    if (ReadConfig(modules, cfgfile, &log_config, NULL) < 0) {
        return (OS_INVALID);
    }

#ifdef CLIENT
    modules |= CAGENT_CONFIG;
    log_config.agent_cfg = 1;
    ReadConfig(modules, AGENTCONFIG, &log_config, NULL);
    log_config.agent_cfg = 0;
#endif

    logff = log_config.config;
    globs = log_config.globs;
    //将读取到的socket的配置赋值给logsk,这里可能影响out thread的创建
    logsk = log_config.socket_list;

    return (1);
}

src/logcollector/logcollector.c为主要处理逻辑:

void LogCollectorStart()
{
    ...
    /* 后面很多地方会用到这个变量 */
    logreader *current;
    ...
    /* 设置*/
    set_sockets();
    ...
    for (i = 0;; i++) {
        /* 更新 current信息,为后面做铺垫*/
        if (f_control = update_current(&current, &i, &j), f_control) {
            if (f_control == NEXT_IT) {
                continue;
            } else {
                break;
            }

            ...
            /*绝大部分read函数在这个函数中进行设置 :read_snortfull、read_audit、
              read_syslog*/
            set_read(current, i, j);
        }

    }


    /* 创建发送数据的线程*/
    w_create_output_threads();

    /* 创建读取数据的线程 */
    w_create_input_threads();
    ...
}

set_read 实现:

/* wazuh支持的日志非常多*/
void set_read(logreader *current, int i, int j) {
	minfo("in set_read func  logformat : %s.", current->logformat);

    int tg;
    current->command = NULL;
    current->ign = 0;

    /* Initialize the files */
    if (current->ffile) {

        /* Day must be zero for all files to be initialized */
        _cday = 0;
        if (update_fname(i, j)) {
            handle_file(i, j, 1, 1);
        } else {
            merror_exit(PARSE_ERROR, current->ffile);
        }

    } else {
        handle_file(i, j, 1, 1);
    }

    tg = 0;
    if (current->target) {
        while (current->target[tg]) {
            mdebug1("Socket target for '%s' -> %s", current->file, current->target[tg]);
            tg++;
        }
    }

    /* Get the log type */
    if (strcmp("snort-full", current->logformat) == 0) {
        current->read = read_snortfull;/* snort日志的读取方式*/
    }
#ifndef WIN32
    if (strcmp("ossecalert", current->logformat) == 0) {
        current->read = read_ossecalert;
    }
#endif
    else if (strcmp("nmapg", current->logformat) == 0) {
        current->read = read_nmapg;
    } else if (strcmp("json", current->logformat) == 0) {
        //wazuh与suricata联动的时候使用的就是json格式的日志
        current->read = read_json;
    } else if (strcmp("mysql_log", current->logformat) == 0) {
        current->read = read_mysql_log;
    } else if (strcmp("mssql_log", current->logformat) == 0) {
        current->read = read_mssql_log;
    } else if (strcmp("postgresql_log", current->logformat) == 0) {
        current->read = read_postgresql_log;
    } else if (strcmp("djb-multilog", current->logformat) == 0) {
        if (!init_djbmultilog(current)) {
            merror(INV_MULTILOG, current->file);
            if (current->fp) {
                fclose(current->fp);
                current->fp = NULL;
            }
            current->file = NULL;
        }
        current->read = read_djbmultilog;
    } else if (strncmp(current->logformat, "multi-line:", 11) == 0) {
        current->read = read_multiline;
    } else if (strcmp("audit", current->logformat) == 0) {
        current->read = read_audit;/* audit日志的读取方式*/
    } else {
#ifdef WIN32
        if (current->filter_binary) {
            /* If the file is empty, set it to UCS-2 LE */
            if (FileSizeWin(current->file) == 0) {
                current->ucs2 = UCS2_LE;
                current->read = read_ucs2_le;
                mdebug2("File '%s' is empty. Setting encoding to UCS-2 LE.",current->file);
                return;
            }
        }

        if(current->ucs2 == UCS2_LE){
            mdebug1("File '%s' is UCS-2 LE",current->file);
            current->read = read_ucs2_le;
            return;
        }

        if(current->ucs2 == UCS2_BE){
            mdebug1("File '%s' is UCS-2 BE",current->file);
            current->read = read_ucs2_be;
            return;
        }
#endif
        /* 设置 syslog的读取方式*/
        current->read = read_syslog;
    }
}

设置好读取方式,后面启动线程进行读取、发送;

先来看看如何读取auditd日志的:

/* type=SYSCALL msg=audit(1572939835.214:135): arch=c000003e syscall=54 
   success=yes exit=0 a0=4 a1=0 a2=40 a3=234a100 items=0 ppid=130689 pid=130690 
   auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) 
   ses=10 comm="iptables" exe="/sbin/xtables-multi" key=(null)
   这是auditd的系统调用日志, 基本就是按照这个去解析的
*/
void *read_audit(logreader *lf, int *rc, int drop_it) {
    char *cache[MAX_CACHE];
    char header[MAX_HEADER] = { '\0' };
    int icache = 0;
    char buffer[OS_MAXSTR];
    char *id;
    char *p;
    size_t z;
    int64_t offset = 0;
    int64_t rbytes = 0;

    int lines = 0;

    *rc = 0;

    for (offset = w_ftell(lf->fp); fgets(buffer, OS_MAXSTR, lf->fp) && (!maximum_lines || lines < maximum_lines) && offset >= 0; offset += rbytes) {
        rbytes = w_ftell(lf->fp) - offset;

        /* Flow control */
        if (rbytes <= 0) {
            break;
        }

        lines++;

        if (buffer[rbytes - 1] == '\n') {
            buffer[rbytes - 1] = '\0';

            if ((int64_t)strlen(buffer) != rbytes - 1)
            {
                mdebug2("Line in '%s' contains some zero-bytes (valid=" FTELL_TT " / total=" FTELL_TT "). Dropping line.", lf->file, FTELL_INT64 strlen(buffer), FTELL_INT64 rbytes - 1);
                continue;
            }
        } else {
            if (rbytes == OS_MAXSTR - 1) {
                // Message too large, discard line
                for (offset += rbytes; fgets(buffer, OS_MAXSTR, lf->fp); offset += rbytes) {
                    rbytes = w_ftell(lf->fp) - offset;

                    /* Flow control */
                    if (rbytes <= 0) {
                        break;
                    }

                    if (buffer[rbytes - 1] == '\n') {
                        break;
                    }
                }
            } else if (feof(lf->fp)) {
                mdebug2("Message not complete. Trying again: '%s'", buffer);

                if (fseek(lf->fp, offset, SEEK_SET) < 0) {
                   merror(FSEEK_ERROR, lf->file, errno, strerror(errno));
                   break;
               }
            }

            break;
        }

        // Extract header: "type=\.* msg=audit(\d+.\d+:\d+):"

        if (strncmp(buffer, "type=", 5) || !((id = strstr(buffer + 5, "msg=audit(")) && (p = strstr(id += 10, "): ")))) {
            merror("Discarding audit message because of invalid syntax.");
            break;
        }

        z = p - id;

        if (strncmp(id, header, z)) {
            // Current message belongs to another event: send cached messages
            if (icache > 0)
                audit_send_msg(cache, icache, lf->file, drop_it, lf->log_target);

            // Store current event
            *cache = strdup(buffer);
            icache = 1;
            strncpy(header, id, z < MAX_HEADER ? z : MAX_HEADER - 1);
        } else {
            // The header is the same: store
            if (icache == MAX_CACHE)
                merror("Discarding audit message because cache is full.");
            else
                cache[icache++] = strdup(buffer);
        }
    }

    if (icache > 0)
        audit_send_msg(cache, icache, lf->file, drop_it, lf->log_target);

    mdebug2("Read %d lines from %s", lines, lf->file);
    return NULL;
}

下面看看在读取线程中如何触发读取的:

/* 默认读取一个线程,可通过配置文件配置input_threads参数进行设置多线程处理 */
void w_create_input_threads(){
    int i;

    N_INPUT_THREADS = getDefine_Int("logcollector", "input_threads", N_MIN_INPUT_THREADS, 128);

#ifdef WIN32
    w_mutex_init(&win_el_mutex, &win_el_mutex_attr);
    w_mutexattr_destroy(&win_el_mutex_attr);
#endif

    for(i = 0; i < N_INPUT_THREADS; i++) {
#ifndef WIN32
        w_create_thread(w_input_thread,NULL);
#else
        if (CreateThread(NULL,
                     0,
                     (LPTHREAD_START_ROUTINE)w_input_thread,
                     NULL,
                     0,
                     NULL) == NULL) {
        merror(THREAD_ERROR);
    }
#endif
    }
}

实现:


void * w_input_thread(__attribute__((unused)) void * t_id){
    ...

    /* Daemon loop */
    while (1) {
        ... 
        /* Check which file is available */
        for (i = 0, j = -1;; i++) {
                ...

                /* Finally, send to the function pointer to read it */
                /* 读取地方*/
                current->read(current, &r, 0);
                /* Check for error */
                if (!ferror(current->fp)) {
                    ... 
                }
                /* If ferror is set */
                else {
                    merror(FREAD_ERROR, current->file, errno, strerror(errno));
    #ifndef WIN32
                    if (fseek(current->fp, 0, SEEK_END) < 0)
    #else
                    if (1)
    #endif
                    {
                        ...
                       /* 在这里进行处理日志 调用w_msg_hash_queues_push 将数据放入队列中*/
                        current->read(current, &r, 1);
    #endif
                    }
                    /* Increase the error count  */
                    current->ign++;
                    ...
                }
            }


        }
    }

    return NULL;
}

看看日志进入队列后怎么处理的:

void w_create_output_threads(){
    unsigned int i;
    const OSHashNode *curr_node;

    /* 循环遍历哈希表,创建于哈希表元素一样多的out  thread*/
    for(i = 0; i <= msg_queues_table->rows; i++){
        if(msg_queues_table->table[i]){
            curr_node = msg_queues_table->table[i];

            /* Create one thread per valid hash entry */
            if(curr_node->key){
#ifndef WIN32
                /* 使用哈希表的key (例如agent)作为参数传入进去,
                   每个线程负责一种key的队列来处理*/
                w_create_thread(w_output_thread, curr_node->key);
#else
             ...
endif
            }
        }
    }
}
/* 该线程只负责处理queue_name的队列*/
void * w_output_thread(void * args){
    char *queue_name = args;
    w_message_t *message;
    w_msg_queue_t *msg_queue;

    if (msg_queue = OSHash_Get(msg_queues_table, queue_name), !msg_queue) {
        mwarn("Could not found the '%s'.", queue_name);
        return NULL;
    }

    while(1)
    {
        /* 将消息从队列中取出来,发送给logr_queue, 
           默认是/var/ossec/queue/ossec/queue 就是unix socket, 
           如果在agent端就是发给ossec-agentd进程 */
        message = w_msg_queue_pop(msg_queue);

        if (SendMSGtoSCK(logr_queue, message->buffer, message->file, message->queue_mq, message->log_target) < 0) {
            merror(QUEUE_SEND);
            /* 如果发送失败 创建 /var/ossec/queue/ossec/queue unix socket */
            if ((logr_queue = StartMQ(DEFAULTQPATH, WRITE)) < 0) {
                merror_exit(QUEUE_FATAL, DEFAULTQPATH);
            }
        }

        free(message->file);
        free(message->buffer);
        free(message);
    }

    return NULL;
}

日志最终会通过ossec-agentd 发送给manager的ossec-remoted进程,最终送到ossec-analysisd进程去分析

ossec-analysisd进程: 通过 decode_queue_event_input 和 decode_queue_event_output 队列进行转发会在w_process_event_thread函数中将decode_queue_event_output的元素出队, 并循环遍历规则进行匹配,这部分工作与 ossec-logtest一样。如果匹配到了规则,那么会产生日志:

<ossec_config>
  <global>
    <jsonout_output>yes</jsonout_output>
    <alerts_log>yes</alerts_log>
    <logall>no</logall>
    <logall_json>no</logall_json>
    <email_notification>no</email_notification>
    <smtp_server>smtp.example.wazuh.com</smtp_server>
    <email_from>ossecm@example.wazuh.com</email_from>
    <email_to>recipient@example.wazuh.com</email_to>
    <email_maxperhour>12</email_maxperhour>
    <email_log_source>alerts.log</email_log_source>
  </global>

日志会放入到writer_queue、writer_queue_log中,ossec-analysisd在启动的时候会创建,一系列队列和线程池。

#ifndef TESTRULE
__attribute__((noreturn))
void OS_ReadMSG(int m_queue)
#else
__attribute__((noreturn))
void OS_ReadMSG_analysisd(int m_queue)
#endif
{
    Eventinfo *lf = NULL;
    int i;

    /* 初始化日志系统 */
    OS_InitLog();
    ...

   /* 初始化前面说的队列*/
    w_init_queues();

    /* Queue stats */
    w_get_initial_queues_size();
    ...

    /* Create message handler thread */
    w_create_thread(ad_input_main, &m_queue);

    /* 创建写归档日志的线程, 从writer_queue队列中获取日志 */
    w_create_thread(w_writer_thread,NULL);

    /* 创建写日志线程 ,从writer_queue_log队列中取日志*/
    w_create_thread(w_writer_log_thread,NULL);

    /* Create statistical log writer thread */
    w_create_thread(w_writer_log_statistical_thread,NULL);

    /* Create firewall log writer thread */
    w_create_thread(w_writer_log_firewall_thread,NULL);

    /* Create FTS log writer thread */
    w_create_thread(w_writer_log_fts_thread,NULL);

    /* Create log rotation thread */
    w_create_thread(w_log_rotate_thread,NULL);

    /* Create decode syscheck threads */
    for(i = 0; i < num_decode_syscheck_threads;i++){
        w_create_thread(w_decode_syscheck_thread,NULL);
    }

    /* Create decode syscollector threads */
    for(i = 0; i < num_decode_syscollector_threads;i++){
        w_create_thread(w_decode_syscollector_thread,NULL);
    }

    /* Create decode hostinfo threads */
    for(i = 0; i < num_decode_hostinfo_threads;i++){
        w_create_thread(w_decode_hostinfo_thread,NULL);
    }

    /* Create decode rootcheck threads */
    for(i = 0; i < num_decode_rootcheck_threads;i++){
        w_create_thread(w_decode_rootcheck_thread,NULL);
    }

    /* Create decode Security Configuration Assessment threads */
    for(i = 0; i < num_decode_sca_threads;i++){
        w_create_thread(w_decode_sca_thread,NULL);
    }

    /* 创建decoder线程池,用于处理agent转发过来的日志数据,
       放入decode_queue_event_output队列中 */
    for(i = 0; i < num_decode_event_threads;i++){
        w_create_thread(w_decode_event_thread,NULL);
    }

    /* 创建规则匹配线程池,decoder线程池处理好(DecodeEvent函数来做)的数据:从
     * decode_queue_event_output拿出数据, 循环遍历初始时从ruleset/rules目录下读取处理规则,
     * 来判定是否匹配成功,如果成功,是否有alert需求, alert level是否大于等于ossec.conf中的 
     * log_alert_level, 如果满足,生成alert log, 放入writer_queue_log队列中。后面由 
     * w_writer_log_thread来处理, 其中会调用OS_Log 往logs/alerts/alerts.log中写日志
     */
    for(i = 0; i < num_rule_matching_threads;i++){
        w_create_thread(w_process_event_thread,(void *) (intptr_t)i);
    }

    /* Create decode winevt threads */
    for(i = 0; i < num_decode_winevt_threads;i++){
        w_create_thread(w_decode_winevt_thread,NULL);
    }

    /* Create State thread */
    w_create_thread(w_analysisd_state_main,NULL);

    mdebug1("Startup completed. Waiting for new messages..");

    while (1) {
        sleep(1);
    }
}
/* 写日志线程, 将writer_queue_log的数据拿出来, 根据配置信息,决定写入日志*/
void * w_writer_log_thread(__attribute__((unused)) void * args ){
    Eventinfo *lf;

    while(1){
            /* Receive message from queue */
            if (lf = queue_pop_ex(writer_queue_log), lf) {

                w_mutex_lock(&writer_threads_mutex);
                w_inc_alerts_written();

                if (Config.custom_alert_output) {
                    __crt_ftell = ftell(_aflog);
                    OS_CustomLog(lf, Config.custom_alert_output_format);
                } else if (Config.alerts_log) {
                    __crt_ftell = ftell(_aflog);
                    OS_Log(lf);//这里写入 alerts.log中
                } else if(Config.jsonout_output){
                    __crt_ftell = ftell(_jflog);
                }
                /* Log to json file */
                if (Config.jsonout_output) {
                    jsonout_output_event(lf);
                }
                ...
                w_mutex_unlock(&writer_threads_mutex);
                Free_Eventinfo(lf);
            }
    }
}

/* 从decode_queue_event_input队列中,将数据拿出来, 根据ruleset/decoders/下的decoder规则
   decode数据, 并存入decode_queue_event_output中
*/
void * w_decode_event_thread(__attribute__((unused)) void * args){
    ...
    while(1){

        /* Receive message from queue */
        if (msg = queue_pop_ex(decode_queue_event_input), msg) {
            ...
            if (msg[0] == CISCAT_MQ) {
                if (!DecodeCiscat(lf, &sock)) {
                    w_free_event_info(lf);
                    free(msg);
                    continue;
                }
            } else {
                DecodeEvent(lf, &decoder_match);
            }

            ...
            if (queue_push_ex_block(decode_queue_event_output,lf) < 0) {
                Free_Eventinfo(lf);
            }

            // 更新统计计数
            w_inc_decoded_events();
        }
    }
}
/* 该线程从decode_queue_event_output拿出decode好的数据,然后,循环遍历规则,检测是否是恶意操作
 * (匹配的细节在OS_CheckIfRuleMatch函数中,并忽略level为0的规则, 如果匹配成功,立即终止循环), 
 * 如果检测到了,将产生日志,并放入 writer_queue_log中,如果配置logall 会放入writer_queue队列中, 
 * 如果配置active response了,会产生响应,所谓的联动
 */
void * w_process_event_thread(__attribute__((unused)) void * id){

    ...

    while(1) {
        RuleNode *rulenode_pt;
        lf_logall = NULL;

        /* Extract decoded event from the queue */
        if (lf = queue_pop_ex(decode_queue_event_output), !lf) {
            continue;
        }

        ...
        /* 从这里开始遍历规则 */
        rulenode_pt = OS_GetFirstRule();
        if (!rulenode_pt) {
            merror_exit("Rules in an inconsistent state. Exiting.");
        }
        do {
            if (lf->decoder_info->type == OSSEC_ALERT) {
                if (!lf->generated_rule) {
                    goto next_it;
                }

                /* Process the alert */
                t_currently_rule = lf->generated_rule;
            }
            /* Categories must match */
            else if (rulenode_pt->ruleinfo->category !=
                        lf->decoder_info->type) {
                continue;
            }

            /* 如果没有匹配上,继续下一条规则 */
            else if ((t_currently_rule = OS_CheckIfRuleMatch(lf, rulenode_pt, &rule_match))
                        == NULL) {
                continue;
            }

            /* Ignore level 0 */
            if (t_currently_rule->level == 0) {
                break;
            }

            /* Check ignore time */
            if (t_currently_rule->ignore_time) {
                if (t_currently_rule->time_ignored == 0) {
                    t_currently_rule->time_ignored = lf->generate_time;
                }
                /* If the current time - the time the rule was ignored
                    * is less than the time it should be ignored,
                    * alert about the parent one instead
                    */
                else if ((lf->generate_time - t_currently_rule->time_ignored)
                            < t_currently_rule->ignore_time) {
                    if (t_currently_rule->prev_rule) {
                        t_currently_rule = (RuleInfo*)t_currently_rule->prev_rule;
                        w_FreeArray(lf->last_events);
                    } else {
                        break;
                    }
                } else {
                    t_currently_rule->time_ignored = lf->generate_time;
                }
            }

            /* Pointer to the rule that generated it */
            lf->generated_rule = t_currently_rule;

            /* Check if we should ignore it */
            if (t_currently_rule->ckignore && IGnore(lf, t_id)) {
                /* Ignore rule */
                lf->generated_rule = NULL;
                break;
            }

            /* Check if we need to add to ignore list */
            if (t_currently_rule->ignore) {
                AddtoIGnore(lf, t_id);
            }

            /* Log the alert if configured to */
            if (t_currently_rule->alert_opts & DO_LOGALERT) {
                lf->comment = ParseRuleComment(lf);

                os_calloc(1, sizeof(Eventinfo), lf_cpy);
                w_copy_event_for_log(lf,lf_cpy);
                //将日志入队
                if (queue_push_ex_block(writer_queue_log, lf_cpy) < 0) {
                    Free_Eventinfo(lf_cpy);
                }
            }

            /* Execute an active response */
            if (t_currently_rule->ar) {
                int do_ar;
                active_response **rule_ar;

                rule_ar = t_currently_rule->ar;

                while (*rule_ar) {
                    do_ar = 1;
                    if ((*rule_ar)->ar_cmd->expect & USERNAME) {
                        if (!lf->dstuser ||
                                !OS_PRegex(lf->dstuser, "^[a-zA-Z._0-9@?-]*$")) {
                            if (lf->dstuser) {
                                mwarn(CRAFTED_USER, lf->dstuser);
                            }
                            do_ar = 0;
                        }
                    }
                    if ((*rule_ar)->ar_cmd->expect & SRCIP) {
                        if (!lf->srcip ||
                                !OS_PRegex(lf->srcip, "^[a-zA-Z.:_0-9-]*$")) {
                            if (lf->srcip) {
                                mwarn(CRAFTED_IP, lf->srcip);
                            }
                            do_ar = 0;
                        }
                    }
                    if ((*rule_ar)->ar_cmd->expect & FILENAME) {
                        if (!lf->filename) {
                            do_ar = 0;
                        }
                    }

                    if (do_ar && execdq >= 0) {
                        OS_Exec(execdq, arq, lf, *rule_ar);
                    }
                    rule_ar++;
                }
            }


            /* Copy the structure to the state memory of if_matched_sid */
            if (t_currently_rule->sid_prev_matched) {
                OSListNode *node;
                w_mutex_lock(&t_currently_rule->mutex);
                if (node = OSList_AddData(t_currently_rule->sid_prev_matched, lf), !node) {
                    merror("Unable to add data to sig list.");
                } else {
                    lf->sid_node_to_delete = node;
                }
                w_mutex_unlock(&t_currently_rule->mutex);
            }
            /* Group list */
            else if (t_currently_rule->group_prev_matched) {
                unsigned int j = 0;
                OSListNode *node;

                w_mutex_lock(&t_currently_rule->mutex);
                os_calloc(t_currently_rule->group_prev_matched_sz, sizeof(OSListNode *), lf->group_node_to_delete);
                while (j < t_currently_rule->group_prev_matched_sz) {
                    if (node = OSList_AddData(t_currently_rule->group_prev_matched[j], lf), !node) {
                        merror("Unable to add data to grp list.");
                    } else {
                        lf->group_node_to_delete[j] = node;
                    }
                    j++;
                }
                w_mutex_unlock(&t_currently_rule->mutex);
            }

            lf->queue_added = 1;
            os_calloc(1, sizeof(Eventinfo), lf_logall);
            w_copy_event_for_log(lf, lf_logall);
            w_free_event_info(lf);
            OS_AddEvent(lf, last_events_list);
            break;// 到这里来,说明匹配成功,不再匹配后面的规则

        } while ((rulenode_pt = rulenode_pt->next) != NULL);

        w_inc_processed_events();//更新统计计数

        // 将日志入队
        if (Config.logall || Config.logall_json){
            if (!lf_logall) {
                os_calloc(1, sizeof(Eventinfo), lf_logall);
                w_copy_event_for_log(lf, lf_logall);
            }
            result = queue_push_ex(writer_queue, lf_logall);
            if (result < 0) {
                if(!reported_writer){
                    reported_writer = 1;
                    mwarn("Archive writer queue is full. %d", t_id);
                }
                Free_Eventinfo(lf_logall);
            }
        } else if (lf_logall) {
            Free_Eventinfo(lf_logall);
        }
next_it:
        if (!lf->queue_added) {
            w_free_event_info(lf);
        }
    }
}

到这里来,整个日志的流程基本就介绍完了。

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值