Coverage Report

Created: 2025-07-23 07:29

/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