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

OISF / suricata / 23374838686

21 Mar 2026 07:29AM UTC coverage: 59.341% (-20.0%) from 79.315%
23374838686

Pull #15075

github

web-flow
Merge 90b4e834f into 6587e363a
Pull Request #15075: Stack 8001 v16.4

38 of 70 new or added lines in 10 files covered. (54.29%)

34165 existing lines in 563 files now uncovered.

119621 of 201584 relevant lines covered (59.34%)

650666.92 hits per line

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

75.86
/src/detect-tcp-seq.c
1
/* Copyright (C) 2007-2010 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 Brian Rectanus <brectanu@gmail.com>
22
 *
23
 * Implements the seq keyword.
24
 */
25

26
#include "suricata-common.h"
27
#include "decode.h"
28
#include "detect.h"
29

30
#include "detect-parse.h"
31
#include "detect-engine.h"
32
#include "detect-engine-prefilter.h"
33
#include "detect-engine-prefilter-common.h"
34
#include "detect-engine-build.h"
35
#include "detect-engine-uint.h"
36

37
#include "detect-tcp-seq.h"
38

39
#include "util-byte.h"
40
#include "util-unittest.h"
41
#include "util-unittest-helper.h"
42
#include "util-debug.h"
43

44
static int DetectSeqSetup(DetectEngineCtx *, Signature *, const char *);
45
static int DetectSeqMatch(DetectEngineThreadCtx *,
46
                          Packet *, const Signature *, const SigMatchCtx *);
47
#ifdef UNITTESTS
48
static void DetectSeqRegisterTests(void);
49
#endif
50
static void DetectSeqFree(DetectEngineCtx *, void *);
51
static int PrefilterSetupTcpSeq(DetectEngineCtx *de_ctx, SigGroupHead *sgh);
52
static bool PrefilterTcpSeqIsPrefilterable(const Signature *s);
53

54
void DetectSeqRegister(void)
55
{
3✔
56
    sigmatch_table[DETECT_SEQ].name = "tcp.seq";
3✔
57
    sigmatch_table[DETECT_SEQ].alias = "seq";
3✔
58
    sigmatch_table[DETECT_SEQ].desc = "check for a specific TCP sequence number";
3✔
59
    sigmatch_table[DETECT_SEQ].url = "/rules/header-keywords.html#seq";
3✔
60
    sigmatch_table[DETECT_SEQ].Match = DetectSeqMatch;
3✔
61
    sigmatch_table[DETECT_SEQ].Setup = DetectSeqSetup;
3✔
62
    sigmatch_table[DETECT_SEQ].Free = DetectSeqFree;
3✔
63
    sigmatch_table[DETECT_SEQ].flags = SIGMATCH_INFO_UINT32;
3✔
64
#ifdef UNITTESTS
65
    sigmatch_table[DETECT_SEQ].RegisterTests = DetectSeqRegisterTests;
66
#endif
67
    sigmatch_table[DETECT_SEQ].SupportsPrefilter = PrefilterTcpSeqIsPrefilterable;
3✔
68
    sigmatch_table[DETECT_SEQ].SetupPrefilter = PrefilterSetupTcpSeq;
3✔
69
}
3✔
70

71
/**
72
 * \internal
73
 * \brief This function is used to match packets with a given Seq number
74
 *
75
 * \param t pointer to thread vars
76
 * \param det_ctx pointer to the pattern matcher thread
77
 * \param p pointer to the current packet
78
 * \param m pointer to the sigmatch that we will cast into DetectSeqData
79
 *
80
 * \retval 0 no match
81
 * \retval 1 match
82
 */
83
static int DetectSeqMatch(DetectEngineThreadCtx *det_ctx,
84
                          Packet *p, const Signature *s, const SigMatchCtx *ctx)
UNCOV
85
{
×
UNCOV
86
    const DetectU32Data *data = (const DetectU32Data *)ctx;
×
87

UNCOV
88
    DEBUG_VALIDATE_BUG_ON(PKT_IS_PSEUDOPKT(p));
×
89
    /* This is only needed on TCP packets */
UNCOV
90
    if (!(PacketIsTCP(p))) {
×
91
        return 0;
×
92
    }
×
93

UNCOV
94
    return DetectU32Match(TCP_GET_RAW_SEQ(PacketGetTCP(p)), data);
×
UNCOV
95
}
×
96

97
/**
98
 * \internal
99
 * \brief this function is used to add the seq option into the signature
100
 *
101
 * \param de_ctx pointer to the Detection Engine Context
102
 * \param s pointer to the Current Signature
103
 * \param optstr pointer to the user provided options
104
 *
105
 * \retval 0 on Success
106
 * \retval -1 on Failure
107
 */
108
static int DetectSeqSetup (DetectEngineCtx *de_ctx, Signature *s, const char *optstr)
109
{
19,316✔
110
    DetectU32Data *data = SCDetectU32Parse(optstr);
19,316✔
111
    if (data == NULL)
19,316✔
112
        return -1;
369✔
113

114
    if (SCSigMatchAppendSMToList(
18,947✔
115
                de_ctx, s, DETECT_SEQ, (SigMatchCtx *)data, DETECT_SM_LIST_MATCH) == NULL) {
18,947✔
116
        DetectSeqFree(de_ctx, data);
×
117
        return -1;
×
118
    }
×
119
    s->flags |= SIG_FLAG_REQUIRE_PACKET;
18,947✔
120
    return 0;
18,947✔
121
}
18,947✔
122

123
/**
124
 * \internal
125
 * \brief this function will free memory associated with seq option
126
 *
127
 * \param data pointer to seq configuration data
128
 */
129
static void DetectSeqFree(DetectEngineCtx *de_ctx, void *ptr)
130
{
18,947✔
131
    SCDetectU32Free(ptr);
18,947✔
132
}
18,947✔
133

134
/* prefilter code */
135

136
static void
137
PrefilterPacketSeqMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
138
{
3,634✔
139
    const PrefilterPacketHeaderCtx *ctx = pectx;
3,634✔
140

141
    DEBUG_VALIDATE_BUG_ON(PKT_IS_PSEUDOPKT(p));
3,634✔
142
    if (!PrefilterPacketHeaderExtraMatch(ctx, p))
3,634✔
143
        return;
3,501✔
144

145
    if (p->proto == IPPROTO_TCP && PacketIsTCP(p)) {
133✔
146
        DetectU32Data du32;
56✔
147
        du32.mode = ctx->v1.u8[0];
56✔
148
        du32.arg1 = ctx->v1.u32[1];
56✔
149
        du32.arg2 = ctx->v1.u32[2];
56✔
150
        if (DetectU32Match(TCP_GET_RAW_SEQ(PacketGetTCP(p)), &du32)) {
56✔
151
            SCLogDebug("packet matches TCP seq %u", ctx->v1.u32[0]);
8✔
152
            PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt);
8✔
153
        }
8✔
154
    }
56✔
155
}
133✔
156

157
static int PrefilterSetupTcpSeq(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
158
{
6,551✔
159
    return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_SEQ, SIG_MASK_REQUIRE_REAL_PKT,
6,551✔
160
            PrefilterPacketU32Set, PrefilterPacketU32Compare, PrefilterPacketSeqMatch);
6,551✔
161
}
6,551✔
162

163
static bool PrefilterTcpSeqIsPrefilterable(const Signature *s)
164
{
×
165
    return PrefilterIsPrefilterableById(s, DETECT_SEQ);
×
166
}
×
167

168

169
#ifdef UNITTESTS
170

171
/**
172
 * \test DetectSeqSigTest01 tests parses
173
 */
174
static int DetectSeqSigTest01(void)
175
{
176
    int result = 0;
177
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
178
    if (de_ctx == NULL)
179
        goto end;
180

181
    /* These three are crammed in here as there is no Parse */
182
    if (SigInit(de_ctx,
183
                "alert tcp any any -> any any "
184
                "(msg:\"Testing seq\";seq:foo;sid:1;)") != NULL)
185
    {
186
        printf("invalid seq accepted: ");
187
        goto cleanup;
188
    }
189
    if (SigInit(de_ctx,
190
                "alert tcp any any -> any any "
191
                "(msg:\"Testing seq\";seq:9999999999;sid:1;)") != NULL)
192
    {
193
        printf("overflowing seq accepted: ");
194
        goto cleanup;
195
    }
196
    if (SigInit(de_ctx,
197
                "alert tcp any any -> any any "
198
                "(msg:\"Testing seq\";seq:-100;sid:1;)") != NULL)
199
    {
200
        printf("negative seq accepted: ");
201
        goto cleanup;
202
    }
203
    result = 1;
204

205
cleanup:
206
    if (de_ctx) {
207
        SigGroupCleanup(de_ctx);
208
        SigCleanSignatures(de_ctx);
209
        DetectEngineCtxFree(de_ctx);
210
    }
211
end:
212
    return result;
213
}
214

215
/**
216
 * \test DetectSeqSigTest02 tests seq keyword
217
 */
218
static int DetectSeqSigTest02(void)
219
{
220
    int result = 0;
221
    uint8_t *buf = (uint8_t *)"Hi all!";
222
    uint16_t buflen = strlen((char *)buf);
223
    Packet *p[3];
224
    p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
225
    p[1] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
226
    p[2] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_ICMP);
227
    if (p[0] == NULL || p[1] == NULL ||p[2] == NULL)
228
        goto end;
229

230
    /* TCP w/seq=42 */
231
    p[0]->l4.hdrs.tcph->th_seq = htonl(42);
232

233
    /* TCP w/seq=100 */
234
    p[1]->l4.hdrs.tcph->th_seq = htonl(100);
235

236
    const char *sigs[2];
237
    sigs[0]= "alert tcp any any -> any any (msg:\"Testing seq\"; seq:41; sid:1;)";
238
    sigs[1]= "alert tcp any any -> any any (msg:\"Testing seq\"; seq:42; sid:2;)";
239

240
    uint32_t sid[2] = {1, 2};
241

242
    uint32_t results[3][2] = {
243
                              /* packet 0 match sid 1 but should not match sid 2 */
244
                              {0, 1},
245
                              /* packet 1 should not match */
246
                              {0, 0},
247
                              /* packet 2 should not match */
248
                              {0, 0} };
249

250
    result = UTHGenericTest(p, 3, sigs, sid, (uint32_t *) results, 2);
251
    UTHFreePackets(p, 3);
252
end:
253
    return result;
254
}
255

256
/**
257
 * \internal
258
 * \brief This function registers unit tests for DetectSeq
259
 */
260
static void DetectSeqRegisterTests(void)
261
{
262
    UtRegisterTest("DetectSeqSigTest01", DetectSeqSigTest01);
263
    UtRegisterTest("DetectSeqSigTest02", DetectSeqSigTest02);
264
}
265
#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