1 /*
2 ** Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 ** Copyright (C) 2002-2013 Sourcefire, Inc.
4 ** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License Version 2 as
8 ** published by the Free Software Foundation.  You may not use, modify or
9 ** distribute this program under any other version of the GNU General
10 ** Public License.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software
19 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 */
21 
22 /* $Id$ */
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 
28 #include <sys/types.h>
29 #include <stdlib.h>
30 #include <ctype.h>
31 
32 #include "sf_types.h"
33 #include "rules.h"
34 #include "treenodes.h"
35 #include "decode.h"
36 #include "parser.h"
37 #include "plugbase.h"
38 #include "snort_debug.h"
39 #include "plugin_enum.h"
40 #include "util.h"
41 
42 #include "snort.h"
43 #include "profiler.h"
44 #ifdef PERF_PROFILING
45 PreprocStats ipIdPerfStats;
46 extern PreprocStats ruleOTNEvalPerfStats;
47 #endif
48 
49 #include "sfhashfcn.h"
50 #include "detection_options.h"
51 
52 typedef struct _IpIdCheckData
53 {
54     u_long ip_id;
55 
56 } IpIdCheckData;
57 
58 void IpIdCheckInit(struct _SnortConfig *, char *, OptTreeNode *, int);
59 void ParseIpId(struct _SnortConfig *, char *, OptTreeNode *);
60 int IpIdCheckEq(void *option_data, Packet *p);
61 
IpIdCheckHash(void * d)62 uint32_t IpIdCheckHash(void *d)
63 {
64     uint32_t a,b,c;
65     IpIdCheckData *data = (IpIdCheckData *)d;
66 
67     a = data->ip_id;
68     b = RULE_OPTION_TYPE_IP_ID;
69     c = 0;
70 
71     final(a,b,c);
72 
73     return c;
74 }
75 
IpIdCheckCompare(void * l,void * r)76 int IpIdCheckCompare(void *l, void *r)
77 {
78     IpIdCheckData *left = (IpIdCheckData *)l;
79     IpIdCheckData *right = (IpIdCheckData *)r;
80 
81     if (!left || !right)
82         return DETECTION_OPTION_NOT_EQUAL;
83 
84     if (left->ip_id == right->ip_id)
85     {
86         return DETECTION_OPTION_EQUAL;
87     }
88 
89     return DETECTION_OPTION_NOT_EQUAL;
90 }
91 
92 /****************************************************************************
93  *
94  * Function: SetupIpIdCheck()
95  *
96  * Purpose: Associate the id keyword with IpIdCheckInit
97  *
98  * Arguments: None.
99  *
100  * Returns: void function
101  *
102  ****************************************************************************/
SetupIpIdCheck(void)103 void SetupIpIdCheck(void)
104 {
105     /* map the keyword to an initialization/processing function */
106     RegisterRuleOption("id", IpIdCheckInit, NULL, OPT_TYPE_DETECTION, NULL);
107 #ifdef PERF_PROFILING
108     RegisterPreprocessorProfile("id", &ipIdPerfStats, 3, &ruleOTNEvalPerfStats, NULL);
109 #endif
110 
111     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Plugin: IpIdCheck Initialized\n"););
112 }
113 
114 
115 /****************************************************************************
116  *
117  * Function: IpIdCheckInit(struct _SnortConfig *, char *, OptTreeNode *)
118  *
119  * Purpose: Setup the id data struct and link the function into option
120  *          function pointer list
121  *
122  * Arguments: data => rule arguments/data
123  *            otn => pointer to the current rule option list node
124  *
125  * Returns: void function
126  *
127  ****************************************************************************/
IpIdCheckInit(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)128 void IpIdCheckInit(struct _SnortConfig *sc, char *data, OptTreeNode *otn, int protocol)
129 {
130     OptFpList *fpl;
131     /* multiple declaration check */
132     if(otn->ds_list[PLUGIN_IP_ID_CHECK])
133     {
134         FatalError("%s(%d): Multiple IP id options in rule\n", file_name,
135                 file_line);
136     }
137 
138     /* allocate the data structure and attach it to the
139        rule's data struct list */
140     otn->ds_list[PLUGIN_IP_ID_CHECK] = (IpIdCheckData *)
141             SnortAlloc(sizeof(IpIdCheckData));
142 
143     /* this is where the keyword arguments are processed and placed into the
144        rule option's data structure */
145     ParseIpId(sc, data, otn);
146 
147     /* finally, attach the option's detection function to the rule's
148        detect function pointer list */
149     fpl = AddOptFuncToList(IpIdCheckEq, otn);
150     fpl->type = RULE_OPTION_TYPE_IP_ID;
151     fpl->context = otn->ds_list[PLUGIN_IP_ID_CHECK];
152 }
153 
154 
155 
156 /****************************************************************************
157  *
158  * Function: ParseIpId(struct _SnortConfig *, char *, OptTreeNode *)
159  *
160  * Purpose: Convert the id option argument to data and plug it into the
161  *          data structure
162  *
163  * Arguments: data => argument data
164  *            otn => pointer to the current rule's OTN
165  *
166  * Returns: void function
167  *
168  ****************************************************************************/
ParseIpId(struct _SnortConfig * sc,char * data,OptTreeNode * otn)169 void ParseIpId(struct _SnortConfig *sc, char *data, OptTreeNode *otn)
170 {
171     IpIdCheckData *ds_ptr;  /* data struct pointer */
172     void *ds_ptr_dup;
173     int ip_id;
174     char *endTok;
175 
176     /* set the ds pointer to make it easier to reference the option's
177        particular data struct */
178     ds_ptr = otn->ds_list[PLUGIN_IP_ID_CHECK];
179 
180     /* get rid of any whitespace */
181     while(isspace((int)*data))
182     {
183         data++;
184     }
185 
186     ip_id = SnortStrtolRange(data, &endTok, 10, 0, UINT16_MAX);
187     if ((endTok == data) || (*endTok != '\0'))
188     {
189         FatalError("%s(%d) => Invalid parameter '%s' to id (not a "
190                    "number?) \n", file_name, file_line, data);
191     }
192     ds_ptr->ip_id = htons( (u_short) ip_id);
193 
194     if (add_detection_option(sc, RULE_OPTION_TYPE_IP_ID, (void *)ds_ptr, &ds_ptr_dup) == DETECTION_OPTION_EQUAL)
195     {
196         free(ds_ptr);
197         ds_ptr = otn->ds_list[PLUGIN_IP_ID_CHECK] = ds_ptr_dup;
198     }
199 
200     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"ID set to %ld\n", ds_ptr->ip_id););
201 }
202 
203 
204 /****************************************************************************
205  *
206  * Function: IpIdCheckEq(char *, OptTreeNode *)
207  *
208  * Purpose: Test the ip header's id field to see if its value is equal to the
209  *          value in the rule.  This is useful to detect things like "elite"
210  *          numbers, oddly repeating numbers, etc.
211  *
212  * Arguments: data => argument data
213  *            otn => pointer to the current rule's OTN
214  *
215  * Returns: void function
216  *
217  ****************************************************************************/
IpIdCheckEq(void * option_data,Packet * p)218 int IpIdCheckEq(void *option_data, Packet *p)
219 {
220     IpIdCheckData *ipIdCheckData = (IpIdCheckData *)option_data;
221     int rval = DETECTION_OPTION_NO_MATCH;
222     PROFILE_VARS;
223 
224     if(!IPH_IS_VALID(p))
225         return rval; /* if error occured while ip header
226                    * was processed, return 0 automagically.  */
227 
228     PREPROC_PROFILE_START(ipIdPerfStats);
229 
230     if(ipIdCheckData->ip_id == GET_IPH_ID(p))
231     {
232         /* call the next function in the function list recursively */
233         rval = DETECTION_OPTION_MATCH;
234     }
235     else
236     {
237         /* you can put debug comments here or not */
238         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "No match for sp_ip_id_check\n"););
239     }
240 
241     /* if the test isn't successful, return 0 */
242     PREPROC_PROFILE_END(ipIdPerfStats);
243     return rval;
244 }
245