Suricata之源代码(三)

Yaml文件的构造

        准备说下面代码所干的事情之前,我准备介绍一下suricata.yaml文件。介绍引用自百度百科Yaml

概念

    YAML(IPA: /ˈjæməl/,尾音类似camel骆驼)是一个可读性高,用来表达资料序列的编程语言,
    YAML是一种很简单的类似于XML的数据描述语言,语法比XML简单很多。

诞生

    YAML参考了其他多种语言,包括:XMLC语言PythonPerl以及电子邮件格式RFC2822。
    Clark Evans在2001年5月在首次发表了这种语言[2],另外Ingy döt Net与Oren Ben-Kiki也是这语言的共同设计者。

命名

    YAML是"YAML Ain't a Markup Language"(YAML不是一种置标语言)的递归缩写。
    在开发的这种语言时,YAML 的意思其实是:"Yet Another Markup Language"(仍是一种置标语言),但为了强调这种语言以数据做为中心,而不是以置标语言为重点,而用返璞词重新命名。

功能

    YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表,标量等资料形态、。
    它使用空白符号缩排和大量依赖外观的特色,特别适合用来表达或编辑数据结构、各种设定档、倾印除错内容、文件大纲(例如:许多电子邮件标题格式和YAML非常接近)。
    尽管它比较适合用来表达阶层式(hierarchical model)的数据结构,不过也有精致的语法可以表示关联性(relational model)的资料。
    由于YAML使用空白字符和分行来分隔资料,使的他特别适合用grep、Python、Perl、Ruby操作。
    其让人最容易上手的特色是巧妙避开各种封闭符号,如:引号、各种括号等,这些符号在巢状结构时会变得复杂而难以辨认。

Suricata.yaml

    suricata的整个配置都是通过Yaml来配置的,在我认为它也就是一种key-value的形式。通过不同的缩进来区分孩子。
  1. <span style="font-family:SimHei;font-size:14px;">classification-file: /etc/suricata/classfication.config  //这是对classification.config的配置路径  
  2. reference-config-file: /etc/suricata/reference.config    //这是对reference.config的配置路径  
  3. magic-file: /usr/share/file/magic                       //这是对magic文件的配置路径</span>  
<span style="font-family:SimHei;font-size:14px;">classification-file: /etc/suricata/classfication.config  //这是对classification.config的配置路径
reference-config-file: /etc/suricata/reference.config    //这是对reference.config的配置路径
magic-file: /usr/share/file/magic                       //这是对magic文件的配置路径</span>

Max-pending-packets(最大包处理数)

    用max-pending-packets来设置允许suricata所能同时处理的数据包的个数。这个设置的范围是在一个数据包到上千个数据包之间的数字。
max-pending-packets: 1024

Runmodes(运行模式)

    对于rumodes的设置是根据你自己的喜好,你喜欢什么样的模式就在这里设置你所喜欢的模式。在安装了Suricata之后你可以在命令行输入suricata  --list-runmodes来查看Suricata支持的所有运行模式。
runmode: autofp

Default-packet-size(默认包的大小)

    对于default-packet-size这个选项,主要是设置你网络中的数据包的大小。
default-packet-size: 1514

Action-order

1)pass:Suricata允许数据包通过网络,接下来Suricata就不会对它再进行检测。

2)drop:这个功能只会存在IPS/inline模式,如果有特征匹配到了,并且这个特征的动作是drop那么这个数据包也不会进行下面的检测,而是丢弃数据包。

3)reject::对错误的ICMP包和TCP的有些错误包产生reject,在IPS模式下reject和drop的含义一样。

4)alert:这种数据包被看作是没有攻击的,这种可以让系统管理员注意到。在Inline/IPS模式中,这种被对待成drop或者是reject。

action-order: 
 - pass
 - drop
 - reject
 - alert

Outputs

    这个模块主要是针对Suricata的输出日志进行配置,可以配置你所感兴趣的日志。

-fast:                    #The log-name.
   enabled:yes            #This log is enabled. Set to 'no' to disable.//是否要开启这个日志文件
   filename: fast.log     #The name of the file in the default logging directory.//日志文件的名称
   append: yes/no         #If this option is set to yes, the last filled fast.log-file will not be
                          #overwritten while restarting Suricata. 

-Unified-log:                     #The log-name.
   enabled: no                    #This log is not enabled. Set 'yes' to enable.
   filename: unified.log          #The name of the file in the default logging directory.
   limit: 32                      #The file size limit in megabytes.//如果日志大小超过就会重新创建下一个日志文件

- http-log:                     #The log-name.
    enabled: yes                #This log is enabled. Set 'no' to disable.
    filename: http.log          #The name of the file in the default logging directory.    
    append: yes/no              #If this option is set to yes, the last filled fast.log-file will not be
                                # overwritten while restarting Suricata. 

detection-engine grouping tree

src             Stands for source IP-address.
dst             Stands for destination IP-address.
sp              Stands for source port.
dp              Stands for destination port.

Multi-pattern-matcher(多模匹配)

mpm-algo: b2gc  //选择的多模匹配算法


pattern-matcher: 
  - b2gc:
      search_algo: B2gSearchBNDMq 
      hash_size: low                    #Determines the size of the hash-table.
      bf_size: medium                   #Determines the size of the bloom- filter.
  - b3g: 
      search_algo: B3gSearchBNDMq 
      hash_size: low                    #See hash-size -b2gc.
      bf_size: medium                   #See bf-size -b2gc.
  - wumanber: 
      hash_size: low                    #See hash-size -b2gc.
      bf_size: medium                   #See bf-size -b2gc.

详细的suricata.yaml

Yaml文件的加载

  1.  <span style="font-size:12px;">/** \todo we need an api for these */  
  2.     /* Load yaml configuration file if provided. */  
  3.     if (conf_filename != NULL) {  
  4. #ifdef UNITTESTS  
  5.         if (run_mode == RUNMODE_UNITTEST) {  
  6.             SCLogError(SC_ERR_CMD_LINE, "should not use a configuration file with unittests");  
  7.             exit(EXIT_FAILURE);  
  8.         }  
  9. #endif  
  10.         if (ConfYamlLoadFile(conf_filename) != 0) {  
  11.             /* Error already displayed. */  
  12.             exit(EXIT_FAILURE);  
  13.         }</span>  
 <span style="font-size:12px;">/** \todo we need an api for these */
    /* Load yaml configuration file if provided. */
    if (conf_filename != NULL) {
#ifdef UNITTESTS
        if (run_mode == RUNMODE_UNITTEST) {
            SCLogError(SC_ERR_CMD_LINE, "should not use a configuration file with unittests");
            exit(EXIT_FAILURE);
        }
#endif
        if (ConfYamlLoadFile(conf_filename) != 0) {
            /* Error already displayed. */
            exit(EXIT_FAILURE);
        }</span>

这里主要函数是ConfYamlLoadFile(conf_filename),该函数是将变量conf_filename加载到内存中。
  1. <span style="font-size:12px;">/** 
  2.  * \brief Load configuration from a YAML file. 
  3.  * 
  4.  * This function will load a configuration file.  On failure -1 will 
  5.  * be returned and it is suggested that the program then exit.  Any 
  6.  * errors while loading the configuration file will have already been 
  7.  * logged. 
  8.  * 
  9.  * \param filename Filename of configuration file to load. 
  10.  * 
  11.  * \retval 0 on success, -1 on failure. 
  12.  */  
  13. int  
  14. ConfYamlLoadFile(const char *filename)  
  15. {  
  16.     FILE *infile;  
  17.     yaml_parser_t parser;  
  18.     int ret;  
  19.     ConfNode *root = ConfGetRootNode();  
  20.   
  21.     if (yaml_parser_initialize(&parser) != 1) {  
  22.         fprintf(stderr, "Failed to initialize yaml parser.\n");  
  23.         return -1;  
  24.     }  
  25.   
  26.     infile = fopen(filename, "r");  
  27.     if (infile == NULL) {  
  28.         fprintf(stderr, "Failed to open file: %s: %s\n", filename,  
  29.             strerror(errno));  
  30.         yaml_parser_delete(&parser);  
  31.         return -1;  
  32.     }  
  33.     yaml_parser_set_input_file(&parser, infile);  
  34.     ret = ConfYamlParse(&parser, root, 0);  
  35.     yaml_parser_delete(&parser);  
  36.     fclose(infile);  
  37.   
  38.     return ret;  
  39. }</span>  
<span style="font-size:12px;">/**
 * \brief Load configuration from a YAML file.
 *
 * This function will load a configuration file.  On failure -1 will
 * be returned and it is suggested that the program then exit.  Any
 * errors while loading the configuration file will have already been
 * logged.
 *
 * \param filename Filename of configuration file to load.
 *
 * \retval 0 on success, -1 on failure.
 */
int
ConfYamlLoadFile(const char *filename)
{
    FILE *infile;
    yaml_parser_t parser;
    int ret;
    ConfNode *root = ConfGetRootNode();

    if (yaml_parser_initialize(&parser) != 1) {
        fprintf(stderr, "Failed to initialize yaml parser.\n");
        return -1;
    }

    infile = fopen(filename, "r");
    if (infile == NULL) {
        fprintf(stderr, "Failed to open file: %s: %s\n", filename,
            strerror(errno));
        yaml_parser_delete(&parser);
        return -1;
    }
    yaml_parser_set_input_file(&parser, infile);
    ret = ConfYamlParse(&parser, root, 0);
    yaml_parser_delete(&parser);
    fclose(infile);

    return ret;
}</span>
    函数ConfYamlLoadFile使用yaml库中的方法进行解析,主要的函数是ConfYamlParse。通过该函数对suricata.yaml全部的选项进行解析。

  1. <span style="font-size:12px;">/** 
  2.  * \brief Parse a YAML layer. 
  3.  * 
  4.  * \param parser A pointer to an active yaml_parser_t. 
  5.  * \param parent The parent configuration node. 
  6.  * 
  7.  * \retval 0 on success, -1 on failure. 
  8.  */  
  9. static int  
  10. ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq)  
  11. {  
  12.     ConfNode *node = parent;  
  13.     yaml_event_t event;  
  14.     int done = 0;  
  15.     int state = 0;  
  16.     int seq_idx = 0;  
  17.   
  18.     while (!done) {  
  19.         if (!yaml_parser_parse(parser, &event)) {  
  20.             fprintf(stderr,  
  21.                 "Failed to parse configuration file at line %" PRIuMAX ": %s\n",  
  22.                 (uintmax_t)parser->problem_mark.line, parser->problem);  
  23.             return -1;  
  24.         }  
  25.   
  26.         if (event.type == YAML_DOCUMENT_START_EVENT) {  
  27.             /* Verify YAML version - its more likely to be a valid 
  28.              * Suricata configuration file if the version is 
  29.              * correct. */  
  30.             yaml_version_directive_t *ver =  
  31.                 event.data.document_start.version_directive;  
  32.             if (ver == NULL) {  
  33.                 fprintf(stderr, "ERROR: Invalid configuration file.\n\n");  
  34.                 fprintf(stderr, "The configuration file must begin with the following two lines:\n\n");  
  35.                 fprintf(stderr, "%%YAML 1.1\n---\n\n");  
  36.                 goto fail;  
  37.             }  
  38.             int major = event.data.document_start.version_directive->major;  
  39.             int minor = event.data.document_start.version_directive->minor;  
  40.             if (!(major == YAML_VERSION_MAJOR && minor == YAML_VERSION_MINOR)) {  
  41.                 fprintf(stderr, "ERROR: Invalid YAML version.  Must be 1.1\n");  
  42.                 goto fail;  
  43.             }  
  44.         }  
  45.         else if (event.type == YAML_SCALAR_EVENT) {  
  46.             char *value = (char *)event.data.scalar.value;  
  47.             SCLogDebug("event.type = YAML_SCALAR_EVENT (%s) inseq=%d",  
  48.                 value, inseq);  
  49.             if (inseq) {  
  50.                 ConfNode *seq_node = ConfNodeNew();  
  51.                 seq_node->name = SCCalloc(1, DEFAULT_NAME_LEN);  
  52.                 if (seq_node->name == NULL)  
  53.                     return -1;  
  54.                 snprintf(seq_node->name, DEFAULT_NAME_LEN, "%d", seq_idx++);  
  55.                 seq_node->val = SCStrdup(value);  
  56.                 TAILQ_INSERT_TAIL(&parent->head, seq_node, next);  
  57.             }  
  58.             else {  
  59.                 if (state == CONF_KEY) {  
  60.                     if (parent->is_seq) {  
  61.                         if (parent->val == NULL) {  
  62.                             parent->val = SCStrdup(value);  
  63.                             if (parent->val && strchr(parent->val, '_'))  
  64.                                 Mangle(parent->val);  
  65.                         }  
  66.                     }  
  67.                     ConfNode *n0 = ConfNodeLookupChild(parent, value);  
  68.                     if (n0 != NULL) {  
  69.                         node = n0;  
  70.                     }  
  71.                     else {  
  72.                         node = ConfNodeNew();  
  73.                         node->name = SCStrdup(value);  
  74.                         if (node->name && strchr(node->name, '_')) {  
  75.                             if (!(parent->name &&  
  76.                                    ((strcmp(parent->name, "address-groups") == 0) ||  
  77.                                     (strcmp(parent->name, "port-groups") == 0)))) {  
  78.                                 Mangle(node->name);  
  79.                                 if (mangle_errors < MANGLE_ERRORS_MAX) {  
  80.                                     SCLogWarning(SC_WARN_DEPRECATED,  
  81.                                             "%s is deprecated. Please use %s on line %"PRIuMAX".",  
  82.                                             value, node->name, (uintmax_t)parser->mark.line+1);  
  83.                                     mangle_errors++;  
  84.                                     if (mangle_errors >= MANGLE_ERRORS_MAX)  
  85.                                         SCLogWarning(SC_WARN_DEPRECATED, "not showing more "  
  86.                                                 "parameter name warnings.");  
  87.                                 }  
  88.                             }  
  89.                         }  
  90.                         TAILQ_INSERT_TAIL(&parent->head, node, next);  
  91.                     }  
  92.                     state = CONF_VAL;  
  93.                 }  
  94.                 else {  
  95.                     if (node->allow_override) {  
  96.                         if (node->val != NULL)  
  97.                             SCFree(node->val);  
  98.                         node->val = SCStrdup(value);  
  99.                     }  
  100.                     state = CONF_KEY;  
  101.                 }  
  102.             }  
  103.         }  
  104.         else if (event.type == YAML_SEQUENCE_START_EVENT) {  
  105.             SCLogDebug("event.type = YAML_SEQUENCE_START_EVENT");  
  106.             if (ConfYamlParse(parser, node, 1) != 0)  
  107.                 goto fail;  
  108.             state = CONF_KEY;  
  109.         }  
  110.         else if (event.type == YAML_SEQUENCE_END_EVENT) {  
  111.             SCLogDebug("event.type = YAML_SEQUENCE_END_EVENT");  
  112.             return 0;  
  113.         }  
  114.         else if (event.type == YAML_MAPPING_START_EVENT) {  
  115.             SCLogDebug("event.type = YAML_MAPPING_START_EVENT");  
  116.             if (inseq) {  
  117.                 ConfNode *seq_node = ConfNodeNew();  
  118.                 seq_node->is_seq = 1;  
  119.                 seq_node->name = SCCalloc(1, DEFAULT_NAME_LEN);  
  120.                 if (seq_node->name == NULL)  
  121.                     return -1;  
  122.                 snprintf(seq_node->name, DEFAULT_NAME_LEN, "%d", seq_idx++);  
  123.                 TAILQ_INSERT_TAIL(&node->head, seq_node, next);  
  124.                 if (ConfYamlParse(parser, seq_node, 0) != 0)  
  125.                     goto fail;  
  126.             }  
  127.             else {  
  128.                 if (ConfYamlParse(parser, node, inseq) != 0)  
  129.                     goto fail;  
  130.             }  
  131.             state = CONF_KEY;  
  132.         }  
  133.         else if (event.type == YAML_MAPPING_END_EVENT) {  
  134.             SCLogDebug("event.type = YAML_MAPPING_END_EVENT");  
  135.             done = 1;  
  136.         }  
  137.         else if (event.type == YAML_STREAM_END_EVENT) {  
  138.             done = 1;  
  139.         }  
  140.   
  141.         yaml_event_delete(&event);  
  142.         continue;  
  143.   
  144.     fail:  
  145.         yaml_event_delete(&event);  
  146.         return -1;  
  147.     }  
  148.   
  149.     return 0;  
  150. }</span>  
<span style="font-size:12px;">/**
 * \brief Parse a YAML layer.
 *
 * \param parser A pointer to an active yaml_parser_t.
 * \param parent The parent configuration node.
 *
 * \retval 0 on success, -1 on failure.
 */
static int
ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq)
{
    ConfNode *node = parent;
    yaml_event_t event;
    int done = 0;
    int state = 0;
    int seq_idx = 0;

    while (!done) {
        if (!yaml_parser_parse(parser, &event)) {
            fprintf(stderr,
                "Failed to parse configuration file at line %" PRIuMAX ": %s\n",
                (uintmax_t)parser->problem_mark.line, parser->problem);
            return -1;
        }

        if (event.type == YAML_DOCUMENT_START_EVENT) {
            /* Verify YAML version - its more likely to be a valid
             * Suricata configuration file if the version is
             * correct. */
            yaml_version_directive_t *ver =
                event.data.document_start.version_directive;
            if (ver == NULL) {
                fprintf(stderr, "ERROR: Invalid configuration file.\n\n");
                fprintf(stderr, "The configuration file must begin with the following two lines:\n\n");
                fprintf(stderr, "%%YAML 1.1\n---\n\n");
                goto fail;
            }
            int major = event.data.document_start.version_directive->major;
            int minor = event.data.document_start.version_directive->minor;
            if (!(major == YAML_VERSION_MAJOR && minor == YAML_VERSION_MINOR)) {
                fprintf(stderr, "ERROR: Invalid YAML version.  Must be 1.1\n");
                goto fail;
            }
        }
        else if (event.type == YAML_SCALAR_EVENT) {
            char *value = (char *)event.data.scalar.value;
            SCLogDebug("event.type = YAML_SCALAR_EVENT (%s) inseq=%d",
                value, inseq);
            if (inseq) {
                ConfNode *seq_node = ConfNodeNew();
                seq_node->name = SCCalloc(1, DEFAULT_NAME_LEN);
                if (seq_node->name == NULL)
                    return -1;
                snprintf(seq_node->name, DEFAULT_NAME_LEN, "%d", seq_idx++);
                seq_node->val = SCStrdup(value);
                TAILQ_INSERT_TAIL(&parent->head, seq_node, next);
            }
            else {
                if (state == CONF_KEY) {
                    if (parent->is_seq) {
                        if (parent->val == NULL) {
                            parent->val = SCStrdup(value);
                            if (parent->val && strchr(parent->val, '_'))
                                Mangle(parent->val);
                        }
                    }
                    ConfNode *n0 = ConfNodeLookupChild(parent, value);
                    if (n0 != NULL) {
                        node = n0;
                    }
                    else {
                        node = ConfNodeNew();
                        node->name = SCStrdup(value);
                        if (node->name && strchr(node->name, '_')) {
                            if (!(parent->name &&
                                   ((strcmp(parent->name, "address-groups") == 0) ||
                                    (strcmp(parent->name, "port-groups") == 0)))) {
                                Mangle(node->name);
                                if (mangle_errors < MANGLE_ERRORS_MAX) {
                                    SCLogWarning(SC_WARN_DEPRECATED,
                                            "%s is deprecated. Please use %s on line %"PRIuMAX".",
                                            value, node->name, (uintmax_t)parser->mark.line+1);
                                    mangle_errors++;
                                    if (mangle_errors >= MANGLE_ERRORS_MAX)
                                        SCLogWarning(SC_WARN_DEPRECATED, "not showing more "
                                                "parameter name warnings.");
                                }
                            }
                        }
                        TAILQ_INSERT_TAIL(&parent->head, node, next);
                    }
                    state = CONF_VAL;
                }
                else {
                    if (node->allow_override) {
                        if (node->val != NULL)
                            SCFree(node->val);
                        node->val = SCStrdup(value);
                    }
                    state = CONF_KEY;
                }
            }
        }
        else if (event.type == YAML_SEQUENCE_START_EVENT) {
            SCLogDebug("event.type = YAML_SEQUENCE_START_EVENT");
            if (ConfYamlParse(parser, node, 1) != 0)
                goto fail;
            state = CONF_KEY;
        }
        else if (event.type == YAML_SEQUENCE_END_EVENT) {
            SCLogDebug("event.type = YAML_SEQUENCE_END_EVENT");
            return 0;
        }
        else if (event.type == YAML_MAPPING_START_EVENT) {
            SCLogDebug("event.type = YAML_MAPPING_START_EVENT");
            if (inseq) {
                ConfNode *seq_node = ConfNodeNew();
                seq_node->is_seq = 1;
                seq_node->name = SCCalloc(1, DEFAULT_NAME_LEN);
                if (seq_node->name == NULL)
                    return -1;
                snprintf(seq_node->name, DEFAULT_NAME_LEN, "%d", seq_idx++);
                TAILQ_INSERT_TAIL(&node->head, seq_node, next);
                if (ConfYamlParse(parser, seq_node, 0) != 0)
                    goto fail;
            }
            else {
                if (ConfYamlParse(parser, node, inseq) != 0)
                    goto fail;
            }
            state = CONF_KEY;
        }
        else if (event.type == YAML_MAPPING_END_EVENT) {
            SCLogDebug("event.type = YAML_MAPPING_END_EVENT");
            done = 1;
        }
        else if (event.type == YAML_STREAM_END_EVENT) {
            done = 1;
        }

        yaml_event_delete(&event);
        continue;

    fail:
        yaml_event_delete(&event);
        return -1;
    }

    return 0;
}</span>
    该函数会通过yaml_parser_parse(parser, &event)得到event变量。再次通过event.type的类型,将所有的配置都存入ConfNode的变量中,然后suricata通过key的值搜索value的值,从而得到配置文件中的值。 

ConfNode结构是这样的:

  1. <span style="font-size:12px;">/** 
  2.  * Structure of a configuration parameter. 
  3.  */  
  4. typedef struct ConfNode_ {  
  5.     char *name;//key  
  6.     char *val;//value  
  7.   
  8.     int is_seq;  
  9.     int allow_override;  
  10.   
  11.     struct ConfNode_ *parent;  
  12.     TAILQ_HEAD(, ConfNode_) head;  
  13.     TAILQ_ENTRY(ConfNode_) next;  
  14. } ConfNode;</span>  
<span style="font-size:12px;">/**
 * Structure of a configuration parameter.
 */
typedef struct ConfNode_ {
    char *name;//key
    char *val;//value

    int is_seq;
    int allow_override;

    struct ConfNode_ *parent;
    TAILQ_HEAD(, ConfNode_) head;
    TAILQ_ENTRY(ConfNode_) next;
} ConfNode;</span>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值