📄 rules.c
字号:
/* $Id: rules.c,v 1.22 2000/03/16 02:58:44 roesch Exp $ */
/*
** Copyright (C) 1998,1999,2000 Martin Roesch <roesch@clark.net>
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "rules.h"
ListHead Alert; /* Alert Block Header */
ListHead Log; /* Log Block Header */
ListHead Pass; /* Pass Block Header */
RuleTreeNode *rtn_tmp; /* temp data holder */
OptTreeNode *otn_tmp; /* OptTreeNode temp ptr */
struct VarEntry *VarHead = NULL;
char *file_name; /* current rules file being processed */
int file_line; /* current line being processed in the rules file */
int list_file_line; /* current line being processed in the list file */
int rule_count; /* number of rules generated */
int head_count; /* number of header blocks (chain heads?) */
int opt_count; /* number of chains */
int do_detect;
extern KeywordXlateList *KeywordList; /* detection plugin keywords */
extern PreprocessKeywordList *PreprocessKeywords; /* preprocessor plugin keywords */
extern PreprocessFuncNode *PreprocessList; /* Preprocessor function list */
extern OutputKeywordList *OutputKeywords; /* Output plugin keyword list */
extern OutputFuncNode *AlertList; /* Alert function list */
extern OutputFuncNode *LogList; /* log function list */
#ifdef BENCHMARK
int check_count; /* number of tests for a given rule to determine a match */
int cmpcount; /* compare counter */
#endif
/****************************************************************************
*
* Function: ParseRulesFile(char *, int)
*
* Purpose: Read the rules file a line at a time and send each rule to
* the rule parser
*
* Arguments: file => rules file filename
* inclevel => nr of stacked "include"s
*
* Returns: void function
*
***************************************************************************/
void ParseRulesFile(char *file, int inclevel)
{
FILE *thefp; /* file pointer for the rules file */
char buf[STD_BUF]; /* file read buffer */
char *index; /* buffer indexing pointer */
char *stored_file_name = file_name;
int stored_file_line = file_line;
#ifdef DEBUG
printf("Opening rules file: %s\n", file);
#endif
if (inclevel == 0)
{
if ( !pv.quiet_flag )
{
printf("\n+++++++++++++++++++++++++++++++++++++++++++++++++++\n");
printf("Initializing rule chains...\n");
}
file_name = strdup(file);
}
/* open the rules file */
if ((thefp = fopen(file,"r")) == NULL)
{
FatalError( "ERROR: Unable to open rules file: %s\n", file);
}
/* clear the line buffer */
bzero((char *)buf, STD_BUF);
stored_file_line = file_line;
stored_file_name = file_name;
file_name = strdup(file);
file_line = 0;
/* loop thru each file line and send it to the rule parser */
while ((fgets(buf, STD_BUF, thefp)) != NULL)
{
/* inc the line counter so the error messages know which line to
bitch about */
file_line++;
index = buf;
#ifdef DEBUG2
printf("Got line %s (%d): %s", file_name, file_line, buf);
#endif
/* if it's not a comment or a <CR>, send it to the parser */
if ((*index != '#') && (*index != 0x0a) && (*index != ';') && (index != NULL))
{
/* advance through any whitespace at the beginning of the line */
while (isspace((int) *index)) index++;
ParseRule(index, inclevel);
}
bzero((char *)buf, STD_BUF);
}
if (file_name)
free(file_name);
file_name = stored_file_name;
file_line = stored_file_line;
if (inclevel == 0 && ! pv.quiet_flag )
{
printf("%d Snort rules read...\n", rule_count);
printf("%d Option Chains linked into %d Chain Headers\n", opt_count, head_count);
printf("+++++++++++++++++++++++++++++++++++++++++++++++++++\n\n");
}
fclose(thefp);
if (inclevel == 0)
{
#ifdef DEBUG
DumpChain(Alert.TcpList, "Alert TCP Chains");
DumpChain(Alert.UdpList, "Alert UDP Chains");
DumpChain(Alert.IcmpList, "Alert ICMP Chains");
DumpChain(Log.TcpList, "Log TCP Chains");
DumpChain(Log.UdpList, "Log UDP Chains");
DumpChain(Log.IcmpList, "Log ICMP Chains");
DumpChain(Pass.TcpList, "Pass TCP Chains");
DumpChain(Pass.UdpList, "Pass UDP Chains");
DumpChain(Pass.IcmpList, "Pass ICMP Chains");
if ( !pv.quiet_flag )
{
printf("Performing Rule List Integrity Tests...\n");
printf("---------------------------------------\n");
}
IntegrityCheck(Alert.TcpList,"Alert TCP Chains" );
IntegrityCheck(Alert.UdpList, "Alert UDP Chains");
IntegrityCheck(Alert.IcmpList, "Alert ICMP Chains");
IntegrityCheck(Log.TcpList, "Log TCP Chains");
IntegrityCheck(Log.UdpList, "Log UDP Chains");
IntegrityCheck(Log.IcmpList, "Log ICMP Chains");
IntegrityCheck(Pass.TcpList, "Pass TCP Chains");
IntegrityCheck(Pass.UdpList, "Pass UDP Chains");
IntegrityCheck(Pass.IcmpList, "Pass ICMP Chains");
if ( !pv.quiet_flag )
{
printf("---------------------------------------\n\n");
}
#endif
}
return;
}
/****************************************************************************
*
* Function: ParseRule(char *, int)
*
* Purpose: Process an individual rule and add it to the rule list
*
* Arguments: rule => rule string
* inclevel => nr of stacked "include"s
*
* Returns: void function
*
***************************************************************************/
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]);
proto_node.type = rule_type;
#ifdef DEBUG
printf("Rule type: ");
#endif
/* handle non-rule entries */
switch (rule_type)
{
case RULE_PASS:
#ifdef DEBUG
printf("Pass\n");
#endif
break;
case RULE_LOG:
#ifdef DEBUG
printf("Log\n");
#endif
break;
case RULE_ALERT:
#ifdef DEBUG
printf("Alert\n");
#endif
break;
case RULE_INCLUDE:
#ifdef DEBUG
printf("Include\n");
#endif
ParseRulesFile(toks[1], inclevel + 1);
return;
case RULE_VAR:
#ifdef DEBUG
printf("Variable\n");
#endif
VarDefine(toks[1], toks[2]);
return;
case RULE_PREPROCESS:
#ifdef DEBUG
printf("Preprocessor\n");
#endif
ParsePreprocessor(rule);
return;
case RULE_OUTPUT:
#ifdef DEBUG
printf("Output Plugin\n");
#endif
ParseOutputPlugin(rule);
return;
}
/* 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 DEBUG
printf("Bidirectional rule!\n");
#endif
proto_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 DEBUG
printf("setting exception flag for dest IP\n");
#endif
proto_node.flags |= EXCEPT_DST_IP;
ParseIP(&toks[5][1], (u_long *) &proto_node.dip,
(u_long *) &proto_node.dmask);
}
else
ParseIP(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);
#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;
}
rule_count++;
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);
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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -