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