suricata
detect-ack.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2016 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  * \author Victor Julien <victor@inliniac.net>
23  *
24  * Implements the "ack" keyword.
25  */
26 
27 #include "suricata-common.h"
28 #include "debug.h"
29 #include "decode.h"
30 #include "detect.h"
31 
32 #include "detect-parse.h"
33 #include "detect-engine.h"
34 #include "detect-engine-mpm.h"
37 
38 #include "detect-ack.h"
39 
40 #include "util-byte.h"
41 #include "util-unittest.h"
42 #include "util-unittest-helper.h"
43 #include "util-debug.h"
44 
45 /* prototypes */
46 static int DetectAckSetup(DetectEngineCtx *, Signature *, const char *);
47 static int DetectAckMatch(ThreadVars *, DetectEngineThreadCtx *,
48  Packet *, const Signature *, const SigMatchCtx *);
49 static void DetectAckRegisterTests(void);
50 static void DetectAckFree(void *);
51 static int PrefilterSetupTcpAck(DetectEngineCtx *de_ctx, SigGroupHead *sgh);
52 static _Bool PrefilterTcpAckIsPrefilterable(const Signature *s);
53 
55 {
57  sigmatch_table[DETECT_ACK].desc = "check for a specific TCP acknowledgement number";
58  sigmatch_table[DETECT_ACK].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#ack";
59  sigmatch_table[DETECT_ACK].Match = DetectAckMatch;
60  sigmatch_table[DETECT_ACK].Setup = DetectAckSetup;
61  sigmatch_table[DETECT_ACK].Free = DetectAckFree;
62 
63  sigmatch_table[DETECT_ACK].SupportsPrefilter = PrefilterTcpAckIsPrefilterable;
64  sigmatch_table[DETECT_ACK].SetupPrefilter = PrefilterSetupTcpAck;
65 
66  sigmatch_table[DETECT_ACK].RegisterTests = DetectAckRegisterTests;
67 }
68 
69 /**
70  * \internal
71  * \brief This function is used to match packets with a given Ack 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 DetectAckData
77  *
78  * \retval 0 no match
79  * \retval 1 match
80  */
81 static int DetectAckMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx,
82  Packet *p, const Signature *s, const SigMatchCtx *ctx)
83 {
84  const DetectAckData *data = (const DetectAckData *)ctx;
85 
86  /* This is only needed on TCP packets */
87  if (!(PKT_IS_TCP(p)) || PKT_IS_PSEUDOPKT(p)) {
88  return 0;
89  }
90 
91  return (data->ack == TCP_GET_ACK(p)) ? 1 : 0;
92 }
93 
94 /**
95  * \internal
96  * \brief this function is used to add the ack option into the signature
97  *
98  * \param de_ctx pointer to the Detection Engine Context
99  * \param s pointer to the Current Signature
100  * \param m pointer to the Current SigMatch
101  * \param optstr pointer to the user provided options
102  *
103  * \retval 0 on Success
104  * \retval -1 on Failure
105  */
106 static int DetectAckSetup(DetectEngineCtx *de_ctx, Signature *s, const char *optstr)
107 {
108  DetectAckData *data = NULL;
109  SigMatch *sm = NULL;
110 
111  data = SCMalloc(sizeof(DetectAckData));
112  if (unlikely(data == NULL))
113  goto error;
114 
115  sm = SigMatchAlloc();
116  if (sm == NULL)
117  goto error;
118 
119  sm->type = DETECT_ACK;
120 
121  if (-1 == ByteExtractStringUint32(&data->ack, 10, 0, optstr)) {
122  goto error;
123  }
124  sm->ctx = (SigMatchCtx*)data;
125 
128 
129  return 0;
130 
131 error:
132  if (data)
133  SCFree(data);
134  if (sm)
135  SigMatchFree(sm);
136  return -1;
137 
138 }
139 
140 /**
141  * \internal
142  * \brief this function will free memory associated with ack option
143  *
144  * \param data pointer to ack configuration data
145  */
146 static void DetectAckFree(void *ptr)
147 {
148  DetectAckData *data = (DetectAckData *)ptr;
149  SCFree(data);
150 }
151 
152 /* prefilter code */
153 
154 static void
155 PrefilterPacketAckMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
156 {
157  const PrefilterPacketHeaderCtx *ctx = pectx;
158 
159  if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE)
160  return;
161 
162  if ((p->proto) == IPPROTO_TCP && !(PKT_IS_PSEUDOPKT(p)) &&
163  (p->tcph != NULL) && (TCP_GET_ACK(p) == ctx->v1.u32[0]))
164  {
165  SCLogDebug("packet matches TCP ack %u", ctx->v1.u32[0]);
166  PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt);
167  }
168 }
169 
170 static void
171 PrefilterPacketAckSet(PrefilterPacketHeaderValue *v, void *smctx)
172 {
173  const DetectAckData *a = smctx;
174  v->u32[0] = a->ack;
175 }
176 
177 static _Bool
178 PrefilterPacketAckCompare(PrefilterPacketHeaderValue v, void *smctx)
179 {
180  const DetectAckData *a = smctx;
181  if (v.u32[0] == a->ack)
182  return TRUE;
183  return FALSE;
184 }
185 
186 static int PrefilterSetupTcpAck(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
187 {
188  return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_ACK,
189  PrefilterPacketAckSet,
190  PrefilterPacketAckCompare,
191  PrefilterPacketAckMatch);
192 }
193 
194 static _Bool PrefilterTcpAckIsPrefilterable(const Signature *s)
195 {
196  const SigMatch *sm;
197  for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) {
198  switch (sm->type) {
199  case DETECT_ACK:
200  return TRUE;
201  }
202  }
203  return FALSE;
204 }
205 
206 #ifdef UNITTESTS
207 /**
208  * \internal
209  * \brief This test tests sameip success and failure.
210  */
211 static int DetectAckSigTest01(void)
212 {
213  Packet *p1 = NULL;
214  Packet *p2 = NULL;
215  Packet *p3 = NULL;
216  ThreadVars th_v;
217  DetectEngineThreadCtx *det_ctx;
218  int result = 0;
219 
220  memset(&th_v, 0, sizeof(th_v));
221 
222  /* TCP w/ack=42 */
223  p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
224  p1->tcph->th_ack = htonl(42);
225 
226  /* TCP w/ack=100 */
227  p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
228  p2->tcph->th_ack = htonl(100);
229 
230  /* ICMP */
231  p3 = UTHBuildPacket(NULL, 0, IPPROTO_ICMP);
232 
234  if (de_ctx == NULL) {
235  goto end;
236  }
237 
238  de_ctx->flags |= DE_QUIET;
239 
240  /* These three are crammed in here as there is no Parse */
241  if (SigInit(de_ctx,
242  "alert tcp any any -> any any "
243  "(msg:\"Testing ack\";ack:foo;sid:1;)") != NULL)
244  {
245  printf("invalid ack accepted: ");
246  goto cleanup_engine;
247  }
248  if (SigInit(de_ctx,
249  "alert tcp any any -> any any "
250  "(msg:\"Testing ack\";ack:9999999999;sid:1;)") != NULL)
251  {
252  printf("overflowing ack accepted: ");
253  goto cleanup_engine;
254  }
255  if (SigInit(de_ctx,
256  "alert tcp any any -> any any "
257  "(msg:\"Testing ack\";ack:-100;sid:1;)") != NULL)
258  {
259  printf("negative ack accepted: ");
260  goto cleanup_engine;
261  }
262 
263  de_ctx->sig_list = SigInit(de_ctx,
264  "alert tcp any any -> any any "
265  "(msg:\"Testing ack\";ack:41;sid:1;)");
266  if (de_ctx->sig_list == NULL) {
267  goto cleanup_engine;
268  }
269 
270  de_ctx->sig_list->next = SigInit(de_ctx,
271  "alert tcp any any -> any any "
272  "(msg:\"Testing ack\";ack:42;sid:2;)");
273  if (de_ctx->sig_list->next == NULL) {
274  goto cleanup_engine;
275  }
276 
277  SigGroupBuild(de_ctx);
278  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
279 
280  SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
281  if (PacketAlertCheck(p1, 1) != 0) {
282  printf("sid 1 alerted, but should not have: ");
283  goto cleanup;
284  }
285  if (PacketAlertCheck(p1, 2) == 0) {
286  printf("sid 2 did not alert, but should have: ");
287  goto cleanup;
288  }
289 
290  SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
291  if (PacketAlertCheck(p2, 1) != 0) {
292  printf("sid 1 alerted, but should not have: ");
293  goto cleanup;
294  }
295  if (PacketAlertCheck(p2, 2) != 0) {
296  printf("sid 2 alerted, but should not have: ");
297  goto cleanup;
298  }
299 
300  SigMatchSignatures(&th_v, de_ctx, det_ctx, p3);
301  if (PacketAlertCheck(p3, 1) != 0) {
302  printf("sid 1 alerted, but should not have: ");
303  goto cleanup;
304  }
305  if (PacketAlertCheck(p3, 2) != 0) {
306  printf("sid 2 alerted, but should not have: ");
307  goto cleanup;
308  }
309 
310  result = 1;
311 
312 cleanup:
313  SigGroupCleanup(de_ctx);
314  SigCleanSignatures(de_ctx);
315 
316  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
317 
318 cleanup_engine:
319  DetectEngineCtxFree(de_ctx);
320 
321 end:
322  return result;
323 }
324 
325 #endif /* UNITTESTS */
326 
327 /**
328  * \internal
329  * \brief This function registers unit tests for DetectAck
330  */
331 static void DetectAckRegisterTests(void)
332 {
333 #ifdef UNITTESTS
334  UtRegisterTest("DetectAckSigTest01", DetectAckSigTest01);
335 #endif /* UNITTESTS */
336 }
337 
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1409
SignatureInitData * init_data
Definition: detect.h:564
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1150
#define SCLogDebug(...)
Definition: util-debug.h:335
int(* SetupPrefilter)(DetectEngineCtx *de_ctx, struct SigGroupHead_ *sgh)
Definition: detect.h:1153
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))
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
uint32_t flags
Definition: detect.h:497
_Bool(* SupportsPrefilter)(const Signature *s)
Definition: detect.h:1152
#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.
Signature * sig_list
Definition: detect.h:730
void SigCleanSignatures(DetectEngineCtx *de_ctx)
Container for matching data for a signature group.
Definition: detect.h:1299
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:228
TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **)
initialize thread specific detection engine context
const char * name
Definition: detect.h:1164
TCPHdr * tcph
Definition: decode.h:520
Signature container.
Definition: detect.h:496
#define TRUE
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:317
struct SigMatch_ * next
Definition: detect.h:326
main detection engine ctx
Definition: detect.h:724
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *)
#define DE_QUIET
Definition: detect.h:296
ack data
Definition: detect-ack.h:30
uint8_t proto
Definition: decode.h:428
uint8_t flags
Definition: detect.h:725
void(* Free)(void *)
Definition: detect.h:1155
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
void SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:1742
PrefilterRuleStore pmq
Definition: detect.h:1065
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.
void DetectAckRegister(void)
Registration function for ack: keyword.
Definition: detect-ack.c:54
int SigGroupCleanup(DetectEngineCtx *de_ctx)
struct Signature_ * next
Definition: detect.h:567
uint8_t type
Definition: detect.h:323
const char * desc
Definition: detect.h:1166
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:490
SigMatchCtx * ctx
Definition: detect.h:325
#define SCMalloc(a)
Definition: util-mem.h:166
#define SCFree(a)
Definition: util-mem.h:228
#define PKT_IS_TCP(p)
Definition: decode.h:251
void SigMatchFree(SigMatch *sm)
free a SigMatch
Definition: detect-parse.c:247
int(* Match)(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1133
const char * url
Definition: detect.h:1167
#define DOC_URL
Definition: suricata.h:86
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition: decode.h:1131
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:232
Per thread variable structure.
Definition: threadvars.h:57
#define TCP_GET_ACK(p)
Definition: decode-tcp.h:107
#define DOC_VERSION
Definition: suricata.h:91
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
uint32_t ack
Definition: detect-ack.h:31
void(* RegisterTests)(void)
Definition: detect.h:1156
a single match condition for a signature
Definition: detect.h:322
DetectEngineCtx * DetectEngineCtxInit(void)