snort中配置文件的处理是一个很重要的部分,因为其不仅是数据的读取过程更是snort初始结构的搭建过程
前面已经对snort解析单个文件做了代码分析.
链接:http://my.oschina.net/u/572632/blog/289256
这里从配置文件读取的总入口开始结合前面的分析做更多的记录,目地是整理出现在snort的整理框架图。以2.9.6.0 Ver 为例
/**************************************************************************** * Function: ParseSnortConf() * * Read the rules file a line at a time and send each rule to the rule parser * This is the first pass of the configuration file. It parses everything * except the rules. * * Arguments: None * * Returns: * SnortConfig * * An initialized and configured snort configuration struct. * This struct should be passed on the second pass of the * configuration file to parse the rules. * ***************************************************************************/ typedef struct _SnortConfig { RunMode run_mode; int run_mode_flags; int run_flags; int output_flags; int logging_flags; int log_tcpdump; int no_log; int no_alert; int dirty_pig; //used for processing command line arguments, checksum configuration //in conf files is maintained at policy level int checksum_flags; /* -k */ int checksum_flags_modified; int checksum_drop_flags; int checksum_drop_flags_modified; uint32_t event_log_id; /* -G */ int pkt_snaplen; uint64_t pkt_cnt; /* -n */ #ifdef REG_TEST uint64_t pkt_skip; #endif char *dynamic_rules_path; /* --dump-dynamic-rules */ /* --dynamic-engine-lib * --dynamic-engine-lib-dir * --dynamic-detection-lib * --dynamic-detection-lib-dir * --dynamic-preprocessor-lib * --dynamic-preprocessor-lib-dir * * See below for struct type */ DynamicLibInfo *dyn_engines; DynamicLibInfo *dyn_rules; DynamicLibInfo *dyn_preprocs; #ifdef SIDE_CHANNEL DynamicLibInfo *dyn_side_channels; #endif char pid_path[STD_BUF]; /* --pid-path or config pidpath */ #ifdef EXIT_CHECK uint64_t exit_check; /* --exit-check */ #endif /* -h and -B */ sfip_t homenet; sfip_t obfuscation_net; uint32_t ipv6_frag_timeout; uint32_t ipv6_max_frag_sessions; uint16_t flowbit_size; char pid_filename[STD_BUF]; /* used with pid_path */ char pidfile_suffix[MAX_PIDFILE_SUFFIX + 1]; /* -R */ char *log_dir; /* -l or config log_dir */ char *orig_log_dir; /* set in case of chroot */ char *interface; /* -i or config interface */ char *bpf_file; /* -F or config bpf_file */ char *pcap_log_file; /* -L */ char *chroot_dir; /* -t or config chroot */ char *alert_file; char *perf_file; /* -Z */ char *bpf_filter; /* last command line arguments */ char* daq_type; /* --daq or config daq */ char* daq_mode; /* --daq-mode or config daq_mode */ void* daq_vars; /* --daq-var or config daq_var */ void* daq_dirs; /* --daq-dir or config daq_dir */ char* event_trace_file; uint16_t event_trace_max; int thiszone; uint8_t ignore_ports[UINT16_MAX]; /* config ignore_ports */ long int tagged_packet_limit; /* config tagged_packet_limit */ long int pcre_match_limit; /* config pcre_match_limit */ long int pcre_match_limit_recursion; /* config pcre_match_limit_recursion */ int *pcre_ovector; int pcre_ovector_size; #ifdef PERF_PROFILING ProfileConfig profile_rules; /* config profile_rules */ ProfileConfig profile_preprocs; /* config profile_preprocs */ #endif int user_id; int group_id; mode_t file_mask; #ifdef MPLS uint8_t mpls_payload_type; /* --mpls_payload_type */ long int mpls_stack_depth; /* --max_mpls_labelchain_len */ #endif int default_rule_state; /* config default_rule_state */ char* react_page; /* config react */ #ifdef ACTIVE_RESPONSE uint8_t respond_attempts; /* config respond */ char* respond_device; uint8_t *eth_dst; /* config destination MAC address */ #endif #ifdef TARGET_BASED uint32_t max_attribute_hosts; /* config max_attribute_hosts */ uint32_t max_attribute_services_per_host; /* config max_attribute_services_per_host */ uint32_t max_metadata_services; /* config max_metadata_services */ #endif OutputConfig *output_configs; OutputConfig *rule_type_output_configs; SFGHASH *config_table; /* table of config keywords and arguments */ int asn1_mem; int active_dynamic_nodes; RuleState *rule_state_list; ClassType *classifications; ReferenceSystemNode *references; SFGHASH *so_rule_otn_map; SFGHASH *otn_map; FastPatternConfig *fast_pattern_config; EventQueueConfig *event_queue_config; PreprocPostConfigFuncNode *preproc_post_config_funcs; PreprocCheckConfigFuncNode *preproc_config_check_funcs; /* XXX XXX policy specific? */ ThresholdConfig *threshold_config; RateFilterConfig *rate_filter_config; DetectionFilterConfig *detection_filter_config; SF_EVENTQ *event_queue[NUM_EVENT_QUEUES]; SF_LIST **ip_proto_only_lists; uint8_t ip_proto_array[NUM_IP_PROTOS]; int num_rule_types; RuleListNode *rule_lists; int evalOrder[RULE_TYPE__MAX + 1]; ListHead Alert; /* Alert Block Header */ ListHead Log; /* Log Block Header */ ListHead Pass; /* Pass Block Header */ ListHead Activation; /* Activation Block Header */ ListHead Dynamic; /* Dynamic Block Header */ ListHead Drop; ListHead SDrop; ListHead Reject; PostConfigFuncNode *plugin_post_config_funcs; OTNX_MATCH_DATA *omd; /* Pattern matcher queue statistics */ unsigned int max_inq; uint64_t tot_inq_flush; uint64_t tot_inq_inserts; uint64_t tot_inq_uinserts; /* master port list table */ rule_port_tables_t *port_tables; #ifdef PPM_MGR ppm_cfg_t ppm_cfg; #endif /* The port-rule-maps map the src-dst ports to rules for * udp and tcp, for Ip we map the dst port as the protocol, * and for Icmp we map the dst port to the Icmp type. This * allows us to use the decode packet information to in O(1) * select a group of rules to apply to the packet. These * rules may have uricontent, content, or they may be no content * rules, or any combination. We process the uricontent 1st, * then the content, and then the no content rules for udp/tcp * and icmp, than we process the ip rules. */ PORT_RULE_MAP *prmIpRTNX; PORT_RULE_MAP *prmTcpRTNX; PORT_RULE_MAP *prmUdpRTNX; PORT_RULE_MAP *prmIcmpRTNX; #ifdef TARGET_BASED srmm_table_t *srmmTable; /* srvc rule map master table */ srmm_table_t *spgmmTable; /* srvc port_group map master table */ sopg_table_t *sopgTable; /* service-oridnal to port_group table */ #endif SFXHASH *detection_option_hash_table; SFXHASH *detection_option_tree_hash_table; tSfPolicyConfig *policy_config; SnortPolicy **targeted_policies; unsigned int num_policies_allocated; char *base_version; uint8_t enable_teredo; /* config enable_deep_teredo_inspection */ uint8_t enable_gtp; /* config enable_gtp */ char *gtp_ports; uint8_t enable_esp; uint8_t vlan_agnostic; /* config vlan_agnostic */ uint8_t addressspace_agnostic; /* config addressspace_agnostic */ uint8_t log_ipv6_extra; /* config log_ipv6_extra_data */ uint8_t tunnel_mask; uint32_t so_rule_memcap; uint32_t paf_max; /* config paf_max */ char *cs_dir; bool ha_peer; char *ha_out; char *ha_in; char *output_dir; void *file_config; int disable_all_policies; uint32_t reenabled_preprocessor_bits; /* flags for preprocessors to check, if all policies are disabled */ #ifdef SIDE_CHANNEL SideChannelConfig side_channel_config; #endif #ifdef SNORT_RELOAD int reloadPolicyFlag; PreprocessorSwapData *preprocSwapData; void *streamReloadConfig; #endif tSfPolicyId parserPolicyId; /* Used when a user defines a new rule type (ruletype keyword) * It points to the new rule type's ListHead and is used for accessing the * rule type's AlertList and LogList. * The output plugins used for the rule type need to be attached to the new * rule type's list head's AlertList or LogList. It's set before calling * the output plugin's initialization routine, because in that routine, * AddFuncToOutputList is called (plugbase.c) and there, the output function * is attached to the new rule type's appropriate list. * NOTE: This variable MUST NOT be used during runtime */ ListHead *head_tmp; } SnortConfig; typedef struct _VarNode { char *name; char *value; char *line; struct _VarNode *next; } VarNode; /** 这是snort配置文件读取的总入口 */ SnortConfig * ParseSnortConf(void) { SnortConfig *sc = SnortConfNew(); /** 创建snortConfig结构*/ VarNode *tmp = cmd_line_var_list; /** 全局结构*/ tSfPolicyId policy_id; /** 无符号整形作为ID 值*/ file_line = 0; /** 记录当前的行数*/ /** 记录当前解析的文件*/ file_name = snort_conf_file ? snort_conf_file : NULL_CONF; InitParser(); /** * 初始化部分全局数据其中最重要的是初始化了rulemap * * typedef struct { * unsigned gid; * unsigned sid; * }rule_number_t; * * typedef struct { * int max_rules; * int num_rules; * rule_number_t * map; * }rule_index_map_t; * * 1. rule_index_map_t 是管理规则id的, * 2 每个规则映射一个rule_number_t对象 保存gid和 sid * 3. 所有rule_number_t 以数组的形式放在rule_index_map_t 中 * 4. 空间时与预分配的大小为 #define MAX_RULE_COUNT (65535 * 2) * * **/ /* Setup the default rule action anchor points * Need to do this now in case we get a user defined rule type */ /** * 1.这部分逻辑比较简单但却很重要,主要是搭建规则管理框架的 * 2.规则信息的管理采用的是三成链表 * 3.这里是第一层 * 4具体见后面该部分的代码片段注释 **/ CreateDefaultRules(sc); /** * 初始化端口规则表,属于数据管理的辅助结构,不是重点 * */ sc->port_tables = PortTablesNew(); /** * 用于匹配查找的结构初始化 */ mpseInitSummary(); /** * 为rule和 option管理初始化了两个hash表 * 使用得是sfghash * 需要说明的是snort中有多个hash结构,而sfghash是带内存管理功能的 * * **/ OtnInit(sc); /** config table 也使用sfghash*/ /* Used to store "config" configurations */ sc->config_table = sfghash_new(20, 0, 0, free); if (sc->config_table == NULL) { ParseError("%s(%d) No memory to create config table.\n", __FILE__, __LINE__); } sc->fast_pattern_config = FastPatternConfigNew(); /** 建立快速匹配配置结构,保存基础配置信息*/ sc->event_queue_config = EventQueueConfigNew(); /** 建立事务队列的配置结构*/ sc->threshold_config = ThresholdConfigNew(); /** 建立阀值数据的配置结构*/ sc->rate_filter_config = RateFilter_ConfigNew(); /** 建立频率过滤配置结构*/ sc->detection_filter_config = DetectionFilterConfigNew(); /** 建立探测配置结构*/ /**协议数组,其中每个单元的索引为协议号,其中存放了一个链表头*/ sc->ip_proto_only_lists = (SF_LIST **)SnortAlloc(NUM_IP_PROTOS * sizeof(SF_LIST *)); /* We're not going to parse rules on the first pass */ parse_rules = 0; /** 初始化策略管理结构*/ sc->policy_config = sfPolicyInit(); if (sc->policy_config == NULL) { ParseError("No memory to create policy configuration.\n"); } /* Add the default policy */ /**这里获得策略ID的方式是使用文件名获得的*/ policy_id = sfPolicyAdd(sc->policy_config, file_name); /**赋值,策略默认ID是第一个读取到的文件的ID*/ sfSetDefaultPolicy(sc->policy_config, policy_id); /**targeted_policies 是一个空指针数组这里是确保其长度大于default policy id*/ sfDynArrayCheckBounds((void **)&sc->targeted_policies, policy_id, &sc->num_policies_allocated); /**分配一个snort policy 放入 targeted_policies数组中 policy id 的位置*/ sc->targeted_policies[policy_id] = SnortPolicyNew(); /**初始化snort policy中的部分辅助结构*/ InitVarTables(sc->targeted_policies[policy_id]); /**根据snort运行模式设置标志,是嗅探模式还是在线模式?*/ InitPolicyMode(sc->targeted_policies[policy_id]); /** * 下面是将正在使用的策略id放入指向的parsePolicyId中 * if (sc) * sc->parserPolicyId = id; * else * snort_conf->parserPolicyId = id; * } */ setParserPolicy(sc, policy_id); #ifndef SOURCEFIRE /* If snort is not run with root privileges, no interfaces will be defined, * so user beware if an iface_ADDRESS variable is used in snort.conf and * snort is not run as root (even if just in read mode) */ DefineAllIfaceVars(sc); #endif /* Add command line defined variables - duplicates will already * have been resolved */ /** * 提取获得的追加变量 */ while (tmp != NULL) { AddVarToTable(sc, tmp->name, tmp->value); tmp = tmp->next; } /* Initialize storage space for preprocessor defined rule options */ /** 也是使用sfghash*/ sc->targeted_policies[policy_id]->preproc_rule_options = PreprocessorRuleOptionsNew(); if (sc->targeted_policies[policy_id]->preproc_rule_options == NULL) { ParseError("Could not allocate storage for preprocessor rule " "options.\n"); } /**解析该文件*/ if ( strcmp(file_name, NULL_CONF) ) ParseConfigFile(sc, sc->targeted_policies[policy_id], file_name); /* We've picked up any targeted policy configs at this point so * it's probably okay to parse them here */ /**遍历所有snort policy 每一个ID标识一个文件**/ for (policy_id = 0; policy_id < sfPolicyNumAllocated(sc->policy_config); policy_id++) { char *fname = sfPolicyGet(sc->policy_config, policy_id); /**如果该id对应首个被解析的文件则忽略*/ /* Already configured default policy */ if (policy_id == sfGetDefaultPolicy(sc->policy_config)) continue; if (fname != NULL) { /**再次确保targed_policies的大小足够*/ sfDynArrayCheckBounds(\ (void **)&sc->targeted_policies, policy_id, &sc->num_policies_allocated); /**为该文件的解析申请一个snort policy 结构并完成初始化工作*/ sc->targeted_policies[policy_id] = SnortPolicyNew(); InitVarTables(sc->targeted_policies[policy_id]); InitPolicyMode(sc->targeted_policies[policy_id]); setParserPolicy(sc, policy_id); /* Need to reset this for each targeted policy */ memset(config_opt_configured, 0, sizeof(config_opt_configured)); /* Add command line defined variables - duplicates will already * have been resolved */ tmp = cmd_line_var_list; while (tmp != NULL) { AddVarToTable(sc, tmp->name, tmp->value); tmp = tmp->next; } /* Initialize storage space for preprocessor defined rule options */ sc->targeted_policies[policy_id]->preproc_rule_options = PreprocessorRuleOptionsNew(); if (sc->targeted_policies[policy_id]->preproc_rule_options == NULL) { ParseError("Could not allocate storage for preprocessor rule " "options.\n"); } /* Parse as include file so if the file is specified relative to * the snort conf directory we'll pick it up */ ParseInclude(sc, sc->targeted_policies[policy_id], fname); } } /* This can be initialized now since we've picked up any user * defined rules */ sc->omd = OtnXMatchDataNew(sc->num_rule_types); /* Reset these. The only issue in not reseting would be if we were * parsing a command line again, but do it anyway */ file_name = NULL; file_line = 0; return sc; } /***************************************************************************************/ /** 规则链第一层*/ typedef struct _RuleListNode { ListHead *RuleList; /* The rule list associated with this node */ RuleType mode; /* the rule mode */ int rval; /* 0 == no detection, 1 == detection event */ int evalIndex; /* 其实是记录该条目是第几个插入底层链表 */ char *name; /* name of this rule list (for debugging) */ struct _RuleListNode *next; /* the next RuleListNode */ } RuleListNode; /** 规则链第二层*/ typedef struct _ListHead { struct _OutputFuncNode *LogList; struct _OutputFuncNode *AlertList; struct _RuleListNode *ruleListNode; } ListHead; /* function pointer list for rule head nodes */ typedef struct _RuleFpList { /* context data for this test */ void *context; /* rule check function pointer */ int (*RuleHeadFunc)(Packet *, struct _RuleTreeNode *, struct _RuleFpList *, int); /* pointer to the next rule function node */ struct _RuleFpList *next; } RuleFpList; /**规则链第三层*/ typedef struct _RuleTreeNode { RuleFpList *rule_func; /* match functions.. (Bidirectional etc.. ) */ int head_node_number; RuleType type; IpAddrSet *sip; IpAddrSet *dip; int proto; PortObject * src_portobject; PortObject * dst_portobject; uint32_t flags; /* control flags */ /* stuff for dynamic rules activation/deactivation */ int active_flag; int activation_counter; int countdown; ActivateListNode *activate_list; /**points to global parent RTN list (Drop/Alert) which contains this * RTN. */ struct _ListHead *listhead; /**reference count from otn. Multiple OTNs can reference this RTN with the same * policy. */ unsigned int otnRefCount; } RuleTreeNode; static void CreateDefaultRules(SnortConfig *sc) { if (sc == NULL) return; /**构建顶层规则链表 * 1. 每个单元代表一个动作 * 2.所有单元以链式存放,且动作的默认优先级在链中的位置决定 * 3.因为是链式存放,因而能靠改变顶层链中的单元顺序来改变顶层规则的优先级 */ CreateRuleType(sc, RULE_LIST_TYPE__ACTIVATION, RULE_TYPE__ACTIVATE, 1, &sc->Activation); CreateRuleType(sc, RULE_LIST_TYPE__DYNAMIC, RULE_TYPE__DYNAMIC, 1, &sc->Dynamic); CreateRuleType(sc, RULE_LIST_TYPE__PASS, RULE_TYPE__PASS, 0, &sc->Pass); /* changed on Jan 06 */ CreateRuleType(sc, RULE_LIST_TYPE__DROP, RULE_TYPE__DROP, 1, &sc->Drop); CreateRuleType(sc, RULE_LIST_TYPE__SDROP, RULE_TYPE__SDROP, 0, &sc->SDrop); CreateRuleType(sc, RULE_LIST_TYPE__REJECT, RULE_TYPE__REJECT, 1, &sc->Reject); CreateRuleType(sc, RULE_LIST_TYPE__ALERT, RULE_TYPE__ALERT, 1, &sc->Alert); CreateRuleType(sc, RULE_LIST_TYPE__LOG, RULE_TYPE__LOG, 1, &sc->Log); } /**************************************************************************** * * Function: CreateRuleType * * Purpose: Creates a new type of rule and adds it to the end of the rule list * * Arguments: name = name of this rule type * mode = the mode for this rule type * rval = return value for this rule type (for detect events) * head = list head to use (or NULL to create a new one) * * Returns: the ListHead for the rule type * ***************************************************************************/ static ListHead * CreateRuleType(SnortConfig *sc, char *name, RuleType mode, int rval, ListHead *head) { RuleListNode *node; int evalIndex = 0; if (sc == NULL) return NULL; node = (RuleListNode *)SnortAlloc(sizeof(RuleListNode)); /* If this is the first rule list node, then we need to * create a new list. */ if (sc->rule_lists == NULL) { sc->rule_lists = node; } else { RuleListNode *tmp = sc->rule_lists; RuleListNode *last; do { /**从这里可以看出snortconfig 中的ruleList 是一个单链表,尾部插入的管理方式*/ /* We do not allow multiple rules types with the same name. */ if (strcasecmp(tmp->name, name) == 0) { free(node); return NULL; } /**这里可以看出RuleListNode单元中 evalIndex数值的来源,即按照插入顺序,递增获取*/ evalIndex++; last = tmp; tmp = tmp->next; } while (tmp != NULL); last->next = node; } /* User defined rule type so we need to create a list head for it */ /** 将顶层链表的RuleList指针指向二层链表, 此时二层链表只有一个单元*/ if (head == NULL) { node->RuleList = (ListHead *)SnortAlloc(sizeof(ListHead)); } else { /* Our default rules already have list heads */ node->RuleList = head; } /** 二层链表头部的ruleListNode指针指向其所属的node*/ node->RuleList->ruleListNode = node; node->mode = mode; node->rval = rval; node->name = SnortStrdup(name); node->evalIndex = evalIndex; /**这里是建立type与ruleListnode在第一层规则链表中的位置序号,方便查找*/ sc->evalOrder[node->mode] = evalIndex; sc->num_rule_types++; return node->RuleList; } static void OtnInit(SnortConfig *sc) { if (sc == NULL) return; /* Don't initialize this more than once */ if ((sc->so_rule_otn_map != NULL) || (sc->otn_map != NULL)) return; /* Init sid-gid -> otn map */ sc->so_rule_otn_map = SoRuleOtnLookupNew(); /**分配初始化sfghash*/ if (sc->so_rule_otn_map == NULL) ParseError("ParseRulesFile so_otn_map sfghash_new failed.\n"); /* Init sid-gid -> otn map */ sc->otn_map = OtnLookupNew(); /**分配初始化sfghash*/ if (sc->otn_map == NULL) ParseError("ParseRulesFile otn_map sfghash_new failed.\n"); } /***********************************************************************************/ typedef struct { /** 这句是重点*/ /**group id assigned to each file name. The groupId is an abstract concept * to tie multiple vlans into one group. */ tSfPolicy **ppPolicies; tSfPolicyId defaultPolicyId; /**policy id of configuration file or packet being processed. */ tSfPolicyId numAllocatedPolicies; unsigned int numActivePolicies; /**vlan to policyId bindings. */ tSfPolicyId vlanBindings[SF_VLAN_BINDING_MAX]; /**policyId to policyId bindings. */ tSfPolicyId policyIdBindings[SF_POLICY_ID_BINDING_MAX]; /**Network to policyId bindings. */ table_t *netBindTable; } tSfPolicyConfig; tSfPolicyConfig * sfPolicyInit(void) { int i; tSfPolicyConfig *new = (tSfPolicyConfig *)calloc(1, sizeof(tSfPolicyConfig)); if (new == NULL) return NULL; //initialize vlan bindings for (i = 0; i < SF_VLAN_BINDING_MAX; i++) { new->vlanBindings[i] = SF_POLICY_UNBOUND; } for (i = 0; i < SF_POLICY_ID_BINDING_MAX; i++) { new->policyIdBindings[i] = SF_POLICY_UNBOUND; } //initialize net bindings /** 初始化查找结构*/ new->netBindTable = sfrt_new(DIR_16x7_4x4, IPv6, SF_NETWORK_BINDING_MAX, 20); return new; } /**********************************************************************************/ SnortPolicy * SnortPolicyNew(void) { SnortPolicy *pPolicy = (SnortPolicy *)SnortAlloc(sizeof(SnortPolicy)); if (pPolicy) { // minimum possible (allows all but errors to pass by default) pPolicy->min_ttl = 1; #ifdef NORMALIZER pPolicy->new_ttl = 5; #endif /* Turn on all decoder alerts by default except for oversized alert. * Useful for bug reports ... */ pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__DEFAULT; pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__TCP_EXP_OPT; pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__TCP_OBS_OPT; pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__TCP_TTCP_OPT; pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__TCP_OPT_ANOMALY; pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__IP_OPT_ANOMALY; pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__IPV6_BAD_FRAG; pPolicy->decoder_alert_flags |= DECODE_EVENT_FLAG__IPV6_BSD_ICMP_FRAG; pPolicy->decoder_drop_flags |= DECODE_EVENT_FLAG__IPV6_BAD_FRAG; pPolicy->checksum_flags = CHECKSUM_FLAG__ALL; } return pPolicy; } ######################################################################################### /**当 ParseConfigFile在配置文件中发现include 规则时会调用下面的回调函数*/ static void ParseInclude(SnortConfig *sc, SnortPolicy *p, char *arg) { struct stat file_stat; /* for include path testing */ /* Save place in previous file */ char *stored_file_name = file_name; int stored_file_line = file_line; /**任何配置文件不能包含顶层文件,避免出现include回路*/ /* Including top level snort conf file */ if (strcmp(arg, snort_conf_file) == 0) { ParseError("Cannot include \"%s\" in an include directive.", snort_conf_file); } /* XXX Maybe not allow an include in an included file to avoid * potential recursion issues */ file_line = 0; file_name = SnortStrdup(arg); /* Stat the file. If that fails, stat it relative to the directory * that the top level snort configuration file was in */ if (stat(file_name, &file_stat) == -1) { int path_len = strlen(snort_conf_dir) + strlen(arg) + 1; DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"ParseConfigFile: stat " "on %s failed - going to config_dir\n", file_name);); free(file_name); file_name = (char *)SnortAlloc(path_len); snprintf(file_name, path_len, "%s%s", snort_conf_dir, arg); DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"ParseConfigFile: Opening " "and parsing %s\n", file_name);); } /**调用parseConfigFile*/ ParseConfigFile(sc, p, file_name); free(file_name); file_name = stored_file_name; file_line = stored_file_line; }
总结
作为配置文件读取的顶层接口,实际主要是在解析文件前对必要数据做了初始化工作
include的回调操作是在解析到include命令时作为插件触发的