/src/suricata7/src/detect-tos.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2007-2020 Open Information Security Foundation |
2 | | * |
3 | | * You can copy, redistribute or modify this Program under the terms of |
4 | | * the GNU General Public License version 2 as published by the Free |
5 | | * Software Foundation. |
6 | | * |
7 | | * This program is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | | * GNU General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU General Public License |
13 | | * version 2 along with this program; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
15 | | * 02110-1301, USA. |
16 | | */ |
17 | | |
18 | | /** |
19 | | * \file |
20 | | * |
21 | | * \author Anoop Saldanha <anoopsaldanha@gmail.com> |
22 | | */ |
23 | | |
24 | | #include "suricata-common.h" |
25 | | #include "threads.h" |
26 | | #include "decode.h" |
27 | | |
28 | | #include "detect.h" |
29 | | #include "detect-parse.h" |
30 | | #include "detect-engine.h" |
31 | | #include "detect-engine-mpm.h" |
32 | | #include "detect-engine-state.h" |
33 | | #include "detect-tos.h" |
34 | | |
35 | | #include "app-layer-protos.h" |
36 | | |
37 | | #include "flow.h" |
38 | | #include "flow-var.h" |
39 | | #include "flow-util.h" |
40 | | |
41 | | #include "util-byte.h" |
42 | | #include "util-debug.h" |
43 | | #include "util-unittest.h" |
44 | | #include "util-unittest-helper.h" |
45 | | |
46 | 73 | #define PARSE_REGEX "^\\s*(!?\\s*[0-9]{1,3}|!?\\s*[xX][0-9a-fA-F]{1,2})\\s*$" |
47 | | |
48 | | static DetectParseRegex parse_regex; |
49 | | |
50 | | static int DetectTosSetup(DetectEngineCtx *, Signature *, const char *); |
51 | | static int DetectTosMatch(DetectEngineThreadCtx *, Packet *, |
52 | | const Signature *, const SigMatchCtx *); |
53 | | #ifdef UNITTESTS |
54 | | static void DetectTosRegisterTests(void); |
55 | | #endif |
56 | | static void DetectTosFree(DetectEngineCtx *, void *); |
57 | | |
58 | 3.07k | #define DETECT_IPTOS_MIN 0 |
59 | 1.53k | #define DETECT_IPTOS_MAX 255 |
60 | | |
61 | | /** |
62 | | * \brief Register Tos keyword. |
63 | | */ |
64 | | void DetectTosRegister(void) |
65 | 73 | { |
66 | 73 | sigmatch_table[DETECT_TOS].name = "tos"; |
67 | 73 | sigmatch_table[DETECT_TOS].desc = "match on specific decimal values of the IP header TOS field"; |
68 | 73 | sigmatch_table[DETECT_TOS].Match = DetectTosMatch; |
69 | 73 | sigmatch_table[DETECT_TOS].Setup = DetectTosSetup; |
70 | 73 | sigmatch_table[DETECT_TOS].Free = DetectTosFree; |
71 | | #ifdef UNITTESTS |
72 | | sigmatch_table[DETECT_TOS].RegisterTests = DetectTosRegisterTests; |
73 | | #endif |
74 | 73 | sigmatch_table[DETECT_TOS].flags = |
75 | 73 | (SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_HANDLE_NEGATION); |
76 | 73 | sigmatch_table[DETECT_TOS].url = |
77 | 73 | "/rules/header-keywords.html#tos"; |
78 | | |
79 | 73 | DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); |
80 | 73 | } |
81 | | |
82 | | /** |
83 | | * \brief Match function for tos keyword. |
84 | | * |
85 | | * \param tv ThreadVars instance. |
86 | | * \param det_ctx Pointer to the detection thread ctx. |
87 | | * \param p Pointer to the packet. |
88 | | * \param m Pointer to the SigMatch containing the tos data. |
89 | | * |
90 | | * \retval 0 no match |
91 | | * \retval 1 match |
92 | | */ |
93 | | static int DetectTosMatch(DetectEngineThreadCtx *det_ctx, Packet *p, |
94 | | const Signature *s, const SigMatchCtx *ctx) |
95 | 108k | { |
96 | 108k | const DetectTosData *tosd = (const DetectTosData *)ctx; |
97 | 108k | int result = 0; |
98 | | |
99 | 108k | if (!PKT_IS_IPV4(p) || PKT_IS_PSEUDOPKT(p)) { |
100 | 8.28k | return 0; |
101 | 8.28k | } |
102 | | |
103 | 100k | if (tosd->tos == IPV4_GET_IPTOS(p)) { |
104 | 99.0k | SCLogDebug("tos match found for %d\n", tosd->tos); |
105 | 99.0k | result = 1; |
106 | 99.0k | } |
107 | | |
108 | 100k | return (tosd->negated ^ result); |
109 | 108k | } |
110 | | |
111 | | static DetectTosData *DetectTosParse(const char *arg, bool negate) |
112 | 1.70k | { |
113 | 1.70k | DetectTosData *tosd = NULL; |
114 | 1.70k | size_t pcre2len; |
115 | | |
116 | 1.70k | pcre2_match_data *match = NULL; |
117 | 1.70k | int ret = DetectParsePcreExec(&parse_regex, &match, arg, 0, 0); |
118 | 1.70k | if (ret != 2) { |
119 | 164 | SCLogError("invalid tos option - %s. " |
120 | 164 | "The tos option value must be in the range " |
121 | 164 | "%u - %u", |
122 | 164 | arg, DETECT_IPTOS_MIN, DETECT_IPTOS_MAX); |
123 | 164 | goto error; |
124 | 164 | } |
125 | | |
126 | | /* For TOS value */ |
127 | 1.54k | char tosbytes_str[64] = ""; |
128 | 1.54k | pcre2len = sizeof(tosbytes_str); |
129 | 1.54k | int res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)tosbytes_str, &pcre2len); |
130 | 1.54k | if (res < 0) { |
131 | 4 | SCLogError("pcre2_substring_copy_bynumber failed"); |
132 | 4 | goto error; |
133 | 4 | } |
134 | | |
135 | 1.54k | int64_t tos = 0; |
136 | | |
137 | 1.54k | if (tosbytes_str[0] == 'x' || tosbytes_str[0] == 'X') { |
138 | 94 | if (StringParseInt64(&tos, 16, 0, &tosbytes_str[1]) < 0) { |
139 | 0 | goto error; |
140 | 0 | } |
141 | 1.44k | } else { |
142 | 1.44k | if (StringParseInt64(&tos, 10, 0, &tosbytes_str[0]) < 0) { |
143 | 3 | goto error; |
144 | 3 | } |
145 | 1.44k | } |
146 | | |
147 | 1.53k | if (!(tos >= DETECT_IPTOS_MIN && tos <= DETECT_IPTOS_MAX)) { |
148 | 10 | SCLogError("Invalid tos argument - " |
149 | 10 | "%s. The tos option value must be in the range " |
150 | 10 | "%u - %u", |
151 | 10 | tosbytes_str, DETECT_IPTOS_MIN, DETECT_IPTOS_MAX); |
152 | 10 | goto error; |
153 | 10 | } |
154 | | |
155 | 1.52k | tosd = SCMalloc(sizeof(DetectTosData)); |
156 | 1.52k | if (unlikely(tosd == NULL)) |
157 | 0 | goto error; |
158 | 1.52k | tosd->tos = (uint8_t)tos; |
159 | 1.52k | tosd->negated = negate; |
160 | | |
161 | 1.52k | pcre2_match_data_free(match); |
162 | 1.52k | return tosd; |
163 | | |
164 | 181 | error: |
165 | 181 | if (match) { |
166 | 181 | pcre2_match_data_free(match); |
167 | 181 | } |
168 | 181 | return NULL; |
169 | 1.52k | } |
170 | | |
171 | | /** |
172 | | * \brief Setup function for tos argument. Parse the argument and |
173 | | * add it into the sig. |
174 | | * |
175 | | * \param de_ctx Detection Engine Context instance. |
176 | | * \param s Pointer to the signature. |
177 | | * \param arg Argument to be parsed. |
178 | | * |
179 | | * \retval 0 on Success. |
180 | | * \retval -1 on Failure. |
181 | | */ |
182 | | static int DetectTosSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) |
183 | 1.70k | { |
184 | 1.70k | DetectTosData *tosd = DetectTosParse(arg, s->init_data->negated); |
185 | 1.70k | if (tosd == NULL) |
186 | 181 | return -1; |
187 | | |
188 | 1.52k | SigMatch *sm = SigMatchAlloc(); |
189 | 1.52k | if (sm == NULL) { |
190 | 0 | DetectTosFree(de_ctx, tosd); |
191 | 0 | return -1; |
192 | 0 | } |
193 | | |
194 | 1.52k | sm->type = DETECT_TOS; |
195 | 1.52k | sm->ctx = (SigMatchCtx *)tosd; |
196 | | |
197 | 1.52k | SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); |
198 | 1.52k | s->flags |= SIG_FLAG_REQUIRE_PACKET; |
199 | 1.52k | return 0; |
200 | 1.52k | } |
201 | | |
202 | | /** |
203 | | * \brief Free data allocated by the tos keyword. |
204 | | * |
205 | | * \param tosd Data to be freed. |
206 | | */ |
207 | | static void DetectTosFree(DetectEngineCtx *de_ctx, void *tosd) |
208 | 1.52k | { |
209 | 1.52k | SCFree(tosd); |
210 | 1.52k | } |
211 | | |
212 | | /********************************Unittests***********************************/ |
213 | | |
214 | | #ifdef UNITTESTS |
215 | | |
216 | | static int DetectTosTest01(void) |
217 | | { |
218 | | DetectTosData *tosd = NULL; |
219 | | tosd = DetectTosParse("12", false); |
220 | | if (tosd != NULL && tosd->tos == 12 && !tosd->negated) { |
221 | | DetectTosFree(NULL, tosd); |
222 | | return 1; |
223 | | } |
224 | | |
225 | | return 0; |
226 | | } |
227 | | |
228 | | static int DetectTosTest02(void) |
229 | | { |
230 | | DetectTosData *tosd = NULL; |
231 | | tosd = DetectTosParse("123", false); |
232 | | if (tosd != NULL && tosd->tos == 123 && !tosd->negated) { |
233 | | DetectTosFree(NULL, tosd); |
234 | | return 1; |
235 | | } |
236 | | |
237 | | return 0; |
238 | | } |
239 | | |
240 | | static int DetectTosTest04(void) |
241 | | { |
242 | | DetectTosData *tosd = NULL; |
243 | | tosd = DetectTosParse("256", false); |
244 | | if (tosd != NULL) { |
245 | | DetectTosFree(NULL, tosd); |
246 | | return 0; |
247 | | } |
248 | | |
249 | | return 1; |
250 | | } |
251 | | |
252 | | static int DetectTosTest05(void) |
253 | | { |
254 | | DetectTosData *tosd = NULL; |
255 | | tosd = DetectTosParse("boom", false); |
256 | | if (tosd != NULL) { |
257 | | DetectTosFree(NULL, tosd); |
258 | | return 0; |
259 | | } |
260 | | |
261 | | return 1; |
262 | | } |
263 | | |
264 | | static int DetectTosTest06(void) |
265 | | { |
266 | | DetectTosData *tosd = NULL; |
267 | | tosd = DetectTosParse("x12", false); |
268 | | if (tosd != NULL && tosd->tos == 0x12 && !tosd->negated) { |
269 | | DetectTosFree(NULL, tosd); |
270 | | return 1; |
271 | | } |
272 | | |
273 | | return 0; |
274 | | } |
275 | | |
276 | | static int DetectTosTest07(void) |
277 | | { |
278 | | DetectTosData *tosd = NULL; |
279 | | tosd = DetectTosParse("X12", false); |
280 | | if (tosd != NULL && tosd->tos == 0x12 && !tosd->negated) { |
281 | | DetectTosFree(NULL, tosd); |
282 | | return 1; |
283 | | } |
284 | | |
285 | | return 0; |
286 | | } |
287 | | |
288 | | static int DetectTosTest08(void) |
289 | | { |
290 | | DetectTosData *tosd = NULL; |
291 | | tosd = DetectTosParse("x121", false); |
292 | | if (tosd != NULL) { |
293 | | DetectTosFree(NULL, tosd); |
294 | | return 0; |
295 | | } |
296 | | |
297 | | return 1; |
298 | | } |
299 | | |
300 | | static int DetectTosTest09(void) |
301 | | { |
302 | | DetectTosData *tosd = NULL; |
303 | | tosd = DetectTosParse("12", true); |
304 | | if (tosd != NULL && tosd->tos == 12 && tosd->negated) { |
305 | | DetectTosFree(NULL, tosd); |
306 | | return 1; |
307 | | } |
308 | | |
309 | | return 0; |
310 | | } |
311 | | |
312 | | static int DetectTosTest10(void) |
313 | | { |
314 | | DetectTosData *tosd = NULL; |
315 | | tosd = DetectTosParse("x12", true); |
316 | | if (tosd != NULL && tosd->tos == 0x12 && tosd->negated) { |
317 | | DetectTosFree(NULL, tosd); |
318 | | return 1; |
319 | | } |
320 | | |
321 | | return 0; |
322 | | } |
323 | | |
324 | | static int DetectTosTest12(void) |
325 | | { |
326 | | int result = 0; |
327 | | uint8_t *buf = (uint8_t *)"Hi all!"; |
328 | | uint16_t buflen = strlen((char *)buf); |
329 | | Packet *p; |
330 | | |
331 | | p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); |
332 | | |
333 | | if (p == NULL) |
334 | | goto end; |
335 | | |
336 | | IPV4_SET_RAW_IPTOS(p->ip4h, 10); |
337 | | |
338 | | const char *sigs[4]; |
339 | | sigs[0]= "alert ip any any -> any any (msg:\"Testing id 1\"; tos: 10 ; sid:1;)"; |
340 | | sigs[1]= "alert ip any any -> any any (msg:\"Testing id 2\"; tos: ! 10; sid:2;)"; |
341 | | sigs[2]= "alert ip any any -> any any (msg:\"Testing id 3\"; tos:20 ; sid:3;)"; |
342 | | sigs[3]= "alert ip any any -> any any (msg:\"Testing id 3\"; tos:! 20; sid:4;)"; |
343 | | |
344 | | uint32_t sid[4] = {1, 2, 3, 4}; |
345 | | |
346 | | uint32_t results[1][4] = |
347 | | { |
348 | | {1, 0, 0, 1}, |
349 | | }; |
350 | | |
351 | | result = UTHGenericTest(&p, 1, sigs, sid, (uint32_t *) results, 4); |
352 | | |
353 | | UTHFreePackets(&p, 1); |
354 | | |
355 | | end: |
356 | | return result; |
357 | | } |
358 | | |
359 | | void DetectTosRegisterTests(void) |
360 | | { |
361 | | UtRegisterTest("DetectTosTest01", DetectTosTest01); |
362 | | UtRegisterTest("DetectTosTest02", DetectTosTest02); |
363 | | UtRegisterTest("DetectTosTest04", DetectTosTest04); |
364 | | UtRegisterTest("DetectTosTest05", DetectTosTest05); |
365 | | UtRegisterTest("DetectTosTest06", DetectTosTest06); |
366 | | UtRegisterTest("DetectTosTest07", DetectTosTest07); |
367 | | UtRegisterTest("DetectTosTest08", DetectTosTest08); |
368 | | UtRegisterTest("DetectTosTest09", DetectTosTest09); |
369 | | UtRegisterTest("DetectTosTest10", DetectTosTest10); |
370 | | UtRegisterTest("DetectTosTest12", DetectTosTest12); |
371 | | return; |
372 | | } |
373 | | #endif |