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 <stdlib.h>
29 #include <string.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 "plugbase.h"
37 #include "parser.h"
38 #include "snort_debug.h"
39 #include "util.h"
40 #include "plugin_enum.h"
41 #include "sp_icmp_type_check.h"
42 #include "sfhashfcn.h"
43
44 #include "snort.h"
45 #include "profiler.h"
46 #ifdef PERF_PROFILING
47 PreprocStats icmpTypePerfStats;
48 extern PreprocStats ruleOTNEvalPerfStats;
49 #endif
50
51 #include "sfhashfcn.h"
52 #include "detection_options.h"
53
54 void IcmpTypeCheckInit(struct _SnortConfig *, char *, OptTreeNode *, int);
55 void ParseIcmpType(struct _SnortConfig *, char *, OptTreeNode *);
56 int IcmpTypeCheck(void *option_data, Packet *p);
57
IcmpTypeCheckHash(void * d)58 uint32_t IcmpTypeCheckHash(void *d)
59 {
60 uint32_t a,b,c;
61 IcmpTypeCheckData *data = (IcmpTypeCheckData *)d;
62
63 a = data->icmp_type;
64 b = data->icmp_type2;
65 c = data->operator;
66
67 mix(a,b,c);
68
69 a += RULE_OPTION_TYPE_ICMP_TYPE;
70
71 final(a,b,c);
72
73 return c;
74 }
75
IcmpTypeCheckCompare(void * l,void * r)76 int IcmpTypeCheckCompare(void *l, void *r)
77 {
78 IcmpTypeCheckData *left = (IcmpTypeCheckData *)l;
79 IcmpTypeCheckData *right = (IcmpTypeCheckData *)r;
80
81 if (!left || !right)
82 return DETECTION_OPTION_NOT_EQUAL;
83
84 if ((left->icmp_type == right->icmp_type) &&
85 (left->icmp_type2 == right->icmp_type2) &&
86 (left->operator == right->operator))
87 {
88 return DETECTION_OPTION_EQUAL;
89 }
90
91 return DETECTION_OPTION_NOT_EQUAL;
92 }
93
94 /****************************************************************************
95 *
96 * Function: SetupIcmpTypeCheck()
97 *
98 * Purpose: Register the itype keyword and configuration function
99 *
100 * Arguments: None.
101 *
102 * Returns: void function
103 *
104 ****************************************************************************/
SetupIcmpTypeCheck(void)105 void SetupIcmpTypeCheck(void)
106 {
107 /* map the keyword to an initialization/processing function */
108 RegisterRuleOption("itype", IcmpTypeCheckInit, NULL, OPT_TYPE_DETECTION, NULL);
109 #ifdef PERF_PROFILING
110 RegisterPreprocessorProfile("itype", &icmpTypePerfStats, 3, &ruleOTNEvalPerfStats, NULL);
111 #endif
112 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Plugin: IcmpTypeCheck Initialized\n"););
113 }
114
115
116 /****************************************************************************
117 *
118 * Function: IcmpTypeCheckInit(struct _SnortConfig *, char *, OptTreeNode *)
119 *
120 * Purpose: Initialize the rule data structs and parse the rule argument
121 * data, then link in the detection function
122 *
123 * Arguments: data => rule arguments/data
124 * otn => pointer to the current rule option list node
125 *
126 * Returns: void function
127 *
128 ****************************************************************************/
IcmpTypeCheckInit(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)129 void IcmpTypeCheckInit(struct _SnortConfig *sc, char *data, OptTreeNode *otn, int protocol)
130 {
131 OptFpList *fpl;
132 if(protocol != IPPROTO_ICMP)
133 {
134 FatalError("%s(%d): ICMP Options on non-ICMP rule\n", file_name, file_line);
135 }
136
137 /* multiple declaration check */
138 if(otn->ds_list[PLUGIN_ICMP_TYPE])
139 {
140 FatalError("%s(%d): Multiple ICMP type options in rule\n", file_name,
141 file_line);
142 }
143
144 /* allocate the data structure and attach it to the
145 rule's data struct list */
146 otn->ds_list[PLUGIN_ICMP_TYPE] = (IcmpTypeCheckData *)
147 SnortAlloc(sizeof(IcmpTypeCheckData));
148
149 /* this is where the keyword arguments are processed and placed into the
150 rule option's data structure */
151 ParseIcmpType(sc, data, otn);
152
153 /* finally, attach the option's detection function to the rule's
154 detect function pointer list */
155 fpl = AddOptFuncToList(IcmpTypeCheck, otn);
156 fpl->type = RULE_OPTION_TYPE_ICMP_TYPE;
157 fpl->context = otn->ds_list[PLUGIN_ICMP_TYPE];
158 }
159
160
161
162 /****************************************************************************
163 *
164 * Function: ParseIcmpType(struct _SnortConfig *, char *, OptTreeNode *)
165 *
166 * Purpose: Process the itype argument and stick it in the data struct
167 *
168 * Arguments: data => argument data
169 * otn => pointer to the current rule's OTN
170 *
171 * Returns: void function
172 *
173 ****************************************************************************/
ParseIcmpType(struct _SnortConfig * sc,char * data,OptTreeNode * otn)174 void ParseIcmpType(struct _SnortConfig *sc, char *data, OptTreeNode *otn)
175 {
176 char *type;
177 IcmpTypeCheckData *ds_ptr; /* data struct pointer */
178 void *ds_ptr_dup;
179 char *endptr = NULL;
180
181 /* set the ds pointer to make it easier to reference the option's
182 particular data struct */
183 ds_ptr = otn->ds_list[PLUGIN_ICMP_TYPE];
184
185 /* set a pointer to the data so to leave the original unchanged */
186 type = data;
187
188 if(!data)
189 {
190 FatalError("%s (%d): No ICMP Type Specified\n",
191 file_name, file_line);
192 }
193
194 /* get rid of spaces before the data */
195 while(isspace((int)*data))
196 data++;
197
198 if (*data == '\0')
199 {
200 FatalError("%s (%d): No ICMP Type Specified : %s\n",
201 file_name, file_line, type);
202 }
203
204 /*
205 * if a range is specified, put the min in icmp_type, and the max in
206 * icmp_type2
207 */
208
209 if (isdigit((int)*data) && strstr(data, "<>"))
210 {
211 ds_ptr->icmp_type = strtol(data, &endptr, 10);
212 while (isspace((int)*endptr))
213 endptr++;
214
215 if (*endptr != '<')
216 {
217 FatalError("%s (%d): Invalid ICMP itype in rule: %s\n",
218 file_name, file_line, type);
219 }
220
221 data = endptr;
222
223 data += 2; /* move past <> */
224
225 while (isspace((int)*data))
226 data++;
227
228 ds_ptr->icmp_type2 = strtol(data, &endptr, 10);
229 if (*data == '\0' || *endptr != '\0')
230 {
231 FatalError("%s (%d): Invalid ICMP itype in rule: %s\n",
232 file_name, file_line, type);
233 }
234
235 ds_ptr->operator = ICMP_TYPE_TEST_RG;
236 }
237 /* otherwise if its greater than... */
238 else if (*data == '>')
239 {
240 data++;
241 while (isspace((int)*data))
242 data++;
243
244 ds_ptr->icmp_type = strtol(data, &endptr, 10);
245 if (*data == '\0' || *endptr != '\0')
246 {
247 FatalError("%s (%d): Invalid ICMP itype in rule: %s\n",
248 file_name, file_line, type);
249 }
250
251 ds_ptr->operator = ICMP_TYPE_TEST_GT;
252 }
253 /* otherwise if its less than ... */
254 else if (*data == '<')
255 {
256 data++;
257 while (isspace((int)*data))
258 data++;
259
260 ds_ptr->icmp_type = strtol(data, &endptr, 10);
261 if (*data == '\0' || *endptr != '\0')
262 {
263 FatalError("%s (%d): Invalid ICMP itype in rule: %s\n",
264 file_name, file_line, type);
265 }
266
267 ds_ptr->operator = ICMP_TYPE_TEST_LT;
268 }
269 /* otherwise check if its a digit */
270 else
271 {
272 ds_ptr->icmp_type = strtol(data, &endptr, 10);
273 if (*endptr != '\0')
274 {
275 FatalError("%s (%d): Invalid ICMP itype in rule: %s\n",
276 file_name, file_line, type);
277 }
278
279 ds_ptr->operator = ICMP_TYPE_TEST_EQ;
280 }
281
282 if (add_detection_option(sc, RULE_OPTION_TYPE_ICMP_TYPE, (void *)ds_ptr, &ds_ptr_dup) == DETECTION_OPTION_EQUAL)
283 {
284 free(ds_ptr);
285 ds_ptr = otn->ds_list[PLUGIN_ICMP_TYPE] = ds_ptr_dup;
286 }
287
288 return;
289 }
290
291 /****************************************************************************
292 *
293 * Function: IcmpTypeCheck(char *, OptTreeNode *)
294 *
295 * Purpose: Test the packet's ICMP type field value against the option's
296 * ICMP type
297 *
298 * Arguments: data => argument data
299 * otn => pointer to the current rule's OTN
300 *
301 * Returns: void function
302 *
303 ****************************************************************************/
IcmpTypeCheck(void * option_data,Packet * p)304 int IcmpTypeCheck(void *option_data, Packet *p)
305 {
306 IcmpTypeCheckData *ds_ptr;
307 int rval = DETECTION_OPTION_NO_MATCH;
308 PROFILE_VARS;
309
310 ds_ptr = (IcmpTypeCheckData *)option_data;
311
312 /* return 0 if we don't have an icmp header */
313 if(!p->icmph)
314 return rval;
315
316 PREPROC_PROFILE_START(icmpTypePerfStats);
317
318 switch(ds_ptr->operator)
319 {
320 case ICMP_TYPE_TEST_EQ:
321 if (p->icmph->type == ds_ptr->icmp_type)
322 rval = DETECTION_OPTION_MATCH;
323 break;
324 case ICMP_TYPE_TEST_GT:
325 if (p->icmph->type > ds_ptr->icmp_type)
326 rval = DETECTION_OPTION_MATCH;
327 break;
328 case ICMP_TYPE_TEST_LT:
329 if (p->icmph->type < ds_ptr->icmp_type)
330 rval = DETECTION_OPTION_MATCH;
331 break;
332 case ICMP_TYPE_TEST_RG:
333 if (p->icmph->type > ds_ptr->icmp_type &&
334 p->icmph->type < ds_ptr->icmp_type2)
335 rval = DETECTION_OPTION_MATCH;
336 break;
337 }
338
339 DEBUG_WRAP(
340 if (rval == DETECTION_OPTION_MATCH)
341 {
342 DebugMessage(DEBUG_PLUGIN, "Got icmp type match!\n");
343 }
344 else
345 {
346 DebugMessage(DEBUG_PLUGIN, "Failed icmp type match!\n");
347 }
348 );
349
350 PREPROC_PROFILE_END(icmpTypePerfStats);
351 return rval;
352 }
353