suricata
detect-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 "debug.h"
28 #include "decode.h"
29 #include "detect.h"
30 
31 #include "detect-parse.h"
32 #include "detect-engine.h"
35 
36 #include "detect-seq.h"
37 
38 #include "util-byte.h"
39 #include "util-unittest.h"
40 #include "util-unittest-helper.h"
41 #include "util-debug.h"
42 
43 static int DetectSeqSetup(DetectEngineCtx *, Signature *, const char *);
44 static int DetectSeqMatch(ThreadVars *, DetectEngineThreadCtx *,
45  Packet *, const Signature *, const SigMatchCtx *);
46 static void DetectSeqRegisterTests(void);
47 static void DetectSeqFree(void *);
48 static int PrefilterSetupTcpSeq(DetectEngineCtx *de_ctx, SigGroupHead *sgh);
49 static _Bool PrefilterTcpSeqIsPrefilterable(const Signature *s);
50 
52 {
54  sigmatch_table[DETECT_SEQ].desc = "check for a specific TCP sequence number";
55  sigmatch_table[DETECT_SEQ].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#seq";
56  sigmatch_table[DETECT_SEQ].Match = DetectSeqMatch;
57  sigmatch_table[DETECT_SEQ].Setup = DetectSeqSetup;
58  sigmatch_table[DETECT_SEQ].Free = DetectSeqFree;
59  sigmatch_table[DETECT_SEQ].RegisterTests = DetectSeqRegisterTests;
60 
61  sigmatch_table[DETECT_SEQ].SupportsPrefilter = PrefilterTcpSeqIsPrefilterable;
62  sigmatch_table[DETECT_SEQ].SetupPrefilter = PrefilterSetupTcpSeq;
63 }
64 
65 /**
66  * \internal
67  * \brief This function is used to match packets with a given Seq number
68  *
69  * \param t pointer to thread vars
70  * \param det_ctx pointer to the pattern matcher thread
71  * \param p pointer to the current packet
72  * \param m pointer to the sigmatch that we will cast into DetectSeqData
73  *
74  * \retval 0 no match
75  * \retval 1 match
76  */
77 static int DetectSeqMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx,
78  Packet *p, const Signature *s, const SigMatchCtx *ctx)
79 {
80  const DetectSeqData *data = (const DetectSeqData *)ctx;
81 
82  /* This is only needed on TCP packets */
83  if (!(PKT_IS_TCP(p)) || PKT_IS_PSEUDOPKT(p)) {
84  return 0;
85  }
86 
87  return (data->seq == TCP_GET_SEQ(p)) ? 1 : 0;
88 }
89 
90 /**
91  * \internal
92  * \brief this function is used to add the seq option into the signature
93  *
94  * \param de_ctx pointer to the Detection Engine Context
95  * \param s pointer to the Current Signature
96  * \param optstr pointer to the user provided options
97  *
98  * \retval 0 on Success
99  * \retval -1 on Failure
100  */
101 static int DetectSeqSetup (DetectEngineCtx *de_ctx, Signature *s, const char *optstr)
102 {
103  DetectSeqData *data = NULL;
104  SigMatch *sm = NULL;
105 
106  data = SCMalloc(sizeof(DetectSeqData));
107  if (unlikely(data == NULL))
108  goto error;
109 
110  sm = SigMatchAlloc();
111  if (sm == NULL)
112  goto error;
113 
114  sm->type = DETECT_SEQ;
115 
116  if (-1 == ByteExtractStringUint32(&data->seq, 10, 0, optstr)) {
117  goto error;
118  }
119  sm->ctx = (SigMatchCtx*)data;
120 
123 
124  return 0;
125 
126 error:
127  if (data)
128  SCFree(data);
129  if (sm)
130  SigMatchFree(sm);
131  return -1;
132 
133 }
134 
135 /**
136  * \internal
137  * \brief this function will free memory associated with seq option
138  *
139  * \param data pointer to seq configuration data
140  */
141 static void DetectSeqFree(void *ptr)
142 {
143  DetectSeqData *data = (DetectSeqData *)ptr;
144  SCFree(data);
145 }
146 
147 /* prefilter code */
148 
149 static void
150 PrefilterPacketSeqMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
151 {
152  const PrefilterPacketHeaderCtx *ctx = pectx;
153 
154  if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE)
155  return;
156 
157  if ((p->proto) == IPPROTO_TCP && !(PKT_IS_PSEUDOPKT(p)) &&
158  (p->tcph != NULL) && (TCP_GET_SEQ(p) == ctx->v1.u32[0]))
159  {
160  SCLogDebug("packet matches TCP seq %u", ctx->v1.u32[0]);
161  PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt);
162  }
163 }
164 
165 static void
166 PrefilterPacketSeqSet(PrefilterPacketHeaderValue *v, void *smctx)
167 {
168  const DetectSeqData *a = smctx;
169  v->u32[0] = a->seq;
170 }
171 
172 static _Bool
173 PrefilterPacketSeqCompare(PrefilterPacketHeaderValue v, void *smctx)
174 {
175  const DetectSeqData *a = smctx;
176  if (v.u32[0] == a->seq)
177  return TRUE;
178  return FALSE;
179 }
180 
181 static int PrefilterSetupTcpSeq(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
182 {
183  return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_SEQ,
184  PrefilterPacketSeqSet,
185  PrefilterPacketSeqCompare,
186  PrefilterPacketSeqMatch);
187 }
188 
189 static _Bool PrefilterTcpSeqIsPrefilterable(const Signature *s)
190 {
191  const SigMatch *sm;
192  for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) {
193  switch (sm->type) {
194  case DETECT_SEQ:
195  return TRUE;
196  }
197  }
198  return FALSE;
199 }
200 
201 
202 #ifdef UNITTESTS
203 
204 /**
205  * \test DetectSeqSigTest01 tests parses
206  */
207 static int DetectSeqSigTest01(void)
208 {
209  int result = 0;
211  if (de_ctx == NULL)
212  goto end;
213 
214  /* These three are crammed in here as there is no Parse */
215  if (SigInit(de_ctx,
216  "alert tcp any any -> any any "
217  "(msg:\"Testing seq\";seq:foo;sid:1;)") != NULL)
218  {
219  printf("invalid seq accepted: ");
220  goto cleanup;
221  }
222  if (SigInit(de_ctx,
223  "alert tcp any any -> any any "
224  "(msg:\"Testing seq\";seq:9999999999;sid:1;)") != NULL)
225  {
226  printf("overflowing seq accepted: ");
227  goto cleanup;
228  }
229  if (SigInit(de_ctx,
230  "alert tcp any any -> any any "
231  "(msg:\"Testing seq\";seq:-100;sid:1;)") != NULL)
232  {
233  printf("negative seq accepted: ");
234  goto cleanup;
235  }
236  result = 1;
237 
238 cleanup:
239  if (de_ctx) {
240  SigGroupCleanup(de_ctx);
241  SigCleanSignatures(de_ctx);
242  DetectEngineCtxFree(de_ctx);
243  }
244 end:
245  return result;
246 }
247 
248 /**
249  * \test DetectSeqSigTest02 tests seq keyword
250  */
251 static int DetectSeqSigTest02(void)
252 {
253  int result = 0;
254  uint8_t *buf = (uint8_t *)"Hi all!";
255  uint16_t buflen = strlen((char *)buf);
256  Packet *p[3];
257  p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
258  p[1] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
259  p[2] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_ICMP);
260  if (p[0] == NULL || p[1] == NULL ||p[2] == NULL)
261  goto end;
262 
263  /* TCP w/seq=42 */
264  p[0]->tcph->th_seq = htonl(42);
265 
266  /* TCP w/seq=100 */
267  p[1]->tcph->th_seq = htonl(100);
268 
269  const char *sigs[2];
270  sigs[0]= "alert tcp any any -> any any (msg:\"Testing seq\"; seq:41; sid:1;)";
271  sigs[1]= "alert tcp any any -> any any (msg:\"Testing seq\"; seq:42; sid:2;)";
272 
273  uint32_t sid[2] = {1, 2};
274 
275  uint32_t results[3][2] = {
276  /* packet 0 match sid 1 but should not match sid 2 */
277  {0, 1},
278  /* packet 1 should not match */
279  {0, 0},
280  /* packet 2 should not match */
281  {0, 0} };
282 
283  result = UTHGenericTest(p, 3, sigs, sid, (uint32_t *) results, 2);
284  UTHFreePackets(p, 3);
285 end:
286  return result;
287 }
288 
289 #endif /* UNITTESTS */
290 
291 /**
292  * \internal
293  * \brief This function registers unit tests for DetectSeq
294  */
295 static void DetectSeqRegisterTests(void)
296 {
297 #ifdef UNITTESTS
298  UtRegisterTest("DetectSeqSigTest01", DetectSeqSigTest01);
299  UtRegisterTest("DetectSeqSigTest02", DetectSeqSigTest02);
300 #endif /* UNITTESTS */
301 }
302 
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1403
SignatureInitData * init_data
Definition: detect.h:560
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1146
#define SCLogDebug(...)
Definition: util-debug.h:335
int(* SetupPrefilter)(DetectEngineCtx *de_ctx, struct SigGroupHead_ *sgh)
Definition: detect.h:1149
int PrefilterSetupPacketHeader(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type, void(*Set)(PrefilterPacketHeaderValue *v, void *), _Bool(*Compare)(PrefilterPacketHeaderValue v, void *), void(*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
void DetectSeqRegister(void)
Registration function for ack: keyword.
Definition: detect-seq.c:51
uint32_t flags
Definition: detect.h:493
_Bool(* SupportsPrefilter)(const Signature *s)
Definition: detect.h:1148
#define FALSE
#define unlikely(expr)
Definition: util-optimize.h:35
Signature * SigInit(DetectEngineCtx *, const char *)
Parses a signature and adds it to the Detection Engine Context.
void SigCleanSignatures(DetectEngineCtx *de_ctx)
Container for matching data for a signature group.
Definition: detect.h:1295
int ByteExtractStringUint32(uint32_t *res, int base, uint16_t len, const char *str)
Definition: util-byte.c:196
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:230
const char * name
Definition: detect.h:1160
TCPHdr * tcph
Definition: decode.h:525
Signature container.
Definition: detect.h:492
#define TRUE
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:319
struct SigMatch_ * next
Definition: detect.h:328
main detection engine ctx
Definition: detect.h:720
#define TCP_GET_SEQ(p)
Definition: decode-tcp.h:106
uint8_t proto
Definition: decode.h:429
void(* Free)(void *)
Definition: detect.h:1151
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
PrefilterRuleStore pmq
Definition: detect.h:1061
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 SigGroupCleanup(DetectEngineCtx *de_ctx)
uint8_t type
Definition: detect.h:325
const char * desc
Definition: detect.h:1162
void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:282
struct SigMatch_ ** smlists
Definition: detect.h:486
SigMatchCtx * ctx
Definition: detect.h:327
#define SCMalloc(a)
Definition: util-mem.h:174
seq data
Definition: detect-seq.h:30
#define SCFree(a)
Definition: util-mem.h:236
#define PKT_IS_TCP(p)
Definition: decode.h:252
uint32_t seq
Definition: detect-seq.h:31
int UTHGenericTest(Packet **pkt, int numpkts, const char *sigs[], uint32_t sids[], uint32_t *results, int numsigs)
UTHGenericTest: function that perfom a generic check taking care of as maximum common unittest elemen...
void SigMatchFree(SigMatch *sm)
free a SigMatch
Definition: detect-parse.c:241
int(* Match)(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1129
const char * url
Definition: detect.h:1163
#define DOC_URL
Definition: suricata.h:86
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition: decode.h:1140
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:226
Per thread variable structure.
Definition: threadvars.h:57
#define DOC_VERSION
Definition: suricata.h:91
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
void UTHFreePackets(Packet **p, int numpkts)
UTHFreePackets: function to release the allocated data from UTHBuildPacket and the packet itself...
void(* RegisterTests)(void)
Definition: detect.h:1152
a single match condition for a signature
Definition: detect.h:324
DetectEngineCtx * DetectEngineCtxInit(void)