suricata
detect-tcp-seq.c
Go to the documentation of this file.
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"
34#include "detect-engine-build.h"
35
36#include "detect-tcp-seq.h"
37
38#include "util-byte.h"
39#include "util-unittest.h"
41#include "util-debug.h"
42
43static int DetectSeqSetup(DetectEngineCtx *, Signature *, const char *);
44static int DetectSeqMatch(DetectEngineThreadCtx *,
45 Packet *, const Signature *, const SigMatchCtx *);
46#ifdef UNITTESTS
47static void DetectSeqRegisterTests(void);
48#endif
49static void DetectSeqFree(DetectEngineCtx *, void *);
50static int PrefilterSetupTcpSeq(DetectEngineCtx *de_ctx, SigGroupHead *sgh);
51static bool PrefilterTcpSeqIsPrefilterable(const Signature *s);
52
54{
55 sigmatch_table[DETECT_SEQ].name = "tcp.seq";
57 sigmatch_table[DETECT_SEQ].desc = "check for a specific TCP sequence number";
58 sigmatch_table[DETECT_SEQ].url = "/rules/header-keywords.html#seq";
59 sigmatch_table[DETECT_SEQ].Match = DetectSeqMatch;
60 sigmatch_table[DETECT_SEQ].Setup = DetectSeqSetup;
61 sigmatch_table[DETECT_SEQ].Free = DetectSeqFree;
62#ifdef UNITTESTS
63 sigmatch_table[DETECT_SEQ].RegisterTests = DetectSeqRegisterTests;
64#endif
65 sigmatch_table[DETECT_SEQ].SupportsPrefilter = PrefilterTcpSeqIsPrefilterable;
66 sigmatch_table[DETECT_SEQ].SetupPrefilter = PrefilterSetupTcpSeq;
67}
68
69/**
70 * \internal
71 * \brief This function is used to match packets with a given Seq number
72 *
73 * \param t pointer to thread vars
74 * \param det_ctx pointer to the pattern matcher thread
75 * \param p pointer to the current packet
76 * \param m pointer to the sigmatch that we will cast into DetectSeqData
77 *
78 * \retval 0 no match
79 * \retval 1 match
80 */
81static int DetectSeqMatch(DetectEngineThreadCtx *det_ctx,
82 Packet *p, const Signature *s, const SigMatchCtx *ctx)
83{
84 const DetectSeqData *data = (const DetectSeqData *)ctx;
85
87 /* This is only needed on TCP packets */
88 if (!(PacketIsTCP(p))) {
89 return 0;
90 }
91
92 return (data->seq == TCP_GET_RAW_SEQ(PacketGetTCP(p))) ? 1 : 0;
93}
94
95/**
96 * \internal
97 * \brief this function is used to add the seq option into the signature
98 *
99 * \param de_ctx pointer to the Detection Engine Context
100 * \param s pointer to the Current Signature
101 * \param optstr pointer to the user provided options
102 *
103 * \retval 0 on Success
104 * \retval -1 on Failure
105 */
106static int DetectSeqSetup (DetectEngineCtx *de_ctx, Signature *s, const char *optstr)
107{
108 DetectSeqData *data = NULL;
109
110 data = SCMalloc(sizeof(DetectSeqData));
111 if (unlikely(data == NULL))
112 goto error;
113
114 if (StringParseUint32(&data->seq, 10, 0, optstr) < 0) {
115 goto error;
116 }
117
119 de_ctx, s, DETECT_SEQ, (SigMatchCtx *)data, DETECT_SM_LIST_MATCH) == NULL) {
120 goto error;
121 }
123
124 return 0;
125
126error:
127 if (data)
128 SCFree(data);
129 return -1;
130
131}
132
133/**
134 * \internal
135 * \brief this function will free memory associated with seq option
136 *
137 * \param data pointer to seq configuration data
138 */
139static void DetectSeqFree(DetectEngineCtx *de_ctx, void *ptr)
140{
141 DetectSeqData *data = (DetectSeqData *)ptr;
142 SCFree(data);
143}
144
145/* prefilter code */
146
147static void
148PrefilterPacketSeqMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
149{
150 const PrefilterPacketHeaderCtx *ctx = pectx;
151
153 if (!PrefilterPacketHeaderExtraMatch(ctx, p))
154 return;
155
156 if (p->proto == IPPROTO_TCP && PacketIsTCP(p) &&
157 (TCP_GET_RAW_SEQ(PacketGetTCP(p)) == ctx->v1.u32[0])) {
158 SCLogDebug("packet matches TCP seq %u", ctx->v1.u32[0]);
159 PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt);
160 }
161}
162
163static void
164PrefilterPacketSeqSet(PrefilterPacketHeaderValue *v, void *smctx)
165{
166 const DetectSeqData *a = smctx;
167 v->u32[0] = a->seq;
168}
169
170static bool
171PrefilterPacketSeqCompare(PrefilterPacketHeaderValue v, void *smctx)
172{
173 const DetectSeqData *a = smctx;
174 if (v.u32[0] == a->seq)
175 return true;
176 return false;
177}
178
179static int PrefilterSetupTcpSeq(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
180{
182 PrefilterPacketSeqSet, PrefilterPacketSeqCompare, PrefilterPacketSeqMatch);
183}
184
185static bool PrefilterTcpSeqIsPrefilterable(const Signature *s)
186{
187 const SigMatch *sm;
188 for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) {
189 switch (sm->type) {
190 case DETECT_SEQ:
191 return true;
192 }
193 }
194 return false;
195}
196
197
198#ifdef UNITTESTS
199
200/**
201 * \test DetectSeqSigTest01 tests parses
202 */
203static int DetectSeqSigTest01(void)
204{
205 int result = 0;
207 if (de_ctx == NULL)
208 goto end;
209
210 /* These three are crammed in here as there is no Parse */
211 if (SigInit(de_ctx,
212 "alert tcp any any -> any any "
213 "(msg:\"Testing seq\";seq:foo;sid:1;)") != NULL)
214 {
215 printf("invalid seq accepted: ");
216 goto cleanup;
217 }
218 if (SigInit(de_ctx,
219 "alert tcp any any -> any any "
220 "(msg:\"Testing seq\";seq:9999999999;sid:1;)") != NULL)
221 {
222 printf("overflowing seq accepted: ");
223 goto cleanup;
224 }
225 if (SigInit(de_ctx,
226 "alert tcp any any -> any any "
227 "(msg:\"Testing seq\";seq:-100;sid:1;)") != NULL)
228 {
229 printf("negative seq accepted: ");
230 goto cleanup;
231 }
232 result = 1;
233
234cleanup:
235 if (de_ctx) {
239 }
240end:
241 return result;
242}
243
244/**
245 * \test DetectSeqSigTest02 tests seq keyword
246 */
247static int DetectSeqSigTest02(void)
248{
249 int result = 0;
250 uint8_t *buf = (uint8_t *)"Hi all!";
251 uint16_t buflen = strlen((char *)buf);
252 Packet *p[3];
253 p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
254 p[1] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
255 p[2] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_ICMP);
256 if (p[0] == NULL || p[1] == NULL ||p[2] == NULL)
257 goto end;
258
259 /* TCP w/seq=42 */
260 p[0]->l4.hdrs.tcph->th_seq = htonl(42);
261
262 /* TCP w/seq=100 */
263 p[1]->l4.hdrs.tcph->th_seq = htonl(100);
264
265 const char *sigs[2];
266 sigs[0]= "alert tcp any any -> any any (msg:\"Testing seq\"; seq:41; sid:1;)";
267 sigs[1]= "alert tcp any any -> any any (msg:\"Testing seq\"; seq:42; sid:2;)";
268
269 uint32_t sid[2] = {1, 2};
270
271 uint32_t results[3][2] = {
272 /* packet 0 match sid 1 but should not match sid 2 */
273 {0, 1},
274 /* packet 1 should not match */
275 {0, 0},
276 /* packet 2 should not match */
277 {0, 0} };
278
279 result = UTHGenericTest(p, 3, sigs, sid, (uint32_t *) results, 2);
280 UTHFreePackets(p, 3);
281end:
282 return result;
283}
284
285/**
286 * \internal
287 * \brief This function registers unit tests for DetectSeq
288 */
289static void DetectSeqRegisterTests(void)
290{
291 UtRegisterTest("DetectSeqSigTest01", DetectSeqSigTest01);
292 UtRegisterTest("DetectSeqSigTest02", DetectSeqSigTest02);
293}
294#endif /* UNITTESTS */
#define TCP_GET_RAW_SEQ(tcph)
Definition decode-tcp.h:80
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition decode.h:1321
void SigCleanSignatures(DetectEngineCtx *de_ctx)
int SigGroupCleanup(DetectEngineCtx *de_ctx)
int PrefilterSetupPacketHeader(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type, SignatureMask mask, void(*Set)(PrefilterPacketHeaderValue *v, void *), bool(*Compare)(PrefilterPacketHeaderValue v, void *), void(*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
DetectEngineCtx * DetectEngineCtxInit(void)
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
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 DetectSeqRegister(void)
Registration function for ack: keyword.
#define SIG_FLAG_REQUIRE_PACKET
Definition detect.h:254
#define SIG_MASK_REQUIRE_REAL_PKT
Definition detect.h:316
@ DETECT_SM_LIST_MATCH
Definition detect.h:117
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
PrefilterRuleStore pmq
Definition detect.h:1349
union PacketL4::L4Hdrs hdrs
struct PacketL4 l4
Definition decode.h:601
uint8_t proto
Definition decode.h:523
Container for matching data for a signature group.
Definition detect.h:1629
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition detect.h:351
a single match condition for a signature
Definition detect.h:356
uint16_t type
Definition detect.h:357
struct SigMatch_ * next
Definition detect.h:360
const char * url
Definition detect.h:1462
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition detect.h:1441
int(* SetupPrefilter)(DetectEngineCtx *de_ctx, struct SigGroupHead_ *sgh)
Definition detect.h:1444
void(* Free)(DetectEngineCtx *, void *)
Definition detect.h:1446
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 * alias
Definition detect.h:1460
const char * name
Definition detect.h:1459
bool(* SupportsPrefilter)(const Signature *s)
Definition detect.h:1443
struct SigMatch_ * smlists[DETECT_SM_LIST_MAX]
Definition detect.h:642
Signature container.
Definition detect.h:668
uint32_t flags
Definition detect.h:669
SignatureInitData * init_data
Definition detect.h:747
uint32_t th_seq
Definition decode-tcp.h:152
TCPHdr * tcph
Definition decode.h:469
int StringParseUint32(uint32_t *res, int base, size_t len, const char *str)
Definition util-byte.c:313
#define SCLogDebug(...)
Definition util-debug.h:275
#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)