suricata
detect-tos.c
Go to the documentation of this file.
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"
45
46#define PARSE_REGEX "^\\s*(!?\\s*[0-9]{1,3}|!?\\s*[xX][0-9a-fA-F]{1,2})\\s*$"
47
48static DetectParseRegex parse_regex;
49
50static int DetectTosSetup(DetectEngineCtx *, Signature *, const char *);
51static int DetectTosMatch(DetectEngineThreadCtx *, Packet *,
52 const Signature *, const SigMatchCtx *);
53#ifdef UNITTESTS
54static void DetectTosRegisterTests(void);
55#endif
56static void DetectTosFree(DetectEngineCtx *, void *);
57
58#define DETECT_IPTOS_MIN 0
59#define DETECT_IPTOS_MAX 255
60
61/**
62 * \brief Register Tos keyword.
63 */
65{
67 sigmatch_table[DETECT_TOS].desc = "match on specific decimal values of the IP header TOS field";
68 sigmatch_table[DETECT_TOS].Match = DetectTosMatch;
69 sigmatch_table[DETECT_TOS].Setup = DetectTosSetup;
70 sigmatch_table[DETECT_TOS].Free = DetectTosFree;
71#ifdef UNITTESTS
72 sigmatch_table[DETECT_TOS].RegisterTests = DetectTosRegisterTests;
73#endif
77 "/rules/header-keywords.html#tos";
78
80}
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 */
93static int DetectTosMatch(DetectEngineThreadCtx *det_ctx, Packet *p,
94 const Signature *s, const SigMatchCtx *ctx)
95{
96 const DetectTosData *tosd = (const DetectTosData *)ctx;
97 int result = 0;
98
100 if (!PacketIsIPv4(p)) {
101 return 0;
102 }
103
104 const IPV4Hdr *ip4h = PacketGetIPv4(p);
105 if (tosd->tos == IPV4_GET_RAW_IPTOS(ip4h)) {
106 SCLogDebug("tos match found for %d", tosd->tos);
107 result = 1;
108 }
109
110 return (tosd->negated ^ result);
111}
112
113static DetectTosData *DetectTosParse(const char *arg, bool negate)
114{
115 DetectTosData *tosd = NULL;
116 size_t pcre2len;
117
118 pcre2_match_data *match = NULL;
119 int ret = DetectParsePcreExec(&parse_regex, &match, arg, 0, 0);
120 if (ret != 2) {
121 SCLogError("invalid tos option - %s. "
122 "The tos option value must be in the range "
123 "%u - %u",
125 goto error;
126 }
127
128 /* For TOS value */
129 char tosbytes_str[64] = "";
130 pcre2len = sizeof(tosbytes_str);
131 int res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)tosbytes_str, &pcre2len);
132 if (res < 0) {
133 SCLogError("pcre2_substring_copy_bynumber failed");
134 goto error;
135 }
136
137 int64_t tos = 0;
138
139 if (tosbytes_str[0] == 'x' || tosbytes_str[0] == 'X') {
140 if (StringParseInt64(&tos, 16, 0, &tosbytes_str[1]) < 0) {
141 goto error;
142 }
143 } else {
144 if (StringParseInt64(&tos, 10, 0, &tosbytes_str[0]) < 0) {
145 goto error;
146 }
147 }
148
149 if (!(tos >= DETECT_IPTOS_MIN && tos <= DETECT_IPTOS_MAX)) {
150 SCLogError("Invalid tos argument - "
151 "%s. The tos option value must be in the range "
152 "%u - %u",
153 tosbytes_str, DETECT_IPTOS_MIN, DETECT_IPTOS_MAX);
154 goto error;
155 }
156
157 tosd = SCMalloc(sizeof(DetectTosData));
158 if (unlikely(tosd == NULL))
159 goto error;
160 tosd->tos = (uint8_t)tos;
161 tosd->negated = negate;
162
163 pcre2_match_data_free(match);
164 return tosd;
165
166error:
167 if (match) {
168 pcre2_match_data_free(match);
169 }
170 return NULL;
171}
172
173/**
174 * \brief Setup function for tos argument. Parse the argument and
175 * add it into the sig.
176 *
177 * \param de_ctx Detection Engine Context instance.
178 * \param s Pointer to the signature.
179 * \param arg Argument to be parsed.
180 *
181 * \retval 0 on Success.
182 * \retval -1 on Failure.
183 */
184static int DetectTosSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
185{
186 DetectTosData *tosd = DetectTosParse(arg, s->init_data->negated);
187 if (tosd == NULL)
188 return -1;
189
191 de_ctx, s, DETECT_TOS, (SigMatchCtx *)tosd, DETECT_SM_LIST_MATCH) == NULL) {
192 DetectTosFree(de_ctx, tosd);
193 return -1;
194 }
196 return 0;
197}
198
199/**
200 * \brief Free data allocated by the tos keyword.
201 *
202 * \param tosd Data to be freed.
203 */
204static void DetectTosFree(DetectEngineCtx *de_ctx, void *tosd)
205{
206 SCFree(tosd);
207}
208
209/********************************Unittests***********************************/
210
211#ifdef UNITTESTS
212
213static int DetectTosTest01(void)
214{
215 DetectTosData *tosd = NULL;
216 tosd = DetectTosParse("12", false);
217 if (tosd != NULL && tosd->tos == 12 && !tosd->negated) {
218 DetectTosFree(NULL, tosd);
219 return 1;
220 }
221
222 return 0;
223}
224
225static int DetectTosTest02(void)
226{
227 DetectTosData *tosd = NULL;
228 tosd = DetectTosParse("123", false);
229 if (tosd != NULL && tosd->tos == 123 && !tosd->negated) {
230 DetectTosFree(NULL, tosd);
231 return 1;
232 }
233
234 return 0;
235}
236
237static int DetectTosTest04(void)
238{
239 DetectTosData *tosd = NULL;
240 tosd = DetectTosParse("256", false);
241 if (tosd != NULL) {
242 DetectTosFree(NULL, tosd);
243 return 0;
244 }
245
246 return 1;
247}
248
249static int DetectTosTest05(void)
250{
251 DetectTosData *tosd = NULL;
252 tosd = DetectTosParse("boom", false);
253 if (tosd != NULL) {
254 DetectTosFree(NULL, tosd);
255 return 0;
256 }
257
258 return 1;
259}
260
261static int DetectTosTest06(void)
262{
263 DetectTosData *tosd = NULL;
264 tosd = DetectTosParse("x12", false);
265 if (tosd != NULL && tosd->tos == 0x12 && !tosd->negated) {
266 DetectTosFree(NULL, tosd);
267 return 1;
268 }
269
270 return 0;
271}
272
273static int DetectTosTest07(void)
274{
275 DetectTosData *tosd = NULL;
276 tosd = DetectTosParse("X12", false);
277 if (tosd != NULL && tosd->tos == 0x12 && !tosd->negated) {
278 DetectTosFree(NULL, tosd);
279 return 1;
280 }
281
282 return 0;
283}
284
285static int DetectTosTest08(void)
286{
287 DetectTosData *tosd = NULL;
288 tosd = DetectTosParse("x121", false);
289 if (tosd != NULL) {
290 DetectTosFree(NULL, tosd);
291 return 0;
292 }
293
294 return 1;
295}
296
297static int DetectTosTest09(void)
298{
299 DetectTosData *tosd = NULL;
300 tosd = DetectTosParse("12", true);
301 if (tosd != NULL && tosd->tos == 12 && tosd->negated) {
302 DetectTosFree(NULL, tosd);
303 return 1;
304 }
305
306 return 0;
307}
308
309static int DetectTosTest10(void)
310{
311 DetectTosData *tosd = NULL;
312 tosd = DetectTosParse("x12", true);
313 if (tosd != NULL && tosd->tos == 0x12 && tosd->negated) {
314 DetectTosFree(NULL, tosd);
315 return 1;
316 }
317
318 return 0;
319}
320
321static int DetectTosTest12(void)
322{
323 int result = 0;
324 uint8_t *buf = (uint8_t *)"Hi all!";
325 uint16_t buflen = strlen((char *)buf);
326 Packet *p;
327
328 p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
329
330 if (p == NULL)
331 goto end;
332
333 p->l3.hdrs.ip4h->ip_tos = 10;
334
335 const char *sigs[4];
336 sigs[0]= "alert ip any any -> any any (msg:\"Testing id 1\"; tos: 10 ; sid:1;)";
337 sigs[1]= "alert ip any any -> any any (msg:\"Testing id 2\"; tos: ! 10; sid:2;)";
338 sigs[2]= "alert ip any any -> any any (msg:\"Testing id 3\"; tos:20 ; sid:3;)";
339 sigs[3]= "alert ip any any -> any any (msg:\"Testing id 3\"; tos:! 20; sid:4;)";
340
341 uint32_t sid[4] = {1, 2, 3, 4};
342
343 uint32_t results[1][4] =
344 {
345 {1, 0, 0, 1},
346 };
347
348 result = UTHGenericTest(&p, 1, sigs, sid, (uint32_t *) results, 4);
349
350 UTHFreePackets(&p, 1);
351
352end:
353 return result;
354}
355
356void DetectTosRegisterTests(void)
357{
358 UtRegisterTest("DetectTosTest01", DetectTosTest01);
359 UtRegisterTest("DetectTosTest02", DetectTosTest02);
360 UtRegisterTest("DetectTosTest04", DetectTosTest04);
361 UtRegisterTest("DetectTosTest05", DetectTosTest05);
362 UtRegisterTest("DetectTosTest06", DetectTosTest06);
363 UtRegisterTest("DetectTosTest07", DetectTosTest07);
364 UtRegisterTest("DetectTosTest08", DetectTosTest08);
365 UtRegisterTest("DetectTosTest09", DetectTosTest09);
366 UtRegisterTest("DetectTosTest10", DetectTosTest10);
367 UtRegisterTest("DetectTosTest12", DetectTosTest12);
368}
369#endif
#define IPV4_GET_RAW_IPTOS(ip4h)
Definition decode-ipv4.h:97
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition decode.h:1321
Data structures and function prototypes for keeping state for the detection engine.
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str, int start_offset, int options)
SigMatch * SCSigMatchAppendSMToList(DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
Append a SigMatch to the list type.
SigTableElmt * sigmatch_table
void DetectTosRegister(void)
Register Tos keyword.
Definition detect-tos.c:64
#define DETECT_IPTOS_MIN
Definition detect-tos.c:58
#define PARSE_REGEX
Definition detect-tos.c:46
#define DETECT_IPTOS_MAX
Definition detect-tos.c:59
#define SIG_FLAG_REQUIRE_PACKET
Definition detect.h:254
#define SIGMATCH_QUOTES_OPTIONAL
Definition detect.h:1664
@ DETECT_SM_LIST_MATCH
Definition detect.h:117
#define SIGMATCH_HANDLE_NEGATION
Definition detect.h:1672
DetectEngineCtx * de_ctx
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
struct Thresholds ctx
main detection engine ctx
Definition detect.h:932
uint8_t negated
Definition detect-tos.h:28
uint8_t ip_tos
Definition decode-ipv4.h:74
union PacketL3::Hdrs hdrs
struct PacketL3 l3
Definition decode.h:600
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition detect.h:351
const char * url
Definition detect.h:1462
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition detect.h:1441
void(* Free)(DetectEngineCtx *, void *)
Definition detect.h:1446
uint16_t flags
Definition detect.h:1450
const char * desc
Definition detect.h:1461
void(* RegisterTests)(void)
Definition detect.h:1448
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition detect.h:1421
const char * name
Definition detect.h:1459
Signature container.
Definition detect.h:668
uint32_t flags
Definition detect.h:669
SignatureInitData * init_data
Definition detect.h:747
IPV4Hdr * ip4h
Definition decode.h:439
int StringParseInt64(int64_t *res, int base, size_t len, const char *str)
Definition util-byte.c:617
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
#define SCMalloc(sz)
Definition util-mem.h:47
#define SCFree(p)
Definition util-mem.h:61
#define unlikely(expr)
void UTHFreePackets(Packet **p, int numpkts)
UTHFreePackets: function to release the allocated data from UTHBuildPacket and the packet itself.
Packet * UTHBuildPacket(uint8_t *payload, uint16_t payload_len, uint8_t ipproto)
UTHBuildPacket is a wrapper that build packets with default ip and port fields.
int UTHGenericTest(Packet **pkt, int numpkts, const char *sigs[], uint32_t sids[], uint32_t *results, int numsigs)
UTHGenericTest: function that perform a generic check taking care of as maximum common unittest eleme...
#define DEBUG_VALIDATE_BUG_ON(exp)