• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 22553492142

01 Mar 2026 09:48PM UTC coverage: 70.74% (-2.9%) from 73.687%
22553492142

Pull #14920

github

web-flow
Merge e15a765bc into 90823fa90
Pull Request #14920: draft: rust based configuration file parser and loader - v4

38209 of 77306 branches covered (49.43%)

Branch coverage included in aggregate %.

533 of 779 new or added lines in 5 files covered. (68.42%)

11924 existing lines in 491 files now uncovered.

252429 of 333548 relevant lines covered (75.68%)

2403268.06 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.1
/src/detect-replace.c
1
/* Copyright (C) 2011-2022 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 Eric Leblond <eric@regit.org>
22
 *
23
 * Replace part of the detection engine.
24
 *
25
 * If previous filter is of content type, replace can be used to change
26
 * the matched part to a new value.
27
 */
28

29
#include "suricata-common.h"
30

31
#include "runmodes.h"
32

33
#include "decode.h"
34

35
#include "detect.h"
36
#include "detect-parse.h"
37
#include "detect-content.h"
38
#include "detect-replace.h"
39
#include "app-layer.h"
40

41
#include "detect-engine-mpm.h"
42
#include "detect-engine.h"
43
#include "detect-engine-build.h"
44

45
#include "util-checksum.h"
46

47
#include "util-unittest.h"
48

49
#include "util-debug.h"
50

51
static int DetectReplaceSetup(DetectEngineCtx *, Signature *, const char *);
52
#ifdef UNITTESTS
53
static void DetectReplaceRegisterTests(void);
54
#endif
55
static int DetectReplacePostMatch(DetectEngineThreadCtx *det_ctx,
56
        Packet *p, const Signature *s, const SigMatchCtx *ctx);
57

58
void DetectReplaceRegister (void)
59
{
2,159✔
60
    sigmatch_table[DETECT_REPLACE].name = "replace";
2,159✔
61
    sigmatch_table[DETECT_REPLACE].desc = "only to be used in IPS-mode. Change the following content into another";
2,159✔
62
    sigmatch_table[DETECT_REPLACE].url = "/rules/payload-keywords.html#replace";
2,159✔
63
    sigmatch_table[DETECT_REPLACE].Match = DetectReplacePostMatch;
2,159✔
64
    sigmatch_table[DETECT_REPLACE].Setup = DetectReplaceSetup;
2,159✔
65
#ifdef UNITTESTS
3✔
66
    sigmatch_table[DETECT_REPLACE].RegisterTests = DetectReplaceRegisterTests;
3✔
67
#endif
3✔
68
    sigmatch_table[DETECT_REPLACE].flags = (SIGMATCH_QUOTES_MANDATORY|SIGMATCH_HANDLE_NEGATION);
2,159✔
69
}
2,159✔
70

71
static int DetectReplacePostMatch(DetectEngineThreadCtx *det_ctx,
72
        Packet *p, const Signature *s, const SigMatchCtx *ctx)
73
{
11✔
74
    if (det_ctx->replist) {
11!
75
        DetectReplaceExecuteInternal(p, det_ctx->replist);
10✔
76
        det_ctx->replist = NULL;
10✔
77
    }
10✔
78
    return 1;
11✔
79
}
11✔
80

81
int DetectReplaceSetup(DetectEngineCtx *de_ctx, Signature *s, const char *replacestr)
82
{
23✔
83
    uint8_t *content = NULL;
23✔
84
    uint16_t len = 0;
23✔
85

86
    if (s->init_data->negated) {
23!
UNCOV
87
        SCLogError("Can't negate replacement string: %s", replacestr);
×
UNCOV
88
        return -1;
×
UNCOV
89
    }
×
90

91
    switch (SCRunmodeGet()) {
23✔
92
        case RUNMODE_NFQ:
23!
93
        case RUNMODE_IPFW:
23!
94
            break;
23✔
UNCOV
95
        default:
×
UNCOV
96
            SCLogWarning("Can't use 'replace' keyword in non IPS mode: %s", s->sig_str);
×
97
            /* this is a success, having the alert is interesting */
UNCOV
98
            return 0;
×
99
    }
23✔
100

101
    int ret = DetectContentDataParse("replace", replacestr, &content, &len);
23✔
102
    if (ret == -1)
23!
103
        return -1;
1✔
104

105
    /* add to the latest "content" keyword from pmatch */
106
    const SigMatch *pm = DetectGetLastSMByListId(s, DETECT_SM_LIST_PMATCH,
22✔
107
            DETECT_CONTENT, -1);
22✔
108
    if (pm == NULL) {
22!
109
        SCLogError("replace needs"
2✔
110
                   "preceding content option for raw sig");
2✔
111
        SCFree(content);
2✔
112
        return -1;
2✔
113
    }
2✔
114

115
    /* we can remove this switch now with the unified structure */
116
    DetectContentData *ud = (DetectContentData *)pm->ctx;
20✔
117
    if (ud == NULL) {
20!
118
        SCLogError("invalid argument");
×
119
        SCFree(content);
×
120
        return -1;
×
121
    }
×
122
    if (ud->flags & DETECT_CONTENT_NEGATED) {
20!
123
        SCLogError("can't have a relative "
×
124
                   "negated keyword set along with a replacement");
×
125
        goto error;
×
126
    }
×
127
    if (ud->content_len != len) {
20!
128
        SCLogError("can't have a content "
1✔
129
                   "length different from replace length");
1✔
130
        goto error;
1✔
131
    }
1✔
132

133
    ud->replace = SCMalloc(len);
19✔
134
    if (ud->replace == NULL) {
19!
135
        goto error;
×
136
    }
×
137
    memcpy(ud->replace, content, len);
19✔
138
    ud->replace_len = len;
19✔
139
    ud->flags |= DETECT_CONTENT_REPLACE;
19✔
140
    /* want packet matching only won't be able to replace data with
141
     * a flow.
142
     */
143
    s->flags |= SIG_FLAG_REQUIRE_PACKET;
19✔
144
    SCFree(content);
19✔
145
    content = NULL;
19✔
146

147
    if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_REPLACE, NULL, DETECT_SM_LIST_POSTMATCH) ==
19!
148
            NULL) {
19✔
149
        goto error;
×
150
    }
×
151
    return 0;
19✔
152

153
error:
1✔
154
    SCFree(ud->replace);
1✔
155
    ud->replace = NULL;
1✔
156
    SCFree(content);
1✔
157
    return -1;
1✔
158
}
19✔
159

160
/* Add to the head of the replace-list.
161
 *
162
 * The first to add to the replace-list has the highest priority. So,
163
 * adding the head of the list results in the newest modifications
164
 * of content being applied first, so later changes can over ride
165
 * earlier changes. Thus the highest priority modifications should be
166
 * applied last.
167
 */
168
DetectReplaceList *DetectReplaceAddToList(
169
        DetectReplaceList *replist, uint8_t *found, const DetectContentData *cd)
170
{
13✔
171
    if (cd->content_len != cd->replace_len)
13!
172
        return NULL;
×
173
    SCLogDebug("replace: Adding match");
13!
174

175
    DetectReplaceList *newlist = SCMalloc(sizeof(DetectReplaceList));
13✔
176
    if (unlikely(newlist == NULL))
13!
177
        return replist;
×
178
    newlist->found = found;
13✔
179
    newlist->cd = cd;
13✔
180
    /* Push new value onto the front of the list. */
181
    newlist->next = replist;
13✔
182
    return newlist;
13✔
183
}
13✔
184

185
void DetectReplaceExecuteInternal(Packet *p, DetectReplaceList *replist)
186
{
10✔
187
    DetectReplaceList *tlist = NULL;
10✔
188

189
    SCLogDebug("replace: Executing match");
10!
190
    while (replist) {
21!
191
        memcpy(replist->found, replist->cd->replace, replist->cd->replace_len);
11✔
192
        SCLogDebug("replace: replaced data");
11!
193
        p->flags |= PKT_STREAM_MODIFIED;
11✔
194
        ReCalculateChecksum(p);
11✔
195
        tlist = replist;
11✔
196
        replist = replist->next;
11✔
197
        SCFree(tlist);
11✔
198
    }
11✔
199
}
10✔
200

201

202
void DetectReplaceFreeInternal(DetectReplaceList *replist)
203
{
2✔
204
    DetectReplaceList *tlist = NULL;
2✔
205
    while (replist) {
4!
206
        SCLogDebug("replace: Freeing match");
2!
207
        tlist = replist;
2✔
208
        replist = replist->next;
2✔
209
        SCFree(tlist);
2✔
210
    }
2✔
211
}
2✔
212

213
#ifdef UNITTESTS /* UNITTESTS */
214
#include "detect-engine-alert.h"
215
#include "packet.h"
216

217
/**
218
 * \test Test packet Matches
219
 * \param raw_eth_pkt pointer to the ethernet packet
220
 * \param pktsize size of the packet
221
 * \param sig pointer to the signature to test
222
 * \param sid sid number of the signature
223
 * \retval return 1 if match
224
 * \retval return 0 if not
225
 */
226
static
227
int DetectReplaceLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize,
228
                                      const char *sig, uint32_t sid, uint8_t *pp,
229
                                      uint16_t *len)
230
{
25✔
231
    int result = 0;
25✔
232

233
    Packet *p = PacketGetFromAlloc();
25✔
234
    if (unlikely(p == NULL))
25✔
235
        return 0;
236

237
    DecodeThreadVars dtv;
25✔
238
    ThreadVars th_v;
25✔
239
    memset(&dtv, 0, sizeof(DecodeThreadVars));
25✔
240
    memset(&th_v, 0, sizeof(th_v));
25✔
241
    StatsThreadInit(&th_v.stats);
25✔
242
    DetectEngineThreadCtx *det_ctx = NULL;
25✔
243

244
    if (pp == NULL) {
25✔
245
        SCLogDebug("replace: looks like a second run");
10✔
246
    }
10✔
247

248
    PacketCopyData(p, raw_eth_pkt, pktsize);
25✔
249
    dtv.app_tctx = AppLayerGetCtxThread();
25✔
250
    FlowInitConfig(FLOW_QUIET);
25✔
251
    DecodeEthernet(&th_v, &dtv, p, GET_PKT_DATA(p), pktsize);
25✔
252

253
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
25✔
254
    if (de_ctx == NULL) {
25✔
255
        goto end;
256
    }
257
    de_ctx->flags |= DE_QUIET;
25✔
258

259
    Signature *s = DetectEngineAppendSig(de_ctx, sig);
25✔
260
    if (s == NULL) {
25✔
261
        goto end;
262
    }
263

264
    if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]->type == DETECT_CONTENT) {
25✔
265
        DetectContentData *co =
25✔
266
                (DetectContentData *)s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]->ctx;
25✔
267
        if (co->flags & DETECT_CONTENT_RELATIVE_NEXT) {
25✔
268
            printf("relative next flag set on final match which is content: ");
269
            goto end;
270
        }
271
    }
25✔
272

273
    SigGroupBuild(de_ctx);
25✔
274
    DetectEngineAddToMaster(de_ctx);
25✔
275
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
25✔
276
    BUG_ON(det_ctx == NULL);
25✔
277

278
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
25✔
279
    DetectEngineMoveToFreeList(de_ctx);
25✔
280

281
    if (PacketAlertCheck(p, sid) != 1) {
25✔
282
        SCLogDebug("replace: no alert on sig %d", sid);
5✔
283
        goto end;
5✔
284
    }
5✔
285

286
    if (pp) {
20✔
287
        memcpy(pp, GET_PKT_DATA(p), GET_PKT_LEN(p));
10✔
288
        *len = pktsize;
10✔
289
        SCLogDebug("replace: copying %d on %p", *len, pp);
10✔
290
    }
10✔
291

292
    result = 1;
20✔
293
end:
25✔
294
    if (dtv.app_tctx != NULL)
25✔
295
        AppLayerDestroyCtxThread(dtv.app_tctx);
25✔
296
    if (det_ctx != NULL)
25✔
297
        DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
25✔
298
    DetectEnginePruneFreeList();
25✔
299
    PacketFree(p);
25✔
300
    FlowShutdown();
25✔
301
    StatsThreadCleanup(&th_v.stats);
25✔
302
    return result;
25✔
303
}
20✔
304

305

306
/**
307
 * \brief Wrapper for DetectContentLongPatternMatchTest
308
 */
309
static int DetectReplaceLongPatternMatchTestWrp(const char *sig, uint32_t sid, const char *sig_rep,  uint32_t sid_rep)
310
{
14✔
311
    int ret;
14✔
312
    /** Real packet with the following tcp data:
313
     * "Hi, this is a big test to check content matches of splitted"
314
     * "patterns between multiple chunks!"
315
     * (without quotes! :) )
316
     */
317
    uint8_t raw_eth_pkt[] = {
14✔
318
        0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,
14✔
319
        0x00,0x00,0x00,0x00,0x08,0x00,0x45,0x00,
14✔
320
        0x00,0x85,0x00,0x01,0x00,0x00,0x40,0x06,
14✔
321
        0x7c,0x70,0x7f,0x00,0x00,0x01,0x7f,0x00,
14✔
322
        0x00,0x01,0x00,0x14,0x00,0x50,0x00,0x00,
14✔
323
        0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x02,
14✔
324
        0x20,0x00,0xc9,0xad,0x00,0x00,0x48,0x69,
14✔
325
        0x2c,0x20,0x74,0x68,0x69,0x73,0x20,0x69,
14✔
326
        0x73,0x20,0x61,0x20,0x62,0x69,0x67,0x20,
14✔
327
        0x74,0x65,0x73,0x74,0x20,0x74,0x6f,0x20,
14✔
328
        0x63,0x68,0x65,0x63,0x6b,0x20,0x63,0x6f,
14✔
329
        0x6e,0x74,0x65,0x6e,0x74,0x20,0x6d,0x61,
14✔
330
        0x74,0x63,0x68,0x65,0x73,0x20,0x6f,0x66,
14✔
331
        0x20,0x73,0x70,0x6c,0x69,0x74,0x74,0x65,
14✔
332
        0x64,0x20,0x70,0x61,0x74,0x74,0x65,0x72,
14✔
333
        0x6e,0x73,0x20,0x62,0x65,0x74,0x77,0x65,
14✔
334
        0x65,0x6e,0x20,0x6d,0x75,0x6c,0x74,0x69,
14✔
335
        0x70,0x6c,0x65,0x20,0x63,0x68,0x75,0x6e,
14✔
336
        0x6b,0x73,0x21 }; /* end raw_eth_pkt */
14✔
337
    uint8_t p[sizeof(raw_eth_pkt)];
14✔
338
    uint16_t psize = sizeof(raw_eth_pkt);
14✔
339

340
    /* would be unittest */
341
    int run_mode_backup = SCRunmodeGet();
14✔
342
    SCRunmodeSet(RUNMODE_NFQ);
14✔
343
    ret = DetectReplaceLongPatternMatchTest(raw_eth_pkt, (uint16_t)sizeof(raw_eth_pkt),
14✔
344
                             sig, sid, p, &psize);
14✔
345
    if (ret == 1) {
14✔
346
        SCLogDebug("replace: test1 phase1");
9✔
347
        ret = DetectReplaceLongPatternMatchTest(p, psize, sig_rep, sid_rep, NULL, NULL);
9✔
348
    }
9✔
349
    SCRunmodeSet(run_mode_backup);
14✔
350
    return ret;
14✔
351
}
14✔
352

353

354
/**
355
 * \brief Wrapper for DetectContentLongPatternMatchTest
356
 */
357
static int DetectReplaceLongPatternMatchTestUDPWrp(const char *sig, uint32_t sid, const char *sig_rep,  uint32_t sid_rep)
358
{
1✔
359
    int ret;
1✔
360
    /** Real UDP DNS packet with a request A to a1.twimg.com
361
     */
362
    uint8_t raw_eth_pkt[] = {
1✔
363
        0x8c, 0xa9, 0x82, 0x75, 0x5d, 0x62, 0xb4, 0x07, 
1✔
364
        0xf9, 0xf3, 0xc7, 0x0a, 0x08, 0x00, 0x45, 0x00, 
1✔
365
        0x00, 0x3a, 0x92, 0x4f, 0x40, 0x00, 0x40, 0x11, 
1✔
366
        0x31, 0x1a, 0xc0, 0xa8, 0x00, 0x02, 0xc1, 0xbd, 
1✔
367
        0xf4, 0xe1, 0x3b, 0x7e, 0x00, 0x35, 0x00, 0x26, 
1✔
368
        0xcb, 0x81, 0x37, 0x62, 0x01, 0x00, 0x00, 0x01, 
1✔
369
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x61, 
1✔
370
        0x31, 0x05, 0x74, 0x77, 0x69, 0x6d, 0x67, 0x03, 
1✔
371
        0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01 };
1✔
372

373
    uint8_t p[sizeof(raw_eth_pkt)];
1✔
374
    uint16_t psize = sizeof(raw_eth_pkt);
1✔
375

376
    int run_mode_backup = SCRunmodeGet();
1✔
377
    SCRunmodeSet(RUNMODE_NFQ);
1✔
378
    ret = DetectReplaceLongPatternMatchTest(raw_eth_pkt, (uint16_t)sizeof(raw_eth_pkt),
1✔
379
                             sig, sid, p, &psize);
1✔
380
    if (ret == 1) {
1✔
381
        SCLogDebug("replace: test1 phase1 ok: %" PRIuMAX" vs %d",(uintmax_t)sizeof(raw_eth_pkt),psize);
1✔
382
        ret = DetectReplaceLongPatternMatchTest(p, psize, sig_rep, sid_rep, NULL, NULL);
1✔
383
    }
1✔
384
    SCRunmodeSet(run_mode_backup);
1✔
385
    return ret;
1✔
386
}
1✔
387

388
/**
389
 * \test Check if replace is working
390
 */
391
static int DetectReplaceMatchTest01(void)
392
{
1✔
393
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
1✔
394
                " content:\"big\"; replace:\"pig\"; sid:1;)";
1✔
395
    const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
1✔
396
                " content:\"this is a pig test\"; sid:2;)";
1✔
397
    FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
1✔
398
    PASS;
1✔
399
}
1✔
400

401
/**
402
 * \test Check if replace is working with offset
403
 */
404
static int DetectReplaceMatchTest02(void)
405
{
1✔
406
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
1✔
407
                " content:\"th\"; offset: 4; replace:\"TH\"; sid:1;)";
1✔
408
    const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
1✔
409
                " content:\"THis\"; offset:4; sid:2;)";
1✔
410
    FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
1✔
411
    PASS;
1✔
412
}
1✔
413

414
/**
415
 * \test Check if replace is working with offset and keyword inversion
416
 */
417
static int DetectReplaceMatchTest03(void)
418
{
1✔
419
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
1✔
420
                " content:\"th\"; replace:\"TH\"; offset: 4; sid:1;)";
1✔
421
    const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
1✔
422
                " content:\"THis\"; offset:4; sid:2;)";
1✔
423
    FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
1✔
424
    PASS;
1✔
425
}
1✔
426

427
/**
428
 * \test Check if replace is working with second content
429
 */
430
static int DetectReplaceMatchTest04(void)
431
{
1✔
432
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
1✔
433
                " content:\"th\"; replace:\"TH\"; content:\"patter\"; replace:\"matter\"; sid:1;)";
1✔
434
    const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
1✔
435
                " content:\"THis\"; content:\"matterns\"; sid:2;)";
1✔
436
    FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
1✔
437
    PASS;
1✔
438
}
1✔
439

440
/**
441
 * \test Check if replace is not done when second content don't match
442
 */
443
static int DetectReplaceMatchTest05(void)
444
{
1✔
445
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
1✔
446
                " content:\"th\"; replace:\"TH\"; content:\"nutella\"; sid:1;)";
1✔
447
    const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
1✔
448
                " content:\"TH\"; sid:2;)";
1✔
449
    FAIL_IF(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
1✔
450
    PASS;
1✔
451
}
1✔
452

453
/**
454
 * \test Check if replace is not done when second content match and not
455
 * first
456
 */
457
static int DetectReplaceMatchTest06(void)
458
{
1✔
459
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
1✔
460
                " content:\"nutella\"; replace:\"commode\"; content:\"this is\"; sid:1;)";
1✔
461
    const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
1✔
462
                " content:\"commode\"; sid:2;)";
1✔
463
    FAIL_IF(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
1✔
464
    PASS;
1✔
465
}
1✔
466

467
/**
468
 * \test Check if replace is working when nocase used
469
 */
470
static int DetectReplaceMatchTest07(void)
471
{
1✔
472
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
1✔
473
                " content:\"BiG\"; nocase; replace:\"pig\"; sid:1;)";
1✔
474
    const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
1✔
475
                " content:\"this is a pig test\"; sid:2;)";
1✔
476
    FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
1✔
477
    PASS;
1✔
478
}
1✔
479

480
/**
481
 * \test Check if replace is working when depth is used
482
 */
483
static int DetectReplaceMatchTest08(void)
484
{
1✔
485
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
1✔
486
                " content:\"big\"; depth:17; replace:\"pig\"; sid:1;)";
1✔
487
    const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
1✔
488
                " content:\"this is a pig test\"; sid:2;)";
1✔
489
    FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
1✔
490
    PASS;
1✔
491
}
1✔
492

493
/**
494
 * \test Check if replace is working when depth block match used
495
 */
496
static int DetectReplaceMatchTest09(void)
497
{
1✔
498
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
1✔
499
                " content:\"big\"; depth:16; replace:\"pig\"; sid:1;)";
1✔
500
    const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
1✔
501
                " content:\"this is a pig test\"; sid:2;)";
1✔
502
    FAIL_IF(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
1✔
503
    PASS;
1✔
504
}
1✔
505

506
/**
507
 * \test Check if replace is working when depth block match used
508
 */
509
static int DetectReplaceMatchTest10(void)
510
{
1✔
511
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
1✔
512
                " content:\"big\"; depth:17; replace:\"pig\"; offset: 14; sid:1;)";
1✔
513
    const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
1✔
514
                " content:\"pig\"; depth:17; offset:14; sid:2;)";
1✔
515
    FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
1✔
516
    PASS;
1✔
517
}
1✔
518

519
/**
520
 * \test Check if replace is working with within
521
 */
522
static int DetectReplaceMatchTest11(void)
523
{
1✔
524
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
1✔
525
                " content:\"big\"; replace:\"pig\"; content:\"to\"; within: 11; sid:1;)";
1✔
526
    const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
1✔
527
                " content:\"pig\"; depth:17; offset:14; sid:2;)";
1✔
528

529
    FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
1✔
530
    PASS;
1✔
531
}
1✔
532

533
/**
534
 * \test Check if replace is working with within
535
 */
536
static int DetectReplaceMatchTest12(void)
537
{
1✔
538
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
1✔
539
                " content:\"big\"; replace:\"pig\"; content:\"to\"; within: 4; sid:1;)";
1✔
540
    const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
1✔
541
                " content:\"pig\"; depth:17; offset:14; sid:2;)";
1✔
542
    FAIL_IF(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
1✔
543
    PASS;
1✔
544
}
1✔
545

546
/**
547
 * \test Check if replace is working with within
548
 */
549
static int DetectReplaceMatchTest13(void)
550
{
1✔
551
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
1✔
552
                " content:\"big\"; replace:\"pig\"; content:\"test\"; distance: 1; sid:1;)";
1✔
553
    const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
1✔
554
                " content:\"pig\"; depth:17; offset:14; sid:2;)";
1✔
555
    FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
1✔
556
    PASS;
1✔
557
}
1✔
558

559
/**
560
 * \test Check if replace is working with within
561
 */
562
static int DetectReplaceMatchTest14(void)
563
{
1✔
564
    const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
1✔
565
                " content:\"big\"; replace:\"pig\"; content:\"test\"; distance: 2; sid:1;)";
1✔
566
    const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
1✔
567
                " content:\"pig\"; depth:17; offset:14; sid:2;)";
1✔
568
    FAIL_IF(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
1✔
569
    PASS;
1✔
570
}
1✔
571

572
/**
573
 * \test Check if replace is working with within
574
 */
575
static int DetectReplaceMatchTest15(void)
576
{
1✔
577
    const char *sig = "alert udp any any -> any any (msg:\"Nothing..\";"
1✔
578
                " content:\"com\"; replace:\"org\"; sid:1;)";
1✔
579
    const char *sig_rep = "alert udp any any -> any any (msg:\"replace worked\";"
1✔
580
                " content:\"twimg|03|org\"; sid:2;)";
1✔
581
    FAIL_IF_NOT(DetectReplaceLongPatternMatchTestUDPWrp(sig, 1, sig_rep, 2));
1✔
582
    PASS;
1✔
583
}
1✔
584

585

586
/**
587
 * \test Parsing test
588
 */
589
static int DetectReplaceParseTest01(void)
590
{
1✔
591
    int run_mode_backup = SCRunmodeGet();
1✔
592
    SCRunmodeSet(RUNMODE_NFQ);
1✔
593

594
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
595
    FAIL_IF_NULL(de_ctx);
1✔
596

597
    de_ctx->flags |= DE_QUIET;
1✔
598
    FAIL_IF_NOT_NULL(DetectEngineAppendSig(de_ctx,
1✔
599
            "alert udp any any -> any any "
1✔
600
            "(msg:\"test\"; content:\"doh\"; replace:\"; sid:238012;)"));
1✔
601

602
    SCRunmodeSet(run_mode_backup);
1✔
603
    DetectEngineCtxFree(de_ctx);
1✔
604
    PASS;
1✔
605
}
1✔
606

607
/**
608
 * \test Parsing test: non valid because of http protocol
609
 */
610
static int DetectReplaceParseTest02(void)
611
{
1✔
612
    int run_mode_backup = SCRunmodeGet();
1✔
613
    SCRunmodeSet(RUNMODE_NFQ);
1✔
614

615
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
616
    FAIL_IF_NULL(de_ctx);
1✔
617

618
    de_ctx->flags |= DE_QUIET;
1✔
619
    FAIL_IF_NULL(DetectEngineAppendSig(de_ctx,
1✔
620
            "alert http any any -> any any "
1✔
621
            "(msg:\"test\"; content:\"doh\"; replace:\"bon\"; sid:238012;)"));
1✔
622

623
    SCRunmodeSet(run_mode_backup);
1✔
624
    DetectEngineCtxFree(de_ctx);
1✔
625
    PASS;
1✔
626
}
1✔
627

628
/**
629
 * \test Parsing test: non valid because of http_header on same content
630
 * as replace keyword
631
 */
632
static int DetectReplaceParseTest03(void)
633
{
1✔
634
    int run_mode_backup = SCRunmodeGet();
1✔
635
    SCRunmodeSet(RUNMODE_NFQ);
1✔
636

637
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
638

639
    FAIL_IF_NULL(de_ctx);
1✔
640

641
    de_ctx->flags |= DE_QUIET;
1✔
642
    FAIL_IF_NOT_NULL(DetectEngineAppendSig(de_ctx,
1✔
643
            "alert tcp any any -> any any "
1✔
644
            "(msg:\"test\"; content:\"doh\"; replace:\"don\"; http_header; sid:238012;)"));
1✔
645

646
    SCRunmodeSet(run_mode_backup);
1✔
647
    DetectEngineCtxFree(de_ctx);
1✔
648
    PASS;
1✔
649
}
1✔
650

651
/**
652
 * \test Parsing test no content
653
 */
654
static int DetectReplaceParseTest04(void)
655
{
1✔
656
    int run_mode_backup = SCRunmodeGet();
1✔
657
    SCRunmodeSet(RUNMODE_NFQ);
1✔
658

659
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
660
    FAIL_IF_NULL(de_ctx);
1✔
661

662
    de_ctx->flags |= DE_QUIET;
1✔
663
    FAIL_IF_NOT_NULL(DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
1✔
664
                                                   "(msg:\"test\"; replace:\"don\"; sid:238012;)"));
1✔
665

666
    SCRunmodeSet(run_mode_backup);
1✔
667
    DetectEngineCtxFree(de_ctx);
1✔
668
    PASS;
1✔
669
}
1✔
670

671
/**
672
 * \test Parsing test content after replace
673
 */
674
static int DetectReplaceParseTest05(void)
675
{
1✔
676
    int run_mode_backup = SCRunmodeGet();
1✔
677
    SCRunmodeSet(RUNMODE_NFQ);
1✔
678

679
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
680
    FAIL_IF_NULL(de_ctx);
1✔
681

682
    de_ctx->flags |= DE_QUIET;
1✔
683
    FAIL_IF_NOT_NULL(DetectEngineAppendSig(de_ctx,
1✔
684
            "alert tcp any any -> any any "
1✔
685
            "(msg:\"test\"; replace:\"don\"; content:\"doh\"; sid:238012;)"));
1✔
686

687
    SCRunmodeSet(run_mode_backup);
1✔
688
    DetectEngineCtxFree(de_ctx);
1✔
689
    PASS;
1✔
690
}
1✔
691

692
/**
693
 * \test Parsing test content and replace length differ
694
 */
695
static int DetectReplaceParseTest06(void)
696
{
1✔
697
    int run_mode_backup = SCRunmodeGet();
1✔
698
    SCRunmodeSet(RUNMODE_NFQ);
1✔
699

700
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
701
    FAIL_IF_NULL(de_ctx);
1✔
702

703
    de_ctx->flags |= DE_QUIET;
1✔
704
    FAIL_IF_NOT_NULL(DetectEngineAppendSig(de_ctx,
1✔
705
            "alert tcp any any -> any any "
1✔
706
            "(msg:\"test\"; content:\"don\"; replace:\"donut\"; sid:238012;)"));
1✔
707

708
    SCRunmodeSet(run_mode_backup);
1✔
709
    DetectEngineCtxFree(de_ctx);
1✔
710
    PASS;
1✔
711
}
1✔
712

713
/**
714
 * \test Parsing test content and replace length differ
715
 */
716
static int DetectReplaceParseTest07(void)
717
{
1✔
718
    int run_mode_backup = SCRunmodeGet();
1✔
719
    SCRunmodeSet(RUNMODE_NFQ);
1✔
720

721
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1✔
722
    FAIL_IF_NULL(de_ctx);
1✔
723

724
    de_ctx->flags |= DE_QUIET;
1✔
725
    FAIL_IF_NOT_NULL(
1✔
726
            DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
1✔
727
                                          "(msg:\"test\"; content:\"don\"; replace:\"dou\"; "
1✔
728
                                          "content:\"jpg\"; http_header; sid:238012;)"));
1✔
729

730
    SCRunmodeSet(run_mode_backup);
1✔
731
    DetectEngineCtxFree(de_ctx);
1✔
732
    PASS;
1✔
733
}
1✔
734

735
/**
736
 * \brief this function registers unit tests for DetectContent
737
 */
738
void DetectReplaceRegisterTests(void)
739
{
1✔
740
/* matching */
741
    UtRegisterTest("DetectReplaceMatchTest01", DetectReplaceMatchTest01);
1✔
742
    UtRegisterTest("DetectReplaceMatchTest02", DetectReplaceMatchTest02);
1✔
743
    UtRegisterTest("DetectReplaceMatchTest03", DetectReplaceMatchTest03);
1✔
744
    UtRegisterTest("DetectReplaceMatchTest04", DetectReplaceMatchTest04);
1✔
745
    UtRegisterTest("DetectReplaceMatchTest05", DetectReplaceMatchTest05);
1✔
746
    UtRegisterTest("DetectReplaceMatchTest06", DetectReplaceMatchTest06);
1✔
747
    UtRegisterTest("DetectReplaceMatchTest07", DetectReplaceMatchTest07);
1✔
748
    UtRegisterTest("DetectReplaceMatchTest08", DetectReplaceMatchTest08);
1✔
749
    UtRegisterTest("DetectReplaceMatchTest09", DetectReplaceMatchTest09);
1✔
750
    UtRegisterTest("DetectReplaceMatchTest10", DetectReplaceMatchTest10);
1✔
751
    UtRegisterTest("DetectReplaceMatchTest11", DetectReplaceMatchTest11);
1✔
752
    UtRegisterTest("DetectReplaceMatchTest12", DetectReplaceMatchTest12);
1✔
753
    UtRegisterTest("DetectReplaceMatchTest13", DetectReplaceMatchTest13);
1✔
754
    UtRegisterTest("DetectReplaceMatchTest14", DetectReplaceMatchTest14);
1✔
755
    UtRegisterTest("DetectReplaceMatchTest15", DetectReplaceMatchTest15);
1✔
756
/* parsing */
757
    UtRegisterTest("DetectReplaceParseTest01", DetectReplaceParseTest01);
1✔
758
    UtRegisterTest("DetectReplaceParseTest02", DetectReplaceParseTest02);
1✔
759
    UtRegisterTest("DetectReplaceParseTest03", DetectReplaceParseTest03);
1✔
760
    UtRegisterTest("DetectReplaceParseTest04", DetectReplaceParseTest04);
1✔
761
    UtRegisterTest("DetectReplaceParseTest05", DetectReplaceParseTest05);
1✔
762
    UtRegisterTest("DetectReplaceParseTest06", DetectReplaceParseTest06);
1✔
763
    UtRegisterTest("DetectReplaceParseTest07", DetectReplaceParseTest07);
1✔
764
}
1✔
765
#endif /* UNITTESTS */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc