前面總結了snort在讀取配置文件時的整體流程,這裏選擇較爲重要且相對有價值的細節部分進行分析,snort的IP串解析方式.
node
由於snort支持[ ]造成IP集合而且支持使用'!'取反,所以可能構成以下的串 ![IP, !IP ![IP, !IP]]。
學習
所以會增長解析的難度.
ui
snort處理這個問題的思想是,當發現一個 '['符號時便尋找與之對應的']'並將之間的串進行遞歸的解析,這樣就能處理層次問題了.
this
如下是snort-2.9.6.0中多個代碼片斷合併而成
spa
typedef struct _ip { int16_t family; int16_t bits; /* see sfip_size(): these address bytes * must be the last field in this struct */ union { u_int8_t u6_addr8[16]; u_int16_t u6_addr16[8]; u_int32_t u6_addr32[4]; // u_int64_t u6_addr64[2]; } ip; #define ip8 ip.u6_addr8 #define ip16 ip.u6_addr16 #define ip32 ip.u6_addr32 // #define ip64 ip.u6_addr64 } sfip_t; /***********************************************************************/ #ifndef SF_IPVAR_H #define SF_IPVAR_H /* Flags */ #define SFIP_NEGATED 1 #define SFIP_ANY 2 #include <stdio.h> #include "sf_ip.h" /* Selects which mode a given variable is using to * store and lookup IP addresses */ typedef enum _modes { SFIP_LIST, SFIP_TABLE } MODES; /* Used by the "list" mode. A doubly linked list of sfip_t objects. */ typedef struct _ip_node { sfip_t *ip; #define ip_addr ip; /* To ease porting Snort */ struct _ip_node *next; int flags; // XXX int addr_flags; /* Flags used exlusively by Snort */ /* Keeping these variables seperate keeps * this from stepping on Snort's toes. */ /* Should merge them later */ } sfip_node_t; /* An IP variable onkect */ typedef struct _var_t { /* Selects whether or not to use the list, the table, * or any other method added later */ MODES mode; /* Linked lists. Switch to something faster later */ sfip_node_t *head; sfip_node_t *neg_head; /* The mode above will select whether to use the sfip_node_t linked list * or the IP routing table */ // sfrt rt; /* Linked list of IP variables for the variable table */ struct _var_t *next; uint32_t id; char *name; char *value; } sfip_var_t; /* A variable table for storing and looking up variables */ /* Expand later to use a faster data structure */ typedef struct _vartable_t { sfip_var_t *head; uint32_t id; } vartable_t; /***********************************************************************/ SFIP_RET sfvar_parse_iplist(vartable_t *table, sfip_var_t *var, char *str, int negation) { char *end, *tok; SFIP_RET ret; int neg_ip; if(!var || !table || !str) /**檢查防止段錯誤*/ return SFIP_ARG_ERR; while(*str) { /* Skip whitespace and leading commas */ /** 跳過IP字符串前面的空指針以及多餘的,*/ if(isspace((int)*str) || *str == ',') { str++; continue; } /**neg IP標誌是爲了標誌如 !192.168.1.1這樣的IP*/ neg_ip = 0; /* Handle multiple negations */ /**基數個 '!'爲真, 偶數個'!'爲否*/ for(; *str == '!'; str++) neg_ip = !neg_ip; /**提取一個IP串,這裏可能會附帶少許多餘符號*/ /* Find end of this token */ for(end = str+1; *end && !isspace((int)*end) && *end != LIST_CLOSE && *end != ','; end++) ; /**拷貝咱們提取出的串*/ tok = SnortStrndup(str, end - str); /**檢查是從[exp1,exp2]中提取出 [exp1 這樣的串*/ if(*str == LIST_OPEN) { char *list_tok; /**找到與開頭的 '['對應的 ']'*/ if((end = _find_end_token(str)) == NULL) { /* No trailing bracket found */ free(tok); return SFIP_UNMATCHED_BRACKET; } str++; /**從 [exp] 中提取出了整個exp, exp多是複數個IP條目*/ list_tok = SnortStrndup(str, end - str); /**遞歸拆分其中的子串, 注意negtive^neg_ip 完成了多重否認的解析*/ if((ret = sfvar_parse_iplist(table, var, list_tok, negation ^ neg_ip)) != SFIP_SUCCESS) { free(list_tok); free(tok); return ret; } free(list_tok); } /**這裏經過遞歸已經將整個串拆分到最小單元即$VAR 或 !192.168.1.1這樣的結構*/ else if(*str == '$') { /**該串是一個變量*/ sfip_var_t *tmp_var; sfip_var_t *copy_var; /**查看是否有這個變量*/ if((tmp_var = sfvt_lookup_var(table, tok)) == NULL) { /**未知變量,錯誤*/ free(tok); return SFIP_LOOKUP_FAILURE; } /**將該變量對應的IP串拷貝出來*/ copy_var = sfvar_deep_copy(tmp_var); /* Apply the negation */ /**肯定該串的符號, 1標識爲取反*/ if(negation ^ neg_ip) { /* Check for a negated "any" */ /**any 取反視爲錯誤*/ if(copy_var->head && copy_var->head->flags & SFIP_ANY) { free(tok); sfvar_free(copy_var); return SFIP_NOT_ANY; } /**對0的IP取反視爲錯誤*/ /* Check if this is a negated, zero'ed IP (equivalent of a "!any") */ if(copy_var->head && !sfip_is_set(copy_var->head->ip)) { free(tok); sfvar_free(copy_var); return SFIP_NOT_ANY; } /**反轉數據, 即將 IP取反的集合與不取反的交換*/ _negate_lists(copy_var); } /**將該集合加入,該改則的IP集合*/ sfvar_add(var, copy_var); sfvar_free(copy_var); } else if(*str == LIST_CLOSE) { /* This should be the last character, if not, then this is an * invalid extra closing bracket */ if(!(*(str+1))) { free(tok); return SFIP_SUCCESS; } free(tok); return SFIP_UNMATCHED_BRACKET; } else { sfip_node_t *node; /* Skip leading commas */ for(; *str == ','; str++) ; /* Check for a negated "any" */ if(negation ^ neg_ip && !strcasecmp(tok, "any")) { free(tok); return SFIP_NOT_ANY; } /**普通的IP串,直接解析後添加*/ /* This should be an IP address! */ /* Allocate new node for this string and add it to "ret" */ if((node = sfipnode_alloc(tok, &ret)) == NULL) { free(tok); return ret; } if(negation ^ neg_ip) { _negate_node(node); } /* Check if this is a negated, zero'ed IP (equivalent of a "!any") */ if(!sfip_is_set(node->ip) && (node->flags & SFIP_NEGATED)) { sfip_node_free(node); free(tok); return SFIP_NOT_ANY; } ret = sfvar_add_node(var, node, negation ^ neg_ip); if(ret != SFIP_SUCCESS ) { free(tok); return ret; } } free(tok); /**只要該串解析完後不是末尾就將解析指針指向下一個*/ if(*end) str = end + 1; else break; } return SFIP_SUCCESS; } /***********************************************************************/ /* Support function for sfvar_parse_iplist. Used to * correctly match up end brackets. * (Can't just do strchr(str, ']') because of the * [a, [b], c] case, and can't do strrchr because * of the [a, [b], [c]] case) */ /**改代碼很是精妙的找到了與第一個'['對應的 ']',並且同時完成了校驗工做*/ static char *_find_end_token(char *str) { int stack = 0; for(; *str; str++) { if(*str == LIST_OPEN) stack++; else if(*str == LIST_CLOSE) stack--; if(!stack) { return str; } } return NULL; }
該段代碼在括號處理得技巧上值得學習指針
還有一處從這部分代碼片斷看不太明顯地方;是對解析過一次的字符串,再次遇到相同的串就將其解析後的IP集合直接採用深度拷貝過來code
對於第二點的深度拷貝目前緣由不明,可能方便後面從新整理構建,但若是不是的話,副本可使用相似智能指針的思想來建立遞歸