入侵检测

来源:互联网 发布:mysql如何卸载干净 编辑:程序博客网 时间:2024/05/06 07:52

入侵检测系统首推开源项目snort,完善的匹配规则定义,灵活的插件扩充能力使其有强大的生命力,创建规则匹配的核心代码节选如下:

可以看出,在分解规则的时候,就已经用多个链表,将不同的规则进行分类了,可以根据分析的场景,有选择的去使用合适的规则,实现高效。

void ParseRule(char *prule, int inclevel){    char **toks;/* dbl ptr for mSplit call, holds rule tokens */    int num_toks;/* holds number of tokens found by mSplit */    int rule_type;/* rule type enumeration variable */    char rule[1024];    int protocol;    RuleTreeNode proto_node;    /* clean house */    bzero((char *) &proto_node, sizeof(RuleTreeNode));    /* chop off the <CR/LF> from the string */    strip(prule);    /* expand all variables */    strcpy(rule, ExpandVars(prule));    /* break out the tokens from the rule string */    toks = mSplit(rule, " ", 10, &num_toks, 0);#ifdef DEBUG    printf("[*] Rule start\n");#endif    /* figure out what we're looking at */    rule_type = RuleType(toks[0]);#ifdef DEBUG    printf("Rule type: ");#endif    /* handle non-rule entries */    switch (rule_type)    {    case RULE_PASS:#ifdef DEBUGprintf("Pass\n");#endifbreak;    case RULE_LOG:#ifdef DEBUGprintf("Log\n");#endifbreak;    case RULE_ALERT:#ifdef DEBUGprintf("Alert\n");#endifbreak;    case RULE_INCLUDE:#ifdef DEBUGprintf("Include\n");#endifParseRulesFile(toks[1], inclevel + 1);return;    case RULE_VAR:#ifdef DEBUGprintf("Variable\n");#endifVarDefine(toks[1], toks[2]);return;    case RULE_PREPROCESS:#ifdef DEBUGprintf("Preprocessor\n");#endifParsePreprocessor(rule);return;    case RULE_OUTPUT:#ifdef DEBUGprintf("Output Plugin\n");#endifParseOutputPlugin(rule);return;    case RULE_ACTIVATE:#ifdef DEBUGprintf("Activation rule\n");#endifbreak;    case RULE_DYNAMIC:#ifdef DEBUGprintf("Dynamic rule\n");#endifbreak;    case RULE_CONFIG:#ifdef DEBUGprintf("Rule file config\n");#endifParseConfig(rule);return;    case RULE_DECLARE:#ifdef DEBUGprintf("Rule type declaration\n");#endifParseRuleTypeDeclaration(rule);return;    case RULE_UNKNOWN:#ifdef DEBUGprintf("Unknown rule type, might be declared\n");#endifParseDeclaredRuleType(rule);return;    default:printf("Invalid input: %s\n", prule);return;    }    proto_node.type = rule_type;    /* set the rule protocol */    protocol = WhichProto(toks[1]);    /* Process the IP address and CIDR netmask */    /* changed version 1.2.1 */    /*     * "any" IP's are now set to addr 0, netmask 0, and the normal rules are     * applied instead of checking the flag     */    /*     * if we see a "!<ip number>" we need to set a flag so that we can     * properly deal with it when we are processing packets     */    if (*toks[2] == '!')/* we found a negated address */    {proto_node.flags |= EXCEPT_SRC_IP;ParseIP(&toks[2][1], (u_long *) & proto_node.sip,(u_long *) & proto_node.smask);    } else    {ParseIP(toks[2], (u_long *) & proto_node.sip,(u_long *) & proto_node.smask);    }    /* do the same for the port */    if (ParsePort(toks[3], (u_short *) & proto_node.hsp,  (u_short *) & proto_node.lsp, toks[1],  (int *) &proto_node.not_sp_flag))    {proto_node.flags |= ANY_SRC_PORT;    }    if (proto_node.not_sp_flag)proto_node.flags |= EXCEPT_SRC_PORT;    /* New in version 1.3: support for bidirectional rules */    /*     * this checks the rule "direction" token and sets the bidirectional flag     * if the token = '<>'     */    if (!strncmp("<>", toks[4], 2))    {#ifdef DEBUGprintf("Bidirectional rule!\n");#endifproto_node.flags |= BIDIRECTIONAL;    }    /* changed version 1.2.1 */    /*     * "any" IP's are now set to addr 0, netmask 0, and the normal rules are     * applied instead of checking the flag     */    /*     * if we see a "!<ip number>" we need to set a flag so that we can     * properly deal with it when we are processing packets     */    if (*toks[5] == '!')/* we found a negated address */    {#ifdef DEBUGprintf("setting exception flag for dest IP\n");#endifproto_node.flags |= EXCEPT_DST_IP;ParseIP(&toks[5][1], (u_long *) & proto_node.dip,(u_long *) & proto_node.dmask);    } elseParseIP(toks[5], (u_long *) & proto_node.dip,(u_long *) & proto_node.dmask);    if (ParsePort(toks[6], (u_short *) & proto_node.hdp,  (u_short *) & proto_node.ldp, toks[1],  (int *) &proto_node.not_dp_flag))    {proto_node.flags |= ANY_DST_PORT;    }    if (proto_node.not_dp_flag)proto_node.flags |= EXCEPT_DST_PORT;#ifdef DEBUG    printf("proto_node.flags = 0x%X\n", proto_node.flags);    printf("Processing Head Node....\n");#endif    switch (rule_type)    {    case RULE_ALERT:ProcessHeadNode(&proto_node, &Alert, protocol);break;    case RULE_LOG:ProcessHeadNode(&proto_node, &Log, protocol);break;    case RULE_PASS:ProcessHeadNode(&proto_node, &Pass, protocol);break;    case RULE_ACTIVATE:ProcessHeadNode(&proto_node, &Activation, protocol);break;    case RULE_DYNAMIC:ProcessHeadNode(&proto_node, &Dynamic, protocol);break;    default:FatalError("Unable to determine rule type (%s) for processing, exiting!\n", toks[0]);    }    rule_count++;#ifdef DEBUG    printf("Parsing Rule Options...\n");#endif    ParseRuleOptions(rule, rule_type, protocol);    free(toks);    return;}/**************************************************************************** * * Function: ProcessHeadNode(RuleTreeNode *, ListHead *, int) * * Purpose:  Process the header block info and add to the block list if *           necessary * * Arguments: test_node => data generated by the rules parsers *            list => List Block Header refernece *            protocol => ip protocol * * Returns: void function * ***************************************************************************/void ProcessHeadNode(RuleTreeNode * test_node, ListHead * list, int protocol){    int match = 0;    RuleTreeNode *rtn_idx;    int count = 0;    /* select the proper protocol list to attach the current rule to */    switch (protocol)    {    case IPPROTO_TCP:rtn_idx = list->TcpList;break;    case IPPROTO_UDP:rtn_idx = list->UdpList;break;    case IPPROTO_ICMP:rtn_idx = list->IcmpList;break;    default:rtn_idx = NULL;break;    }    /*     * if the list head is NULL (empty), make a new one and attach the     * ListHead to it     */    if (rtn_idx == NULL)    {head_count++;switch (protocol){case IPPROTO_TCP:    list->TcpList = (RuleTreeNode *) calloc(sizeof(RuleTreeNode), sizeof(char));    rtn_tmp = list->TcpList;    break;case IPPROTO_UDP:    list->UdpList = (RuleTreeNode *) calloc(sizeof(RuleTreeNode), sizeof(char));    rtn_tmp = list->UdpList;    break;case IPPROTO_ICMP:    list->IcmpList = (RuleTreeNode *) calloc(sizeof(RuleTreeNode), sizeof(char));    rtn_tmp = list->IcmpList;    break;}/* copy the prototype header data into the new node */XferHeader(test_node, rtn_tmp);rtn_tmp->head_node_number = head_count;/* null out the down (options) pointer */rtn_tmp->down = NULL;/* add the function list to the new rule */SetupRTNFuncList(rtn_tmp);/* add link to parent listhead */rtn_tmp->listhead = list;return;    }    /* see if this prototype node matches any of the existing header nodes */    match = TestHeader(rtn_idx, test_node);    while ((rtn_idx->right != NULL) && !match)    {count++;match = TestHeader(rtn_idx, test_node);if (!match)    rtn_idx = rtn_idx->right;else    break;    }    /*     * have to check this twice since my loop above exits early, which sucks     * but it's not performance critical     */    match = TestHeader(rtn_idx, test_node);    /*     * if it doesn't match any of the existing nodes, make a new node and     * stick it at the end of the list     */    if (!match)    {#ifdef DEBUGprintf("Building New Chain head node\n");#endifhead_count++;/* build a new node */rtn_idx->right = (RuleTreeNode *) calloc(sizeof(RuleTreeNode), sizeof(char));/* set the global ptr so we can play with this from anywhere */rtn_tmp = rtn_idx->right;/* uh oh */if (rtn_tmp == NULL){    FatalError("ERROR: Unable to allocate Rule Head Node!!\n");}/* copy the prototype header info into the new header block */XferHeader(test_node, rtn_tmp);rtn_tmp->head_node_number = head_count;rtn_tmp->down = NULL;/* initialize the function list for the new RTN */SetupRTNFuncList(rtn_tmp);/* add link to parent listhead */rtn_tmp->listhead = list;#ifdef DEBUGprintf("New Chain head flags = 0x%X\n", rtn_tmp->flags);#endif    } else    {rtn_tmp = rtn_idx;#ifdef DEBUGprintf("Chain head %d  flags = 0x%X\n", count, rtn_tmp->flags);#endif#ifdef DEBUGprintf("Adding options to chain head %d\n", count);#endif    }}/**************************************************************************** * * Function: AddRuleFuncToList(int (*func)(), RuleTreeNode *) * * Purpose:  Adds RuleTreeNode associated detection functions to the *          current rule's function list * * Arguments: *func => function pointer to the detection function *            rtn   => pointer to the current rule * * Returns: void function * ***************************************************************************/void AddRuleFuncToList(int (*func) (Packet *, struct _RuleTreeNode *, struct _RuleFpList *), RuleTreeNode * rtn){    RuleFpList *idx;#ifdef DEBUG    printf("Adding new rule to list\n");#endif    idx = rtn->rule_func;    if (idx == NULL)    {rtn->rule_func = (RuleFpList *) calloc(sizeof(RuleFpList), sizeof(char));rtn->rule_func->RuleHeadFunc = func;    } else    {while (idx->next != NULL)    idx = idx->next;idx->next = (RuleFpList *) calloc(sizeof(RuleFpList), sizeof(char));idx = idx->next;idx->RuleHeadFunc = func;    }}/**************************************************************************** * * Function: SetupRTNFuncList(RuleTreeNode *) * * Purpose: Configures the function list for the rule header detection *          functions (addrs and ports) * * Arguments: rtn => the pointer to the current rules list entry to attach to * * Returns: void function * ***************************************************************************/void SetupRTNFuncList(RuleTreeNode * rtn){#ifdef DEBUG    printf("Initializing RTN function list!\n");    printf("Functions: ");#endif    if (rtn->flags & BIDIRECTIONAL)    {#ifdef DEBUGprintf("CheckBidirectional->\n");#endifAddRuleFuncToList(CheckBidirectional, rtn);    } else    {/* link in the proper IP address detection function *//* * the in-line "if" determines whether or not the negation operator * has been set for this rule and tells the AddrToFunc call which * function it should be linking in */AddrToFunc(rtn, rtn->sip, rtn->smask, (rtn->flags & EXCEPT_SRC_IP ? 1 : 0), SRC);/* last verse, same as the first (but for dest IP) ;) */AddrToFunc(rtn, rtn->dip, rtn->dmask, (rtn->flags & EXCEPT_DST_IP ? 1 : 0), DST);/* Attach the proper port checking function to the function list *//* * the in-line "if's" check to see if the "any" or "not" flags have * been set so the PortToFunc call can determine which port testing * function to attach to the list */PortToFunc(rtn, (rtn->flags & ANY_SRC_PORT ? 1 : 0),   (rtn->flags & EXCEPT_SRC_PORT ? 1 : 0), SRC);/* as above */PortToFunc(rtn, (rtn->flags & ANY_DST_PORT ? 1 : 0),   (rtn->flags & EXCEPT_DST_PORT ? 1 : 0), DST);    }#ifdef DEBUG    printf("RuleListEnd\n");#endif    /* tack the end (success) function to the list */    AddRuleFuncToList(RuleListEnd, rtn);}/**************************************************************************** * * Function: AddrToFunc(RuleTreeNode *, u_long, u_long, int, int) * * Purpose: Links the proper IP address testing function to the current RTN *          based on the address, netmask, and addr flags * * Arguments: rtn => the pointer to the current rules list entry to attach to *            ip =>  IP address of the current rule *            mask => netmask of the current rule *            exception_flag => indicates that a "!" has been set for this *                              address *            mode => indicates whether this is a rule for the source *                    or destination IP for the rule * * Returns: void function * ***************************************************************************/void AddrToFunc(RuleTreeNode * rtn, u_long ip, u_long mask, int exception_flag, int mode){    /*     * if IP and mask are both 0, this is a "any" IP and we don't need to     * check it     */    if ((ip == 0) && (mask == 0))return;    /* if the exception flag is up, test with the exception function */    if (exception_flag)    {switch (mode){case SRC:#ifdef DEBUG    printf("CheckSrcIPNotEq -> ");#endif    AddRuleFuncToList(CheckSrcIPNotEq, rtn);    break;case DST:#ifdef DEBUG    printf("CheckDstIPNotEq -> ");#endif    AddRuleFuncToList(CheckDstIPNotEq, rtn);    break;}return;    }    switch (mode)    {    case SRC:#ifdef DEBUGprintf("CheckSrcIPEqual -> ");#endifAddRuleFuncToList(CheckSrcIPEqual, rtn);break;    case DST:#ifdef DEBUGprintf("CheckDstIPEqual -> ");#endifAddRuleFuncToList(CheckDstIPEqual, rtn);break;    }}/**************************************************************************** * * Function: PortToFunc(RuleTreeNode *, int, int, int) * * Purpose: Links in the port analysis function for the current rule * * Arguments: rtn => the pointer to the current rules list entry to attach to *            any_flag =>  accept any port if set *            except_flag => indicates negation (logical NOT) of the test *            mode => indicates whether this is a rule for the source *                    or destination port for the rule * * Returns: void function * ***************************************************************************/void PortToFunc(RuleTreeNode * rtn, int any_flag, int except_flag, int mode){    /*     * if the any flag is set we don't need to perform any test to match on     * this port     */    if (any_flag)return;    /* if the except_flag is up, test with the "NotEq" funcs */    if (except_flag)    {switch (mode){case SRC:#ifdef DEBUG    printf("CheckSrcPortNotEq -> ");#endif    AddRuleFuncToList(CheckSrcPortNotEq, rtn);    break;case DST:#ifdef DEBUG    printf("CheckDstPortNotEq -> ");#endif    AddRuleFuncToList(CheckDstPortNotEq, rtn);    break;}return;    }    /* default to setting the straight test function */    switch (mode)    {    case SRC:#ifdef DEBUGprintf("CheckSrcPortEqual -> ");#endifAddRuleFuncToList(CheckSrcPortEqual, rtn);break;    case DST:#ifdef DEBUGprintf("CheckDstPortEqual -> ");#endifAddRuleFuncToList(CheckDstPortEqual, rtn);break;    }    return;}/**************************************************************************** * * Function: AddOptFuncToList(int (*func)(), OptTreeNode *) * * Purpose: Links the option detection module to the OTN * * Arguments: (*func)() => function pointer to the detection module *            otn =>  pointer to the current OptTreeNode * * Returns: void function * ***************************************************************************/void AddOptFuncToList(int (*func) (Packet *, struct _OptTreeNode *, struct _OptFpList *), OptTreeNode * otn){    OptFpList *idx;/* index pointer */#ifdef DEBUG    printf("Adding new rule to list\n");#endif    /* set the index pointer to the start of this OTN's function list */    idx = otn->opt_func;    /* if there are no nodes on the function list... */    if (idx == NULL)    {/* calloc the list head */otn->opt_func = (OptFpList *) calloc(sizeof(OptFpList), sizeof(char));if (otn->opt_func == NULL){    FatalError("ERROR => AddOptFuncToList new node calloc failed: %s\n", strerror(errno));}/* set the head function */otn->opt_func->OptTestFunc = func;    } else    {/* walk to the end of the list */while (idx->next != NULL){    idx = idx->next;}/* allocate a new node on the end of the list */idx->next = (OptFpList *) calloc(sizeof(OptFpList), sizeof(char));if (idx->next == NULL){    FatalError("ERROR => AddOptFuncToList new node calloc failed: %s\n", strerror(errno));}/* move up to the new node */idx = idx->next;/* link the function to the new node */idx->OptTestFunc = func;#ifdef DEBUGprintf("Set OptTestFunc to %p\n", func);#endif    }}/**************************************************************************** * * Function: ParsePreprocessor(char *) * * Purpose: Walks the preprocessor function list looking for the user provided *          keyword.  Once found, call the preprocessor's initialization *          function. * * Arguments: rule => the preprocessor initialization string from the rules file * * Returns: void function * ***************************************************************************/void ParsePreprocessor(char *rule){    char **toks;/* pointer to the tokenized array parsed from * the rules list */    char **pp_head;/* parsed keyword list, with preprocessor * keyword being the 2nd element */    char *funcname;/* the ptr to the actual preprocessor keyword */    char *pp_args = NULL;/* parsed list of arguments to the * preprocessor */    int num_toks;/* number of tokens returned by the mSplit * function */    int found = 0;/* flag var */    PreprocessKeywordList *pl_idx;/* index into the preprocessor * keyword/func list */    /* break out the arguments from the keywords */    toks = mSplit(rule, ":", 2, &num_toks, '\\');    if (num_toks >= 1)    {#ifdef DEBUGprintf("toks[1] = %s\n", toks[1]);#endif/* the args are everything after the ":" */pp_args = toks[1];    }    /* split the head section for the preprocessor keyword */    pp_head = mSplit(toks[0], " ", 2, &num_toks, '\\');    /* set a pointer to the actual keyword */    funcname = pp_head[1];    /* set the index to the head of the keyword list */    pl_idx = PreprocessKeywords;    /* walk the keyword list */    while (pl_idx != NULL)    {#ifdef DEBUGprintf("comparing: \"%s\" => \"%s\"\n", funcname, pl_idx->entry.keyword);#endif/* compare the keyword against the current list element's keyword */if (!strcasecmp(funcname, pl_idx->entry.keyword)){    pl_idx->entry.func(pp_args);    found = 1;}if (!found){    pl_idx = pl_idx->next;} else    break;    }    if (!found)printf("\n*WARNING*: unknown preprocessor \"%s\", ignoring!\n\n",       funcname);}void AddFuncToPreprocList(void (*func) (Packet *)){    PreprocessFuncNode *idx;    idx = PreprocessList;    if (idx == NULL)    {PreprocessList = (PreprocessFuncNode *) calloc(sizeof(PreprocessFuncNode), sizeof(char));PreprocessList->func = func;    } else    {while (idx->next != NULL)    idx = idx->next;idx->next = (PreprocessFuncNode *) calloc(sizeof(PreprocessFuncNode), sizeof(char));idx = idx->next;idx->func = func;    }    return;}void ParseOutputPlugin(char *rule){    char **toks;    char **pp_head;    char *funcname;    char *pp_args = NULL;    int num_toks;    int found = 0;    OutputKeywordList *pl_idx;    toks = mSplit(rule, ":", 2, &num_toks, '\\');    if (num_toks >= 1)    {pp_args = toks[1];    }    pp_head = mSplit(toks[0], " ", 2, &num_toks, '\\');    funcname = pp_head[1];    pl_idx = OutputKeywords;    while (pl_idx != NULL)    {#ifdef DEBUGprintf("comparing: \"%s\" => \"%s\"\n", funcname, pl_idx->entry.keyword);#endifif (!strcasecmp(funcname, pl_idx->entry.keyword)){    switch (pl_idx->entry.node_type)    {    case NT_OUTPUT_ALERT:if (!pv.alert_cmd_override){    if (AlertFunc == NULL)    {AlertFunc = CallAlertPlugins;    }    /* call the configuration function for the plugin */    pl_idx->entry.func(pp_args);} else{    ErrorMessage("WARNING: command line overrides rules file alert plugin!\n");}break;    case NT_OUTPUT_LOG:if (!pv.log_cmd_override){    if (LogFunc == NULL)    {LogFunc = CallLogPlugins;    }    /* call the configuration function for the plugin */    pl_idx->entry.func(pp_args);} else{    ErrorMessage("WARNING: command line overrides rules file logging plugin!\n");}break;    }    found = 1;}if (!found){    pl_idx = pl_idx->next;} else    break;    }    if (!found)    {printf("\n*WARNING*: unknown output plugin \"%s\", ignoring!\n\n", funcname);    }}/* * frees the existing OutputList ands sets it a single node for the * function argument */void SetOutputList(void (*func) (Packet *, char *, void *), char node_type,        void *arg){    OutputFuncNode *idx;    OutputFuncNode *prev;    switch (node_type)    {    case NT_OUTPUT_ALERT:prev = AlertList;break;    case NT_OUTPUT_LOG:prev = LogList;break;    default:return;    }    while (prev != NULL)    {idx = prev->next;free(prev);prev = idx;    }    return AddFuncToOutputList(func, node_type, arg);}void AddFuncToOutputList(void (*func) (Packet *, char *, void *), char node_type,      void *arg){    switch (node_type)    {case NT_OUTPUT_ALERT:if (head_tmp != NULL)    head_tmp->AlertList = AppendOutputFuncList(func, arg,       head_tmp->AlertList);else    AlertList = AppendOutputFuncList(func, arg, AlertList);break;    case NT_OUTPUT_LOG:if (head_tmp != NULL)    head_tmp->LogList = AppendOutputFuncList(func, arg,     head_tmp->LogList);else    LogList = AppendOutputFuncList(func, arg, LogList);break;    default:/* just to be error-prone */FatalError("Unknown nodetype: %i. Possible bug. please report\n",   node_type);    }}OutputFuncNode *AppendOutputFuncList(void (*func) (Packet *, char *, void *),                   void *arg, OutputFuncNode * list){    OutputFuncNode *idx = list;    if (idx == NULL)    {idx = (OutputFuncNode *) calloc(sizeof(OutputFuncNode), sizeof(char));idx->func = func;idx->arg = arg;list = idx;    } else    {while (idx->next != NULL)    idx = idx->next;idx->next = (OutputFuncNode *) calloc(sizeof(OutputFuncNode), sizeof(char));idx = idx->next;idx->func = func;idx->arg = arg;    }    idx->next = NULL;    return list;}/**************************************************************************** * * Function: ParseRuleOptions(char *, int) * * Purpose:  Process an individual rule's options and add it to the *           appropriate rule chain * * Arguments: rule => rule string *            rule_type => enumerated rule type (alert, pass, log) * * Returns: void function * ***************************************************************************/void ParseRuleOptions(char *rule, int rule_type, int protocol){    char **toks = NULL;    char **opts;    char *idx;    char *aux;    int num_toks;    int i;    int num_opts;    int found = 0;    OptTreeNode *otn_idx;    KeywordXlateList *kw_idx;    /* set the OTN to the beginning of the list */    otn_idx = rtn_tmp->down;    /*     * make a new one and stick it either at the end of the list or hang it     * off the RTN pointer     */    if (otn_idx != NULL)    {/* loop to the end of the list */while (otn_idx->next != NULL){    otn_idx = otn_idx->next;}/* setup the new node */otn_idx->next = (OptTreeNode *) calloc(sizeof(OptTreeNode), sizeof(char));/* set the global temp ptr */otn_tmp = otn_idx->next;if (otn_tmp == NULL){    FatalError("ERROR: Unable to alloc OTN: %s", strerror(errno));}otn_tmp->next = NULL;opt_count++;    } else    {/* first entry on the chain, make a new node and attach it */otn_idx = (OptTreeNode *) calloc(sizeof(OptTreeNode), sizeof(char));bzero((char *) otn_idx, sizeof(OptTreeNode));otn_tmp = otn_idx;if (otn_tmp == NULL){    FatalError("ERROR: Unable to alloc OTN!\n");}otn_tmp->next = NULL;rtn_tmp->down = otn_tmp;opt_count++;    }    otn_tmp->chain_node_number = opt_count;    otn_tmp->type = rule_type;    /* add link to parent RuleTreeNode */    otn_tmp->rtn = rtn_tmp;    /* find the start of the options block */    idx = index(rule, '(');    i = 0;    if (idx != NULL)    {idx++;/* find the end of the options block */aux = strrchr(idx, ')');/* get rid of the trailing ")" */if (aux == NULL){    FatalError("ERROR: problems parsing rule file.\n");}*aux = 0;/* seperate all the options out, the seperation token is a semicolon *//* * NOTE: if you want to include a semicolon in the content of your * rule, it must be preceeded with a '\' */toks = mSplit(idx, ";", 10, &num_toks, '\\');#ifdef DEBUGprintf("   Got %d tokens\n", num_toks);#endif/* decrement the number of toks */num_toks--;#ifdef DEBUGprintf("Parsing options list: ");#endifwhile (num_toks){#ifdef DEBUG    printf("   option: %s\n", toks[i]);#endif    /* break out the option name from its data */    opts = mSplit(toks[i], ":", 4, &num_opts, '\\');#ifdef DEBUG    printf("   option name: %s\n", opts[0]);    printf("   option args: %s\n", opts[1]);#endif    /* advance to the beginning of the data (past the whitespace) */    while (isspace((int) *opts[0]))opts[0]++;    /* figure out which option tag we're looking at */    if (!strncasecmp(opts[0], "msg", 3))    {ParseMessage(opts[1]);    } else if (!strncasecmp(opts[0], "logto", 5))    {ParseLogto(opts[1]);    } else if (!strncasecmp(opts[0], "activates", 9))    {ParseActivates(opts[1]);dynamic_rules_present++;    } else if (!strncasecmp(opts[0], "activated_by", 12))    {ParseActivatedBy(opts[1]);dynamic_rules_present++;    } else if (!strncasecmp(opts[0], "count", 5))    {if (otn_tmp->type != RULE_DYNAMIC)    FatalError("The \"count\" option may only be used with the dynamic rule type!\n");ParseCount(opts[1]);    }#ifdef ENABLE_RESPONSE    else if (!strncasecmp(opts[0], "resp", 4))    {otn_tmp->response_flag = RESP_RST_SND;ParseResponse(opts[1]);    }#endif    else    {kw_idx = KeywordList;found = 0;while (kw_idx != NULL){#ifdef DEBUG    printf("comparing: \"%s\" => \"%s\"\n", opts[0], kw_idx->entry.keyword);#endif    if (!strcasecmp(opts[0], kw_idx->entry.keyword))    {kw_idx->entry.func(opts[1], otn_tmp, protocol);found = 1;#ifdef DEBUGprintf("%s->", kw_idx->entry.keyword);#endif    }    if (!found)    {kw_idx = kw_idx->next;    } elsebreak;}if (!found){    if (!strcasecmp(opts[0], "minfrag"))    {FatalError("\nERROR: %s (%d) => Minfrag is no longer a rule option, it is a\npreprocessor (please remove it from your rules file).  See RULES.SAMPLE or\nsnort-lib for examples of using the new preprocessors!\n", file_name, file_line);    } else    {FatalError("\nERROR: %s (%d) => Unknown keyword \"%s\" in rule!\n", file_name, file_line, opts[0]);    }}    }    free(opts);    --num_toks;    i++;}#ifdef DEBUGprintf("OptListEnd\n");#endifAddOptFuncToList(OptListEnd, otn_tmp);    } else    {#ifdef DEBUGprintf("OptListEnd\n");#endifAddOptFuncToList(OptListEnd, otn_tmp);    }    free(toks);}/**************************************************************************** * * Function: RuleType(char *) * * Purpose:  Determine what type of rule is being processed and return its *           equivalent value * * Arguments: func => string containing the rule type * * Returns: The rule type designation * ***************************************************************************/int RuleType(char *func){    if (func == NULL)    {FatalError("ERROR line %s (%d) => Unknown rule type (%s)\n", file_name, file_line, func);    }    if (!strncasecmp(func, "log", 3))return RULE_LOG;    if (!strncasecmp(func, "alert", 5))return RULE_ALERT;    if (!strncasecmp(func, "pass", 4))return RULE_PASS;    if (!strncasecmp(func, "var", 3))return RULE_VAR;    if (!strncasecmp(func, "include", 7))return RULE_INCLUDE;    if (!strncasecmp(func, "preprocessor", 12))return RULE_PREPROCESS;    if (!strncasecmp(func, "output", 6))return RULE_OUTPUT;    if (!strncasecmp(func, "activate", 8))return RULE_ACTIVATE;    if (!strncasecmp(func, "dynamic", 7))return RULE_DYNAMIC;    if (!strncasecmp(func, "config", 6))return RULE_CONFIG;    if (!strncasecmp(func, "ruletype", 8))return RULE_DECLARE;    return RULE_UNKNOWN;}/**************************************************************************** * * Function: WhichProto(char *) * * Purpose: Figure out which protocol the current rule is talking about * * Arguments: proto_str => the protocol string * * Returns: The integer value of the protocol * ***************************************************************************/int WhichProto(char *proto_str){    if (!strncasecmp(proto_str, "tcp", 3))return IPPROTO_TCP;    if (!strncasecmp(proto_str, "udp", 3))return IPPROTO_UDP;    if (!strncasecmp(proto_str, "icmp", 4))return IPPROTO_ICMP;    /*     * if we've gotten here, we have a protocol string we din't recognize and     * should exit     */    FatalError("ERROR %s (%d) => Bad protocol: %s\n", file_name, file_line, proto_str);    return 0;}/**************************************************************************** * * Function: ParseIP(char *, u_long *, u_long *) * * Purpose: Convert a supplied IP address to it's network order 32-bit long           value.  Also convert the CIDR block notation into a real *          netmask. * * Arguments: addr => address string to convert *            ip_addr => storage point for the converted ip address *            netmask => storage point for the converted netmask * * Returns: 0 for normal addresses, 1 for an "any" address * ***************************************************************************/int ParseIP(char *paddr, u_long * ip_addr, u_long * netmask){    char **toks;/* token dbl buffer */    int num_toks;/* number of tokens found by mSplit() */    int cidr = 1;/* is network expressed in CIDR format */    int nmask;/* netmask temporary storage */    char *addr;/* string to parse, eventually a * variable-contents */    struct hostent *host_info;/* various struct pointers for stuff */    struct sockaddr_in sin;/* addr struct */    /* check for variable */    if (!strncmp(paddr, "{1}quot;, 1))    {if ((addr = VarGet(paddr + 1)) == NULL){    FatalError("ERROR %s (%d) => Undefined variable %s\n", file_name, file_line, paddr);}    } elseaddr = paddr;    /* check for wildcards */    if (!strncasecmp(addr, "any", 3))    {*ip_addr = 0;*netmask = 0;return 1;    }    /* break out the CIDR notation from the IP address */    toks = mSplit(addr, "/", 2, &num_toks, 0);    /* "/" was not used as a delimeter, try ":" */    if (num_toks == 1)toks = mSplit(addr, ":", 2, &num_toks, 0);    /*     * if we have a mask spec and it is more than two characters long, assume     * it is netmask format     */    if ((num_toks > 1) && strlen(toks[1]) > 2)cidr = 0;    switch (num_toks)    {    case 1:*netmask = netmasks[32];break;    case 2:if (cidr){    /* convert the CIDR notation into a real live netmask */    nmask = atoi(toks[1]);    /* it's pain to differ whether toks[1] is correct if netmask */    /* is /0, so we deploy some sort of evil hack with isdigit */    if (!isdigit((int) toks[1][0]))nmask = -1;    if ((nmask > -1) && (nmask < 33))    {*netmask = netmasks[nmask];    } else    {FatalError("ERROR %s (%d) => Invalid CIDR block for IP addr %s\n", file_name, file_line, addr);    }} else{    /* convert the netmask into its 32-bit value */    /* broadcast address fix from Steve Beaty <beaty@emess.mscd.edu> */    /*     * * if the address is the (v4) broadcast address, inet_addr *     * returns -1 which usually signifies an error, but in the *     * broadcast address case, is correct.  we'd use inet_aton() *     * here, but it's less portable.     */    if (!strncmp(toks[1], "255.255.255.255", 15))    {*netmask = INADDR_BROADCAST;    } else if ((*netmask = inet_addr(toks[1])) == -1)    {FatalError("ERROR %s (%d) => Rule netmask (%s) didn't x-late, WTF?\n", file_name, file_line, toks[1]);    }}break;    default:FatalError("ERROR %s (%d) => Unrecognized IP address/netmask %s\n", file_name, file_line, addr);break;    }#ifndef WORDS_BIGENDIAN    /*     * since PC's store things the "wrong" way, shuffle the bytes into the     * right order.  Non-CIDR netmasks are already correct.     */    if (cidr)    {*netmask = htonl(*netmask);    }#endif    /* convert names to IP addrs */    if (isalpha((int) toks[0][0]))    {/* get the hostname and fill in the host_info struct */if ((host_info = gethostbyname(toks[0]))){    bcopy(host_info->h_addr, (char *) &sin.sin_addr, host_info->h_length);} else if ((sin.sin_addr.s_addr = inet_addr(toks[0])) == INADDR_NONE){    FatalError("ERROR %s (%d) => Couldn't resolve hostname %s\n",       file_name, file_line, toks[0]);}*ip_addr = ((u_long) (sin.sin_addr.s_addr) & (*netmask));return 1;    }    /* convert the IP addr into its 32-bit value */    /* broadcast address fix from Steve Beaty <beaty@emess.mscd.edu> */    /*     * * if the address is the (v4) broadcast address, inet_addr returns -1 *     * which usually signifies an error, but in the broadcast address case, *     * is correct.  we'd use inet_aton() here, but it's less portable.     */    if (!strncmp(toks[0], "255.255.255.255", 15))    {*ip_addr = INADDR_BROADCAST;    } else if ((*ip_addr = inet_addr(toks[0])) == -1)    {FatalError("ERROR %s (%d) => Rule IP addr (%s) didn't x-late, WTF?\n", file_name, file_line, toks[0]);    } else    {/* set the final homenet address up */*ip_addr = ((u_long) (*ip_addr) & (*netmask));    }    free(toks);    return 0;}/**************************************************************************** * * Function: ParsePort(char *, u_short *) * * Purpose:  Convert the port string over to an integer value * * Arguments: prule_port => port rule string *            port => converted integer value of the port * * Returns: 0 for a normal port number, 1 for an "any" port * ***************************************************************************/int ParsePort(char *prule_port, u_short * hi_port, u_short * lo_port, char *proto, int *not_flag){    char **toks;/* token dbl buffer */    int num_toks;/* number of tokens found by mSplit() */    char *rule_port;/* port string */    *not_flag = 0;    /* check for variable */    if (!strncmp(prule_port, "{1}quot;, 1))    {if ((rule_port = VarGet(prule_port + 1)) == NULL){    FatalError("ERROR %s (%d) => Undefined variable %s\n", file_name, file_line, prule_port);}    } elserule_port = prule_port;    /* check for wildcards */    if (!strncasecmp(rule_port, "any", 3))    {*hi_port = 0;*lo_port = 0;return 1;    }    if (rule_port[0] == '!')    {*not_flag = 1;rule_port++;    }    if (rule_port[0] == ':')    {*lo_port = 0;    }    toks = mSplit(rule_port, ":", 2, &num_toks, 0);    switch (num_toks)    {    case 1:*hi_port = ConvPort(toks[0], proto);if (rule_port[0] == ':'){    *lo_port = 0;} else{    *lo_port = *hi_port;    if (index(rule_port, ':') != NULL)    {*hi_port = 65535;    }}return 0;    case 2:*lo_port = ConvPort(toks[0], proto);if (toks[1][0] == 0)    *hi_port = 65535;else    *hi_port = ConvPort(toks[1], proto);return 0;    default:FatalError("ERROR %s (%d) => port conversion failed on \"%s\"\n",   file_name, file_line, rule_port);    }    return 0;}/**************************************************************************** * * Function: ConvPort(char *, char *) * * Purpose:  Convert the port string over to an integer value * * Arguments: port => port string *            proto => converted integer value of the port * * Returns:  the port number * ***************************************************************************/int ConvPort(char *port, char *proto){    int conv;/* storage for the converted number */    struct servent *service_info;    /*     * convert a "word port" (http, ftp, imap, whatever) to its corresponding     * numeric port value     */    if (isalpha((int) port[0]) != 0)    {service_info = getservbyname(port, proto);if (service_info != NULL){    conv = ntohs(service_info->s_port);    return conv;} else{    FatalError("ERROR %s (%d) => getservbyname() failed on \"%s\"\n",       file_name, file_line, port);}    }    if (!isdigit((int) port[0]))    {FatalError("ERROR %s (%d) => Invalid port: %s\n", file_name,   file_line, port);    }    /* convert the value */    conv = atoi(port);    /* make sure it's in bounds */    if ((conv >= 0) && (conv < 65536))    {return conv;    } else    {FatalError("ERROR %s (%d) => bad port number: %s", file_name,   file_line, port);    }    return 0;}/**************************************************************************** * * Function: ParseMessage(char *) * * Purpose: Stuff the alert message onto the rule * * Arguments: msg => the msg string * * Returns: void function * ***************************************************************************/void ParseMessage(char *msg){    char *ptr;    char *end;    int size;    /* figure out where the message starts */    ptr = index(msg, '"');    if (ptr == NULL)    {ptr = msg;    } elseptr++;    end = index(ptr, '"');    if (end != NULL)*end = 0;    while (isspace((int) *ptr))ptr++;    /* find the end of the alert string */    size = strlen(msg) + 1;    /* alloc space for the string and put it in the rule */    if (size > 0)    {otn_tmp->message = (char *) calloc((sizeof(char) * size), sizeof(char));strncpy(otn_tmp->message, ptr, size);otn_tmp->message[size - 1] = 0;#ifdef DEBUGprintf("Rule message set to: %s\n", otn_tmp->message);#endif    } else    {ErrorMessage("ERROR %s (%d): bad alert message size %d\n", file_name, file_line, size);    }}/**************************************************************************** * * Function: ParseLogto(char *) * * Purpose: stuff the special log filename onto the proper rule option * * Arguments: filename => the file name * * Returns: void function * ***************************************************************************/void ParseLogto(char *filename){    char *sptr;    char *eptr;    /* grab everything between the starting " and the end one */    sptr = index(filename, '"');    eptr = strrchr(filename, '"');    if (sptr != NULL && eptr != NULL)    {/* increment past the first quote */sptr++;/* zero out the second one */*eptr = 0;    } else    {sptr = filename;    }    /* malloc up a nice shiny clean buffer */    otn_tmp->logto = (char *) calloc(strlen(sptr) + 1, sizeof(char));    bzero((char *) otn_tmp->logto, strlen(sptr) + 1);    strncpy(otn_tmp->logto, sptr, strlen(sptr));}#ifdef ENABLE_RESPONSE/**************************************************************************** * * Function: ParseResponse(char *) * * Purpose: Figure out how to handle hostile connection attempts * * Arguments: type => string of comma-sepatared modifiers * * Returns: void function * ***************************************************************************/void ParseResponse(char *type){    char *p;    while (isspace((int) *type))type++;    if (!type || !(*type))return;    otn_tmp->response_flag = 0;    p = strtok(type, ",");    while (p)    {if (!strncasecmp(p, "rst_snd", 7))    otn_tmp->response_flag |= RESP_RST_SND;else if (!strncasecmp(p, "rst_rcv", 7))    otn_tmp->response_flag |= RESP_RST_RCV;else if (!strncasecmp(p, "rst_all", 7))    otn_tmp->response_flag |= (RESP_RST_SND | RESP_RST_RCV);else if (!strncasecmp(p, "icmp_net", 8))    otn_tmp->response_flag |= RESP_BAD_NET;else if (!strncasecmp(p, "icmp_host", 9))    otn_tmp->response_flag |= RESP_BAD_HOST;else if (!strncasecmp(p, "icmp_port", 9))    otn_tmp->response_flag |= RESP_BAD_PORT;else if (!strncasecmp(p, "icmp_all", 9))    otn_tmp->response_flag |= (RESP_BAD_NET | RESP_BAD_HOST | RESP_BAD_PORT);else{    FatalError("ERROR %s (%d): invalid response modifier: %s\n", file_name, file_line, p);}p = strtok(NULL, ",");    }}#endif/**************************************************************************** * * Function: ParseActivates(char *) * * Purpose: Set an activation link record * * Arguments: act_num => rule number to be activated * * Returns: void function * ****************************************************************************/void ParseActivates(char *act_num){    /*     * allocate a new node on the RTN get rid of whitespace at the front of     * the list     */    while (!isdigit((int) *act_num))act_num++;    otn_tmp->activates = atoi(act_num);}/**************************************************************************** * * Function: ParseActivatedBy(char *) * * Purpose: Set an activation link record * * Arguments: act_by => rule number to be activated * * Returns: void function * ****************************************************************************/void ParseActivatedBy(char *act_by){    ActivateList *al_ptr;    al_ptr = rtn_tmp->activate_list;    if (al_ptr == NULL)    {rtn_tmp->activate_list = (ActivateList *) calloc(sizeof(ActivateList), sizeof(char));if (rtn_tmp->activate_list == NULL){    FatalError("ERROR: ParseActivatedBy() calloc failed: %s\n", strerror(errno));}al_ptr = rtn_tmp->activate_list;    } else    {while (al_ptr->next != NULL){    al_ptr = al_ptr->next;}al_ptr->next = (ActivateList *) calloc(sizeof(ActivateList), sizeof(char));al_ptr = al_ptr->next;if (al_ptr == NULL){    FatalError("ERROR: ParseActivatedBy() calloc failed: %s\n", strerror(errno));}    }    /* get rid of whitespace at the front of the list */    while (!isdigit((int) *act_by))act_by++;    /* set the RTN list node number */    al_ptr->activated_by = atoi(act_by);    /* set the OTN list node number */    otn_tmp->activated_by = atoi(act_by);    return;}void ParseCount(char *num){    while (!isdigit((int) *num))num++;    otn_tmp->activation_counter = atoi(num);#ifdef DEBUG    printf("Set activation counter to %d\n", otn_tmp->activation_counter);#endif    return;}/**************************************************************************** * * Function: XferHeader(RuleTreeNode *, RuleTreeNode *) * * Purpose: Transfer the rule block header data from point A to point B * * Arguments: rule => the place to xfer from *            rtn => the place to xfer to * * Returns: void function * ***************************************************************************/void XferHeader(RuleTreeNode * rule, RuleTreeNode * rtn){    rtn->type = rule->type;    rtn->sip = rule->sip;    rtn->dip = rule->dip;    rtn->smask = rule->smask;    rtn->dmask = rule->dmask;    rtn->hsp = rule->hsp;    rtn->lsp = rule->lsp;    rtn->hdp = rule->hdp;    rtn->ldp = rule->ldp;    rtn->flags = rule->flags;}/**************************************************************************** * * Function: TestHeader(RuleTreeNode *, RuleTreeNode *) * * Purpose: Check to see if the two header blocks are identical * * Arguments: rule => uh *            rtn  => uuuuhhhhh.... * * Returns: 1 if they match, 0 if they don't * ***************************************************************************/int TestHeader(RuleTreeNode * rule, RuleTreeNode * rtn){    if (rtn->sip == rule->sip)    {if (rtn->dip == rule->dip){    if (rtn->dmask == rule->dmask)    {if (rtn->smask == rule->smask){    if (rtn->hsp == rule->hsp)    {if (rtn->lsp == rule->lsp){    if (rtn->hdp == rule->hdp)    {if (rtn->ldp == rule->ldp){    if (rtn->flags == rule->flags)    {return 1;    }}    }}    }}    }}    }    return 0;}/**************************************************************************** * * Function: VarAlloc() * * Purpose: allocates memory for a variable * * Arguments: none * * Returns: pointer to new VarEntry * ***************************************************************************/struct VarEntry *VarAlloc(){    struct VarEntry *new;    if ((new = (struct VarEntry *) calloc(sizeof(struct VarEntry), sizeof(char))) == NULL)    {FatalError("ERROR: cannot allocate memory for VarEntry.");    }    new->name = NULL;    new->value = NULL;    new->prev = NULL;    new->next = NULL;    return (new);}/**************************************************************************** * * Function: VarDefine(char *, char *) * * Purpose: define the contents of a variable * * Arguments: name => the name of the variable *            value => the contents of the variable * * Returns: void function * ***************************************************************************/void VarDefine(char *name, char *value){    struct VarEntry *p;    int found = 0;    if (!VarHead)    {p = VarAlloc();p->name = strdup(name);p->value = strdup(value);p->prev = p;p->next = p;VarHead = p;return;    }    p = VarHead;    do    {if (strcasecmp(p->name, name) == 0){    found = 1;    break;}p = p->next;    } while (p != VarHead);    if (found)    {if (p->value)    free(p->value);p->value = strdup(value);    } else    {p = VarAlloc();p->name = strdup(name);p->value = strdup(value);p->prev = VarHead;p->next = VarHead->next;p->next->prev = p;VarHead->next = p;    }}/**************************************************************************** * * Function: VarDelete(char *) * * Purpose: deletes a defined variable * * Arguments: name => the name of the variable * * Returns: void function * ***************************************************************************/void VarDelete(char *name){    struct VarEntry *p;    if (!VarHead)return;    p = VarHead;    do    {if (strcasecmp(p->name, name) == 0){    p->prev->next = p->next;    p->next->prev = p->prev;    if (VarHead == p)if ((VarHead = p->next) == p)    VarHead = NULL;    if (p->name)free(p->name);    if (p->value)free(p->value);    free(p);    return;}p = p->next;    } while (p != VarHead);}/**************************************************************************** * * Function: VarGet(char *) * * Purpose: get the contents of a variable * * Arguments: name => the name of the variable * * Returns: char * to contents of variable or NULL * ***************************************************************************/char *VarGet(char *name){    struct VarEntry *p;    if (!VarHead)return (NULL);    p = VarHead;    do    {if (strcasecmp(p->name, name) == 0)    return (p->value);p = p->next;    } while (p != VarHead);    return (NULL);}


原创粉丝点击