suricata
detect-distance.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 Victor Julien <victor@inliniac.net>
22  * \author Anoop Saldanha <anoopsaldanha@gmail.com>
23  *
24  * Implements the distance keyword
25  */
26 
27 #include "suricata-common.h"
28 
29 #include "decode.h"
30 
31 #include "detect.h"
32 #include "detect-parse.h"
33 #include "detect-engine.h"
34 #include "app-layer.h"
35 
36 #include "detect-content.h"
37 #include "detect-uricontent.h"
38 #include "detect-pcre.h"
39 #include "detect-byte-extract.h"
40 #include "detect-distance.h"
41 
42 #include "flow-var.h"
43 
44 #include "util-byte.h"
45 #include "util-debug.h"
46 #include "util-unittest.h"
47 #include "detect-bytejump.h"
48 #include "util-unittest-helper.h"
49 
50 static int DetectDistanceSetup(DetectEngineCtx *, Signature *, const char *);
51 static void DetectDistanceRegisterTests(void);
52 
54 {
55  sigmatch_table[DETECT_DISTANCE].name = "distance";
56  sigmatch_table[DETECT_DISTANCE].desc = "indicates a relation between this content keyword and the content preceding it";
57  sigmatch_table[DETECT_DISTANCE].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#distance";
59  sigmatch_table[DETECT_DISTANCE].Setup = DetectDistanceSetup;
61  sigmatch_table[DETECT_DISTANCE].RegisterTests = DetectDistanceRegisterTests;
62 }
63 
64 static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s,
65  const char *distancestr)
66 {
67  const char *str = distancestr;
68  SigMatch *pm = NULL;
69  int ret = -1;
70 
71  /* retrieve the sm to apply the distance against */
73  if (pm == NULL) {
74  SCLogError(SC_ERR_OFFSET_MISSING_CONTENT, "distance needs "
75  "preceding content, uricontent option, http_client_body, "
76  "http_server_body, http_header option, http_raw_header option, "
77  "http_method option, http_cookie, http_raw_uri, "
78  "http_stat_msg, http_stat_code, http_user_agent or "
79  "file_data/dce_stub_data sticky buffer option");
80  goto end;
81  }
82 
83  /* verify other conditions */
85  if (cd->flags & DETECT_CONTENT_DISTANCE) {
86  SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use multiple distances for the same content.");
87  goto end;
88  }
89  if ((cd->flags & DETECT_CONTENT_DEPTH) || (cd->flags & DETECT_CONTENT_OFFSET)) {
90  SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use a relative "
91  "keyword like within/distance with a absolute "
92  "relative keyword like depth/offset for the same "
93  "content." );
94  goto end;
95  }
97  SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a relative "
98  "negated keyword set along with a fast_pattern");
99  goto end;
100  }
102  SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a relative "
103  "keyword set along with a fast_pattern:only;");
104  goto end;
105  }
106  if (str[0] != '-' && isalpha((unsigned char)str[0])) {
107  SigMatch *bed_sm = DetectByteExtractRetrieveSMVar(str, s);
108  if (bed_sm == NULL) {
109  SCLogError(SC_ERR_INVALID_SIGNATURE, "unknown byte_extract var "
110  "seen in distance - %s\n", str);
111  goto end;
112  }
113  cd->distance = ((DetectByteExtractData *)bed_sm->ctx)->local_id;
115  } else {
116  if (ByteExtractStringInt32(&cd->distance, 0, 0, str) != (int)strlen(str)) {
118  "invalid value for distance: %s", str);
119  goto end;
120  }
121  }
123 
124  SigMatch *prev_pm = DetectGetLastSMByListPtr(s, pm->prev,
126  if (prev_pm == NULL) {
127  ret = 0;
128  goto end;
129  }
130  if (prev_pm->type == DETECT_CONTENT) {
131  DetectContentData *prev_cd = (DetectContentData *)prev_pm->ctx;
132  if (prev_cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) {
133  SCLogError(SC_ERR_INVALID_SIGNATURE, "previous keyword "
134  "has a fast_pattern:only; set. Can't "
135  "have relative keywords around a fast_pattern "
136  "only content");
137  goto end;
138  }
139  if ((cd->flags & DETECT_CONTENT_NEGATED) == 0) {
141  } else {
143  }
144  } else if (prev_pm->type == DETECT_PCRE) {
145  DetectPcreData *pd = (DetectPcreData *)prev_pm->ctx;
147  }
148 
149  ret = 0;
150  end:
151  return ret;
152 }
153 
154 #ifdef UNITTESTS
155 
156 static int DetectDistanceTest01(void)
157 {
158  int result = 0;
159 
161  if (de_ctx == NULL) {
162  printf("no de_ctx: ");
163  goto end;
164  }
165 
166  de_ctx->flags |= DE_QUIET;
167 
168  de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (content:\"|AA BB|\"; content:\"|CC DD EE FF 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE|\"; distance: 4; within: 19; sid:1; rev:1;)");
169  if (de_ctx->sig_list == NULL) {
170  printf("sig parse failed: ");
171  goto end;
172  }
173 
174  SigMatch *sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH];
175  if (sm == NULL) {
176  printf("sm NULL: ");
177  goto end;
178  }
179 
180  sm = sm->next;
181  if (sm == NULL) {
182  printf("sm2 NULL: ");
183  goto end;
184  }
185 
187  if (co == NULL) {
188  printf("co == NULL: ");
189  goto end;
190  }
191 
192  if (co->distance != 4) {
193  printf("distance %"PRIi32", expected 4: ", co->distance);
194  goto end;
195  }
196 
197  /* within needs to be 23: distance + content_len as Snort auto fixes this */
198  if (co->within != 19) {
199  printf("within %"PRIi32", expected 23: ", co->within);
200  goto end;
201  }
202 
203  result = 1;
204 end:
205  DetectEngineCtxFree(de_ctx);
206  return result;
207 }
208 
209 /**
210  * \test DetectDistanceTestPacket01 is a test to check matches of
211  * distance works, if the previous keyword is byte_jump and content
212  * (bug 163)
213  */
214 static int DetectDistanceTestPacket01 (void)
215 {
216  int result = 0;
217  uint8_t buf[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
218  uint16_t buflen = sizeof(buf);
219  Packet *p;
220  p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
221 
222  if (p == NULL)
223  goto end;
224 
225  char sig[] = "alert tcp any any -> any any (msg:\"suricata test\"; "
226  "byte_jump:1,2; content:\"|00|\"; "
227  "within:1; distance:2; sid:98711212; rev:1;)";
228 
230  result = UTHPacketMatchSig(p, sig);
231 
232  UTHFreePacket(p);
233 end:
234  return result;
235 }
236 #endif /* UNITTESTS */
237 
238 static void DetectDistanceRegisterTests(void)
239 {
240 #ifdef UNITTESTS
241  UtRegisterTest("DetectDistanceTest01 -- distance / within mix",
242  DetectDistanceTest01);
243  UtRegisterTest("DetectDistanceTestPacket01", DetectDistanceTestPacket01);
244 #endif /* UNITTESTS */
245 }
246 
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1448
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1186
int ByteExtractStringInt32(int32_t *res, int base, uint16_t len, const char *str)
Definition: util-byte.c:360
#define DETECT_CONTENT_FAST_PATTERN
Signature * SigInit(DetectEngineCtx *, const char *)
Parses a signature and adds it to the Detection Engine Context.
struct SigMatch_ * prev
Definition: detect.h:323
Signature * sig_list
Definition: detect.h:767
#define FLOW_PKT_ESTABLISHED
Definition: flow.h:203
#define DETECT_CONTENT_DISTANCE_BE
#define DETECT_CONTENT_DISTANCE
const char * name
Definition: detect.h:1200
Signature container.
Definition: detect.h:522
#define DETECT_CONTENT_DEPTH
uint16_t flags
Definition: detect-pcre.h:42
struct SigMatch_ * next
Definition: detect.h:322
main detection engine ctx
Definition: detect.h:761
#define DETECT_CONTENT_DISTANCE_NEXT
#define DE_QUIET
Definition: detect.h:292
SigMatch * DetectGetLastSMByListPtr(const Signature *s, SigMatch *sm_list,...)
Returns the sm with the largest index (added last) from the list passed to us as a pointer...
Definition: detect-parse.c:505
#define str(s)
uint8_t flags
Definition: detect.h:762
void(* Free)(void *)
Definition: detect.h:1191
int UTHPacketMatchSig(Packet *p, const char *sig)
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
uint8_t flowflags
Definition: decode.h:440
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:1170
uint8_t type
Definition: detect.h:319
#define DETECT_CONTENT_FAST_PATTERN_ONLY
const char * desc
Definition: detect.h:1202
SigMatch * DetectByteExtractRetrieveSMVar(const char *arg, const Signature *s)
Lookup the SigMatch for a named byte_extract variable.
SigMatchCtx * ctx
Definition: detect.h:321
#define DETECT_CONTENT_NEGATED
SigMatch * DetectGetLastSMFromLists(const Signature *s,...)
Returns the sm with the largest index (added latest) from the lists passed to us. ...
Definition: detect-parse.c:465
const char * url
Definition: detect.h:1203
void DetectDistanceRegister(void)
void UTHFreePacket(Packet *p)
UTHFreePacket: function to release the allocated data from UTHBuildPacket and the packet itself...
#define DOC_URL
Definition: suricata.h:86
#define DETECT_PCRE_RELATIVE_NEXT
Definition: detect-pcre.h:32
#define DETECT_CONTENT_RELATIVE_NEXT
#define FLOW_PKT_TOCLIENT
Definition: flow.h:202
Holds data related to byte_extract keyword.
#define DOC_VERSION
Definition: suricata.h:91
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
#define DETECT_CONTENT_OFFSET
void(* RegisterTests)(void)
Definition: detect.h:1192
a single match condition for a signature
Definition: detect.h:318
DetectEngineCtx * DetectEngineCtxInit(void)