/src/suricata7/src/detect-parse.c
Line | Count | Source |
1 | | /* Copyright (C) 2007-2021 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 | | * |
23 | | * signature parser |
24 | | */ |
25 | | |
26 | | #include "suricata-common.h" |
27 | | |
28 | | #include "detect.h" |
29 | | #include "detect-engine.h" |
30 | | #include "detect-engine-address.h" |
31 | | #include "detect-engine-port.h" |
32 | | #include "detect-engine-mpm.h" |
33 | | #include "detect-engine-state.h" |
34 | | #include "detect-engine-build.h" |
35 | | |
36 | | #include "detect-content.h" |
37 | | #include "detect-bsize.h" |
38 | | #include "detect-pcre.h" |
39 | | #include "detect-uricontent.h" |
40 | | #include "detect-reference.h" |
41 | | #include "detect-ipproto.h" |
42 | | #include "detect-flow.h" |
43 | | #include "detect-app-layer-protocol.h" |
44 | | #include "detect-lua.h" |
45 | | #include "detect-app-layer-event.h" |
46 | | #include "detect-http-method.h" |
47 | | |
48 | | #include "pkt-var.h" |
49 | | #include "host.h" |
50 | | #include "util-profiling.h" |
51 | | #include "decode.h" |
52 | | |
53 | | #include "flow.h" |
54 | | |
55 | | #include "util-rule-vars.h" |
56 | | #include "conf.h" |
57 | | #include "conf-yaml-loader.h" |
58 | | |
59 | | #include "app-layer.h" |
60 | | #include "app-layer-protos.h" |
61 | | #include "app-layer-parser.h" |
62 | | #include "app-layer-htp.h" |
63 | | |
64 | | #include "util-classification-config.h" |
65 | | #include "util-unittest.h" |
66 | | #include "util-unittest-helper.h" |
67 | | #include "util-debug.h" |
68 | | #include "string.h" |
69 | | #include "detect-parse.h" |
70 | | #include "detect-engine-iponly.h" |
71 | | #include "app-layer-detect-proto.h" |
72 | | |
73 | | #include "action-globals.h" |
74 | | #include "util-validate.h" |
75 | | |
76 | | /* Table with all filehandler registrations */ |
77 | | DetectFileHandlerTableElmt filehandler_table[DETECT_TBLSIZE]; |
78 | | |
79 | | void DetectFileRegisterFileProtocols(DetectFileHandlerTableElmt *reg) |
80 | 102 | { |
81 | | // file protocols with common file handling |
82 | 102 | typedef struct { |
83 | 102 | AppProto al_proto; |
84 | 102 | int direction; |
85 | 102 | int to_client_progress; |
86 | 102 | int to_server_progress; |
87 | 102 | } DetectFileHandlerProtocol_t; |
88 | 102 | static DetectFileHandlerProtocol_t al_protocols[] = { |
89 | 102 | { .al_proto = ALPROTO_NFS, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT }, |
90 | 102 | { .al_proto = ALPROTO_SMB, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT }, |
91 | 102 | { .al_proto = ALPROTO_FTP, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT }, |
92 | 102 | { .al_proto = ALPROTO_FTPDATA, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT }, |
93 | 102 | { .al_proto = ALPROTO_HTTP1, |
94 | 102 | .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT, |
95 | 102 | .to_client_progress = HTP_RESPONSE_BODY, |
96 | 102 | .to_server_progress = HTP_REQUEST_BODY }, |
97 | 102 | { .al_proto = ALPROTO_HTTP2, |
98 | 102 | .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT, |
99 | 102 | .to_client_progress = HTTP2StateDataServer, |
100 | 102 | .to_server_progress = HTTP2StateDataClient }, |
101 | 102 | { .al_proto = ALPROTO_SMTP, .direction = SIG_FLAG_TOSERVER } |
102 | 102 | }; |
103 | | |
104 | 816 | for (size_t i = 0; i < ARRAY_SIZE(al_protocols); i++) { |
105 | 714 | int direction = al_protocols[i].direction == 0 |
106 | 714 | ? (int)(SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT) |
107 | 714 | : al_protocols[i].direction; |
108 | | |
109 | 714 | if (direction & SIG_FLAG_TOCLIENT) { |
110 | 612 | DetectAppLayerMpmRegister2(reg->name, SIG_FLAG_TOCLIENT, reg->priority, |
111 | 612 | reg->PrefilterFn, reg->GetData, al_protocols[i].al_proto, |
112 | 612 | al_protocols[i].to_client_progress); |
113 | 612 | DetectAppLayerInspectEngineRegister2(reg->name, al_protocols[i].al_proto, |
114 | 612 | SIG_FLAG_TOCLIENT, al_protocols[i].to_client_progress, reg->Callback, |
115 | 612 | reg->GetData); |
116 | 612 | } |
117 | 714 | if (direction & SIG_FLAG_TOSERVER) { |
118 | 714 | DetectAppLayerMpmRegister2(reg->name, SIG_FLAG_TOSERVER, reg->priority, |
119 | 714 | reg->PrefilterFn, reg->GetData, al_protocols[i].al_proto, |
120 | 714 | al_protocols[i].to_server_progress); |
121 | 714 | DetectAppLayerInspectEngineRegister2(reg->name, al_protocols[i].al_proto, |
122 | 714 | SIG_FLAG_TOSERVER, al_protocols[i].to_server_progress, reg->Callback, |
123 | 714 | reg->GetData); |
124 | 714 | } |
125 | 714 | } |
126 | 102 | } |
127 | | |
128 | | /* Table with all SigMatch registrations */ |
129 | | SigTableElmt sigmatch_table[DETECT_TBLSIZE]; |
130 | | |
131 | | extern int sc_set_caps; |
132 | | |
133 | | static void SigMatchTransferSigMatchAcrossLists(SigMatch *sm, |
134 | | SigMatch **src_sm_list, SigMatch **src_sm_list_tail, |
135 | | SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail); |
136 | | |
137 | | /** |
138 | | * \brief Registration table for file handlers |
139 | | */ |
140 | | /** |
141 | | * \brief We use this as data to the hash table DetectEngineCtx->dup_sig_hash_table. |
142 | | */ |
143 | | typedef struct SigDuplWrapper_ { |
144 | | /* the signature we want to wrap */ |
145 | | Signature *s; |
146 | | /* the signature right before the above signature in the det_ctx->sig_list */ |
147 | | Signature *s_prev; |
148 | | } SigDuplWrapper; |
149 | | |
150 | | #define CONFIG_PARTS 8 |
151 | | |
152 | | #define CONFIG_ACTION 0 |
153 | | #define CONFIG_PROTO 1 |
154 | | #define CONFIG_SRC 2 |
155 | | #define CONFIG_SP 3 |
156 | | #define CONFIG_DIREC 4 |
157 | | #define CONFIG_DST 5 |
158 | | #define CONFIG_DP 6 |
159 | | #define CONFIG_OPTS 7 |
160 | | |
161 | | /** helper structure for sig parsing */ |
162 | | typedef struct SignatureParser_ { |
163 | | char action[DETECT_MAX_RULE_SIZE]; |
164 | | char protocol[DETECT_MAX_RULE_SIZE]; |
165 | | char direction[DETECT_MAX_RULE_SIZE]; |
166 | | char src[DETECT_MAX_RULE_SIZE]; |
167 | | char dst[DETECT_MAX_RULE_SIZE]; |
168 | | char sp[DETECT_MAX_RULE_SIZE]; |
169 | | char dp[DETECT_MAX_RULE_SIZE]; |
170 | | char opts[DETECT_MAX_RULE_SIZE]; |
171 | | } SignatureParser; |
172 | | |
173 | | const char *DetectListToHumanString(int list) |
174 | 21.4k | { |
175 | 21.4k | #define CASE_CODE_STRING(E, S) case E: return S; break |
176 | 21.4k | switch (list) { |
177 | 4.31k | CASE_CODE_STRING(DETECT_SM_LIST_MATCH, "packet"); |
178 | 14.2k | CASE_CODE_STRING(DETECT_SM_LIST_PMATCH, "payload"); |
179 | 84 | CASE_CODE_STRING(DETECT_SM_LIST_BASE64_DATA, "base64_data"); |
180 | 2.68k | CASE_CODE_STRING(DETECT_SM_LIST_POSTMATCH, "postmatch"); |
181 | 50 | CASE_CODE_STRING(DETECT_SM_LIST_TMATCH, "tag"); |
182 | 0 | CASE_CODE_STRING(DETECT_SM_LIST_SUPPRESS, "suppress"); |
183 | 58 | CASE_CODE_STRING(DETECT_SM_LIST_THRESHOLD, "threshold"); |
184 | 21.4k | CASE_CODE_STRING(DETECT_SM_LIST_MAX, "max (internal)"); |
185 | 21.4k | } |
186 | 0 | #undef CASE_CODE_STRING |
187 | 0 | return "unknown"; |
188 | 21.4k | } |
189 | | |
190 | 0 | #define CASE_CODE(E) case E: return #E |
191 | | const char *DetectListToString(int list) |
192 | 0 | { |
193 | 0 | switch (list) { |
194 | 0 | CASE_CODE(DETECT_SM_LIST_MATCH); |
195 | 0 | CASE_CODE(DETECT_SM_LIST_PMATCH); |
196 | 0 | CASE_CODE(DETECT_SM_LIST_BASE64_DATA); |
197 | 0 | CASE_CODE(DETECT_SM_LIST_TMATCH); |
198 | 0 | CASE_CODE(DETECT_SM_LIST_POSTMATCH); |
199 | 0 | CASE_CODE(DETECT_SM_LIST_SUPPRESS); |
200 | 0 | CASE_CODE(DETECT_SM_LIST_THRESHOLD); |
201 | 0 | CASE_CODE(DETECT_SM_LIST_MAX); |
202 | 0 | } |
203 | 0 | return "unknown"; |
204 | 0 | } |
205 | | |
206 | | /** \param arg NULL or empty string */ |
207 | | int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, |
208 | | Signature *s, const char *arg, int sm_type, int sm_list, |
209 | | AppProto alproto) |
210 | 133k | { |
211 | 133k | SigMatch *sm = NULL; |
212 | 133k | int ret = -1; |
213 | | |
214 | 133k | if (arg != NULL && strcmp(arg, "") != 0) { |
215 | 0 | SCLogError("%s shouldn't be supplied " |
216 | 0 | "with an argument", |
217 | 0 | sigmatch_table[sm_type].name); |
218 | 0 | goto end; |
219 | 0 | } |
220 | | |
221 | 133k | if (s->init_data->list != DETECT_SM_LIST_NOTSET) { |
222 | 218 | SCLogError("\"%s\" keyword seen " |
223 | 218 | "with a sticky buffer still set. Reset sticky buffer " |
224 | 218 | "with pkt_data before using the modifier.", |
225 | 218 | sigmatch_table[sm_type].name); |
226 | 218 | goto end; |
227 | 218 | } |
228 | 133k | if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(s->alproto, alproto)) { |
229 | 304 | SCLogError("rule contains conflicting " |
230 | 304 | "alprotos set"); |
231 | 304 | goto end; |
232 | 304 | } |
233 | | |
234 | 133k | sm = DetectGetLastSMByListId(s, |
235 | 133k | DETECT_SM_LIST_PMATCH, DETECT_CONTENT, -1); |
236 | 133k | if (sm == NULL) { |
237 | 682 | SCLogError("\"%s\" keyword " |
238 | 682 | "found inside the rule without a content context. " |
239 | 682 | "Please use a \"content\" keyword before using the " |
240 | 682 | "\"%s\" keyword", |
241 | 682 | sigmatch_table[sm_type].name, sigmatch_table[sm_type].name); |
242 | 682 | goto end; |
243 | 682 | } |
244 | 132k | DetectContentData *cd = (DetectContentData *)sm->ctx; |
245 | 132k | if (cd->flags & DETECT_CONTENT_RAWBYTES) { |
246 | 1 | SCLogError("%s rule can not " |
247 | 1 | "be used with the rawbytes rule keyword", |
248 | 1 | sigmatch_table[sm_type].name); |
249 | 1 | goto end; |
250 | 1 | } |
251 | 132k | if (cd->flags & DETECT_CONTENT_REPLACE) { |
252 | 0 | SCLogError("%s rule can not " |
253 | 0 | "be used with the replace rule keyword", |
254 | 0 | sigmatch_table[sm_type].name); |
255 | 0 | goto end; |
256 | 0 | } |
257 | 132k | if (cd->flags & (DETECT_CONTENT_WITHIN | DETECT_CONTENT_DISTANCE)) { |
258 | 4.94k | SigMatch *pm = DetectGetLastSMByListPtr(s, sm->prev, |
259 | 4.94k | DETECT_CONTENT, DETECT_PCRE, -1); |
260 | 4.94k | if (pm != NULL) { |
261 | 3.99k | if (pm->type == DETECT_CONTENT) { |
262 | 2.84k | DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; |
263 | 2.84k | tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT; |
264 | 2.84k | } else { |
265 | 1.15k | DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; |
266 | 1.15k | tmp_pd->flags &= ~DETECT_PCRE_RELATIVE_NEXT; |
267 | 1.15k | } |
268 | 3.99k | } |
269 | | |
270 | 4.94k | if (s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id == sm_list) { |
271 | 2.09k | pm = DetectGetLastSMByListPtr( |
272 | 2.09k | s, s->init_data->curbuf->tail, DETECT_CONTENT, DETECT_PCRE, -1); |
273 | 2.09k | if (pm != NULL) { |
274 | 2.09k | if (pm->type == DETECT_CONTENT) { |
275 | 1.86k | DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; |
276 | 1.86k | tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; |
277 | 1.86k | } else { |
278 | 226 | DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx; |
279 | 226 | tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT; |
280 | 226 | } |
281 | 2.09k | } |
282 | 2.09k | } |
283 | 4.94k | } |
284 | 132k | s->alproto = alproto; |
285 | 132k | s->flags |= SIG_FLAG_APPLAYER; |
286 | | |
287 | 132k | if (s->init_data->curbuf == NULL || (int)s->init_data->curbuf->id != sm_list) { |
288 | 67.8k | if (s->init_data->curbuf != NULL && s->init_data->curbuf->head == NULL) { |
289 | 166 | SCLogError("no matches for previous buffer"); |
290 | 166 | return -1; |
291 | 166 | } |
292 | 67.8k | bool reuse_buffer = false; |
293 | 67.7k | if (s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id != sm_list) { |
294 | 22.6k | for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { |
295 | 17.1k | if (s->init_data->buffers[x].id == (uint32_t)sm_list) { |
296 | 5.79k | s->init_data->curbuf = &s->init_data->buffers[x]; |
297 | 5.79k | reuse_buffer = true; |
298 | 5.79k | break; |
299 | 5.79k | } |
300 | 17.1k | } |
301 | 11.2k | } |
302 | | |
303 | 67.7k | if (!reuse_buffer) { |
304 | 61.9k | if (SignatureInitDataBufferCheckExpand(s) < 0) { |
305 | 2 | SCLogError("failed to expand rule buffer array"); |
306 | 2 | return -1; |
307 | 2 | } |
308 | | |
309 | | /* initialize a new buffer */ |
310 | 61.9k | s->init_data->curbuf = &s->init_data->buffers[s->init_data->buffer_index++]; |
311 | 61.9k | s->init_data->curbuf->id = sm_list; |
312 | 61.9k | s->init_data->curbuf->head = NULL; |
313 | 61.9k | s->init_data->curbuf->tail = NULL; |
314 | 61.9k | SCLogDebug("idx %u list %d set up curbuf %p s->init_data->buffer_index %u", |
315 | 61.9k | s->init_data->buffer_index - 1, sm_list, s->init_data->curbuf, |
316 | 61.9k | s->init_data->buffer_index); |
317 | 61.9k | } |
318 | 67.7k | } |
319 | | |
320 | | /* transfer the sm from the pmatch list to sm_list */ |
321 | 132k | SigMatchTransferSigMatchAcrossLists(sm, &s->init_data->smlists[DETECT_SM_LIST_PMATCH], |
322 | 132k | &s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], &s->init_data->curbuf->head, |
323 | 132k | &s->init_data->curbuf->tail); |
324 | | |
325 | 132k | if (sm->type == DETECT_CONTENT) { |
326 | 132k | s->init_data->max_content_list_id = |
327 | 132k | MAX(s->init_data->max_content_list_id, (uint32_t)sm_list); |
328 | 132k | } |
329 | | |
330 | 132k | ret = 0; |
331 | 133k | end: |
332 | 133k | return ret; |
333 | 132k | } |
334 | | |
335 | | SigMatch *SigMatchAlloc(void) |
336 | 3.37M | { |
337 | 3.37M | SigMatch *sm = SCMalloc(sizeof(SigMatch)); |
338 | 3.37M | if (unlikely(sm == NULL)) |
339 | 0 | return NULL; |
340 | | |
341 | 3.37M | memset(sm, 0, sizeof(SigMatch)); |
342 | 3.37M | sm->prev = NULL; |
343 | 3.37M | sm->next = NULL; |
344 | 3.37M | return sm; |
345 | 3.37M | } |
346 | | |
347 | | /** \brief free a SigMatch |
348 | | * \param sm SigMatch to free. |
349 | | */ |
350 | | void SigMatchFree(DetectEngineCtx *de_ctx, SigMatch *sm) |
351 | 3.37M | { |
352 | 3.37M | if (sm == NULL) |
353 | 0 | return; |
354 | | |
355 | | /** free the ctx, for that we call the Free func */ |
356 | 3.37M | if (sm->ctx != NULL) { |
357 | 2.68M | if (sigmatch_table[sm->type].Free != NULL) { |
358 | 2.68M | sigmatch_table[sm->type].Free(de_ctx, sm->ctx); |
359 | 2.68M | } |
360 | 2.68M | } |
361 | 3.37M | SCFree(sm); |
362 | 3.37M | } |
363 | | |
364 | | static enum DetectKeywordId SigTableGetIndex(const SigTableElmt *e) |
365 | 5.03M | { |
366 | 5.03M | const SigTableElmt *table = &sigmatch_table[0]; |
367 | 5.03M | ptrdiff_t offset = e - table; |
368 | 5.03M | BUG_ON(offset >= DETECT_TBLSIZE); |
369 | 5.03M | return (enum DetectKeywordId)offset; |
370 | 5.03M | } |
371 | | |
372 | | /* Get the detection module by name */ |
373 | | static SigTableElmt *SigTableGet(char *name) |
374 | 12.4M | { |
375 | 12.4M | SigTableElmt *st = NULL; |
376 | 12.4M | int i = 0; |
377 | | |
378 | 765M | for (i = 0; i < DETECT_TBLSIZE; i++) { |
379 | 765M | st = &sigmatch_table[i]; |
380 | | |
381 | 765M | if (st->name != NULL) { |
382 | 750M | if (strcasecmp(name,st->name) == 0) |
383 | 11.8M | return st; |
384 | 738M | if (st->alias != NULL && strcasecmp(name,st->alias) == 0) |
385 | 172k | return st; |
386 | 738M | } |
387 | 765M | } |
388 | | |
389 | 436k | return NULL; |
390 | 12.4M | } |
391 | | |
392 | | bool SigMatchSilentErrorEnabled(const DetectEngineCtx *de_ctx, |
393 | | const enum DetectKeywordId id) |
394 | 0 | { |
395 | 0 | return de_ctx->sm_types_silent_error[id]; |
396 | 0 | } |
397 | | |
398 | | bool SigMatchStrictEnabled(const enum DetectKeywordId id) |
399 | 69.8k | { |
400 | 69.8k | if (id < DETECT_TBLSIZE) { |
401 | 69.8k | return ((sigmatch_table[id].flags & SIGMATCH_STRICT_PARSING) != 0); |
402 | 69.8k | } |
403 | 0 | return false; |
404 | 69.8k | } |
405 | | |
406 | | void SigTableApplyStrictCommandLineOption(const char *str) |
407 | 73 | { |
408 | 73 | if (str == NULL) { |
409 | | /* nothing to be done */ |
410 | 73 | return; |
411 | 73 | } |
412 | | |
413 | | /* "all" just sets the flag for each keyword */ |
414 | 0 | if (strcmp(str, "all") == 0) { |
415 | 0 | for (int i = 0; i < DETECT_TBLSIZE; i++) { |
416 | 0 | SigTableElmt *st = &sigmatch_table[i]; |
417 | 0 | st->flags |= SIGMATCH_STRICT_PARSING; |
418 | 0 | } |
419 | 0 | return; |
420 | 0 | } |
421 | | |
422 | 0 | char *copy = SCStrdup(str); |
423 | 0 | if (copy == NULL) |
424 | 0 | FatalError("could not duplicate opt string"); |
425 | | |
426 | 0 | char *xsaveptr = NULL; |
427 | 0 | char *key = strtok_r(copy, ",", &xsaveptr); |
428 | 0 | while (key != NULL) { |
429 | 0 | SigTableElmt *st = SigTableGet(key); |
430 | 0 | if (st != NULL) { |
431 | 0 | st->flags |= SIGMATCH_STRICT_PARSING; |
432 | 0 | } else { |
433 | 0 | SCLogWarning("'strict' command line " |
434 | 0 | "argument '%s' not found", |
435 | 0 | key); |
436 | 0 | } |
437 | 0 | key = strtok_r(NULL, ",", &xsaveptr); |
438 | 0 | } |
439 | |
|
440 | 0 | SCFree(copy); |
441 | 0 | } |
442 | | |
443 | | /** |
444 | | * \brief Append a SigMatch to the list type. |
445 | | * |
446 | | * \param s Signature. |
447 | | * \param new The sig match to append. |
448 | | * \param list The list to append to. |
449 | | */ |
450 | | void SigMatchAppendSMToList(Signature *s, SigMatch *new, const int list) |
451 | 1.90M | { |
452 | 1.90M | if (new->type == DETECT_CONTENT) { |
453 | 597k | s->init_data->max_content_list_id = MAX(s->init_data->max_content_list_id, (uint32_t)list); |
454 | 597k | } |
455 | | |
456 | 1.90M | SCLogDebug("s:%p new:%p list:%d: %s, s->init_data->list_set %s s->init_data->list %d", s, new, |
457 | 1.90M | list, sigmatch_table[new->type].name, BOOL2STR(s->init_data->list_set), |
458 | 1.90M | s->init_data->list); |
459 | | |
460 | 1.90M | if (list < DETECT_SM_LIST_MAX) { |
461 | 1.17M | if (s->init_data->smlists[list] == NULL) { |
462 | 775k | s->init_data->smlists[list] = new; |
463 | 775k | s->init_data->smlists_tail[list] = new; |
464 | 775k | new->next = NULL; |
465 | 775k | new->prev = NULL; |
466 | 775k | } else { |
467 | 396k | SigMatch *cur = s->init_data->smlists_tail[list]; |
468 | 396k | cur->next = new; |
469 | 396k | new->prev = cur; |
470 | 396k | new->next = NULL; |
471 | 396k | s->init_data->smlists_tail[list] = new; |
472 | 396k | } |
473 | 1.17M | new->idx = s->init_data->sm_cnt; |
474 | 1.17M | s->init_data->sm_cnt++; |
475 | | |
476 | 1.17M | } else { |
477 | | /* app-layer-events (and possibly others?) can get here w/o a "list" |
478 | | * already set up. */ |
479 | | |
480 | | /* unset any existing list if it isn't the same as the new */ |
481 | 731k | if (s->init_data->list != DETECT_SM_LIST_NOTSET && list != s->init_data->list) { |
482 | 14.1k | SCLogDebug("reset: list %d != s->init_data->list %d", list, s->init_data->list); |
483 | 14.1k | s->init_data->list = DETECT_SM_LIST_NOTSET; |
484 | 14.1k | } |
485 | | |
486 | 731k | if (s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id != list) { |
487 | 46.9k | for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { |
488 | 26.3k | if (s->init_data->buffers[x].id == (uint32_t)list && |
489 | 2.91k | !s->init_data->buffers[x].multi_capable) { |
490 | 2.47k | SCLogDebug("reusing buffer %u as it isn't multi-capable", x); |
491 | 2.47k | s->init_data->curbuf = &s->init_data->buffers[x]; |
492 | 2.47k | break; |
493 | 2.47k | } |
494 | 26.3k | } |
495 | 23.1k | } |
496 | | |
497 | 731k | if ((s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id != list) || |
498 | 711k | s->init_data->curbuf == NULL) { |
499 | 344k | if (SignatureInitDataBufferCheckExpand(s) < 0) { |
500 | 2 | SCLogError("failed to expand rule buffer array"); |
501 | 2 | s->init_data->init_flags |= SIG_FLAG_INIT_OVERFLOW; |
502 | | // SignatureInitDataBufferCheckExpand should not fail in this case |
503 | 2 | DEBUG_VALIDATE_BUG_ON(s->init_data->curbuf == NULL); |
504 | | // keep curbuf even with wrong id as we error on this signature |
505 | 344k | } else { |
506 | | /* initialize new buffer */ |
507 | 344k | s->init_data->curbuf = &s->init_data->buffers[s->init_data->buffer_index++]; |
508 | 344k | s->init_data->curbuf->id = list; |
509 | | /* buffer set up by sigmatch is tracked in case we add a stickybuffer for the |
510 | | * same list. */ |
511 | 344k | s->init_data->curbuf->sm_init = true; |
512 | 344k | SCLogDebug("s->init_data->buffer_index %u", s->init_data->buffer_index); |
513 | 344k | } |
514 | 344k | } |
515 | 731k | BUG_ON(s->init_data->curbuf == NULL); |
516 | | |
517 | 731k | new->prev = s->init_data->curbuf->tail; |
518 | 731k | if (s->init_data->curbuf->tail) |
519 | 138k | s->init_data->curbuf->tail->next = new; |
520 | 731k | if (s->init_data->curbuf->head == NULL) |
521 | 593k | s->init_data->curbuf->head = new; |
522 | 731k | s->init_data->curbuf->tail = new; |
523 | 731k | new->idx = s->init_data->sm_cnt; |
524 | 731k | s->init_data->sm_cnt++; |
525 | 731k | SCLogDebug("appended %s to list %d, rule pos %u (s->init_data->list %d)", |
526 | 731k | sigmatch_table[new->type].name, list, new->idx, s->init_data->list); |
527 | | |
528 | 3.21M | for (SigMatch *sm = s->init_data->curbuf->head; sm != NULL; sm = sm->next) { |
529 | 2.48M | SCLogDebug("buf:%p: id:%u: '%s' pos %u", s->init_data->curbuf, s->init_data->curbuf->id, |
530 | 2.48M | sigmatch_table[sm->type].name, sm->idx); |
531 | 2.48M | } |
532 | 731k | } |
533 | 1.90M | } |
534 | | |
535 | | void SigMatchRemoveSMFromList(Signature *s, SigMatch *sm, int sm_list) |
536 | 8.74k | { |
537 | 8.74k | if (sm == s->init_data->smlists[sm_list]) { |
538 | 5.76k | s->init_data->smlists[sm_list] = sm->next; |
539 | 5.76k | } |
540 | 8.74k | if (sm == s->init_data->smlists_tail[sm_list]) { |
541 | 5.33k | s->init_data->smlists_tail[sm_list] = sm->prev; |
542 | 5.33k | } |
543 | 8.74k | if (sm->prev != NULL) |
544 | 2.97k | sm->prev->next = sm->next; |
545 | 8.74k | if (sm->next != NULL) |
546 | 3.40k | sm->next->prev = sm->prev; |
547 | | |
548 | 8.74k | return; |
549 | 8.74k | } |
550 | | |
551 | | /** |
552 | | * \brief Returns a pointer to the last SigMatch instance of a particular type |
553 | | * in a Signature of the payload list. |
554 | | * |
555 | | * \param s Pointer to the tail of the sigmatch list |
556 | | * \param type SigMatch type which has to be searched for in the Signature. |
557 | | * |
558 | | * \retval match Pointer to the last SigMatch instance of type 'type'. |
559 | | */ |
560 | | static SigMatch *SigMatchGetLastSMByType(SigMatch *sm, int type) |
561 | 2.27M | { |
562 | 7.31M | while (sm != NULL) { |
563 | 6.26M | if (sm->type == type) { |
564 | 1.23M | return sm; |
565 | 1.23M | } |
566 | 5.03M | sm = sm->prev; |
567 | 5.03M | } |
568 | | |
569 | 1.04M | return NULL; |
570 | 2.27M | } |
571 | | |
572 | | /** \brief get the last SigMatch from lists that support |
573 | | * MPM. |
574 | | * \note only supports the lists that are registered through |
575 | | * DetectBufferTypeSupportsMpm(). |
576 | | */ |
577 | | SigMatch *DetectGetLastSMFromMpmLists(const DetectEngineCtx *de_ctx, const Signature *s) |
578 | 38.8k | { |
579 | 38.8k | SigMatch *sm_last = NULL; |
580 | 38.8k | SigMatch *sm_new; |
581 | 38.8k | uint32_t sm_type; |
582 | | |
583 | 98.2k | for (uint32_t i = 0; i < s->init_data->buffer_index; i++) { |
584 | 59.3k | const int id = s->init_data->buffers[i].id; |
585 | 59.3k | if (DetectEngineBufferTypeSupportsMpmGetById(de_ctx, id)) { |
586 | 58.8k | sm_new = DetectGetLastSMByListPtr(s, s->init_data->buffers[i].tail, DETECT_CONTENT, -1); |
587 | 58.8k | if (sm_new == NULL) |
588 | 5.08k | continue; |
589 | 53.7k | if (sm_last == NULL || sm_new->idx > sm_last->idx) |
590 | 50.2k | sm_last = sm_new; |
591 | 53.7k | } |
592 | 59.3k | } |
593 | | /* otherwise brute force it */ |
594 | 310k | for (sm_type = 0; sm_type < DETECT_SM_LIST_MAX; sm_type++) { |
595 | 271k | if (!DetectEngineBufferTypeSupportsMpmGetById(de_ctx, sm_type)) |
596 | 271k | continue; |
597 | 0 | SigMatch *sm_list = s->init_data->smlists_tail[sm_type]; |
598 | 0 | sm_new = SigMatchGetLastSMByType(sm_list, DETECT_CONTENT); |
599 | 0 | if (sm_new == NULL) |
600 | 0 | continue; |
601 | 0 | if (sm_last == NULL || sm_new->idx > sm_last->idx) |
602 | 0 | sm_last = sm_new; |
603 | 0 | } |
604 | | |
605 | 38.8k | return sm_last; |
606 | 38.8k | } |
607 | | |
608 | | /** |
609 | | * \brief Returns the sm with the largest index (added latest) from the lists |
610 | | * passed to us. |
611 | | * |
612 | | * \retval Pointer to Last sm. |
613 | | */ |
614 | | SigMatch *DetectGetLastSMFromLists(const Signature *s, ...) |
615 | 423k | { |
616 | 423k | SigMatch *sm_last = NULL; |
617 | 423k | SigMatch *sm_new; |
618 | | |
619 | 423k | SCLogDebug("s->init_data->buffer_index %u", s->init_data->buffer_index); |
620 | 679k | for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { |
621 | 256k | if (s->init_data->list != DETECT_SM_LIST_NOTSET && |
622 | 142k | s->init_data->list != (int)s->init_data->buffers[x].id) { |
623 | 24.5k | SCLogDebug("skip x %u s->init_data->list %d (int)s->init_data->buffers[x].id %d", x, |
624 | 24.5k | s->init_data->list, (int)s->init_data->buffers[x].id); |
625 | | |
626 | 24.5k | continue; |
627 | 24.5k | } |
628 | 231k | int sm_type; |
629 | 231k | va_list ap; |
630 | 231k | va_start(ap, s); |
631 | | |
632 | 560k | for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) { |
633 | 328k | sm_new = SigMatchGetLastSMByType(s->init_data->buffers[x].tail, sm_type); |
634 | 328k | if (sm_new == NULL) |
635 | 135k | continue; |
636 | 193k | if (sm_last == NULL || sm_new->idx > sm_last->idx) |
637 | 188k | sm_last = sm_new; |
638 | 193k | } |
639 | 231k | va_end(ap); |
640 | 231k | } |
641 | | |
642 | 3.38M | for (int buf_type = 0; buf_type < DETECT_SM_LIST_MAX; buf_type++) { |
643 | 2.96M | if (s->init_data->smlists[buf_type] == NULL) |
644 | 2.53M | continue; |
645 | 425k | if (s->init_data->list != DETECT_SM_LIST_NOTSET && |
646 | 69.1k | buf_type != s->init_data->list) |
647 | 67.1k | continue; |
648 | | |
649 | 357k | int sm_type; |
650 | 357k | va_list ap; |
651 | 357k | va_start(ap, s); |
652 | | |
653 | 982k | for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) |
654 | 624k | { |
655 | 624k | sm_new = SigMatchGetLastSMByType(s->init_data->smlists_tail[buf_type], sm_type); |
656 | 624k | if (sm_new == NULL) |
657 | 371k | continue; |
658 | 252k | if (sm_last == NULL || sm_new->idx > sm_last->idx) |
659 | 227k | sm_last = sm_new; |
660 | 252k | } |
661 | 357k | va_end(ap); |
662 | 357k | } |
663 | | |
664 | 423k | return sm_last; |
665 | 423k | } |
666 | | |
667 | | /** |
668 | | * \brief Returns the sm with the largest index (added last) from the list |
669 | | * passed to us as a pointer. |
670 | | * |
671 | | * \param sm_list pointer to the SigMatch we should look before |
672 | | * \param va_args list of keyword types terminated by -1 |
673 | | * |
674 | | * \retval sm_last to last sm. |
675 | | */ |
676 | | SigMatch *DetectGetLastSMByListPtr(const Signature *s, SigMatch *sm_list, ...) |
677 | 271k | { |
678 | 271k | SigMatch *sm_last = NULL; |
679 | 271k | SigMatch *sm_new; |
680 | 271k | int sm_type; |
681 | | |
682 | 271k | va_list ap; |
683 | 271k | va_start(ap, sm_list); |
684 | | |
685 | 754k | for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) |
686 | 483k | { |
687 | 483k | sm_new = SigMatchGetLastSMByType(sm_list, sm_type); |
688 | 483k | if (sm_new == NULL) |
689 | 240k | continue; |
690 | 242k | if (sm_last == NULL || sm_new->idx > sm_last->idx) |
691 | 228k | sm_last = sm_new; |
692 | 242k | } |
693 | | |
694 | 271k | va_end(ap); |
695 | | |
696 | 271k | return sm_last; |
697 | 271k | } |
698 | | |
699 | | /** |
700 | | * \brief Returns the sm with the largest index (added last) from the list |
701 | | * passed to us as an id. |
702 | | * |
703 | | * \param list_id id of the list to be searched |
704 | | * \param va_args list of keyword types terminated by -1 |
705 | | * |
706 | | * \retval sm_last to last sm. |
707 | | */ |
708 | | SigMatch *DetectGetLastSMByListId(const Signature *s, int list_id, ...) |
709 | 256k | { |
710 | 256k | SigMatch *sm_last = NULL; |
711 | 256k | SigMatch *sm_new; |
712 | 256k | int sm_type; |
713 | | |
714 | 256k | if ((uint32_t)list_id >= DETECT_SM_LIST_MAX) { |
715 | 89.0k | for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { |
716 | 55.6k | sm_new = s->init_data->buffers[x].tail; |
717 | 55.6k | if (sm_new == NULL) |
718 | 21.3k | continue; |
719 | | |
720 | 34.3k | va_list ap; |
721 | 34.3k | va_start(ap, list_id); |
722 | | |
723 | 68.6k | for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) { |
724 | 34.3k | sm_new = SigMatchGetLastSMByType(s->init_data->buffers[x].tail, sm_type); |
725 | 34.3k | if (sm_new == NULL) |
726 | 15.2k | continue; |
727 | 19.0k | if (sm_last == NULL || sm_new->idx > sm_last->idx) |
728 | 18.0k | sm_last = sm_new; |
729 | 19.0k | } |
730 | | |
731 | 34.3k | va_end(ap); |
732 | 34.3k | } |
733 | 223k | } else { |
734 | 223k | SigMatch *sm_list = s->init_data->smlists_tail[list_id]; |
735 | 223k | if (sm_list == NULL) |
736 | 55.2k | return NULL; |
737 | | |
738 | 168k | va_list ap; |
739 | 168k | va_start(ap, list_id); |
740 | | |
741 | 336k | for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) { |
742 | 168k | sm_new = SigMatchGetLastSMByType(sm_list, sm_type); |
743 | 168k | if (sm_new == NULL) |
744 | 11.4k | continue; |
745 | 156k | if (sm_last == NULL || sm_new->idx > sm_last->idx) |
746 | 156k | sm_last = sm_new; |
747 | 156k | } |
748 | | |
749 | 168k | va_end(ap); |
750 | 168k | } |
751 | 201k | return sm_last; |
752 | 256k | } |
753 | | |
754 | | /** |
755 | | * \brief Returns the sm with the largest index (added latest) from this sig |
756 | | * |
757 | | * \retval sm_last Pointer to last sm |
758 | | */ |
759 | | SigMatch *DetectGetLastSM(const Signature *s) |
760 | 78.1k | { |
761 | 78.1k | SigMatch *sm_last = NULL; |
762 | 78.1k | SigMatch *sm_new; |
763 | | |
764 | 90.5k | for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { |
765 | 12.4k | sm_new = s->init_data->buffers[x].tail; |
766 | 12.4k | if (sm_new == NULL) |
767 | 977 | continue; |
768 | 11.4k | if (sm_last == NULL || sm_new->idx > sm_last->idx) |
769 | 8.43k | sm_last = sm_new; |
770 | 11.4k | } |
771 | | |
772 | 625k | for (int i = 0; i < DETECT_SM_LIST_MAX; i++) { |
773 | 546k | sm_new = s->init_data->smlists_tail[i]; |
774 | 546k | if (sm_new == NULL) |
775 | 462k | continue; |
776 | 84.6k | if (sm_last == NULL || sm_new->idx > sm_last->idx) |
777 | 75.9k | sm_last = sm_new; |
778 | 84.6k | } |
779 | | |
780 | 78.1k | return sm_last; |
781 | 78.1k | } |
782 | | |
783 | | static void SigMatchTransferSigMatchAcrossLists(SigMatch *sm, |
784 | | SigMatch **src_sm_list, SigMatch **src_sm_list_tail, |
785 | | SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail) |
786 | 65.8k | { |
787 | | /* we won't do any checks for args */ |
788 | | |
789 | 65.8k | if (sm->prev != NULL) |
790 | 22.7k | sm->prev->next = sm->next; |
791 | 65.8k | if (sm->next != NULL) |
792 | 1.24k | sm->next->prev = sm->prev; |
793 | | |
794 | 65.8k | if (sm == *src_sm_list) |
795 | 43.0k | *src_sm_list = sm->next; |
796 | 65.8k | if (sm == *src_sm_list_tail) |
797 | 64.5k | *src_sm_list_tail = sm->prev; |
798 | | |
799 | 65.8k | if (*dst_sm_list == NULL) { |
800 | 35.8k | *dst_sm_list = sm; |
801 | 35.8k | *dst_sm_list_tail = sm; |
802 | 35.8k | sm->next = NULL; |
803 | 35.8k | sm->prev = NULL; |
804 | 35.8k | } else { |
805 | 29.9k | SigMatch *cur = *dst_sm_list_tail; |
806 | 29.9k | cur->next = sm; |
807 | 29.9k | sm->prev = cur; |
808 | 29.9k | sm->next = NULL; |
809 | 29.9k | *dst_sm_list_tail = sm; |
810 | 29.9k | } |
811 | | |
812 | 65.8k | return; |
813 | 65.8k | } |
814 | | |
815 | | int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm) |
816 | 74.7k | { |
817 | 74.7k | if (key_sm == NULL) |
818 | 0 | return -1; |
819 | | |
820 | 98.0k | for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { |
821 | 57.6k | const SigMatch *sm = s->init_data->buffers[x].head; |
822 | 246k | while (sm != NULL) { |
823 | 223k | if (sm == key_sm) |
824 | 34.3k | return s->init_data->buffers[x].id; |
825 | 188k | sm = sm->next; |
826 | 188k | } |
827 | 57.6k | } |
828 | | |
829 | 81.1k | for (int list = 0; list < DETECT_SM_LIST_MAX; list++) { |
830 | 81.1k | const SigMatch *sm = s->init_data->smlists[list]; |
831 | 328k | while (sm != NULL) { |
832 | 287k | if (sm == key_sm) |
833 | 40.4k | return list; |
834 | 247k | sm = sm->next; |
835 | 247k | } |
836 | 81.1k | } |
837 | | |
838 | 0 | SCLogError("Unable to find the sm in any of the " |
839 | 0 | "sm lists"); |
840 | 0 | return -1; |
841 | 40.4k | } |
842 | | |
843 | | static int SigParseOptions(DetectEngineCtx *de_ctx, Signature *s, char *optstr, char *output, |
844 | | size_t output_size, bool requires) |
845 | 18.9M | { |
846 | 18.9M | SigTableElmt *st = NULL; |
847 | 18.9M | char *optname = NULL; |
848 | 18.9M | char *optvalue = NULL; |
849 | | |
850 | | /* Trim leading space. */ |
851 | 18.9M | while (isblank(*optstr)) { |
852 | 15.7M | optstr++; |
853 | 15.7M | } |
854 | | |
855 | | /* Look for the end of this option, handling escaped semicolons. */ |
856 | 18.9M | char *optend = optstr; |
857 | 18.9M | for (;;) { |
858 | 18.9M | optend = strchr(optend, ';'); |
859 | 18.9M | if (optend == NULL) { |
860 | 224k | SCLogError("no terminating \";\" found"); |
861 | 224k | goto error; |
862 | 224k | } |
863 | 18.7M | else if (optend > optstr && *(optend -1 ) == '\\') { |
864 | 12.1k | optend++; |
865 | 18.6M | } else { |
866 | 18.6M | break; |
867 | 18.6M | } |
868 | 18.9M | } |
869 | 18.6M | *(optend++) = '\0'; |
870 | | |
871 | | /* Find the start of the option value. */ |
872 | 18.6M | char *optvalptr = strchr(optstr, ':'); |
873 | 18.6M | if (optvalptr) { |
874 | 15.8M | *(optvalptr++) = '\0'; |
875 | | |
876 | | /* Trim trailing space from name. */ |
877 | 16.1M | for (size_t i = strlen(optvalptr); i > 0; i--) { |
878 | 16.1M | if (isblank(optvalptr[i - 1])) { |
879 | 308k | optvalptr[i - 1] = '\0'; |
880 | 15.7M | } else { |
881 | 15.7M | break; |
882 | 15.7M | } |
883 | 16.1M | } |
884 | | |
885 | 15.8M | optvalue = optvalptr; |
886 | 15.8M | } |
887 | | |
888 | | /* Trim trailing space from name. */ |
889 | 18.9M | for (size_t i = strlen(optstr); i > 0; i--) { |
890 | 18.8M | if (isblank(optstr[i - 1])) { |
891 | 237k | optstr[i - 1] = '\0'; |
892 | 18.6M | } else { |
893 | 18.6M | break; |
894 | 18.6M | } |
895 | 18.8M | } |
896 | 18.6M | optname = optstr; |
897 | | |
898 | | /* Check for options that are only to be processed during the |
899 | | * first "requires" pass. */ |
900 | 18.6M | bool requires_only = strcasecmp(optname, "requires") == 0 || strcasecmp(optname, "sid") == 0; |
901 | 18.6M | if ((requires && !requires_only) || (!requires && requires_only)) { |
902 | 11.4M | goto finish; |
903 | 11.4M | } |
904 | | |
905 | | /* Call option parsing */ |
906 | 7.28M | st = SigTableGet(optname); |
907 | 7.28M | if (st == NULL || st->Setup == NULL) { |
908 | 260k | SCLogError("unknown rule keyword '%s'.", optname); |
909 | 260k | goto error; |
910 | 260k | } |
911 | | |
912 | 7.02M | if (!(st->flags & (SIGMATCH_NOOPT|SIGMATCH_OPTIONAL_OPT))) { |
913 | 6.35M | if (optvalue == NULL || strlen(optvalue) == 0) { |
914 | 5.45k | SCLogError( |
915 | 5.45k | "invalid formatting or malformed option to %s keyword: '%s'", optname, optstr); |
916 | 5.45k | goto error; |
917 | 5.45k | } |
918 | 6.35M | } else if (st->flags & SIGMATCH_NOOPT) { |
919 | 599k | if (optvalue && strlen(optvalue)) { |
920 | 84 | SCLogError("unexpected option to %s keyword: '%s'", optname, optstr); |
921 | 84 | goto error; |
922 | 84 | } |
923 | 599k | } |
924 | 7.01M | s->init_data->negated = false; |
925 | | |
926 | 7.01M | if (st->flags & SIGMATCH_INFO_DEPRECATED) { |
927 | 2.66k | #define URL "https://suricata.io/our-story/deprecation-policy/" |
928 | 2.66k | if (st->alternative == 0) |
929 | 0 | SCLogWarning("keyword '%s' is deprecated " |
930 | 2.66k | "and will be removed soon. See %s", |
931 | 2.66k | st->name, URL); |
932 | 2.66k | else |
933 | 2.66k | SCLogWarning("keyword '%s' is deprecated " |
934 | 2.66k | "and will be removed soon. Use '%s' instead. " |
935 | 2.66k | "See %s", |
936 | 2.66k | st->name, sigmatch_table[st->alternative].name, URL); |
937 | 2.66k | #undef URL |
938 | 2.66k | } |
939 | | |
940 | 7.01M | int setup_ret = 0; |
941 | | |
942 | | /* Validate double quoting, trimming trailing white space along the way. */ |
943 | 7.01M | if (optvalue != NULL && strlen(optvalue) > 0) { |
944 | 6.36M | size_t ovlen = strlen(optvalue); |
945 | 6.36M | char *ptr = optvalue; |
946 | | |
947 | | /* skip leading whitespace */ |
948 | 6.66M | while (ovlen > 0) { |
949 | 6.66M | if (!isblank(*ptr)) |
950 | 6.36M | break; |
951 | 298k | ptr++; |
952 | 298k | ovlen--; |
953 | 298k | } |
954 | 6.36M | if (ovlen == 0) { |
955 | 0 | SCLogError("invalid formatting or malformed option to %s keyword: \'%s\'", optname, |
956 | 0 | optstr); |
957 | 0 | goto error; |
958 | 0 | } |
959 | | |
960 | | /* see if value is negated */ |
961 | 6.36M | if ((st->flags & SIGMATCH_HANDLE_NEGATION) && *ptr == '!') { |
962 | 49.4k | s->init_data->negated = true; |
963 | 49.4k | ptr++; |
964 | 49.4k | ovlen--; |
965 | 49.4k | } |
966 | | /* skip more whitespace */ |
967 | 6.37M | while (ovlen > 0) { |
968 | 6.37M | if (!isblank(*ptr)) |
969 | 6.36M | break; |
970 | 3.02k | ptr++; |
971 | 3.02k | ovlen--; |
972 | 3.02k | } |
973 | 6.36M | if (ovlen == 0) { |
974 | 455 | SCLogError("invalid formatting or malformed option to %s keyword: \'%s\'", optname, |
975 | 455 | optstr); |
976 | 455 | goto error; |
977 | 455 | } |
978 | | /* if quoting is mandatory, enforce it */ |
979 | 6.36M | if (st->flags & SIGMATCH_QUOTES_MANDATORY && ovlen && *ptr != '"') { |
980 | 8.15k | SCLogError("invalid formatting to %s keyword: " |
981 | 8.15k | "value must be double quoted \'%s\'", |
982 | 8.15k | optname, optstr); |
983 | 8.15k | goto error; |
984 | 8.15k | } |
985 | | |
986 | 6.36M | if ((st->flags & (SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_QUOTES_MANDATORY)) |
987 | 2.02M | && ovlen && *ptr == '"') |
988 | 1.68M | { |
989 | 1.68M | for (; ovlen > 0; ovlen--) { |
990 | 1.68M | if (isblank(ptr[ovlen - 1])) { |
991 | 0 | ptr[ovlen - 1] = '\0'; |
992 | 1.68M | } else { |
993 | 1.68M | break; |
994 | 1.68M | } |
995 | 1.68M | } |
996 | 1.68M | if (ovlen && ptr[ovlen - 1] != '"') { |
997 | 45.0k | SCLogError("bad option value formatting (possible missing semicolon) " |
998 | 45.0k | "for keyword %s: \'%s\'", |
999 | 45.0k | optname, optvalue); |
1000 | 45.0k | goto error; |
1001 | 45.0k | } |
1002 | 1.63M | if (ovlen > 1) { |
1003 | | /* strip leading " */ |
1004 | 1.60M | ptr++; |
1005 | 1.60M | ovlen--; |
1006 | 1.60M | ptr[ovlen - 1] = '\0'; |
1007 | 1.60M | ovlen--; |
1008 | 1.60M | } |
1009 | 1.63M | if (ovlen == 0) { |
1010 | 316 | SCLogError("bad input " |
1011 | 316 | "for keyword %s: \'%s\'", |
1012 | 316 | optname, optvalue); |
1013 | 316 | goto error; |
1014 | 316 | } |
1015 | 4.67M | } else { |
1016 | 4.67M | if (*ptr == '"') { |
1017 | 829 | SCLogError( |
1018 | 829 | "quotes on %s keyword that doesn't support them: \'%s\'", optname, optstr); |
1019 | 829 | goto error; |
1020 | 829 | } |
1021 | 4.67M | } |
1022 | | /* setup may or may not add a new SigMatch to the list */ |
1023 | 6.31M | setup_ret = st->Setup(de_ctx, s, ptr); |
1024 | 6.31M | } else { |
1025 | | /* setup may or may not add a new SigMatch to the list */ |
1026 | 646k | setup_ret = st->Setup(de_ctx, s, NULL); |
1027 | 646k | } |
1028 | 6.96M | if (setup_ret < 0 || (s->init_data->init_flags & SIG_FLAG_INIT_OVERFLOW)) { |
1029 | 584k | SCLogDebug("\"%s\" failed to setup", st->name); |
1030 | 584k | if (s->init_data->init_flags & SIG_FLAG_INIT_OVERFLOW) { |
1031 | 2 | SCLogError("rule %u tries to use too many buffers", s->id); |
1032 | 2 | } |
1033 | | |
1034 | | /* handle 'silent' error case */ |
1035 | 584k | if (setup_ret == -2) { |
1036 | 0 | enum DetectKeywordId idx = SigTableGetIndex(st); |
1037 | 0 | if (de_ctx->sm_types_silent_error[idx] == false) { |
1038 | 0 | de_ctx->sm_types_silent_error[idx] = true; |
1039 | 0 | return -1; |
1040 | 0 | } |
1041 | 0 | return -2; |
1042 | 0 | } |
1043 | 584k | return setup_ret; |
1044 | 584k | } |
1045 | 6.37M | s->init_data->negated = false; |
1046 | | |
1047 | 17.7M | finish: |
1048 | 17.7M | if (strlen(optend) > 0) { |
1049 | 14.5M | strlcpy(output, optend, output_size); |
1050 | 14.5M | return 1; |
1051 | 14.5M | } |
1052 | | |
1053 | 3.18M | return 0; |
1054 | | |
1055 | 544k | error: |
1056 | 544k | return -1; |
1057 | 17.7M | } |
1058 | | |
1059 | | /** \brief Parse address string and update signature |
1060 | | * |
1061 | | * \retval 0 ok, -1 error |
1062 | | */ |
1063 | | static int SigParseAddress(DetectEngineCtx *de_ctx, |
1064 | | Signature *s, const char *addrstr, char flag) |
1065 | 5.99M | { |
1066 | 5.99M | SCLogDebug("Address Group \"%s\" to be parsed now", addrstr); |
1067 | | |
1068 | | /* pass on to the address(list) parser */ |
1069 | 5.99M | if (flag == 0) { |
1070 | 3.03M | if (strcasecmp(addrstr, "any") == 0) |
1071 | 2.62M | s->flags |= SIG_FLAG_SRC_ANY; |
1072 | | |
1073 | 3.03M | s->init_data->src = DetectParseAddress(de_ctx, addrstr, |
1074 | 3.03M | &s->init_data->src_contains_negation); |
1075 | 3.03M | if (s->init_data->src == NULL) |
1076 | 61.3k | goto error; |
1077 | 3.03M | } else { |
1078 | 2.96M | if (strcasecmp(addrstr, "any") == 0) |
1079 | 2.61M | s->flags |= SIG_FLAG_DST_ANY; |
1080 | | |
1081 | 2.96M | s->init_data->dst = DetectParseAddress(de_ctx, addrstr, |
1082 | 2.96M | &s->init_data->dst_contains_negation); |
1083 | 2.96M | if (s->init_data->dst == NULL) |
1084 | 114k | goto error; |
1085 | 2.96M | } |
1086 | | |
1087 | 5.82M | return 0; |
1088 | | |
1089 | 175k | error: |
1090 | 175k | return -1; |
1091 | 5.99M | } |
1092 | | |
1093 | | /** |
1094 | | * \brief Parses the protocol supplied by the Signature. |
1095 | | * |
1096 | | * http://www.iana.org/assignments/protocol-numbers |
1097 | | * |
1098 | | * \param s Pointer to the Signature instance to which the parsed |
1099 | | * protocol has to be added. |
1100 | | * \param protostr Pointer to the character string containing the protocol name. |
1101 | | * |
1102 | | * \retval 0 On successfully parsing the protocol sent as the argument. |
1103 | | * \retval -1 On failure |
1104 | | */ |
1105 | | static int SigParseProto(Signature *s, const char *protostr) |
1106 | 1.88M | { |
1107 | 1.88M | SCEnter(); |
1108 | | |
1109 | 1.88M | int r = DetectProtoParse(&s->proto, (char *)protostr); |
1110 | 1.88M | if (r < 0) { |
1111 | 877k | s->alproto = AppLayerGetProtoByName((char *)protostr); |
1112 | | /* indicate that the signature is app-layer */ |
1113 | 877k | if (s->alproto != ALPROTO_UNKNOWN) { |
1114 | 823k | s->flags |= SIG_FLAG_APPLAYER; |
1115 | | |
1116 | 823k | AppLayerProtoDetectSupportedIpprotos(s->alproto, s->proto.proto); |
1117 | 823k | } |
1118 | 53.1k | else { |
1119 | 53.1k | SCLogError("protocol \"%s\" cannot be used " |
1120 | 53.1k | "in a signature. Either detection for this protocol " |
1121 | 53.1k | "is not yet supported OR detection has been disabled for " |
1122 | 53.1k | "protocol through the yaml option " |
1123 | 53.1k | "app-layer.protocols.%s.detection-enabled", |
1124 | 53.1k | protostr, protostr); |
1125 | 53.1k | SCReturnInt(-1); |
1126 | 53.1k | } |
1127 | 877k | } |
1128 | | |
1129 | | /* if any of these flags are set they are set in a mutually exclusive |
1130 | | * manner */ |
1131 | 1.83M | if (s->proto.flags & DETECT_PROTO_ONLY_PKT) { |
1132 | 80.1k | s->flags |= SIG_FLAG_REQUIRE_PACKET; |
1133 | 1.75M | } else if (s->proto.flags & DETECT_PROTO_ONLY_STREAM) { |
1134 | 15.6k | s->flags |= SIG_FLAG_REQUIRE_STREAM; |
1135 | 15.6k | } |
1136 | | |
1137 | 1.83M | SCReturnInt(0); |
1138 | 1.88M | } |
1139 | | |
1140 | | /** |
1141 | | * \brief Parses the port(source or destination) field, from a Signature. |
1142 | | * |
1143 | | * \param s Pointer to the signature which has to be updated with the |
1144 | | * port information. |
1145 | | * \param portstr Pointer to the character string containing the port info. |
1146 | | * \param Flag which indicates if the portstr received is src or dst |
1147 | | * port. For src port: flag = 0, dst port: flag = 1. |
1148 | | * |
1149 | | * \retval 0 On success. |
1150 | | * \retval -1 On failure. |
1151 | | */ |
1152 | | static int SigParsePort(const DetectEngineCtx *de_ctx, |
1153 | | Signature *s, const char *portstr, char flag) |
1154 | 5.68M | { |
1155 | 5.68M | int r = 0; |
1156 | | |
1157 | | /* XXX VJ exclude handling this for none UDP/TCP proto's */ |
1158 | | |
1159 | 5.68M | SCLogDebug("Port group \"%s\" to be parsed", portstr); |
1160 | | |
1161 | 5.68M | if (flag == 0) { |
1162 | 2.85M | if (strcasecmp(portstr, "any") == 0) |
1163 | 2.26M | s->flags |= SIG_FLAG_SP_ANY; |
1164 | | |
1165 | 2.85M | r = DetectPortParse(de_ctx, &s->sp, (char *)portstr); |
1166 | 2.85M | } else if (flag == 1) { |
1167 | 2.82M | if (strcasecmp(portstr, "any") == 0) |
1168 | 2.03M | s->flags |= SIG_FLAG_DP_ANY; |
1169 | | |
1170 | 2.82M | r = DetectPortParse(de_ctx, &s->dp, (char *)portstr); |
1171 | 2.82M | } |
1172 | | |
1173 | 5.68M | if (r < 0) |
1174 | 129k | return -1; |
1175 | | |
1176 | 5.55M | return 0; |
1177 | 5.68M | } |
1178 | | |
1179 | | /** \retval 1 valid |
1180 | | * \retval 0 invalid |
1181 | | */ |
1182 | | static int SigParseActionRejectValidate(const char *action) |
1183 | 691 | { |
1184 | | #ifdef HAVE_LIBNET11 |
1185 | | #if defined HAVE_LIBCAP_NG && !defined HAVE_LIBNET_CAPABILITIES |
1186 | | if (sc_set_caps == TRUE) { |
1187 | | SCLogError("Libnet 1.1 is " |
1188 | | "incompatible with POSIX based capabilities with privs dropping. " |
1189 | | "For rejects to work, run as root/super user."); |
1190 | | return 0; |
1191 | | } |
1192 | | #endif |
1193 | | #else /* no libnet 1.1 */ |
1194 | 691 | SCLogError("Libnet 1.1.x is " |
1195 | 691 | "required for action \"%s\" but is not compiled into Suricata", |
1196 | 691 | action); |
1197 | 691 | return 0; |
1198 | 0 | #endif |
1199 | 0 | return 1; |
1200 | 691 | } |
1201 | | |
1202 | | /** |
1203 | | * \brief Parses the action that has been used by the Signature and allots it |
1204 | | * to its Signature instance. |
1205 | | * |
1206 | | * \param s Pointer to the Signature instance to which the action belongs. |
1207 | | * \param action Pointer to the action string used by the Signature. |
1208 | | * |
1209 | | * \retval 0 On successfully parsing the action string and adding it to the |
1210 | | * Signature. |
1211 | | * \retval -1 On failure. |
1212 | | */ |
1213 | | static int SigParseAction(Signature *s, const char *action) |
1214 | 1.95M | { |
1215 | 1.95M | if (strcasecmp(action, "alert") == 0) { |
1216 | 1.62M | s->action = ACTION_ALERT; |
1217 | 1.62M | } else if (strcasecmp(action, "drop") == 0) { |
1218 | 73.2k | s->action = ACTION_DROP | ACTION_ALERT; |
1219 | 248k | } else if (strcasecmp(action, "pass") == 0) { |
1220 | 168k | s->action = ACTION_PASS; |
1221 | 168k | } else if (strcasecmp(action, "reject") == 0 || |
1222 | 79.8k | strcasecmp(action, "rejectsrc") == 0) |
1223 | 85 | { |
1224 | 85 | if (!(SigParseActionRejectValidate(action))) |
1225 | 85 | return -1; |
1226 | 0 | s->action = ACTION_REJECT | ACTION_DROP | ACTION_ALERT; |
1227 | 79.8k | } else if (strcasecmp(action, "rejectdst") == 0) { |
1228 | 84 | if (!(SigParseActionRejectValidate(action))) |
1229 | 84 | return -1; |
1230 | 0 | s->action = ACTION_REJECT_DST | ACTION_DROP | ACTION_ALERT; |
1231 | 79.7k | } else if (strcasecmp(action, "rejectboth") == 0) { |
1232 | 75 | if (!(SigParseActionRejectValidate(action))) |
1233 | 75 | return -1; |
1234 | 0 | s->action = ACTION_REJECT_BOTH | ACTION_DROP | ACTION_ALERT; |
1235 | 79.6k | } else if (strcasecmp(action, "config") == 0) { |
1236 | 16.0k | s->action = ACTION_CONFIG; |
1237 | 63.6k | } else { |
1238 | 63.6k | SCLogError("An invalid action \"%s\" was given", action); |
1239 | 63.6k | return -1; |
1240 | 63.6k | } |
1241 | 1.88M | return 0; |
1242 | 1.95M | } |
1243 | | |
1244 | | /** |
1245 | | * \brief Parse the next token in rule. |
1246 | | * |
1247 | | * For rule parsing a token is considered to be a string of characters |
1248 | | * separated by white space. |
1249 | | * |
1250 | | * \param input double pointer to input buffer, will be advanced as input is |
1251 | | * parsed. |
1252 | | * \param output buffer to copy token into. |
1253 | | * \param output_size length of output buffer. |
1254 | | */ |
1255 | | static inline int SigParseToken(char **input, char *output, |
1256 | | const size_t output_size) |
1257 | 19.0M | { |
1258 | 19.0M | size_t len = *input == NULL ? 0 : strlen(*input); |
1259 | | |
1260 | 19.0M | if (!len) { |
1261 | 1.05M | return 0; |
1262 | 1.05M | } |
1263 | | |
1264 | 18.2M | while (len && isblank(**input)) { |
1265 | 243k | (*input)++; |
1266 | 243k | len--; |
1267 | 243k | } |
1268 | | |
1269 | 18.0M | char *endptr = strpbrk(*input, " \t\n\r"); |
1270 | 18.0M | if (endptr != NULL) { |
1271 | 17.5M | *(endptr++) = '\0'; |
1272 | 17.5M | } |
1273 | 18.0M | strlcpy(output, *input, output_size); |
1274 | 18.0M | *input = endptr; |
1275 | | |
1276 | 18.0M | return 1; |
1277 | 19.0M | } |
1278 | | |
1279 | | /** |
1280 | | * \brief Parse the next rule "list" token. |
1281 | | * |
1282 | | * Parses rule tokens that may be lists such as addresses and ports |
1283 | | * handling the case when they may not be lists. |
1284 | | * |
1285 | | * \param input double pointer to input buffer, will be advanced as input is |
1286 | | * parsed. |
1287 | | * \param output buffer to copy token into. |
1288 | | * \param output_size length of output buffer. |
1289 | | */ |
1290 | | static inline int SigParseList(char **input, char *output, |
1291 | | const size_t output_size) |
1292 | 47.7M | { |
1293 | 47.7M | int in_list = 0; |
1294 | 47.7M | size_t len = *input != NULL ? strlen(*input) : 0; |
1295 | | |
1296 | 47.7M | if (len == 0) { |
1297 | 4.51M | return 0; |
1298 | 4.51M | } |
1299 | | |
1300 | 44.1M | while (len && isblank(**input)) { |
1301 | 919k | (*input)++; |
1302 | 919k | len--; |
1303 | 919k | } |
1304 | | |
1305 | 43.1M | size_t i = 0; |
1306 | 245M | for (i = 0; i < len; i++) { |
1307 | 244M | char c = (*input)[i]; |
1308 | 244M | if (c == '[') { |
1309 | 734k | in_list++; |
1310 | 244M | } else if (c == ']') { |
1311 | 822k | in_list--; |
1312 | 243M | } else if (c == ' ') { |
1313 | 43.1M | if (!in_list) { |
1314 | 42.3M | break; |
1315 | 42.3M | } |
1316 | 43.1M | } |
1317 | 244M | } |
1318 | 43.1M | if (i == len) { |
1319 | 880k | *input = NULL; |
1320 | 880k | return 0; |
1321 | 880k | } |
1322 | 42.3M | (*input)[i] = '\0'; |
1323 | 42.3M | strlcpy(output, *input, output_size); |
1324 | 42.3M | *input = *input + i + 1; |
1325 | | |
1326 | 42.3M | return 1; |
1327 | 43.1M | } |
1328 | | |
1329 | | /** |
1330 | | * \internal |
1331 | | * \brief split a signature string into a few blocks for further parsing |
1332 | | * |
1333 | | * \param scan_only just scan, don't validate |
1334 | | */ |
1335 | | static int SigParseBasics(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr, |
1336 | | SignatureParser *parser, uint8_t addrs_direction, bool scan_only) |
1337 | 5.63M | { |
1338 | 5.63M | char *index, dup[DETECT_MAX_RULE_SIZE]; |
1339 | | |
1340 | 5.63M | strlcpy(dup, sigstr, DETECT_MAX_RULE_SIZE); |
1341 | 5.63M | index = dup; |
1342 | | |
1343 | | /* Action. */ |
1344 | 5.63M | SigParseToken(&index, parser->action, sizeof(parser->action)); |
1345 | | |
1346 | | /* Protocol. */ |
1347 | 5.63M | SigParseList(&index, parser->protocol, sizeof(parser->protocol)); |
1348 | | |
1349 | | /* Source. */ |
1350 | 5.63M | SigParseList(&index, parser->src, sizeof(parser->src)); |
1351 | | |
1352 | | /* Source port(s). */ |
1353 | 5.63M | SigParseList(&index, parser->sp, sizeof(parser->sp)); |
1354 | | |
1355 | | /* Direction. */ |
1356 | 5.63M | SigParseToken(&index, parser->direction, sizeof(parser->direction)); |
1357 | | |
1358 | | /* Destination. */ |
1359 | 5.63M | SigParseList(&index, parser->dst, sizeof(parser->dst)); |
1360 | | |
1361 | | /* Destination port(s). */ |
1362 | 5.63M | SigParseList(&index, parser->dp, sizeof(parser->dp)); |
1363 | | |
1364 | | /* Options. */ |
1365 | 5.63M | if (index == NULL) { |
1366 | 842k | SCLogError("no rule options."); |
1367 | 842k | goto error; |
1368 | 842k | } |
1369 | 8.25M | while (isspace(*index) || *index == '(') { |
1370 | 3.46M | index++; |
1371 | 3.46M | } |
1372 | 9.35M | for (size_t i = strlen(index); i > 0; i--) { |
1373 | 9.24M | if (isspace(index[i - 1]) || index[i - 1] == ')') { |
1374 | 4.56M | index[i - 1] = '\0'; |
1375 | 4.68M | } else { |
1376 | 4.68M | break; |
1377 | 4.68M | } |
1378 | 9.24M | } |
1379 | 4.78M | strlcpy(parser->opts, index, sizeof(parser->opts)); |
1380 | | |
1381 | 4.78M | if (scan_only) { |
1382 | 2.83M | return 0; |
1383 | 2.83M | } |
1384 | | |
1385 | | /* Parse Action */ |
1386 | 1.95M | if (SigParseAction(s, parser->action) < 0) |
1387 | 63.8k | goto error; |
1388 | | |
1389 | 1.88M | if (SigParseProto(s, parser->protocol) < 0) |
1390 | 53.1k | goto error; |
1391 | | |
1392 | 1.83M | if (strcmp(parser->direction, "<>") == 0) { |
1393 | 439k | s->init_data->init_flags |= SIG_FLAG_INIT_BIDIREC; |
1394 | 1.39M | } else if (strcmp(parser->direction, "->") != 0) { |
1395 | 74.9k | SCLogError("\"%s\" is not a valid direction modifier, " |
1396 | 74.9k | "\"->\" and \"<>\" are supported.", |
1397 | 74.9k | parser->direction); |
1398 | 74.9k | goto error; |
1399 | 74.9k | } |
1400 | | |
1401 | | /* Parse Address & Ports */ |
1402 | 1.75M | if (SigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ addrs_direction) < 0) |
1403 | 37.5k | goto error; |
1404 | | |
1405 | 1.72M | if (SigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0) |
1406 | 61.4k | goto error; |
1407 | | |
1408 | | /* By AWS - Traditionally we should be doing this only for tcp/udp/sctp, |
1409 | | * but we do it for regardless of ip proto, since the dns/dnstcp/dnsudp |
1410 | | * changes that we made sees to it that at this point of time we don't |
1411 | | * set the ip proto for the sig. We do it a bit later. */ |
1412 | 1.65M | if (SigParsePort(de_ctx, s, parser->sp, SIG_DIREC_SRC ^ addrs_direction) < 0) |
1413 | 14.3k | goto error; |
1414 | 1.64M | if (SigParsePort(de_ctx, s, parser->dp, SIG_DIREC_DST ^ addrs_direction) < 0) |
1415 | 59.4k | goto error; |
1416 | | |
1417 | 1.58M | return 0; |
1418 | | |
1419 | 1.20M | error: |
1420 | 1.20M | return -1; |
1421 | 1.64M | } |
1422 | | |
1423 | | static inline bool CheckAscii(const char *str) |
1424 | 9.97M | { |
1425 | 1.53G | for (size_t i = 0; i < strlen(str); i++) { |
1426 | 1.52G | if (str[i] < 0x20) { |
1427 | | // LF CR TAB |
1428 | 3.38M | if (str[i] == 0x0a || str[i] == 0x0d || str[i] == 0x09) { |
1429 | 2.98M | continue; |
1430 | 2.98M | } |
1431 | 401k | return false; |
1432 | 1.52G | } else if (str[i] == 0x7f) { |
1433 | 31.1k | return false; |
1434 | 31.1k | } |
1435 | 1.52G | } |
1436 | 9.54M | return true; |
1437 | 9.97M | } |
1438 | | |
1439 | | /** |
1440 | | * \brief parse a signature |
1441 | | * |
1442 | | * \param de_ctx detection engine ctx to add it to |
1443 | | * \param s memory structure to store the signature in |
1444 | | * \param sigstr the raw signature as a null terminated string |
1445 | | * \param addrs_direction direction (for bi-directional sigs) |
1446 | | * \param require only scan rule for requires |
1447 | | * |
1448 | | * \param -1 parse error |
1449 | | * \param 0 ok |
1450 | | */ |
1451 | | static int SigParse(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr, |
1452 | | uint8_t addrs_direction, SignatureParser *parser, bool requires) |
1453 | 6.72M | { |
1454 | 6.72M | SCEnter(); |
1455 | | |
1456 | 6.72M | if (!rs_check_utf8(sigstr)) { |
1457 | 844k | SCLogError("rule is not valid UTF-8"); |
1458 | 844k | SCReturnInt(-1); |
1459 | 844k | } |
1460 | | |
1461 | 5.88M | if (!CheckAscii(sigstr)) { |
1462 | 253k | SCLogError("rule contains invalid (control) characters"); |
1463 | 253k | SCReturnInt(-1); |
1464 | 253k | } |
1465 | | |
1466 | 5.63M | int ret = SigParseBasics(de_ctx, s, sigstr, parser, addrs_direction, requires); |
1467 | 5.63M | if (ret < 0) { |
1468 | 1.20M | SCLogDebug("SigParseBasics failed"); |
1469 | 1.20M | SCReturnInt(-1); |
1470 | 1.20M | } |
1471 | | |
1472 | | /* we can have no options, so make sure we have them */ |
1473 | 4.42M | if (strlen(parser->opts) > 0) { |
1474 | 4.31M | size_t buffer_size = strlen(parser->opts) + 1; |
1475 | 4.31M | char input[buffer_size]; |
1476 | 4.31M | char output[buffer_size]; |
1477 | 4.31M | memset(input, 0x00, buffer_size); |
1478 | 4.31M | memcpy(input, parser->opts, strlen(parser->opts) + 1); |
1479 | | |
1480 | | /* loop the option parsing. Each run processes one option |
1481 | | * and returns the rest of the option string through the |
1482 | | * output variable. */ |
1483 | 18.9M | do { |
1484 | 18.9M | memset(output, 0x00, buffer_size); |
1485 | 18.9M | ret = SigParseOptions(de_ctx, s, input, output, buffer_size, requires); |
1486 | 18.9M | if (ret == 1) { |
1487 | 14.5M | memcpy(input, output, buffer_size); |
1488 | 14.5M | } |
1489 | | |
1490 | 18.9M | } while (ret == 1); |
1491 | | |
1492 | 4.31M | if (ret < 0) { |
1493 | | /* Suricata didn't meet the rule requirements, skip. */ |
1494 | 1.12M | goto end; |
1495 | 1.12M | } |
1496 | 4.31M | } |
1497 | | |
1498 | 4.42M | end: |
1499 | 4.42M | DetectIPProtoRemoveAllSMs(de_ctx, s); |
1500 | | |
1501 | 4.42M | SCReturnInt(ret); |
1502 | 4.42M | } |
1503 | | |
1504 | | /** \brief check if buffers array still has space left, expand if not |
1505 | | */ |
1506 | | int SignatureInitDataBufferCheckExpand(Signature *s) |
1507 | 1.34M | { |
1508 | 1.34M | if (s->init_data->buffers_size >= 64) |
1509 | 17 | return -1; |
1510 | | |
1511 | 1.34M | if (s->init_data->buffer_index + 1 == s->init_data->buffers_size) { |
1512 | 4.65k | void *ptr = SCRealloc(s->init_data->buffers, |
1513 | 4.65k | (s->init_data->buffers_size + 8) * sizeof(SignatureInitDataBuffer)); |
1514 | 4.65k | if (ptr == NULL) |
1515 | 0 | return -1; |
1516 | 4.65k | s->init_data->buffers = ptr; |
1517 | 41.9k | for (uint32_t x = s->init_data->buffers_size; x < s->init_data->buffers_size + 8; x++) { |
1518 | 37.2k | SignatureInitDataBuffer *b = &s->init_data->buffers[x]; |
1519 | 37.2k | memset(b, 0, sizeof(*b)); |
1520 | 37.2k | } |
1521 | 4.65k | s->init_data->buffers_size += 8; |
1522 | 4.65k | } |
1523 | 1.34M | return 0; |
1524 | 1.34M | } |
1525 | | |
1526 | | Signature *SigAlloc (void) |
1527 | 7.99M | { |
1528 | 7.99M | Signature *sig = SCMalloc(sizeof(Signature)); |
1529 | 7.99M | if (unlikely(sig == NULL)) |
1530 | 0 | return NULL; |
1531 | 7.99M | memset(sig, 0, sizeof(Signature)); |
1532 | | |
1533 | 7.99M | sig->init_data = SCCalloc(1, sizeof(SignatureInitData)); |
1534 | 7.99M | if (sig->init_data == NULL) { |
1535 | 0 | SCFree(sig); |
1536 | 0 | return NULL; |
1537 | 0 | } |
1538 | 7.99M | sig->init_data->mpm_sm_list = -1; |
1539 | | |
1540 | 7.99M | sig->init_data->buffers = SCCalloc(8, sizeof(SignatureInitDataBuffer)); |
1541 | 7.99M | if (sig->init_data->buffers == NULL) { |
1542 | 0 | SCFree(sig->init_data); |
1543 | 0 | SCFree(sig); |
1544 | 0 | return NULL; |
1545 | 0 | } |
1546 | 7.99M | sig->init_data->buffers_size = 8; |
1547 | | |
1548 | | /* assign it to -1, so that we can later check if the value has been |
1549 | | * overwritten after the Signature has been parsed, and if it hasn't been |
1550 | | * overwritten, we can then assign the default value of 3 */ |
1551 | 7.99M | sig->prio = -1; |
1552 | | |
1553 | 7.99M | sig->init_data->list = DETECT_SM_LIST_NOTSET; |
1554 | 7.99M | return sig; |
1555 | 7.99M | } |
1556 | | |
1557 | | /** |
1558 | | * \internal |
1559 | | * \brief Free Metadata list |
1560 | | * |
1561 | | * \param s Pointer to the signature |
1562 | | */ |
1563 | | static void SigMetadataFree(Signature *s) |
1564 | 7.99M | { |
1565 | 7.99M | SCEnter(); |
1566 | | |
1567 | 7.99M | DetectMetadata *mdata = NULL; |
1568 | 7.99M | DetectMetadata *next_mdata = NULL; |
1569 | | |
1570 | 7.99M | if (s == NULL || s->metadata == NULL) { |
1571 | 7.93M | SCReturn; |
1572 | 7.93M | } |
1573 | | |
1574 | 69.1k | SCLogDebug("s %p, s->metadata %p", s, s->metadata); |
1575 | | |
1576 | 238k | for (mdata = s->metadata->list; mdata != NULL;) { |
1577 | 168k | next_mdata = mdata->next; |
1578 | 168k | DetectMetadataFree(mdata); |
1579 | 168k | mdata = next_mdata; |
1580 | 168k | } |
1581 | 69.1k | SCFree(s->metadata->json_str); |
1582 | 69.1k | SCFree(s->metadata); |
1583 | 69.1k | s->metadata = NULL; |
1584 | | |
1585 | 69.1k | SCReturn; |
1586 | 7.99M | } |
1587 | | |
1588 | | /** |
1589 | | * \internal |
1590 | | * \brief Free Reference list |
1591 | | * |
1592 | | * \param s Pointer to the signature |
1593 | | */ |
1594 | | static void SigRefFree (Signature *s) |
1595 | 7.99M | { |
1596 | 7.99M | SCEnter(); |
1597 | | |
1598 | 7.99M | DetectReference *ref = NULL; |
1599 | 7.99M | DetectReference *next_ref = NULL; |
1600 | | |
1601 | 7.99M | if (s == NULL) { |
1602 | 0 | SCReturn; |
1603 | 0 | } |
1604 | | |
1605 | 7.99M | SCLogDebug("s %p, s->references %p", s, s->references); |
1606 | | |
1607 | 8.25M | for (ref = s->references; ref != NULL;) { |
1608 | 253k | next_ref = ref->next; |
1609 | 253k | DetectReferenceFree(ref); |
1610 | 253k | ref = next_ref; |
1611 | 253k | } |
1612 | | |
1613 | 7.99M | s->references = NULL; |
1614 | | |
1615 | 7.99M | SCReturn; |
1616 | 7.99M | } |
1617 | | |
1618 | | static void SigMatchFreeArrays(DetectEngineCtx *de_ctx, Signature *s, int ctxs) |
1619 | 7.99M | { |
1620 | 7.99M | if (s != NULL) { |
1621 | 7.99M | int type; |
1622 | 63.9M | for (type = 0; type < DETECT_SM_LIST_MAX; type++) { |
1623 | 55.9M | if (s->sm_arrays[type] != NULL) { |
1624 | 168k | if (ctxs) { |
1625 | 168k | SigMatchData *smd = s->sm_arrays[type]; |
1626 | 296k | while(1) { |
1627 | 296k | if (sigmatch_table[smd->type].Free != NULL) { |
1628 | 292k | sigmatch_table[smd->type].Free(de_ctx, smd->ctx); |
1629 | 292k | } |
1630 | 296k | if (smd->is_last) |
1631 | 168k | break; |
1632 | 128k | smd++; |
1633 | 128k | } |
1634 | 168k | } |
1635 | | |
1636 | 168k | SCFree(s->sm_arrays[type]); |
1637 | 168k | } |
1638 | 55.9M | } |
1639 | 7.99M | } |
1640 | 7.99M | } |
1641 | | |
1642 | | void SigFree(DetectEngineCtx *de_ctx, Signature *s) |
1643 | 4.79M | { |
1644 | 4.79M | if (s == NULL) |
1645 | 14.5k | return; |
1646 | | |
1647 | 4.77M | if (s->cidr_dst != NULL) |
1648 | 65.7k | IPOnlyCIDRListFree(s->cidr_dst); |
1649 | | |
1650 | 4.77M | if (s->cidr_src != NULL) |
1651 | 66.0k | IPOnlyCIDRListFree(s->cidr_src); |
1652 | | |
1653 | 4.77M | int i; |
1654 | | |
1655 | 4.77M | if (s->init_data && s->init_data->transforms.cnt) { |
1656 | 34.2k | for(i = 0; i < s->init_data->transforms.cnt; i++) { |
1657 | 19.3k | if (s->init_data->transforms.transforms[i].options) { |
1658 | 8.02k | int transform = s->init_data->transforms.transforms[i].transform; |
1659 | 8.02k | sigmatch_table[transform].Free( |
1660 | 8.02k | de_ctx, s->init_data->transforms.transforms[i].options); |
1661 | 8.02k | s->init_data->transforms.transforms[i].options = NULL; |
1662 | 8.02k | } |
1663 | 19.3k | } |
1664 | 14.9k | } |
1665 | 4.77M | if (s->init_data) { |
1666 | 37.2M | for (i = 0; i < DETECT_SM_LIST_MAX; i++) { |
1667 | 32.5M | SigMatch *sm = s->init_data->smlists[i]; |
1668 | 33.5M | while (sm != NULL) { |
1669 | 952k | SigMatch *nsm = sm->next; |
1670 | 952k | SigMatchFree(de_ctx, sm); |
1671 | 952k | sm = nsm; |
1672 | 952k | } |
1673 | 32.5M | } |
1674 | | |
1675 | 5.34M | for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { |
1676 | 693k | SigMatch *sm = s->init_data->buffers[x].head; |
1677 | 1.41M | while (sm != NULL) { |
1678 | 718k | SigMatch *nsm = sm->next; |
1679 | 718k | SigMatchFree(de_ctx, sm); |
1680 | 718k | sm = nsm; |
1681 | 718k | } |
1682 | 693k | } |
1683 | 4.65M | SCFree(s->init_data->buffers); |
1684 | 4.65M | s->init_data->buffers = NULL; |
1685 | 4.65M | } |
1686 | 4.77M | SigMatchFreeArrays(de_ctx, s, (s->init_data == NULL)); |
1687 | 4.77M | if (s->init_data) { |
1688 | 4.65M | SCFree(s->init_data); |
1689 | 4.65M | s->init_data = NULL; |
1690 | 4.65M | } |
1691 | | |
1692 | 4.77M | if (s->sp != NULL) { |
1693 | 1.64M | DetectPortCleanupList(NULL, s->sp); |
1694 | 1.64M | } |
1695 | 4.77M | if (s->dp != NULL) { |
1696 | 1.58M | DetectPortCleanupList(NULL, s->dp); |
1697 | 1.58M | } |
1698 | | |
1699 | 4.77M | if (s->msg != NULL) |
1700 | 864k | SCFree(s->msg); |
1701 | | |
1702 | 4.77M | if (s->addr_src_match4 != NULL) { |
1703 | 735k | SCFree(s->addr_src_match4); |
1704 | 735k | } |
1705 | 4.77M | if (s->addr_dst_match4 != NULL) { |
1706 | 740k | SCFree(s->addr_dst_match4); |
1707 | 740k | } |
1708 | 4.77M | if (s->addr_src_match6 != NULL) { |
1709 | 803k | SCFree(s->addr_src_match6); |
1710 | 803k | } |
1711 | 4.77M | if (s->addr_dst_match6 != NULL) { |
1712 | 799k | SCFree(s->addr_dst_match6); |
1713 | 799k | } |
1714 | 4.77M | if (s->sig_str != NULL) { |
1715 | 4.77M | SCFree(s->sig_str); |
1716 | 4.77M | } |
1717 | | |
1718 | 4.77M | SigRefFree(s); |
1719 | 4.77M | SigMetadataFree(s); |
1720 | | |
1721 | 4.77M | DetectEngineAppInspectionEngineSignatureFree(de_ctx, s); |
1722 | | |
1723 | 4.77M | SCFree(s); |
1724 | 4.77M | } |
1725 | | |
1726 | | int DetectSignatureAddTransform(Signature *s, int transform, void *options) |
1727 | 110k | { |
1728 | | /* we only support buffers */ |
1729 | 110k | if (s->init_data->list == 0) { |
1730 | 0 | SCReturnInt(-1); |
1731 | 0 | } |
1732 | 110k | if (!s->init_data->list_set) { |
1733 | 1.64k | SCLogError("transforms must directly follow stickybuffers"); |
1734 | 1.64k | SCReturnInt(-1); |
1735 | 1.64k | } |
1736 | 108k | if (s->init_data->transforms.cnt >= DETECT_TRANSFORMS_MAX) { |
1737 | 2 | SCReturnInt(-1); |
1738 | 2 | } |
1739 | | |
1740 | 108k | s->init_data->transforms.transforms[s->init_data->transforms.cnt].transform = transform; |
1741 | 108k | s->init_data->transforms.transforms[s->init_data->transforms.cnt].options = options; |
1742 | | |
1743 | 108k | s->init_data->transforms.cnt++; |
1744 | 108k | SCLogDebug("Added transform #%d [%s]", |
1745 | 108k | s->init_data->transforms.cnt, |
1746 | 108k | s->sig_str); |
1747 | | |
1748 | 108k | SCReturnInt(0); |
1749 | 108k | } |
1750 | | |
1751 | | int DetectSignatureSetAppProto(Signature *s, AppProto alproto) |
1752 | 696k | { |
1753 | 696k | if (alproto == ALPROTO_UNKNOWN || |
1754 | 696k | alproto >= ALPROTO_FAILED) { |
1755 | 0 | SCLogError("invalid alproto %u", alproto); |
1756 | 0 | return -1; |
1757 | 0 | } |
1758 | | |
1759 | | /* since AppProtoEquals is quite permissive wrt dcerpc and smb, make sure |
1760 | | * we refuse `alert dcerpc ... smb.share; content...` explicitly. */ |
1761 | 696k | if (alproto == ALPROTO_SMB && s->alproto == ALPROTO_DCERPC) { |
1762 | 0 | SCLogError("can't set rule app proto to %s: already set to %s", AppProtoToString(alproto), |
1763 | 0 | AppProtoToString(s->alproto)); |
1764 | 0 | return -1; |
1765 | 0 | } |
1766 | | |
1767 | 696k | if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(s->alproto, alproto)) { |
1768 | 64.8k | if (AppProtoEquals(alproto, s->alproto)) { |
1769 | | // happens if alproto = HTTP_ANY and s->alproto = HTTP1 |
1770 | | // in this case, we must keep the most restrictive HTTP1 |
1771 | 42.7k | alproto = s->alproto; |
1772 | 42.7k | } else { |
1773 | 22.1k | SCLogError("can't set rule app proto to %s: already set to %s", |
1774 | 22.1k | AppProtoToString(alproto), AppProtoToString(s->alproto)); |
1775 | 22.1k | return -1; |
1776 | 22.1k | } |
1777 | 64.8k | } |
1778 | | |
1779 | 674k | if (AppLayerProtoDetectGetProtoName(alproto) == NULL) { |
1780 | 505 | SCLogError("disabled alproto %s, rule can never match", AppProtoToString(alproto)); |
1781 | 505 | return -1; |
1782 | 505 | } |
1783 | 674k | s->alproto = alproto; |
1784 | 674k | s->flags |= SIG_FLAG_APPLAYER; |
1785 | 674k | return 0; |
1786 | 674k | } |
1787 | | |
1788 | | /** |
1789 | | * \internal |
1790 | | * \brief build address match array for cache efficient matching |
1791 | | * |
1792 | | * \param s the signature |
1793 | | */ |
1794 | | static void SigBuildAddressMatchArray(Signature *s) |
1795 | 814k | { |
1796 | | /* source addresses */ |
1797 | 814k | uint16_t cnt = 0; |
1798 | 814k | uint16_t idx = 0; |
1799 | 814k | DetectAddress *da = s->init_data->src->ipv4_head; |
1800 | 1.55M | for ( ; da != NULL; da = da->next) { |
1801 | 742k | cnt++; |
1802 | 742k | } |
1803 | 814k | if (cnt > 0) { |
1804 | 735k | s->addr_src_match4 = SCMalloc(cnt * sizeof(DetectMatchAddressIPv4)); |
1805 | 735k | if (s->addr_src_match4 == NULL) { |
1806 | 0 | exit(EXIT_FAILURE); |
1807 | 0 | } |
1808 | | |
1809 | 1.47M | for (da = s->init_data->src->ipv4_head; da != NULL; da = da->next) { |
1810 | 742k | s->addr_src_match4[idx].ip = SCNtohl(da->ip.addr_data32[0]); |
1811 | 742k | s->addr_src_match4[idx].ip2 = SCNtohl(da->ip2.addr_data32[0]); |
1812 | 742k | idx++; |
1813 | 742k | } |
1814 | 735k | s->addr_src_match4_cnt = cnt; |
1815 | 735k | } |
1816 | | |
1817 | | /* destination addresses */ |
1818 | 814k | cnt = 0; |
1819 | 814k | idx = 0; |
1820 | 814k | da = s->init_data->dst->ipv4_head; |
1821 | 1.55M | for ( ; da != NULL; da = da->next) { |
1822 | 744k | cnt++; |
1823 | 744k | } |
1824 | 814k | if (cnt > 0) { |
1825 | 740k | s->addr_dst_match4 = SCMalloc(cnt * sizeof(DetectMatchAddressIPv4)); |
1826 | 740k | if (s->addr_dst_match4 == NULL) { |
1827 | 0 | exit(EXIT_FAILURE); |
1828 | 0 | } |
1829 | | |
1830 | 1.48M | for (da = s->init_data->dst->ipv4_head; da != NULL; da = da->next) { |
1831 | 744k | s->addr_dst_match4[idx].ip = SCNtohl(da->ip.addr_data32[0]); |
1832 | 744k | s->addr_dst_match4[idx].ip2 = SCNtohl(da->ip2.addr_data32[0]); |
1833 | 744k | idx++; |
1834 | 744k | } |
1835 | 740k | s->addr_dst_match4_cnt = cnt; |
1836 | 740k | } |
1837 | | |
1838 | | /* source addresses IPv6 */ |
1839 | 814k | cnt = 0; |
1840 | 814k | idx = 0; |
1841 | 814k | da = s->init_data->src->ipv6_head; |
1842 | 1.65M | for ( ; da != NULL; da = da->next) { |
1843 | 843k | cnt++; |
1844 | 843k | } |
1845 | 814k | if (cnt > 0) { |
1846 | 803k | s->addr_src_match6 = SCMalloc(cnt * sizeof(DetectMatchAddressIPv6)); |
1847 | 803k | if (s->addr_src_match6 == NULL) { |
1848 | 0 | exit(EXIT_FAILURE); |
1849 | 0 | } |
1850 | | |
1851 | 1.64M | for (da = s->init_data->src->ipv6_head; da != NULL; da = da->next) { |
1852 | 843k | s->addr_src_match6[idx].ip[0] = SCNtohl(da->ip.addr_data32[0]); |
1853 | 843k | s->addr_src_match6[idx].ip[1] = SCNtohl(da->ip.addr_data32[1]); |
1854 | 843k | s->addr_src_match6[idx].ip[2] = SCNtohl(da->ip.addr_data32[2]); |
1855 | 843k | s->addr_src_match6[idx].ip[3] = SCNtohl(da->ip.addr_data32[3]); |
1856 | 843k | s->addr_src_match6[idx].ip2[0] = SCNtohl(da->ip2.addr_data32[0]); |
1857 | 843k | s->addr_src_match6[idx].ip2[1] = SCNtohl(da->ip2.addr_data32[1]); |
1858 | 843k | s->addr_src_match6[idx].ip2[2] = SCNtohl(da->ip2.addr_data32[2]); |
1859 | 843k | s->addr_src_match6[idx].ip2[3] = SCNtohl(da->ip2.addr_data32[3]); |
1860 | 843k | idx++; |
1861 | 843k | } |
1862 | 803k | s->addr_src_match6_cnt = cnt; |
1863 | 803k | } |
1864 | | |
1865 | | /* destination addresses IPv6 */ |
1866 | 814k | cnt = 0; |
1867 | 814k | idx = 0; |
1868 | 814k | da = s->init_data->dst->ipv6_head; |
1869 | 1.65M | for ( ; da != NULL; da = da->next) { |
1870 | 841k | cnt++; |
1871 | 841k | } |
1872 | 814k | if (cnt > 0) { |
1873 | 799k | s->addr_dst_match6 = SCMalloc(cnt * sizeof(DetectMatchAddressIPv6)); |
1874 | 799k | if (s->addr_dst_match6 == NULL) { |
1875 | 0 | exit(EXIT_FAILURE); |
1876 | 0 | } |
1877 | | |
1878 | 1.64M | for (da = s->init_data->dst->ipv6_head; da != NULL; da = da->next) { |
1879 | 841k | s->addr_dst_match6[idx].ip[0] = SCNtohl(da->ip.addr_data32[0]); |
1880 | 841k | s->addr_dst_match6[idx].ip[1] = SCNtohl(da->ip.addr_data32[1]); |
1881 | 841k | s->addr_dst_match6[idx].ip[2] = SCNtohl(da->ip.addr_data32[2]); |
1882 | 841k | s->addr_dst_match6[idx].ip[3] = SCNtohl(da->ip.addr_data32[3]); |
1883 | 841k | s->addr_dst_match6[idx].ip2[0] = SCNtohl(da->ip2.addr_data32[0]); |
1884 | 841k | s->addr_dst_match6[idx].ip2[1] = SCNtohl(da->ip2.addr_data32[1]); |
1885 | 841k | s->addr_dst_match6[idx].ip2[2] = SCNtohl(da->ip2.addr_data32[2]); |
1886 | 841k | s->addr_dst_match6[idx].ip2[3] = SCNtohl(da->ip2.addr_data32[3]); |
1887 | 841k | idx++; |
1888 | 841k | } |
1889 | 799k | s->addr_dst_match6_cnt = cnt; |
1890 | 799k | } |
1891 | 814k | } |
1892 | | |
1893 | | static int SigMatchListLen(SigMatch *sm) |
1894 | 1.77M | { |
1895 | 1.77M | int len = 0; |
1896 | 2.37M | for (; sm != NULL; sm = sm->next) |
1897 | 603k | len++; |
1898 | | |
1899 | 1.77M | return len; |
1900 | 1.77M | } |
1901 | | |
1902 | | /** \brief convert SigMatch list to SigMatchData array |
1903 | | * \note ownership of sm->ctx is transferred to smd->ctx |
1904 | | */ |
1905 | | SigMatchData* SigMatchList2DataArray(SigMatch *head) |
1906 | 1.77M | { |
1907 | 1.77M | int len = SigMatchListLen(head); |
1908 | 1.77M | if (len == 0) |
1909 | 1.45M | return NULL; |
1910 | | |
1911 | 321k | SigMatchData *smd = (SigMatchData *)SCCalloc(len, sizeof(SigMatchData)); |
1912 | 321k | if (smd == NULL) { |
1913 | 0 | FatalError("initializing the detection engine failed"); |
1914 | 0 | } |
1915 | 321k | SigMatchData *out = smd; |
1916 | | |
1917 | | /* Copy sm type and Context into array */ |
1918 | 321k | SigMatch *sm = head; |
1919 | 925k | for (; sm != NULL; sm = sm->next, smd++) { |
1920 | 603k | smd->type = sm->type; |
1921 | 603k | smd->ctx = sm->ctx; |
1922 | 603k | sm->ctx = NULL; // SigMatch no longer owns the ctx |
1923 | 603k | smd->is_last = (sm->next == NULL); |
1924 | 603k | } |
1925 | 321k | return out; |
1926 | 321k | } |
1927 | | |
1928 | | /** |
1929 | | * \internal |
1930 | | * \brief validate a just parsed signature for internal inconsistencies |
1931 | | * |
1932 | | * \param s just parsed signature |
1933 | | * |
1934 | | * \retval 0 invalid |
1935 | | * \retval 1 valid |
1936 | | */ |
1937 | | static int SigValidate(DetectEngineCtx *de_ctx, Signature *s) |
1938 | 814k | { |
1939 | 814k | SCEnter(); |
1940 | | |
1941 | 814k | uint32_t sig_flags = 0; |
1942 | 814k | int nlists = 0; |
1943 | 1.28M | for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { |
1944 | 473k | nlists = MAX(nlists, (int)s->init_data->buffers[x].id); |
1945 | 473k | } |
1946 | 814k | nlists += (nlists > 0); |
1947 | 814k | SCLogDebug("nlists %d", nlists); |
1948 | | |
1949 | 814k | if (s->init_data->curbuf && s->init_data->curbuf->head == NULL) { |
1950 | 928 | SCLogError("rule %u setup buffer %s but didn't add matches to it", s->id, |
1951 | 928 | DetectEngineBufferTypeGetNameById(de_ctx, s->init_data->curbuf->id)); |
1952 | 928 | SCReturnInt(0); |
1953 | 928 | } |
1954 | | |
1955 | 814k | bool has_frame = false; |
1956 | 813k | bool has_app = false; |
1957 | 813k | bool has_pkt = false; |
1958 | 813k | bool has_pmatch = false; |
1959 | | |
1960 | | /* run buffer type validation callbacks if any */ |
1961 | 813k | if (s->init_data->smlists[DETECT_SM_LIST_PMATCH]) { |
1962 | 181k | if (!DetectContentPMATCHValidateCallback(s)) |
1963 | 1.24k | SCReturnInt(0); |
1964 | | |
1965 | 180k | has_pmatch = true; |
1966 | 180k | } |
1967 | | |
1968 | 812k | struct BufferVsDir { |
1969 | 812k | int ts; |
1970 | 812k | int tc; |
1971 | 812k | } bufdir[nlists + 1]; |
1972 | 812k | memset(&bufdir, 0, (nlists + 1) * sizeof(struct BufferVsDir)); |
1973 | | |
1974 | 1.26M | for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { |
1975 | 471k | SignatureInitDataBuffer *b = &s->init_data->buffers[x]; |
1976 | 471k | const DetectBufferType *bt = DetectEngineBufferTypeGetById(de_ctx, b->id); |
1977 | 471k | if (bt == NULL) { |
1978 | 0 | DEBUG_VALIDATE_BUG_ON(1); // should be impossible |
1979 | 0 | continue; |
1980 | 0 | } |
1981 | 471k | SCLogDebug("x %u b->id %u name %s", x, b->id, bt->name); |
1982 | 1.06M | for (SigMatch *sm = b->head; sm != NULL; sm = sm->next) { |
1983 | 591k | SCLogDebug("sm %u %s", sm->type, sigmatch_table[sm->type].name); |
1984 | 591k | } |
1985 | | |
1986 | 471k | if (b->head == NULL) { |
1987 | 134 | SCLogError("no matches in sticky buffer %s", bt->name); |
1988 | 134 | SCReturnInt(0); |
1989 | 134 | } |
1990 | | |
1991 | 471k | has_frame |= bt->frame; |
1992 | 471k | has_app |= (bt->frame == false && bt->packet == false); |
1993 | 471k | has_pkt |= bt->packet; |
1994 | | |
1995 | 471k | if ((s->flags & SIG_FLAG_REQUIRE_PACKET) && bt->packet == false) { |
1996 | 1.93k | SCLogError("Signature combines packet " |
1997 | 1.93k | "specific matches (like dsize, flags, ttl) with stream / " |
1998 | 1.93k | "state matching by matching on app layer proto (like using " |
1999 | 1.93k | "http_* keywords)."); |
2000 | 1.93k | SCReturnInt(0); |
2001 | 1.93k | } |
2002 | | |
2003 | 469k | const DetectEngineAppInspectionEngine *app = de_ctx->app_inspect_engines; |
2004 | 164M | for (; app != NULL; app = app->next) { |
2005 | 163M | if (app->sm_list == b->id && |
2006 | 1.58M | (AppProtoEquals(s->alproto, app->alproto) || s->alproto == 0)) { |
2007 | 1.24M | SCLogDebug("engine %s dir %d alproto %d", |
2008 | 1.24M | DetectEngineBufferTypeGetNameById(de_ctx, app->sm_list), app->dir, |
2009 | 1.24M | app->alproto); |
2010 | 1.24M | SCLogDebug("b->id %d nlists %d", b->id, nlists); |
2011 | 1.24M | bufdir[b->id].ts += (app->dir == 0); |
2012 | 1.24M | bufdir[b->id].tc += (app->dir == 1); |
2013 | 1.24M | } |
2014 | 163M | } |
2015 | | |
2016 | 469k | if (!DetectEngineBufferRunValidateCallback(de_ctx, b->id, s, &de_ctx->sigerror)) { |
2017 | 8.24k | SCReturnInt(0); |
2018 | 8.24k | } |
2019 | | |
2020 | 461k | if (!DetectBsizeValidateContentCallback(s, b)) { |
2021 | 11.9k | SCReturnInt(0); |
2022 | 11.9k | } |
2023 | 461k | } |
2024 | | |
2025 | 789k | int ts_excl = 0; |
2026 | 789k | int tc_excl = 0; |
2027 | 789k | int dir_amb = 0; |
2028 | 29.7M | for (int x = 0; x < nlists; x++) { |
2029 | 28.9M | if (bufdir[x].ts == 0 && bufdir[x].tc == 0) |
2030 | 28.5M | continue; |
2031 | 386k | ts_excl += (bufdir[x].ts > 0 && bufdir[x].tc == 0); |
2032 | 386k | tc_excl += (bufdir[x].ts == 0 && bufdir[x].tc > 0); |
2033 | 386k | dir_amb += (bufdir[x].ts > 0 && bufdir[x].tc > 0); |
2034 | | |
2035 | 386k | SCLogDebug("%s/%d: %d/%d", DetectEngineBufferTypeGetNameById(de_ctx, x), x, bufdir[x].ts, |
2036 | 386k | bufdir[x].tc); |
2037 | 386k | } |
2038 | 789k | if (ts_excl && tc_excl) { |
2039 | 378 | SCLogError("rule %u mixes keywords with conflicting directions", s->id); |
2040 | 378 | SCReturnInt(0); |
2041 | 789k | } else if (ts_excl) { |
2042 | 217k | SCLogDebug("%u: implied rule direction is toserver", s->id); |
2043 | 217k | if (DetectFlowSetupImplicit(s, SIG_FLAG_TOSERVER) < 0) { |
2044 | 174 | SCLogError("rule %u mixes keywords with conflicting directions", s->id); |
2045 | 174 | SCReturnInt(0); |
2046 | 174 | } |
2047 | 571k | } else if (tc_excl) { |
2048 | 35.9k | SCLogDebug("%u: implied rule direction is toclient", s->id); |
2049 | 35.9k | if (DetectFlowSetupImplicit(s, SIG_FLAG_TOCLIENT) < 0) { |
2050 | 2.09k | SCLogError("rule %u mixes keywords with conflicting directions", s->id); |
2051 | 2.09k | SCReturnInt(0); |
2052 | 2.09k | } |
2053 | 535k | } else if (dir_amb) { |
2054 | 97.8k | SCLogDebug("%u: rule direction cannot be deduced from keywords", s->id); |
2055 | 97.8k | } |
2056 | | |
2057 | 787k | if ((s->flags & SIG_FLAG_REQUIRE_PACKET) && |
2058 | 88.6k | (s->flags & SIG_FLAG_REQUIRE_STREAM)) { |
2059 | 86 | SCLogError("can't mix packet keywords with " |
2060 | 86 | "tcp-stream or flow:only_stream. Invalidating signature."); |
2061 | 86 | SCReturnInt(0); |
2062 | 86 | } |
2063 | | |
2064 | 786k | if ((sig_flags & (SIG_FLAG_TOCLIENT | SIG_FLAG_TOSERVER)) == (SIG_FLAG_TOCLIENT | SIG_FLAG_TOSERVER)) { |
2065 | 0 | SCLogError("You seem to have mixed keywords " |
2066 | 0 | "that require inspection in both directions. Atm we only " |
2067 | 0 | "support keywords in one direction within a rule."); |
2068 | 0 | SCReturnInt(0); |
2069 | 0 | } |
2070 | | |
2071 | 786k | if (has_pmatch && has_frame) { |
2072 | 187 | SCLogError("can't mix pure content and frame inspection"); |
2073 | 187 | SCReturnInt(0); |
2074 | 187 | } |
2075 | 786k | if (has_app && has_frame) { |
2076 | 12 | SCLogError("can't mix app-layer buffer and frame inspection"); |
2077 | 12 | SCReturnInt(0); |
2078 | 12 | } |
2079 | 786k | if (has_pkt && has_frame) { |
2080 | 0 | SCLogError("can't mix pkt buffer and frame inspection"); |
2081 | 0 | SCReturnInt(0); |
2082 | 0 | } |
2083 | | |
2084 | | /* TCP: corner cases: |
2085 | | * - pkt vs stream vs depth/offset |
2086 | | * - pkt vs stream vs stream_size |
2087 | | */ |
2088 | 786k | if (s->proto.proto[IPPROTO_TCP / 8] & (1 << (IPPROTO_TCP % 8))) { |
2089 | 745k | if (s->init_data->smlists[DETECT_SM_LIST_PMATCH]) { |
2090 | 171k | if (!(s->flags & (SIG_FLAG_REQUIRE_PACKET | SIG_FLAG_REQUIRE_STREAM))) { |
2091 | 136k | s->flags |= SIG_FLAG_REQUIRE_STREAM; |
2092 | 371k | for (SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; sm != NULL; |
2093 | 247k | sm = sm->next) { |
2094 | 247k | if (sm->type == DETECT_CONTENT && |
2095 | 110k | (((DetectContentData *)(sm->ctx))->flags & |
2096 | 110k | (DETECT_CONTENT_DEPTH | DETECT_CONTENT_OFFSET))) { |
2097 | 12.9k | s->flags |= SIG_FLAG_REQUIRE_PACKET; |
2098 | 12.9k | break; |
2099 | 12.9k | } |
2100 | 247k | } |
2101 | | /* if stream_size is in use, also inspect packets */ |
2102 | 177k | for (SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; |
2103 | 136k | sm = sm->next) { |
2104 | 42.8k | if (sm->type == DETECT_STREAM_SIZE) { |
2105 | 2.06k | s->flags |= SIG_FLAG_REQUIRE_PACKET; |
2106 | 2.06k | break; |
2107 | 2.06k | } |
2108 | 42.8k | } |
2109 | 136k | } |
2110 | 171k | } |
2111 | 745k | } |
2112 | | #ifdef HAVE_LUA |
2113 | | DetectLuaPostSetup(s); |
2114 | | #endif |
2115 | | |
2116 | 786k | if ((s->init_data->init_flags & SIG_FLAG_INIT_JA) && s->alproto != ALPROTO_UNKNOWN && |
2117 | 4.01k | s->alproto != ALPROTO_TLS && s->alproto != ALPROTO_QUIC) { |
2118 | 19 | SCLogError("Cannot have ja3/ja4 with protocol %s.", AppProtoToString(s->alproto)); |
2119 | 19 | SCReturnInt(0); |
2120 | 19 | } |
2121 | 786k | if ((s->flags & SIG_FLAG_FILESTORE) || s->file_flags != 0 || |
2122 | 759k | (s->init_data->init_flags & SIG_FLAG_INIT_FILEDATA)) { |
2123 | 51.9k | if (s->alproto != ALPROTO_UNKNOWN && |
2124 | 12.9k | !AppLayerParserSupportsFiles(IPPROTO_TCP, s->alproto)) |
2125 | 501 | { |
2126 | 501 | SCLogError("protocol %s doesn't " |
2127 | 501 | "support file matching", |
2128 | 501 | AppProtoToString(s->alproto)); |
2129 | 501 | SCReturnInt(0); |
2130 | 501 | } |
2131 | 51.4k | if (s->alproto == ALPROTO_HTTP2 && (s->file_flags & FILE_SIG_NEED_FILENAME)) { |
2132 | 261 | SCLogError("protocol HTTP2 doesn't support file name matching"); |
2133 | 261 | SCReturnInt(0); |
2134 | 261 | } |
2135 | | |
2136 | 51.1k | if (s->alproto == ALPROTO_HTTP1 || s->alproto == ALPROTO_HTTP) { |
2137 | 9.77k | AppLayerHtpNeedFileInspection(); |
2138 | 9.77k | } |
2139 | 51.1k | } |
2140 | | |
2141 | 786k | SCReturnInt(1); |
2142 | 786k | } |
2143 | | |
2144 | | /** |
2145 | | * \internal |
2146 | | * \brief Helper function for SigInit(). |
2147 | | */ |
2148 | | static Signature *SigInitHelper(DetectEngineCtx *de_ctx, const char *sigstr, |
2149 | | uint8_t dir) |
2150 | 4.77M | { |
2151 | 4.77M | SignatureParser parser; |
2152 | 4.77M | memset(&parser, 0x00, sizeof(parser)); |
2153 | | |
2154 | 4.77M | Signature *sig = SigAlloc(); |
2155 | 4.77M | if (sig == NULL) |
2156 | 0 | goto error; |
2157 | | |
2158 | 4.77M | sig->sig_str = SCStrdup(sigstr); |
2159 | 4.77M | if (unlikely(sig->sig_str == NULL)) { |
2160 | 0 | goto error; |
2161 | 0 | } |
2162 | | |
2163 | | /* default gid to 1 */ |
2164 | 4.77M | sig->gid = 1; |
2165 | | |
2166 | | /* We do a first parse of the rule in a requires, or scan-only |
2167 | | * mode. Syntactic errors will be picked up here, but the only |
2168 | | * part of the rule that is validated completely is the "requires" |
2169 | | * keyword. */ |
2170 | 4.77M | int ret = SigParse(de_ctx, sig, sigstr, dir, &parser, true); |
2171 | 4.77M | if (ret == -4) { |
2172 | | /* Rule requirements not met. */ |
2173 | 9.14k | de_ctx->sigerror_silent = true; |
2174 | 9.14k | de_ctx->sigerror_ok = true; |
2175 | 9.14k | de_ctx->sigerror_requires = true; |
2176 | 9.14k | goto error; |
2177 | 4.77M | } else if (ret < 0) { |
2178 | 2.28M | goto error; |
2179 | 2.28M | } |
2180 | | |
2181 | | /* Check for a SID before continuuing. */ |
2182 | 2.48M | if (sig->id == 0) { |
2183 | 529k | SCLogError("Signature missing required value \"sid\"."); |
2184 | 529k | goto error; |
2185 | 529k | } |
2186 | | |
2187 | | /* Now completely parse the rule. */ |
2188 | 1.95M | ret = SigParse(de_ctx, sig, sigstr, dir, &parser, false); |
2189 | 1.95M | BUG_ON(ret == -4); |
2190 | 1.95M | if (ret == -3) { |
2191 | 10.2k | de_ctx->sigerror_silent = true; |
2192 | 10.2k | de_ctx->sigerror_ok = true; |
2193 | 10.2k | goto error; |
2194 | 1.94M | } else if (ret == -2) { |
2195 | 0 | de_ctx->sigerror_silent = true; |
2196 | 0 | goto error; |
2197 | 1.94M | } else if (ret < 0) { |
2198 | 1.12M | goto error; |
2199 | 1.12M | } |
2200 | | |
2201 | | /* signature priority hasn't been overwritten. Using default priority */ |
2202 | 814k | if (sig->prio == -1) |
2203 | 678k | sig->prio = DETECT_DEFAULT_PRIO; |
2204 | | |
2205 | 814k | sig->num = de_ctx->signum; |
2206 | 814k | de_ctx->signum++; |
2207 | | |
2208 | 814k | if (sig->alproto != ALPROTO_UNKNOWN) { |
2209 | 475k | int override_needed = 0; |
2210 | 475k | if (sig->proto.flags & DETECT_PROTO_ANY) { |
2211 | 79.4k | sig->proto.flags &= ~DETECT_PROTO_ANY; |
2212 | 79.4k | memset(sig->proto.proto, 0x00, sizeof(sig->proto.proto)); |
2213 | 79.4k | override_needed = 1; |
2214 | 396k | } else { |
2215 | 396k | override_needed = 1; |
2216 | 396k | size_t s = 0; |
2217 | 449k | for (s = 0; s < sizeof(sig->proto.proto); s++) { |
2218 | 449k | if (sig->proto.proto[s] != 0x00) { |
2219 | 396k | override_needed = 0; |
2220 | 396k | break; |
2221 | 396k | } |
2222 | 449k | } |
2223 | 396k | } |
2224 | | |
2225 | | /* at this point if we had alert ip and the ip proto was not |
2226 | | * overridden, we use the ip proto that has been configured |
2227 | | * against the app proto in use. */ |
2228 | 475k | if (override_needed) |
2229 | 79.4k | AppLayerProtoDetectSupportedIpprotos(sig->alproto, sig->proto.proto); |
2230 | 475k | } |
2231 | | |
2232 | | /* set the packet and app layer flags, but only if the |
2233 | | * app layer flag wasn't already set in which case we |
2234 | | * only consider the app layer */ |
2235 | 814k | if (!(sig->flags & SIG_FLAG_APPLAYER)) { |
2236 | 335k | if (sig->init_data->smlists[DETECT_SM_LIST_MATCH] != NULL) { |
2237 | 137k | SigMatch *sm = sig->init_data->smlists[DETECT_SM_LIST_MATCH]; |
2238 | 342k | for ( ; sm != NULL; sm = sm->next) { |
2239 | 204k | if (sigmatch_table[sm->type].Match != NULL) |
2240 | 204k | sig->init_data->init_flags |= SIG_FLAG_INIT_PACKET; |
2241 | 204k | } |
2242 | 198k | } else { |
2243 | 198k | sig->init_data->init_flags |= SIG_FLAG_INIT_PACKET; |
2244 | 198k | } |
2245 | 335k | } |
2246 | | |
2247 | 814k | if (!(sig->init_data->init_flags & SIG_FLAG_INIT_FLOW)) { |
2248 | 727k | if ((sig->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) { |
2249 | 705k | sig->flags |= SIG_FLAG_TOSERVER; |
2250 | 705k | sig->flags |= SIG_FLAG_TOCLIENT; |
2251 | 705k | } |
2252 | 727k | } |
2253 | | |
2254 | 814k | SCLogDebug("sig %"PRIu32" SIG_FLAG_APPLAYER: %s, SIG_FLAG_PACKET: %s", |
2255 | 814k | sig->id, sig->flags & SIG_FLAG_APPLAYER ? "set" : "not set", |
2256 | 814k | sig->init_data->init_flags & SIG_FLAG_INIT_PACKET ? "set" : "not set"); |
2257 | | |
2258 | 814k | SigBuildAddressMatchArray(sig); |
2259 | | |
2260 | | /* run buffer type callbacks if any */ |
2261 | 6.51M | for (uint32_t x = 0; x < DETECT_SM_LIST_MAX; x++) { |
2262 | 5.69M | if (sig->init_data->smlists[x]) |
2263 | 470k | DetectEngineBufferRunSetupCallback(de_ctx, x, sig); |
2264 | 5.69M | } |
2265 | 1.28M | for (uint32_t x = 0; x < sig->init_data->buffer_index; x++) { |
2266 | 473k | DetectEngineBufferRunSetupCallback(de_ctx, sig->init_data->buffers[x].id, sig); |
2267 | 473k | } |
2268 | | |
2269 | | /* validate signature, SigValidate will report the error reason */ |
2270 | 814k | if (SigValidate(de_ctx, sig) == 0) { |
2271 | 28.1k | goto error; |
2272 | 28.1k | } |
2273 | | |
2274 | | /* check what the type of this sig is */ |
2275 | 786k | SignatureSetType(de_ctx, sig); |
2276 | | |
2277 | 786k | if (sig->type == SIG_TYPE_IPONLY) { |
2278 | | /* For IPOnly */ |
2279 | 74.6k | if (IPOnlySigParseAddress(de_ctx, sig, parser.src, SIG_DIREC_SRC ^ dir) < 0) |
2280 | 608 | goto error; |
2281 | | |
2282 | 74.0k | if (IPOnlySigParseAddress(de_ctx, sig, parser.dst, SIG_DIREC_DST ^ dir) < 0) |
2283 | 309 | goto error; |
2284 | 74.0k | } |
2285 | 785k | return sig; |
2286 | | |
2287 | 3.99M | error: |
2288 | 3.99M | if (sig != NULL) { |
2289 | 3.99M | SigFree(de_ctx, sig); |
2290 | 3.99M | } |
2291 | 3.99M | return NULL; |
2292 | 786k | } |
2293 | | |
2294 | | /** |
2295 | | * \brief Checks if a signature has the same source and destination |
2296 | | * \param s parsed signature |
2297 | | * |
2298 | | * \retval true if source and destination are the same, false otherwise |
2299 | | */ |
2300 | | static bool SigHasSameSourceAndDestination(const Signature *s) |
2301 | 239k | { |
2302 | 239k | if (!(s->flags & SIG_FLAG_SP_ANY) || !(s->flags & SIG_FLAG_DP_ANY)) { |
2303 | 224k | if (!DetectPortListsAreEqual(s->sp, s->dp)) { |
2304 | 217k | return false; |
2305 | 217k | } |
2306 | 224k | } |
2307 | | |
2308 | 21.9k | if (!(s->flags & SIG_FLAG_SRC_ANY) || !(s->flags & SIG_FLAG_DST_ANY)) { |
2309 | 21.5k | DetectAddress *src = s->init_data->src->ipv4_head; |
2310 | 21.5k | DetectAddress *dst = s->init_data->dst->ipv4_head; |
2311 | | |
2312 | 21.5k | if (!DetectAddressListsAreEqual(src, dst)) { |
2313 | 11.4k | return false; |
2314 | 11.4k | } |
2315 | | |
2316 | 10.0k | src = s->init_data->src->ipv6_head; |
2317 | 10.0k | dst = s->init_data->dst->ipv6_head; |
2318 | | |
2319 | 10.0k | if (!DetectAddressListsAreEqual(src, dst)) { |
2320 | 5.27k | return false; |
2321 | 5.27k | } |
2322 | 10.0k | } |
2323 | | |
2324 | 5.21k | return true; |
2325 | 21.9k | } |
2326 | | |
2327 | | /** |
2328 | | * \brief Parses a signature and adds it to the Detection Engine Context. |
2329 | | * |
2330 | | * \param de_ctx Pointer to the Detection Engine Context. |
2331 | | * \param sigstr Pointer to a character string containing the signature to be |
2332 | | * parsed. |
2333 | | * |
2334 | | * \retval Pointer to the Signature instance on success; NULL on failure. |
2335 | | */ |
2336 | | Signature *SigInit(DetectEngineCtx *de_ctx, const char *sigstr) |
2337 | 4.64M | { |
2338 | 4.64M | SCEnter(); |
2339 | | |
2340 | 4.64M | uint32_t oldsignum = de_ctx->signum; |
2341 | 4.64M | de_ctx->sigerror_ok = false; |
2342 | 4.64M | de_ctx->sigerror_silent = false; |
2343 | 4.64M | de_ctx->sigerror_requires = false; |
2344 | | |
2345 | 4.64M | Signature *sig; |
2346 | | |
2347 | 4.64M | if ((sig = SigInitHelper(de_ctx, sigstr, SIG_DIREC_NORMAL)) == NULL) { |
2348 | 3.99M | goto error; |
2349 | 3.99M | } |
2350 | | |
2351 | 649k | if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { |
2352 | 138k | if (SigHasSameSourceAndDestination(sig)) { |
2353 | 2.70k | SCLogInfo("Rule with ID %u is bidirectional, but source and destination are the same, " |
2354 | 2.70k | "treating the rule as unidirectional", sig->id); |
2355 | | |
2356 | 2.70k | sig->init_data->init_flags &= ~SIG_FLAG_INIT_BIDIREC; |
2357 | 135k | } else { |
2358 | 135k | sig->next = SigInitHelper(de_ctx, sigstr, SIG_DIREC_SWITCHED); |
2359 | 135k | if (sig->next == NULL) { |
2360 | 0 | goto error; |
2361 | 0 | } |
2362 | 135k | } |
2363 | 138k | } |
2364 | | |
2365 | 649k | SCReturnPtr(sig, "Signature"); |
2366 | | |
2367 | 3.99M | error: |
2368 | 3.99M | if (sig != NULL) { |
2369 | 0 | SigFree(de_ctx, sig); |
2370 | 0 | } |
2371 | | /* if something failed, restore the old signum count |
2372 | | * since we didn't install it */ |
2373 | 3.99M | de_ctx->signum = oldsignum; |
2374 | | |
2375 | 3.99M | SCReturnPtr(NULL, "Signature"); |
2376 | 649k | } |
2377 | | |
2378 | | /** |
2379 | | * \brief The hash free function to be the used by the hash table - |
2380 | | * DetectEngineCtx->dup_sig_hash_table. |
2381 | | * |
2382 | | * \param data Pointer to the data, in our case SigDuplWrapper to be freed. |
2383 | | */ |
2384 | | static void DetectParseDupSigFreeFunc(void *data) |
2385 | 107k | { |
2386 | 107k | if (data != NULL) |
2387 | 107k | SCFree(data); |
2388 | | |
2389 | 107k | return; |
2390 | 107k | } |
2391 | | |
2392 | | /** |
2393 | | * \brief The hash function to be the used by the hash table - |
2394 | | * DetectEngineCtx->dup_sig_hash_table. |
2395 | | * |
2396 | | * \param ht Pointer to the hash table. |
2397 | | * \param data Pointer to the data, in our case SigDuplWrapper. |
2398 | | * \param datalen Not used in our case. |
2399 | | * |
2400 | | * \retval sw->s->id The generated hash value. |
2401 | | */ |
2402 | | static uint32_t DetectParseDupSigHashFunc(HashListTable *ht, void *data, uint16_t datalen) |
2403 | 1.46M | { |
2404 | 1.46M | SigDuplWrapper *sw = (SigDuplWrapper *)data; |
2405 | | |
2406 | 1.46M | return (sw->s->id % ht->array_size); |
2407 | 1.46M | } |
2408 | | |
2409 | | /** |
2410 | | * \brief The Compare function to be used by the hash table - |
2411 | | * DetectEngineCtx->dup_sig_hash_table. |
2412 | | * |
2413 | | * \param data1 Pointer to the first SigDuplWrapper. |
2414 | | * \param len1 Not used. |
2415 | | * \param data2 Pointer to the second SigDuplWrapper. |
2416 | | * \param len2 Not used. |
2417 | | * |
2418 | | * \retval 1 If the 2 SigDuplWrappers sent as args match. |
2419 | | * \retval 0 If the 2 SigDuplWrappers sent as args do not match. |
2420 | | */ |
2421 | | static char DetectParseDupSigCompareFunc(void *data1, uint16_t len1, void *data2, |
2422 | | uint16_t len2) |
2423 | 1.06M | { |
2424 | 1.06M | SigDuplWrapper *sw1 = (SigDuplWrapper *)data1; |
2425 | 1.06M | SigDuplWrapper *sw2 = (SigDuplWrapper *)data2; |
2426 | | |
2427 | 1.06M | if (sw1 == NULL || sw2 == NULL || |
2428 | 1.06M | sw1->s == NULL || sw2->s == NULL) |
2429 | 0 | return 0; |
2430 | | |
2431 | | /* sid and gid match required */ |
2432 | 1.06M | if (sw1->s->id == sw2->s->id && sw1->s->gid == sw2->s->gid) return 1; |
2433 | | |
2434 | 18.1k | return 0; |
2435 | 1.06M | } |
2436 | | |
2437 | | /** |
2438 | | * \brief Initializes the hash table that is used to cull duplicate sigs. |
2439 | | * |
2440 | | * \param de_ctx Pointer to the detection engine context. |
2441 | | * |
2442 | | * \retval 0 On success. |
2443 | | * \retval -1 On failure. |
2444 | | */ |
2445 | | int DetectParseDupSigHashInit(DetectEngineCtx *de_ctx) |
2446 | 156k | { |
2447 | 156k | de_ctx->dup_sig_hash_table = HashListTableInit(15000, |
2448 | 156k | DetectParseDupSigHashFunc, |
2449 | 156k | DetectParseDupSigCompareFunc, |
2450 | 156k | DetectParseDupSigFreeFunc); |
2451 | 156k | if (de_ctx->dup_sig_hash_table == NULL) |
2452 | 0 | return -1; |
2453 | | |
2454 | 156k | return 0; |
2455 | 156k | } |
2456 | | |
2457 | | /** |
2458 | | * \brief Frees the hash table that is used to cull duplicate sigs. |
2459 | | * |
2460 | | * \param de_ctx Pointer to the detection engine context that holds this table. |
2461 | | */ |
2462 | | void DetectParseDupSigHashFree(DetectEngineCtx *de_ctx) |
2463 | 128k | { |
2464 | 128k | if (de_ctx->dup_sig_hash_table != NULL) |
2465 | 64.3k | HashListTableFree(de_ctx->dup_sig_hash_table); |
2466 | | |
2467 | 128k | de_ctx->dup_sig_hash_table = NULL; |
2468 | | |
2469 | 128k | return; |
2470 | 128k | } |
2471 | | |
2472 | | /** |
2473 | | * \brief Check if a signature is a duplicate. |
2474 | | * |
2475 | | * There are 3 types of return values for this function. |
2476 | | * |
2477 | | * - 0, which indicates that the Signature is not a duplicate |
2478 | | * and has to be added to the detection engine list. |
2479 | | * - 1, Signature is duplicate, and the existing signature in |
2480 | | * the list shouldn't be replaced with this duplicate. |
2481 | | * - 2, Signature is duplicate, and the existing signature in |
2482 | | * the list should be replaced with this duplicate. |
2483 | | * |
2484 | | * \param de_ctx Pointer to the detection engine context. |
2485 | | * \param sig Pointer to the Signature that has to be checked. |
2486 | | * |
2487 | | * \retval 2 If Signature is duplicate and the existing signature in |
2488 | | * the list should be chucked out and replaced with this. |
2489 | | * \retval 1 If Signature is duplicate, and should be chucked out. |
2490 | | * \retval 0 If Signature is not a duplicate. |
2491 | | */ |
2492 | | static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx, |
2493 | | Signature *sig) |
2494 | 634k | { |
2495 | | /* we won't do any NULL checks on the args */ |
2496 | | |
2497 | | /* return value */ |
2498 | 634k | int ret = 0; |
2499 | | |
2500 | 634k | SigDuplWrapper *sw_dup = NULL; |
2501 | 634k | SigDuplWrapper *sw = NULL; |
2502 | | |
2503 | | /* used for making a duplicate_sig_hash_table entry */ |
2504 | 634k | sw = SCMalloc(sizeof(SigDuplWrapper)); |
2505 | 634k | if (unlikely(sw == NULL)) { |
2506 | 0 | exit(EXIT_FAILURE); |
2507 | 0 | } |
2508 | 634k | memset(sw, 0, sizeof(SigDuplWrapper)); |
2509 | 634k | sw->s = sig; |
2510 | | |
2511 | | /* check if we have a duplicate entry for this signature */ |
2512 | 634k | sw_dup = HashListTableLookup(de_ctx->dup_sig_hash_table, (void *)sw, 0); |
2513 | | /* we don't have a duplicate entry for this sig */ |
2514 | 634k | if (sw_dup == NULL) { |
2515 | | /* add it to the hash table */ |
2516 | 107k | HashListTableAdd(de_ctx->dup_sig_hash_table, (void *)sw, 0); |
2517 | | |
2518 | | /* add the s_prev entry for the previously loaded sw in the hash_table */ |
2519 | 107k | if (de_ctx->sig_list != NULL) { |
2520 | 80.5k | SigDuplWrapper *sw_old = NULL; |
2521 | 80.5k | SigDuplWrapper sw_tmp; |
2522 | 80.5k | memset(&sw_tmp, 0, sizeof(SigDuplWrapper)); |
2523 | | |
2524 | | /* the topmost sig would be the last loaded sig */ |
2525 | 80.5k | sw_tmp.s = de_ctx->sig_list; |
2526 | 80.5k | sw_old = HashListTableLookup(de_ctx->dup_sig_hash_table, |
2527 | 80.5k | (void *)&sw_tmp, 0); |
2528 | | /* sw_old == NULL case is impossible */ |
2529 | 80.5k | sw_old->s_prev = sig; |
2530 | 80.5k | } |
2531 | | |
2532 | 107k | ret = 0; |
2533 | 107k | goto end; |
2534 | 107k | } |
2535 | | |
2536 | | /* if we have reached here we have a duplicate entry for this signature. |
2537 | | * Check the signature revision. Store the signature with the latest rev |
2538 | | * and discard the other one */ |
2539 | 527k | if (sw->s->rev <= sw_dup->s->rev) { |
2540 | 526k | ret = 1; |
2541 | 526k | SCFree(sw); |
2542 | 526k | sw = NULL; |
2543 | 526k | goto end; |
2544 | 526k | } |
2545 | | |
2546 | | /* the new sig is of a newer revision than the one that is already in the |
2547 | | * list. Remove the old sig from the list */ |
2548 | 1.02k | if (sw_dup->s_prev == NULL) { |
2549 | 139 | SigDuplWrapper sw_temp; |
2550 | 139 | memset(&sw_temp, 0, sizeof(SigDuplWrapper)); |
2551 | 139 | if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { |
2552 | 22 | sw_temp.s = sw_dup->s->next->next; |
2553 | 22 | de_ctx->sig_list = sw_dup->s->next->next; |
2554 | 22 | SigFree(de_ctx, sw_dup->s->next); |
2555 | 117 | } else { |
2556 | 117 | sw_temp.s = sw_dup->s->next; |
2557 | 117 | de_ctx->sig_list = sw_dup->s->next; |
2558 | 117 | } |
2559 | 139 | SigDuplWrapper *sw_next = NULL; |
2560 | 139 | if (sw_temp.s != NULL) { |
2561 | 109 | sw_next = HashListTableLookup(de_ctx->dup_sig_hash_table, |
2562 | 109 | (void *)&sw_temp, 0); |
2563 | 109 | sw_next->s_prev = sw_dup->s_prev; |
2564 | 109 | } |
2565 | 139 | SigFree(de_ctx, sw_dup->s); |
2566 | 883 | } else { |
2567 | 883 | SigDuplWrapper sw_temp; |
2568 | 883 | memset(&sw_temp, 0, sizeof(SigDuplWrapper)); |
2569 | 883 | if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { |
2570 | 262 | sw_temp.s = sw_dup->s->next->next; |
2571 | | /* If previous signature is bidirectional, |
2572 | | * it has 2 items in the linked list. |
2573 | | * So we need to change next->next instead of next |
2574 | | */ |
2575 | 262 | if (sw_dup->s_prev->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { |
2576 | 130 | sw_dup->s_prev->next->next = sw_dup->s->next->next; |
2577 | 132 | } else { |
2578 | 132 | sw_dup->s_prev->next = sw_dup->s->next->next; |
2579 | 132 | } |
2580 | 262 | SigFree(de_ctx, sw_dup->s->next); |
2581 | 621 | } else { |
2582 | 621 | sw_temp.s = sw_dup->s->next; |
2583 | 621 | if (sw_dup->s_prev->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { |
2584 | 150 | sw_dup->s_prev->next->next = sw_dup->s->next; |
2585 | 471 | } else { |
2586 | 471 | sw_dup->s_prev->next = sw_dup->s->next; |
2587 | 471 | } |
2588 | 621 | } |
2589 | 883 | SigDuplWrapper *sw_next = NULL; |
2590 | 883 | if (sw_temp.s != NULL) { |
2591 | 718 | sw_next = HashListTableLookup(de_ctx->dup_sig_hash_table, |
2592 | 718 | (void *)&sw_temp, 0); |
2593 | 718 | sw_next->s_prev = sw_dup->s_prev; |
2594 | 718 | } |
2595 | 883 | SigFree(de_ctx, sw_dup->s); |
2596 | 883 | } |
2597 | | |
2598 | | /* make changes to the entry to reflect the presence of the new sig */ |
2599 | 1.02k | sw_dup->s = sig; |
2600 | 1.02k | sw_dup->s_prev = NULL; |
2601 | | |
2602 | 1.02k | if (de_ctx->sig_list != NULL) { |
2603 | 992 | SigDuplWrapper sw_tmp; |
2604 | 992 | memset(&sw_tmp, 0, sizeof(SigDuplWrapper)); |
2605 | 992 | sw_tmp.s = de_ctx->sig_list; |
2606 | 992 | SigDuplWrapper *sw_old = HashListTableLookup(de_ctx->dup_sig_hash_table, |
2607 | 992 | (void *)&sw_tmp, 0); |
2608 | 992 | if (sw_old->s != sw_dup->s) { |
2609 | | // Link on top of the list if there was another element |
2610 | 992 | sw_old->s_prev = sig; |
2611 | 992 | } |
2612 | 992 | } |
2613 | | |
2614 | | /* this is duplicate, but a duplicate that replaced the existing sig entry */ |
2615 | 1.02k | ret = 2; |
2616 | | |
2617 | 1.02k | SCFree(sw); |
2618 | | |
2619 | 634k | end: |
2620 | 634k | return ret; |
2621 | 1.02k | } |
2622 | | |
2623 | | /** |
2624 | | * \brief Parse and append a Signature into the Detection Engine Context |
2625 | | * signature list. |
2626 | | * |
2627 | | * If the signature is bidirectional it should append two signatures |
2628 | | * (with the addresses switched) into the list. Also handle duplicate |
2629 | | * signatures. In case of duplicate sigs, use the ones that have the |
2630 | | * latest revision. We use the sid and the msg to identify duplicate |
2631 | | * sigs. If 2 sigs have the same sid and gid, they are duplicates. |
2632 | | * |
2633 | | * \param de_ctx Pointer to the Detection Engine Context. |
2634 | | * \param sigstr Pointer to a character string containing the signature to be |
2635 | | * parsed. |
2636 | | * \param sig_file Pointer to a character string containing the filename from |
2637 | | * which signature is read |
2638 | | * \param lineno Line number from where signature is read |
2639 | | * |
2640 | | * \retval Pointer to the head Signature in the detection engine ctx sig_list |
2641 | | * on success; NULL on failure. |
2642 | | */ |
2643 | | Signature *DetectEngineAppendSig(DetectEngineCtx *de_ctx, const char *sigstr) |
2644 | 7.73M | { |
2645 | 7.73M | Signature *sig = SigInit(de_ctx, sigstr); |
2646 | 7.73M | if (sig == NULL) { |
2647 | 6.61M | return NULL; |
2648 | 6.61M | } |
2649 | | |
2650 | | /* checking for the status of duplicate signature */ |
2651 | 1.11M | int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig); |
2652 | | /* a duplicate signature that should be chucked out. Check the previously |
2653 | | * called function details to understand the different return values */ |
2654 | 1.11M | if (dup_sig == 1) { |
2655 | 908k | SCLogError("Duplicate signature \"%s\"", sigstr); |
2656 | 908k | goto error; |
2657 | 908k | } else if (dup_sig == 2) { |
2658 | 1.72k | SCLogWarning("Signature with newer revision," |
2659 | 1.72k | " so the older sig replaced by this new signature \"%s\"", |
2660 | 1.72k | sigstr); |
2661 | 1.72k | } |
2662 | | |
2663 | 210k | if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { |
2664 | 37.3k | if (sig->next != NULL) { |
2665 | 37.3k | sig->next->next = de_ctx->sig_list; |
2666 | 37.3k | } else { |
2667 | 0 | goto error; |
2668 | 0 | } |
2669 | 173k | } else { |
2670 | | /* if this sig is the first one, sig_list should be null */ |
2671 | 173k | sig->next = de_ctx->sig_list; |
2672 | 173k | } |
2673 | | |
2674 | 210k | de_ctx->sig_list = sig; |
2675 | | |
2676 | | /** |
2677 | | * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one |
2678 | | * so if the signature is bidirectional, the returned sig will point through "next" ptr |
2679 | | * to the cloned signatures with the switched addresses |
2680 | | */ |
2681 | 210k | return (dup_sig == 0 || dup_sig == 2) ? sig : NULL; |
2682 | | |
2683 | 908k | error: |
2684 | | /* free the 2nd sig bidir may have set up */ |
2685 | 908k | if (sig != NULL && sig->next != NULL) { |
2686 | 185k | SigFree(de_ctx, sig->next); |
2687 | 185k | sig->next = NULL; |
2688 | 185k | } |
2689 | 908k | if (sig != NULL) { |
2690 | 908k | SigFree(de_ctx, sig); |
2691 | 908k | } |
2692 | 908k | return NULL; |
2693 | 210k | } |
2694 | | |
2695 | | static DetectParseRegex *g_detect_parse_regex_list = NULL; |
2696 | | |
2697 | | int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str, |
2698 | | int start_offset, int options) |
2699 | 2.25M | { |
2700 | 2.25M | *match = pcre2_match_data_create_from_pattern(parse_regex->regex, NULL); |
2701 | 2.25M | if (*match) |
2702 | 2.25M | return pcre2_match(parse_regex->regex, (PCRE2_SPTR8)str, strlen(str), options, start_offset, |
2703 | 2.25M | *match, parse_regex->context); |
2704 | 0 | return -1; |
2705 | 2.25M | } |
2706 | | |
2707 | | void DetectParseFreeRegex(DetectParseRegex *r) |
2708 | 390k | { |
2709 | 390k | if (r->regex) { |
2710 | 327k | pcre2_code_free(r->regex); |
2711 | 327k | } |
2712 | 390k | if (r->context) { |
2713 | 327k | pcre2_match_context_free(r->context); |
2714 | 327k | } |
2715 | 390k | if (r->match) { |
2716 | 327k | pcre2_match_data_free(r->match); |
2717 | 327k | } |
2718 | 390k | } |
2719 | | |
2720 | | void DetectParseFreeRegexes(void) |
2721 | 0 | { |
2722 | 0 | DetectParseRegex *r = g_detect_parse_regex_list; |
2723 | 0 | while (r) { |
2724 | 0 | DetectParseRegex *next = r->next; |
2725 | |
|
2726 | 0 | DetectParseFreeRegex(r); |
2727 | |
|
2728 | 0 | SCFree(r); |
2729 | 0 | r = next; |
2730 | 0 | } |
2731 | 0 | g_detect_parse_regex_list = NULL; |
2732 | 0 | } |
2733 | | |
2734 | | /** \brief add regex and/or study to at exit free list |
2735 | | */ |
2736 | | void DetectParseRegexAddToFreeList(DetectParseRegex *detect_parse) |
2737 | 3.29k | { |
2738 | 3.29k | DetectParseRegex *r = SCCalloc(1, sizeof(*r)); |
2739 | 3.29k | if (r == NULL) { |
2740 | 0 | FatalError("failed to alloc memory for pcre free list"); |
2741 | 0 | } |
2742 | 3.29k | r->regex = detect_parse->regex; |
2743 | 3.29k | r->match = detect_parse->match; |
2744 | 3.29k | r->next = g_detect_parse_regex_list; |
2745 | 3.29k | g_detect_parse_regex_list = r; |
2746 | 3.29k | } |
2747 | | |
2748 | | bool DetectSetupParseRegexesOpts(const char *parse_str, DetectParseRegex *detect_parse, int opts) |
2749 | 3.29k | { |
2750 | 3.29k | int en; |
2751 | 3.29k | PCRE2_SIZE eo; |
2752 | | |
2753 | 3.29k | detect_parse->regex = |
2754 | 3.29k | pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL); |
2755 | 3.29k | if (detect_parse->regex == NULL) { |
2756 | 0 | PCRE2_UCHAR errbuffer[256]; |
2757 | 0 | pcre2_get_error_message(en, errbuffer, sizeof(errbuffer)); |
2758 | 0 | SCLogError("pcre compile of \"%s\" failed at " |
2759 | 0 | "offset %d: %s", |
2760 | 0 | parse_str, en, errbuffer); |
2761 | 0 | return false; |
2762 | 0 | } |
2763 | | |
2764 | 3.29k | detect_parse->context = pcre2_match_context_create(NULL); |
2765 | 3.29k | if (detect_parse->context == NULL) { |
2766 | 0 | SCLogError("pcre2 could not create match context"); |
2767 | 0 | pcre2_code_free(detect_parse->regex); |
2768 | 0 | detect_parse->regex = NULL; |
2769 | 0 | return false; |
2770 | 0 | } |
2771 | 3.29k | pcre2_set_match_limit(detect_parse->context, SC_MATCH_LIMIT_DEFAULT); |
2772 | 3.29k | pcre2_set_recursion_limit(detect_parse->context, SC_MATCH_LIMIT_RECURSION_DEFAULT); |
2773 | 3.29k | DetectParseRegexAddToFreeList(detect_parse); |
2774 | | |
2775 | 3.29k | return true; |
2776 | 3.29k | } |
2777 | | |
2778 | | DetectParseRegex *DetectSetupPCRE2(const char *parse_str, int opts) |
2779 | 432 | { |
2780 | 432 | int en; |
2781 | 432 | PCRE2_SIZE eo; |
2782 | 432 | DetectParseRegex *detect_parse = SCCalloc(1, sizeof(DetectParseRegex)); |
2783 | 432 | if (detect_parse == NULL) { |
2784 | 0 | return NULL; |
2785 | 0 | } |
2786 | | |
2787 | 432 | detect_parse->regex = |
2788 | 432 | pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL); |
2789 | 432 | if (detect_parse->regex == NULL) { |
2790 | 0 | PCRE2_UCHAR errbuffer[256]; |
2791 | 0 | pcre2_get_error_message(en, errbuffer, sizeof(errbuffer)); |
2792 | 0 | SCLogError("pcre2 compile of \"%s\" failed at " |
2793 | 0 | "offset %d: %s", |
2794 | 0 | parse_str, (int)eo, errbuffer); |
2795 | 0 | SCFree(detect_parse); |
2796 | 0 | return NULL; |
2797 | 0 | } |
2798 | 432 | detect_parse->match = pcre2_match_data_create_from_pattern(detect_parse->regex, NULL); |
2799 | | |
2800 | 432 | detect_parse->next = g_detect_parse_regex_list; |
2801 | 432 | g_detect_parse_regex_list = detect_parse; |
2802 | 432 | return detect_parse; |
2803 | 432 | } |
2804 | | |
2805 | | int SC_Pcre2SubstringCopy( |
2806 | | pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR *buffer, PCRE2_SIZE *bufflen) |
2807 | 534k | { |
2808 | 534k | int r = pcre2_substring_copy_bynumber(match_data, number, buffer, bufflen); |
2809 | 534k | if (r == PCRE2_ERROR_UNSET) { |
2810 | 89.3k | buffer[0] = 0; |
2811 | 89.3k | *bufflen = 0; |
2812 | 89.3k | return 0; |
2813 | 89.3k | } |
2814 | 445k | return r; |
2815 | 534k | } |
2816 | | |
2817 | | int SC_Pcre2SubstringGet( |
2818 | | pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR **bufferptr, PCRE2_SIZE *bufflen) |
2819 | 63.9k | { |
2820 | 63.9k | int r = pcre2_substring_get_bynumber(match_data, number, bufferptr, bufflen); |
2821 | 63.9k | if (r == PCRE2_ERROR_UNSET) { |
2822 | 21.4k | *bufferptr = NULL; |
2823 | 21.4k | *bufflen = 0; |
2824 | 21.4k | return 0; |
2825 | 21.4k | } |
2826 | 42.4k | return r; |
2827 | 63.9k | } |
2828 | | |
2829 | | void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse) |
2830 | 3.29k | { |
2831 | 3.29k | if (!DetectSetupParseRegexesOpts(parse_str, detect_parse, 0)) { |
2832 | 0 | FatalError("pcre compile and study failed"); |
2833 | 0 | } |
2834 | 3.29k | } |
2835 | | |
2836 | | |
2837 | | /* |
2838 | | * TESTS |
2839 | | */ |
2840 | | |
2841 | | #ifdef UNITTESTS |
2842 | | #include "detect-engine-alert.h" |
2843 | | #include "packet.h" |
2844 | | |
2845 | | static int SigParseTest01 (void) |
2846 | | { |
2847 | | int result = 1; |
2848 | | Signature *sig = NULL; |
2849 | | |
2850 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
2851 | | if (de_ctx == NULL) |
2852 | | goto end; |
2853 | | |
2854 | | sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)"); |
2855 | | if (sig == NULL) |
2856 | | result = 0; |
2857 | | |
2858 | | end: |
2859 | | if (sig != NULL) SigFree(de_ctx, sig); |
2860 | | if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); |
2861 | | return result; |
2862 | | } |
2863 | | |
2864 | | static int SigParseTest02 (void) |
2865 | | { |
2866 | | int result = 0; |
2867 | | Signature *sig = NULL; |
2868 | | DetectPort *port = NULL; |
2869 | | |
2870 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
2871 | | |
2872 | | if (de_ctx == NULL) |
2873 | | goto end; |
2874 | | |
2875 | | FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); |
2876 | | SCClassConfLoadClassificationConfigFile(de_ctx, fd); |
2877 | | |
2878 | | sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"ET MALWARE Suspicious 220 Banner on Local Port\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; sid:2003055; rev:4;)"); |
2879 | | if (sig == NULL) { |
2880 | | goto end; |
2881 | | } |
2882 | | |
2883 | | int r = DetectPortParse(de_ctx, &port, "0:20"); |
2884 | | if (r < 0) |
2885 | | goto end; |
2886 | | |
2887 | | if (DetectPortCmp(sig->sp, port) == PORT_EQ) { |
2888 | | result = 1; |
2889 | | } else { |
2890 | | DetectPortPrint(port); printf(" != "); DetectPortPrint(sig->sp); printf(": "); |
2891 | | } |
2892 | | |
2893 | | end: |
2894 | | if (port != NULL) |
2895 | | DetectPortCleanupList(de_ctx, port); |
2896 | | if (sig != NULL) |
2897 | | SigFree(de_ctx, sig); |
2898 | | if (de_ctx != NULL) |
2899 | | DetectEngineCtxFree(de_ctx); |
2900 | | return result; |
2901 | | } |
2902 | | |
2903 | | /** |
2904 | | * \test SigParseTest03 test for invalid direction operator in rule |
2905 | | */ |
2906 | | static int SigParseTest03 (void) |
2907 | | { |
2908 | | int result = 1; |
2909 | | Signature *sig = NULL; |
2910 | | |
2911 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
2912 | | if (de_ctx == NULL) |
2913 | | goto end; |
2914 | | |
2915 | | sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any <- !1.2.3.4 any (msg:\"SigParseTest03\"; sid:1;)"); |
2916 | | if (sig != NULL) { |
2917 | | result = 0; |
2918 | | printf("expected NULL got sig ptr %p: ",sig); |
2919 | | } |
2920 | | |
2921 | | end: |
2922 | | if (sig != NULL) SigFree(de_ctx, sig); |
2923 | | if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); |
2924 | | return result; |
2925 | | } |
2926 | | |
2927 | | static int SigParseTest04 (void) |
2928 | | { |
2929 | | int result = 1; |
2930 | | Signature *sig = NULL; |
2931 | | |
2932 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
2933 | | if (de_ctx == NULL) |
2934 | | goto end; |
2935 | | |
2936 | | sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024: -> !1.2.3.4 1024: (msg:\"SigParseTest04\"; sid:1;)"); |
2937 | | if (sig == NULL) |
2938 | | result = 0; |
2939 | | |
2940 | | end: |
2941 | | if (sig != NULL) SigFree(de_ctx, sig); |
2942 | | if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); |
2943 | | return result; |
2944 | | } |
2945 | | |
2946 | | /** \test Port validation */ |
2947 | | static int SigParseTest05 (void) |
2948 | | { |
2949 | | int result = 0; |
2950 | | Signature *sig = NULL; |
2951 | | |
2952 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
2953 | | if (de_ctx == NULL) |
2954 | | goto end; |
2955 | | |
2956 | | sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024:65536 -> !1.2.3.4 any (msg:\"SigParseTest05\"; sid:1;)"); |
2957 | | if (sig == NULL) { |
2958 | | result = 1; |
2959 | | } else { |
2960 | | printf("signature didn't fail to parse as we expected: "); |
2961 | | } |
2962 | | |
2963 | | end: |
2964 | | if (sig != NULL) SigFree(de_ctx, sig); |
2965 | | if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); |
2966 | | return result; |
2967 | | } |
2968 | | |
2969 | | /** \test Parsing bug debugging at 2010-03-18 */ |
2970 | | static int SigParseTest06 (void) |
2971 | | { |
2972 | | int result = 0; |
2973 | | Signature *sig = NULL; |
2974 | | |
2975 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
2976 | | if (de_ctx == NULL) |
2977 | | goto end; |
2978 | | |
2979 | | sig = SigInit(de_ctx, "alert tcp any any -> any any (flow:to_server; content:\"GET\"; nocase; http_method; uricontent:\"/uri/\"; nocase; content:\"Host|3A| abc\"; nocase; sid:1; rev:1;)"); |
2980 | | if (sig != NULL) { |
2981 | | result = 1; |
2982 | | } else { |
2983 | | printf("signature failed to parse: "); |
2984 | | } |
2985 | | |
2986 | | end: |
2987 | | if (sig != NULL) |
2988 | | SigFree(de_ctx, sig); |
2989 | | if (de_ctx != NULL) |
2990 | | DetectEngineCtxFree(de_ctx); |
2991 | | return result; |
2992 | | } |
2993 | | |
2994 | | /** |
2995 | | * \test Parsing duplicate sigs. |
2996 | | */ |
2997 | | static int SigParseTest07(void) |
2998 | | { |
2999 | | int result = 0; |
3000 | | |
3001 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3002 | | if (de_ctx == NULL) |
3003 | | goto end; |
3004 | | |
3005 | | DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)"); |
3006 | | DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)"); |
3007 | | |
3008 | | result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL); |
3009 | | |
3010 | | end: |
3011 | | if (de_ctx != NULL) |
3012 | | DetectEngineCtxFree(de_ctx); |
3013 | | return result; |
3014 | | } |
3015 | | |
3016 | | /** |
3017 | | * \test Parsing duplicate sigs. |
3018 | | */ |
3019 | | static int SigParseTest08(void) |
3020 | | { |
3021 | | int result = 0; |
3022 | | |
3023 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3024 | | if (de_ctx == NULL) |
3025 | | goto end; |
3026 | | |
3027 | | DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)"); |
3028 | | DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)"); |
3029 | | |
3030 | | result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL && |
3031 | | de_ctx->sig_list->rev == 2); |
3032 | | |
3033 | | end: |
3034 | | if (de_ctx != NULL) |
3035 | | DetectEngineCtxFree(de_ctx); |
3036 | | return result; |
3037 | | } |
3038 | | |
3039 | | /** |
3040 | | * \test Parsing duplicate sigs. |
3041 | | */ |
3042 | | static int SigParseTest09(void) |
3043 | | { |
3044 | | int result = 1; |
3045 | | |
3046 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3047 | | if (de_ctx == NULL) |
3048 | | goto end; |
3049 | | |
3050 | | DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)"); |
3051 | | DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)"); |
3052 | | DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:6;)"); |
3053 | | DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:4;)"); |
3054 | | DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)"); |
3055 | | result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 && |
3056 | | de_ctx->sig_list->rev == 2); |
3057 | | if (result == 0) |
3058 | | goto end; |
3059 | | result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 && |
3060 | | de_ctx->sig_list->next->rev == 6); |
3061 | | if (result == 0) |
3062 | | goto end; |
3063 | | |
3064 | | DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)"); |
3065 | | result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 && |
3066 | | de_ctx->sig_list->rev == 2); |
3067 | | if (result == 0) |
3068 | | goto end; |
3069 | | result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 && |
3070 | | de_ctx->sig_list->next->rev == 6); |
3071 | | if (result == 0) |
3072 | | goto end; |
3073 | | |
3074 | | DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:4;)"); |
3075 | | result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 && |
3076 | | de_ctx->sig_list->rev == 4); |
3077 | | if (result == 0) |
3078 | | goto end; |
3079 | | result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 && |
3080 | | de_ctx->sig_list->next->rev == 6); |
3081 | | if (result == 0) |
3082 | | goto end; |
3083 | | |
3084 | | end: |
3085 | | if (de_ctx != NULL) |
3086 | | DetectEngineCtxFree(de_ctx); |
3087 | | return result; |
3088 | | } |
3089 | | |
3090 | | /** |
3091 | | * \test Parsing duplicate sigs. |
3092 | | */ |
3093 | | static int SigParseTest10(void) |
3094 | | { |
3095 | | int result = 1; |
3096 | | |
3097 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3098 | | if (de_ctx == NULL) |
3099 | | goto end; |
3100 | | |
3101 | | DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)"); |
3102 | | DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)"); |
3103 | | DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:1;)"); |
3104 | | DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:4; rev:1;)"); |
3105 | | DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:5; rev:1;)"); |
3106 | | DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:2;)"); |
3107 | | DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)"); |
3108 | | |
3109 | | result &= ((de_ctx->sig_list->id == 2) && |
3110 | | (de_ctx->sig_list->next->id == 3) && |
3111 | | (de_ctx->sig_list->next->next->id == 5) && |
3112 | | (de_ctx->sig_list->next->next->next->id == 4) && |
3113 | | (de_ctx->sig_list->next->next->next->next->id == 1)); |
3114 | | |
3115 | | end: |
3116 | | if (de_ctx != NULL) |
3117 | | DetectEngineCtxFree(de_ctx); |
3118 | | return result; |
3119 | | } |
3120 | | |
3121 | | /** |
3122 | | * \test Parsing sig with trailing space(s) as reported by |
3123 | | * Morgan Cox on oisf-users. |
3124 | | */ |
3125 | | static int SigParseTest11(void) |
3126 | | { |
3127 | | int result = 0; |
3128 | | |
3129 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3130 | | if (de_ctx == NULL) |
3131 | | goto end; |
3132 | | |
3133 | | Signature *s = NULL; |
3134 | | |
3135 | | s = DetectEngineAppendSig(de_ctx, |
3136 | | "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking the http link\"; sid:1;) "); |
3137 | | if (s == NULL) { |
3138 | | printf("sig 1 didn't parse: "); |
3139 | | goto end; |
3140 | | } |
3141 | | |
3142 | | s = DetectEngineAppendSig(de_ctx, "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking " |
3143 | | "the http link\"; sid:2;) "); |
3144 | | if (s == NULL) { |
3145 | | printf("sig 2 didn't parse: "); |
3146 | | goto end; |
3147 | | } |
3148 | | |
3149 | | result = 1; |
3150 | | end: |
3151 | | if (de_ctx != NULL) |
3152 | | DetectEngineCtxFree(de_ctx); |
3153 | | return result; |
3154 | | } |
3155 | | |
3156 | | /** |
3157 | | * \test file_data with rawbytes |
3158 | | */ |
3159 | | static int SigParseTest12(void) |
3160 | | { |
3161 | | int result = 0; |
3162 | | |
3163 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3164 | | if (de_ctx == NULL) |
3165 | | goto end; |
3166 | | |
3167 | | Signature *s = NULL; |
3168 | | |
3169 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (file_data; content:\"abc\"; rawbytes; sid:1;)"); |
3170 | | if (s != NULL) { |
3171 | | printf("sig 1 should have given an error: "); |
3172 | | goto end; |
3173 | | } |
3174 | | |
3175 | | result = 1; |
3176 | | end: |
3177 | | if (de_ctx != NULL) |
3178 | | DetectEngineCtxFree(de_ctx); |
3179 | | return result; |
3180 | | } |
3181 | | |
3182 | | /** |
3183 | | * \test packet/stream sig |
3184 | | */ |
3185 | | static int SigParseTest13(void) |
3186 | | { |
3187 | | int result = 0; |
3188 | | |
3189 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3190 | | if (de_ctx == NULL) |
3191 | | goto end; |
3192 | | |
3193 | | Signature *s = NULL; |
3194 | | |
3195 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; sid:1;)"); |
3196 | | if (s == NULL) { |
3197 | | printf("sig 1 invalidated: failure"); |
3198 | | goto end; |
3199 | | } |
3200 | | |
3201 | | if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) { |
3202 | | printf("sig doesn't have stream flag set\n"); |
3203 | | goto end; |
3204 | | } |
3205 | | |
3206 | | if (s->flags & SIG_FLAG_REQUIRE_PACKET) { |
3207 | | printf("sig has packet flag set\n"); |
3208 | | goto end; |
3209 | | } |
3210 | | |
3211 | | result = 1; |
3212 | | |
3213 | | end: |
3214 | | if (de_ctx != NULL) |
3215 | | DetectEngineCtxFree(de_ctx); |
3216 | | return result; |
3217 | | } |
3218 | | |
3219 | | /** |
3220 | | * \test packet/stream sig |
3221 | | */ |
3222 | | static int SigParseTest14(void) |
3223 | | { |
3224 | | int result = 0; |
3225 | | |
3226 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3227 | | if (de_ctx == NULL) |
3228 | | goto end; |
3229 | | |
3230 | | Signature *s = NULL; |
3231 | | |
3232 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; dsize:>0; sid:1;)"); |
3233 | | if (s == NULL) { |
3234 | | printf("sig 1 invalidated: failure"); |
3235 | | goto end; |
3236 | | } |
3237 | | |
3238 | | if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) { |
3239 | | printf("sig doesn't have packet flag set\n"); |
3240 | | goto end; |
3241 | | } |
3242 | | |
3243 | | if (s->flags & SIG_FLAG_REQUIRE_STREAM) { |
3244 | | printf("sig has stream flag set\n"); |
3245 | | goto end; |
3246 | | } |
3247 | | |
3248 | | result = 1; |
3249 | | |
3250 | | end: |
3251 | | if (de_ctx != NULL) |
3252 | | DetectEngineCtxFree(de_ctx); |
3253 | | return result; |
3254 | | } |
3255 | | |
3256 | | /** |
3257 | | * \test packet/stream sig |
3258 | | */ |
3259 | | static int SigParseTest15(void) |
3260 | | { |
3261 | | int result = 0; |
3262 | | |
3263 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3264 | | if (de_ctx == NULL) |
3265 | | goto end; |
3266 | | |
3267 | | Signature *s = NULL; |
3268 | | |
3269 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:5; sid:1;)"); |
3270 | | if (s == NULL) { |
3271 | | printf("sig 1 invalidated: failure"); |
3272 | | goto end; |
3273 | | } |
3274 | | |
3275 | | if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) { |
3276 | | printf("sig doesn't have packet flag set\n"); |
3277 | | goto end; |
3278 | | } |
3279 | | |
3280 | | if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) { |
3281 | | printf("sig doesn't have stream flag set\n"); |
3282 | | goto end; |
3283 | | } |
3284 | | |
3285 | | result = 1; |
3286 | | |
3287 | | end: |
3288 | | if (de_ctx != NULL) |
3289 | | DetectEngineCtxFree(de_ctx); |
3290 | | return result; |
3291 | | } |
3292 | | |
3293 | | /** |
3294 | | * \test packet/stream sig |
3295 | | */ |
3296 | | static int SigParseTest16(void) |
3297 | | { |
3298 | | int result = 0; |
3299 | | |
3300 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3301 | | if (de_ctx == NULL) |
3302 | | goto end; |
3303 | | |
3304 | | Signature *s = NULL; |
3305 | | |
3306 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; depth:5; sid:1;)"); |
3307 | | if (s == NULL) { |
3308 | | printf("sig 1 invalidated: failure"); |
3309 | | goto end; |
3310 | | } |
3311 | | |
3312 | | if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) { |
3313 | | printf("sig doesn't have packet flag set\n"); |
3314 | | goto end; |
3315 | | } |
3316 | | |
3317 | | if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) { |
3318 | | printf("sig doesn't have stream flag set\n"); |
3319 | | goto end; |
3320 | | } |
3321 | | |
3322 | | result = 1; |
3323 | | |
3324 | | end: |
3325 | | if (de_ctx != NULL) |
3326 | | DetectEngineCtxFree(de_ctx); |
3327 | | return result; |
3328 | | } |
3329 | | |
3330 | | /** |
3331 | | * \test packet/stream sig |
3332 | | */ |
3333 | | static int SigParseTest17(void) |
3334 | | { |
3335 | | int result = 0; |
3336 | | |
3337 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3338 | | if (de_ctx == NULL) |
3339 | | goto end; |
3340 | | |
3341 | | Signature *s = NULL; |
3342 | | |
3343 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)"); |
3344 | | if (s == NULL) { |
3345 | | printf("sig 1 invalidated: failure"); |
3346 | | goto end; |
3347 | | } |
3348 | | |
3349 | | if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) { |
3350 | | printf("sig doesn't have packet flag set\n"); |
3351 | | goto end; |
3352 | | } |
3353 | | |
3354 | | if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) { |
3355 | | printf("sig doesn't have stream flag set\n"); |
3356 | | goto end; |
3357 | | } |
3358 | | |
3359 | | result = 1; |
3360 | | |
3361 | | end: |
3362 | | if (de_ctx != NULL) |
3363 | | DetectEngineCtxFree(de_ctx); |
3364 | | return result; |
3365 | | } |
3366 | | |
3367 | | /** \test sid value too large. Bug #779 */ |
3368 | | static int SigParseTest18 (void) |
3369 | | { |
3370 | | int result = 0; |
3371 | | |
3372 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3373 | | if (de_ctx == NULL) |
3374 | | goto end; |
3375 | | |
3376 | | if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:99999999999999999999;)") != NULL) |
3377 | | goto end; |
3378 | | |
3379 | | result = 1; |
3380 | | end: |
3381 | | if (de_ctx != NULL) |
3382 | | DetectEngineCtxFree(de_ctx); |
3383 | | return result; |
3384 | | } |
3385 | | |
3386 | | /** \test gid value too large. Related to bug #779 */ |
3387 | | static int SigParseTest19 (void) |
3388 | | { |
3389 | | int result = 0; |
3390 | | |
3391 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3392 | | if (de_ctx == NULL) |
3393 | | goto end; |
3394 | | |
3395 | | if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; gid:99999999999999999999;)") != NULL) |
3396 | | goto end; |
3397 | | |
3398 | | result = 1; |
3399 | | end: |
3400 | | if (de_ctx != NULL) |
3401 | | DetectEngineCtxFree(de_ctx); |
3402 | | return result; |
3403 | | } |
3404 | | |
3405 | | /** \test rev value too large. Related to bug #779 */ |
3406 | | static int SigParseTest20 (void) |
3407 | | { |
3408 | | int result = 0; |
3409 | | |
3410 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3411 | | if (de_ctx == NULL) |
3412 | | goto end; |
3413 | | |
3414 | | if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; rev:99999999999999999999;)") != NULL) |
3415 | | goto end; |
3416 | | |
3417 | | result = 1; |
3418 | | end: |
3419 | | if (de_ctx != NULL) |
3420 | | DetectEngineCtxFree(de_ctx); |
3421 | | return result; |
3422 | | } |
3423 | | |
3424 | | /** \test address parsing */ |
3425 | | static int SigParseTest21 (void) |
3426 | | { |
3427 | | int result = 0; |
3428 | | |
3429 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3430 | | if (de_ctx == NULL) |
3431 | | goto end; |
3432 | | |
3433 | | if (DetectEngineAppendSig(de_ctx, "alert tcp [1.2.3.4, 1.2.3.5] any -> !1.2.3.4 any (sid:1;)") == NULL) |
3434 | | goto end; |
3435 | | |
3436 | | result = 1; |
3437 | | end: |
3438 | | if (de_ctx != NULL) |
3439 | | DetectEngineCtxFree(de_ctx); |
3440 | | return result; |
3441 | | } |
3442 | | |
3443 | | /** \test address parsing */ |
3444 | | static int SigParseTest22 (void) |
3445 | | { |
3446 | | int result = 0; |
3447 | | |
3448 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3449 | | if (de_ctx == NULL) |
3450 | | goto end; |
3451 | | |
3452 | | if (DetectEngineAppendSig(de_ctx, "alert tcp [10.10.10.0/24, !10.10.10.247] any -> [10.10.10.0/24, !10.10.10.247] any (sid:1;)") == NULL) |
3453 | | goto end; |
3454 | | |
3455 | | result = 1; |
3456 | | end: |
3457 | | if (de_ctx != NULL) |
3458 | | DetectEngineCtxFree(de_ctx); |
3459 | | return result; |
3460 | | } |
3461 | | |
3462 | | /** |
3463 | | * \test rule ending in carriage return |
3464 | | */ |
3465 | | static int SigParseTest23(void) |
3466 | | { |
3467 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3468 | | FAIL_IF_NULL(de_ctx); |
3469 | | |
3470 | | Signature *s = NULL; |
3471 | | |
3472 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)\r"); |
3473 | | FAIL_IF_NULL(s); |
3474 | | |
3475 | | DetectEngineCtxFree(de_ctx); |
3476 | | PASS; |
3477 | | } |
3478 | | |
3479 | | /** \test Direction operator validation (invalid) */ |
3480 | | static int SigParseBidirecTest06 (void) |
3481 | | { |
3482 | | int result = 1; |
3483 | | Signature *sig = NULL; |
3484 | | |
3485 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3486 | | if (de_ctx == NULL) |
3487 | | goto end; |
3488 | | |
3489 | | sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any - 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); |
3490 | | if (sig == NULL) |
3491 | | result = 1; |
3492 | | |
3493 | | end: |
3494 | | if (sig != NULL) SigFree(de_ctx, sig); |
3495 | | if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); |
3496 | | return result; |
3497 | | } |
3498 | | |
3499 | | /** \test Direction operator validation (invalid) */ |
3500 | | static int SigParseBidirecTest07 (void) |
3501 | | { |
3502 | | int result = 1; |
3503 | | Signature *sig = NULL; |
3504 | | |
3505 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3506 | | if (de_ctx == NULL) |
3507 | | goto end; |
3508 | | |
3509 | | sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); |
3510 | | if (sig == NULL) |
3511 | | result = 1; |
3512 | | |
3513 | | end: |
3514 | | if (sig != NULL) SigFree(de_ctx, sig); |
3515 | | if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); |
3516 | | return result; |
3517 | | } |
3518 | | |
3519 | | /** \test Direction operator validation (invalid) */ |
3520 | | static int SigParseBidirecTest08 (void) |
3521 | | { |
3522 | | int result = 1; |
3523 | | Signature *sig = NULL; |
3524 | | |
3525 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3526 | | if (de_ctx == NULL) |
3527 | | goto end; |
3528 | | |
3529 | | sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any < 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); |
3530 | | if (sig == NULL) |
3531 | | result = 1; |
3532 | | |
3533 | | end: |
3534 | | if (sig != NULL) SigFree(de_ctx, sig); |
3535 | | if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); |
3536 | | return result; |
3537 | | } |
3538 | | |
3539 | | /** \test Direction operator validation (invalid) */ |
3540 | | static int SigParseBidirecTest09 (void) |
3541 | | { |
3542 | | int result = 1; |
3543 | | Signature *sig = NULL; |
3544 | | |
3545 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3546 | | if (de_ctx == NULL) |
3547 | | goto end; |
3548 | | |
3549 | | sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any > 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); |
3550 | | if (sig == NULL) |
3551 | | result = 1; |
3552 | | |
3553 | | end: |
3554 | | if (sig != NULL) SigFree(de_ctx, sig); |
3555 | | if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); |
3556 | | return result; |
3557 | | } |
3558 | | |
3559 | | /** \test Direction operator validation (invalid) */ |
3560 | | static int SigParseBidirecTest10 (void) |
3561 | | { |
3562 | | int result = 1; |
3563 | | Signature *sig = NULL; |
3564 | | |
3565 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3566 | | if (de_ctx == NULL) |
3567 | | goto end; |
3568 | | |
3569 | | sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); |
3570 | | if (sig == NULL) |
3571 | | result = 1; |
3572 | | |
3573 | | end: |
3574 | | if (sig != NULL) SigFree(de_ctx, sig); |
3575 | | if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); |
3576 | | return result; |
3577 | | } |
3578 | | |
3579 | | /** \test Direction operator validation (invalid) */ |
3580 | | static int SigParseBidirecTest11 (void) |
3581 | | { |
3582 | | int result = 1; |
3583 | | Signature *sig = NULL; |
3584 | | |
3585 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3586 | | if (de_ctx == NULL) |
3587 | | goto end; |
3588 | | |
3589 | | sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); |
3590 | | if (sig == NULL) |
3591 | | result = 1; |
3592 | | |
3593 | | end: |
3594 | | if (sig != NULL) SigFree(de_ctx, sig); |
3595 | | if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); |
3596 | | return result; |
3597 | | } |
3598 | | |
3599 | | /** \test Direction operator validation (invalid) */ |
3600 | | static int SigParseBidirecTest12 (void) |
3601 | | { |
3602 | | int result = 1; |
3603 | | Signature *sig = NULL; |
3604 | | |
3605 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3606 | | if (de_ctx == NULL) |
3607 | | goto end; |
3608 | | |
3609 | | sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); |
3610 | | if (sig == NULL) |
3611 | | result = 1; |
3612 | | |
3613 | | end: |
3614 | | if (sig != NULL) SigFree(de_ctx, sig); |
3615 | | if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); |
3616 | | return result; |
3617 | | } |
3618 | | |
3619 | | /** \test Direction operator validation (valid) */ |
3620 | | static int SigParseBidirecTest13 (void) |
3621 | | { |
3622 | | int result = 1; |
3623 | | Signature *sig = NULL; |
3624 | | |
3625 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3626 | | if (de_ctx == NULL) |
3627 | | goto end; |
3628 | | |
3629 | | sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); |
3630 | | if (sig != NULL) |
3631 | | result = 1; |
3632 | | |
3633 | | end: |
3634 | | if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); |
3635 | | return result; |
3636 | | } |
3637 | | |
3638 | | /** \test Direction operator validation (valid) */ |
3639 | | static int SigParseBidirecTest14 (void) |
3640 | | { |
3641 | | int result = 1; |
3642 | | Signature *sig = NULL; |
3643 | | |
3644 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3645 | | if (de_ctx == NULL) |
3646 | | goto end; |
3647 | | |
3648 | | sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); |
3649 | | if (sig != NULL) |
3650 | | result = 1; |
3651 | | |
3652 | | end: |
3653 | | if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); |
3654 | | return result; |
3655 | | } |
3656 | | |
3657 | | /** \test Ensure that we don't set bidirectional in a |
3658 | | * normal (one direction) Signature |
3659 | | */ |
3660 | | static int SigTestBidirec01 (void) |
3661 | | { |
3662 | | Signature *sig = NULL; |
3663 | | int result = 0; |
3664 | | |
3665 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3666 | | if (de_ctx == NULL) |
3667 | | goto end; |
3668 | | |
3669 | | sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 -> !1.2.3.4 any (msg:\"SigTestBidirec01\"; sid:1;)"); |
3670 | | if (sig == NULL) |
3671 | | goto end; |
3672 | | if (sig->next != NULL) |
3673 | | goto end; |
3674 | | if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) |
3675 | | goto end; |
3676 | | if (de_ctx->signum != 1) |
3677 | | goto end; |
3678 | | |
3679 | | result = 1; |
3680 | | |
3681 | | end: |
3682 | | if (de_ctx != NULL) { |
3683 | | SigCleanSignatures(de_ctx); |
3684 | | SigGroupCleanup(de_ctx); |
3685 | | DetectEngineCtxFree(de_ctx); |
3686 | | } |
3687 | | return result; |
3688 | | } |
3689 | | |
3690 | | /** \test Ensure that we set a bidirectional Signature correctly */ |
3691 | | static int SigTestBidirec02 (void) |
3692 | | { |
3693 | | int result = 0; |
3694 | | Signature *sig = NULL; |
3695 | | Signature *copy = NULL; |
3696 | | |
3697 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3698 | | if (de_ctx == NULL) |
3699 | | goto end; |
3700 | | |
3701 | | de_ctx->flags |= DE_QUIET; |
3702 | | |
3703 | | sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 <> !1.2.3.4 any (msg:\"SigTestBidirec02\"; sid:1;)"); |
3704 | | if (sig == NULL) |
3705 | | goto end; |
3706 | | if (de_ctx->sig_list != sig) |
3707 | | goto end; |
3708 | | if (!(sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC)) |
3709 | | goto end; |
3710 | | if (sig->next == NULL) |
3711 | | goto end; |
3712 | | if (de_ctx->signum != 2) |
3713 | | goto end; |
3714 | | copy = sig->next; |
3715 | | if (copy->next != NULL) |
3716 | | goto end; |
3717 | | if (!(copy->init_data->init_flags & SIG_FLAG_INIT_BIDIREC)) |
3718 | | goto end; |
3719 | | |
3720 | | result = 1; |
3721 | | |
3722 | | end: |
3723 | | if (de_ctx != NULL) { |
3724 | | SigCleanSignatures(de_ctx); |
3725 | | SigGroupCleanup(de_ctx); |
3726 | | DetectEngineCtxFree(de_ctx); |
3727 | | } |
3728 | | |
3729 | | return result; |
3730 | | } |
3731 | | |
3732 | | /** \test Ensure that we set a bidirectional Signature correctly |
3733 | | * and we install it with the rest of the signatures, checking |
3734 | | * also that it match with the correct addr directions |
3735 | | */ |
3736 | | static int SigTestBidirec03 (void) |
3737 | | { |
3738 | | int result = 0; |
3739 | | Signature *sig = NULL; |
3740 | | Packet *p = NULL; |
3741 | | |
3742 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3743 | | if (de_ctx == NULL) |
3744 | | goto end; |
3745 | | |
3746 | | de_ctx->flags |= DE_QUIET; |
3747 | | |
3748 | | const char *sigs[3]; |
3749 | | sigs[0] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)"; |
3750 | | sigs[1] = "alert tcp any any <> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)"; |
3751 | | sigs[2] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)"; |
3752 | | UTHAppendSigs(de_ctx, sigs, 3); |
3753 | | |
3754 | | /* Checking that bidirectional rules are set correctly */ |
3755 | | sig = de_ctx->sig_list; |
3756 | | if (sig == NULL) |
3757 | | goto end; |
3758 | | if (sig->next == NULL) |
3759 | | goto end; |
3760 | | if (sig->next->next == NULL) |
3761 | | goto end; |
3762 | | if (sig->next->next->next == NULL) |
3763 | | goto end; |
3764 | | if (sig->next->next->next->next != NULL) |
3765 | | goto end; |
3766 | | if (de_ctx->signum != 4) |
3767 | | goto end; |
3768 | | |
3769 | | uint8_t rawpkt1_ether[] = { |
3770 | | 0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c, |
3771 | | 0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00, |
3772 | | 0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06, |
3773 | | 0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8, |
3774 | | 0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2, |
3775 | | 0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18, |
3776 | | 0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45, |
3777 | | 0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50, |
3778 | | 0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f, |
3779 | | 0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e, |
3780 | | 0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d, |
3781 | | 0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67, |
3782 | | 0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a, |
3783 | | 0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30, |
3784 | | 0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55, |
3785 | | 0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20, |
3786 | | 0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20, |
3787 | | 0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72, |
3788 | | 0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e, |
3789 | | 0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b, |
3790 | | 0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39, |
3791 | | 0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75, |
3792 | | 0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34, |
3793 | | 0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79, |
3794 | | 0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f, |
3795 | | 0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34, |
3796 | | 0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74, |
3797 | | 0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68, |
3798 | | 0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c, |
3799 | | 0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f, |
3800 | | 0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d, |
3801 | | 0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63, |
3802 | | 0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d, |
3803 | | 0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c, |
3804 | | 0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e, |
3805 | | 0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70, |
3806 | | 0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61, |
3807 | | 0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75, |
3808 | | 0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30, |
3809 | | 0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65, |
3810 | | 0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64, |
3811 | | 0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69, |
3812 | | 0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74, |
3813 | | 0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70, |
3814 | | 0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65, |
3815 | | 0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38, |
3816 | | 0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74, |
3817 | | 0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e, |
3818 | | 0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e, |
3819 | | 0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d, |
3820 | | 0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33, |
3821 | | 0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e, |
3822 | | 0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20, |
3823 | | 0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69, |
3824 | | 0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */ |
3825 | | |
3826 | | FlowInitConfig(FLOW_QUIET); |
3827 | | p = UTHBuildPacketFromEth(rawpkt1_ether, sizeof(rawpkt1_ether)); |
3828 | | if (p == NULL) { |
3829 | | SCLogDebug("Error building packet"); |
3830 | | goto end; |
3831 | | } |
3832 | | UTHMatchPackets(de_ctx, &p, 1); |
3833 | | |
3834 | | uint32_t sids[3] = {1, 2, 3}; |
3835 | | uint32_t results[3] = {1, 1, 1}; |
3836 | | result = UTHCheckPacketMatchResults(p, sids, results, 1); |
3837 | | |
3838 | | end: |
3839 | | if (p != NULL) { |
3840 | | PacketRecycle(p); |
3841 | | SCFree(p); |
3842 | | } |
3843 | | FlowShutdown(); |
3844 | | return result; |
3845 | | } |
3846 | | |
3847 | | /** \test Ensure that we set a bidirectional Signature correctly |
3848 | | * and we install it with the rest of the signatures, checking |
3849 | | * also that it match with the correct addr directions |
3850 | | */ |
3851 | | static int SigTestBidirec04 (void) |
3852 | | { |
3853 | | int result = 0; |
3854 | | Signature *sig = NULL; |
3855 | | Packet *p = NULL; |
3856 | | |
3857 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
3858 | | if (de_ctx == NULL) |
3859 | | goto end; |
3860 | | |
3861 | | de_ctx->flags |= DE_QUIET; |
3862 | | |
3863 | | sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)"); |
3864 | | if (sig == NULL) |
3865 | | goto end; |
3866 | | sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> any any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)"); |
3867 | | if (sig == NULL) |
3868 | | goto end; |
3869 | | if ( !(sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC)) |
3870 | | goto end; |
3871 | | if (sig->next == NULL) |
3872 | | goto end; |
3873 | | if (sig->next->next == NULL) |
3874 | | goto end; |
3875 | | if (sig->next->next->next != NULL) |
3876 | | goto end; |
3877 | | if (de_ctx->signum != 3) |
3878 | | goto end; |
3879 | | |
3880 | | sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)"); |
3881 | | if (sig == NULL) |
3882 | | goto end; |
3883 | | if (sig->next == NULL) |
3884 | | goto end; |
3885 | | if (sig->next->next == NULL) |
3886 | | goto end; |
3887 | | if (sig->next->next->next == NULL) |
3888 | | goto end; |
3889 | | if (sig->next->next->next->next != NULL) |
3890 | | goto end; |
3891 | | if (de_ctx->signum != 4) |
3892 | | goto end; |
3893 | | |
3894 | | uint8_t rawpkt1_ether[] = { |
3895 | | 0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c, |
3896 | | 0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00, |
3897 | | 0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06, |
3898 | | 0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8, |
3899 | | 0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2, |
3900 | | 0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18, |
3901 | | 0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45, |
3902 | | 0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50, |
3903 | | 0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f, |
3904 | | 0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e, |
3905 | | 0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d, |
3906 | | 0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67, |
3907 | | 0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a, |
3908 | | 0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30, |
3909 | | 0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55, |
3910 | | 0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20, |
3911 | | 0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20, |
3912 | | 0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72, |
3913 | | 0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e, |
3914 | | 0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b, |
3915 | | 0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39, |
3916 | | 0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75, |
3917 | | 0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34, |
3918 | | 0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79, |
3919 | | 0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f, |
3920 | | 0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34, |
3921 | | 0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74, |
3922 | | 0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68, |
3923 | | 0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c, |
3924 | | 0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f, |
3925 | | 0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d, |
3926 | | 0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63, |
3927 | | 0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d, |
3928 | | 0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c, |
3929 | | 0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e, |
3930 | | 0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70, |
3931 | | 0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61, |
3932 | | 0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75, |
3933 | | 0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30, |
3934 | | 0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65, |
3935 | | 0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64, |
3936 | | 0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69, |
3937 | | 0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74, |
3938 | | 0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70, |
3939 | | 0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65, |
3940 | | 0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38, |
3941 | | 0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74, |
3942 | | 0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e, |
3943 | | 0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e, |
3944 | | 0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d, |
3945 | | 0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33, |
3946 | | 0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e, |
3947 | | 0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20, |
3948 | | 0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69, |
3949 | | 0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */ |
3950 | | |
3951 | | p = PacketGetFromAlloc(); |
3952 | | if (unlikely(p == NULL)) |
3953 | | return 0; |
3954 | | DecodeThreadVars dtv; |
3955 | | ThreadVars th_v; |
3956 | | DetectEngineThreadCtx *det_ctx; |
3957 | | |
3958 | | memset(&th_v, 0, sizeof(th_v)); |
3959 | | |
3960 | | FlowInitConfig(FLOW_QUIET); |
3961 | | DecodeEthernet(&th_v, &dtv, p, rawpkt1_ether, sizeof(rawpkt1_ether)); |
3962 | | DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); |
3963 | | |
3964 | | /* At this point we have a list of 4 signatures. The last one |
3965 | | is a copy of the second one. If we receive a packet |
3966 | | with source 192.168.1.1 80, all the sids should match */ |
3967 | | |
3968 | | SigGroupBuild(de_ctx); |
3969 | | SigMatchSignatures(&th_v, de_ctx, det_ctx, p); |
3970 | | |
3971 | | /* only sid 2 should match with a packet going to 192.168.1.1 port 80 */ |
3972 | | if (PacketAlertCheck(p, 1) <= 0 && PacketAlertCheck(p, 3) <= 0 && |
3973 | | PacketAlertCheck(p, 2) == 1) { |
3974 | | result = 1; |
3975 | | } |
3976 | | |
3977 | | if (p != NULL) { |
3978 | | PacketRecycle(p); |
3979 | | } |
3980 | | FlowShutdown(); |
3981 | | DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); |
3982 | | |
3983 | | end: |
3984 | | if (de_ctx != NULL) { |
3985 | | SigCleanSignatures(de_ctx); |
3986 | | SigGroupCleanup(de_ctx); |
3987 | | DetectEngineCtxFree(de_ctx); |
3988 | | } |
3989 | | |
3990 | | if (p != NULL) |
3991 | | SCFree(p); |
3992 | | return result; |
3993 | | } |
3994 | | |
3995 | | /** |
3996 | | * \test check that we don't allow invalid negation options |
3997 | | */ |
3998 | | static int SigParseTestNegation01 (void) |
3999 | | { |
4000 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
4001 | | FAIL_IF_NULL(de_ctx); |
4002 | | de_ctx->flags |= DE_QUIET; |
4003 | | Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp !any any -> any any (sid:1;)"); |
4004 | | FAIL_IF_NOT_NULL(s); |
4005 | | DetectEngineCtxFree(de_ctx); |
4006 | | PASS; |
4007 | | } |
4008 | | |
4009 | | /** |
4010 | | * \test check that we don't allow invalid negation options |
4011 | | */ |
4012 | | static int SigParseTestNegation02 (void) |
4013 | | { |
4014 | | int result = 0; |
4015 | | DetectEngineCtx *de_ctx; |
4016 | | Signature *s=NULL; |
4017 | | |
4018 | | de_ctx = DetectEngineCtxInit(); |
4019 | | if (de_ctx == NULL) |
4020 | | goto end; |
4021 | | de_ctx->flags |= DE_QUIET; |
4022 | | |
4023 | | s = SigInit(de_ctx,"alert tcp any !any -> any any (msg:\"SigTest41-02 src ip is !any \"; classtype:misc-activity; sid:410002; rev:1;)"); |
4024 | | if (s != NULL) { |
4025 | | SigFree(de_ctx, s); |
4026 | | goto end; |
4027 | | } |
4028 | | |
4029 | | result = 1; |
4030 | | end: |
4031 | | if (de_ctx != NULL) |
4032 | | DetectEngineCtxFree(de_ctx); |
4033 | | return result; |
4034 | | } |
4035 | | /** |
4036 | | * \test check that we don't allow invalid negation options |
4037 | | */ |
4038 | | static int SigParseTestNegation03 (void) |
4039 | | { |
4040 | | int result = 0; |
4041 | | DetectEngineCtx *de_ctx; |
4042 | | Signature *s=NULL; |
4043 | | |
4044 | | de_ctx = DetectEngineCtxInit(); |
4045 | | if (de_ctx == NULL) |
4046 | | goto end; |
4047 | | de_ctx->flags |= DE_QUIET; |
4048 | | |
4049 | | s = SigInit(de_ctx,"alert tcp any any -> any [80:!80] (msg:\"SigTest41-03 dst port [80:!80] \"; classtype:misc-activity; sid:410003; rev:1;)"); |
4050 | | if (s != NULL) { |
4051 | | SigFree(de_ctx, s); |
4052 | | goto end; |
4053 | | } |
4054 | | |
4055 | | result = 1; |
4056 | | end: |
4057 | | if (de_ctx != NULL) |
4058 | | DetectEngineCtxFree(de_ctx); |
4059 | | return result; |
4060 | | } |
4061 | | /** |
4062 | | * \test check that we don't allow invalid negation options |
4063 | | */ |
4064 | | static int SigParseTestNegation04 (void) |
4065 | | { |
4066 | | int result = 0; |
4067 | | DetectEngineCtx *de_ctx; |
4068 | | Signature *s=NULL; |
4069 | | |
4070 | | de_ctx = DetectEngineCtxInit(); |
4071 | | if (de_ctx == NULL) |
4072 | | goto end; |
4073 | | de_ctx->flags |= DE_QUIET; |
4074 | | |
4075 | | s = SigInit(de_ctx,"alert tcp any any -> any [80,!80] (msg:\"SigTest41-03 dst port [80:!80] \"; classtype:misc-activity; sid:410003; rev:1;)"); |
4076 | | if (s != NULL) { |
4077 | | SigFree(de_ctx, s); |
4078 | | goto end; |
4079 | | } |
4080 | | |
4081 | | result = 1; |
4082 | | end: |
4083 | | if (de_ctx != NULL) |
4084 | | DetectEngineCtxFree(de_ctx); |
4085 | | return result; |
4086 | | } |
4087 | | /** |
4088 | | * \test check that we don't allow invalid negation options |
4089 | | */ |
4090 | | static int SigParseTestNegation05 (void) |
4091 | | { |
4092 | | int result = 0; |
4093 | | DetectEngineCtx *de_ctx; |
4094 | | Signature *s=NULL; |
4095 | | |
4096 | | de_ctx = DetectEngineCtxInit(); |
4097 | | if (de_ctx == NULL) |
4098 | | goto end; |
4099 | | de_ctx->flags |= DE_QUIET; |
4100 | | |
4101 | | s = SigInit(de_ctx,"alert tcp any any -> [192.168.0.2,!192.168.0.2] any (msg:\"SigTest41-04 dst ip [192.168.0.2,!192.168.0.2] \"; classtype:misc-activity; sid:410004; rev:1;)"); |
4102 | | if (s != NULL) { |
4103 | | SigFree(de_ctx, s); |
4104 | | goto end; |
4105 | | } |
4106 | | |
4107 | | result = 1; |
4108 | | end: |
4109 | | if (de_ctx != NULL) |
4110 | | DetectEngineCtxFree(de_ctx); |
4111 | | return result; |
4112 | | } |
4113 | | /** |
4114 | | * \test check that we don't allow invalid negation options |
4115 | | */ |
4116 | | static int SigParseTestNegation06 (void) |
4117 | | { |
4118 | | int result = 0; |
4119 | | DetectEngineCtx *de_ctx; |
4120 | | Signature *s=NULL; |
4121 | | |
4122 | | de_ctx = DetectEngineCtxInit(); |
4123 | | if (de_ctx == NULL) |
4124 | | goto end; |
4125 | | de_ctx->flags |= DE_QUIET; |
4126 | | |
4127 | | s = SigInit(de_ctx,"alert tcp any any -> any [100:1000,!1:20000] (msg:\"SigTest41-05 dst port [100:1000,!1:20000] \"; classtype:misc-activity; sid:410005; rev:1;)"); |
4128 | | if (s != NULL) { |
4129 | | SigFree(de_ctx, s); |
4130 | | goto end; |
4131 | | } |
4132 | | |
4133 | | result = 1; |
4134 | | end: |
4135 | | if (de_ctx != NULL) |
4136 | | DetectEngineCtxFree(de_ctx); |
4137 | | return result; |
4138 | | } |
4139 | | |
4140 | | /** |
4141 | | * \test check that we don't allow invalid negation options |
4142 | | */ |
4143 | | static int SigParseTestNegation07 (void) |
4144 | | { |
4145 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
4146 | | FAIL_IF_NULL(de_ctx); |
4147 | | de_ctx->flags |= DE_QUIET; |
4148 | | Signature *s = DetectEngineAppendSig( |
4149 | | de_ctx, "alert tcp any any -> [192.168.0.2,!192.168.0.0/24] any (sid:410006;)"); |
4150 | | FAIL_IF_NOT_NULL(s); |
4151 | | DetectEngineCtxFree(de_ctx); |
4152 | | PASS; |
4153 | | } |
4154 | | |
4155 | | /** |
4156 | | * \test check valid negation bug 1079 |
4157 | | */ |
4158 | | static int SigParseTestNegation08 (void) |
4159 | | { |
4160 | | int result = 0; |
4161 | | DetectEngineCtx *de_ctx; |
4162 | | Signature *s=NULL; |
4163 | | |
4164 | | de_ctx = DetectEngineCtxInit(); |
4165 | | if (de_ctx == NULL) |
4166 | | goto end; |
4167 | | de_ctx->flags |= DE_QUIET; |
4168 | | |
4169 | | s = SigInit(de_ctx,"alert tcp any any -> [192.168.0.0/16,!192.168.0.0/24] any (sid:410006; rev:1;)"); |
4170 | | if (s == NULL) { |
4171 | | goto end; |
4172 | | } |
4173 | | |
4174 | | result = 1; |
4175 | | end: |
4176 | | if (de_ctx != NULL) |
4177 | | DetectEngineCtxFree(de_ctx); |
4178 | | return result; |
4179 | | } |
4180 | | |
4181 | | /** |
4182 | | * \test mpm |
4183 | | */ |
4184 | | static int SigParseTestMpm01 (void) |
4185 | | { |
4186 | | int result = 0; |
4187 | | Signature *sig = NULL; |
4188 | | |
4189 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
4190 | | if (de_ctx == NULL) |
4191 | | goto end; |
4192 | | |
4193 | | sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; sid:1;)"); |
4194 | | if (sig == NULL) { |
4195 | | printf("sig failed to init: "); |
4196 | | goto end; |
4197 | | } |
4198 | | |
4199 | | if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) { |
4200 | | printf("sig doesn't have content list: "); |
4201 | | goto end; |
4202 | | } |
4203 | | |
4204 | | result = 1; |
4205 | | end: |
4206 | | if (sig != NULL) |
4207 | | SigFree(de_ctx, sig); |
4208 | | DetectEngineCtxFree(de_ctx); |
4209 | | return result; |
4210 | | } |
4211 | | |
4212 | | /** |
4213 | | * \test mpm |
4214 | | */ |
4215 | | static int SigParseTestMpm02 (void) |
4216 | | { |
4217 | | int result = 0; |
4218 | | Signature *sig = NULL; |
4219 | | |
4220 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
4221 | | if (de_ctx == NULL) |
4222 | | goto end; |
4223 | | |
4224 | | sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; content:\"abcdef\"; sid:1;)"); |
4225 | | if (sig == NULL) { |
4226 | | printf("sig failed to init: "); |
4227 | | goto end; |
4228 | | } |
4229 | | |
4230 | | if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) { |
4231 | | printf("sig doesn't have content list: "); |
4232 | | goto end; |
4233 | | } |
4234 | | |
4235 | | result = 1; |
4236 | | end: |
4237 | | if (sig != NULL) |
4238 | | SigFree(de_ctx, sig); |
4239 | | DetectEngineCtxFree(de_ctx); |
4240 | | return result; |
4241 | | } |
4242 | | |
4243 | | /** |
4244 | | * \test test tls (app layer) rule |
4245 | | */ |
4246 | | static int SigParseTestAppLayerTLS01(void) |
4247 | | { |
4248 | | int result = 0; |
4249 | | DetectEngineCtx *de_ctx; |
4250 | | Signature *s=NULL; |
4251 | | |
4252 | | de_ctx = DetectEngineCtxInit(); |
4253 | | if (de_ctx == NULL) |
4254 | | goto end; |
4255 | | de_ctx->flags |= DE_QUIET; |
4256 | | |
4257 | | s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS01 \"; sid:410006; rev:1;)"); |
4258 | | if (s == NULL) { |
4259 | | printf("parsing sig failed: "); |
4260 | | goto end; |
4261 | | } |
4262 | | |
4263 | | if (s->alproto == 0) { |
4264 | | printf("alproto not set: "); |
4265 | | goto end; |
4266 | | } |
4267 | | |
4268 | | result = 1; |
4269 | | end: |
4270 | | if (s != NULL) |
4271 | | SigFree(de_ctx, s); |
4272 | | if (de_ctx != NULL) |
4273 | | DetectEngineCtxFree(de_ctx); |
4274 | | |
4275 | | return result; |
4276 | | } |
4277 | | |
4278 | | /** |
4279 | | * \test test tls (app layer) rule |
4280 | | */ |
4281 | | static int SigParseTestAppLayerTLS02(void) |
4282 | | { |
4283 | | int result = 0; |
4284 | | DetectEngineCtx *de_ctx; |
4285 | | Signature *s=NULL; |
4286 | | |
4287 | | de_ctx = DetectEngineCtxInit(); |
4288 | | if (de_ctx == NULL) |
4289 | | goto end; |
4290 | | de_ctx->flags |= DE_QUIET; |
4291 | | |
4292 | | s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS02 \"; tls.version:1.0; sid:410006; rev:1;)"); |
4293 | | if (s == NULL) { |
4294 | | printf("parsing sig failed: "); |
4295 | | goto end; |
4296 | | } |
4297 | | |
4298 | | if (s->alproto == 0) { |
4299 | | printf("alproto not set: "); |
4300 | | goto end; |
4301 | | } |
4302 | | |
4303 | | result = 1; |
4304 | | end: |
4305 | | if (s != NULL) |
4306 | | SigFree(de_ctx, s); |
4307 | | if (de_ctx != NULL) |
4308 | | DetectEngineCtxFree(de_ctx); |
4309 | | return result; |
4310 | | } |
4311 | | |
4312 | | /** |
4313 | | * \test test tls (app layer) rule |
4314 | | */ |
4315 | | static int SigParseTestAppLayerTLS03(void) |
4316 | | { |
4317 | | int result = 0; |
4318 | | DetectEngineCtx *de_ctx; |
4319 | | Signature *s=NULL; |
4320 | | |
4321 | | de_ctx = DetectEngineCtxInit(); |
4322 | | if (de_ctx == NULL) |
4323 | | goto end; |
4324 | | de_ctx->flags |= DE_QUIET; |
4325 | | |
4326 | | s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS03 \"; tls.version:2.5; sid:410006; rev:1;)"); |
4327 | | if (s != NULL) { |
4328 | | SigFree(de_ctx, s); |
4329 | | goto end; |
4330 | | } |
4331 | | |
4332 | | result = 1; |
4333 | | end: |
4334 | | if (de_ctx != NULL) |
4335 | | DetectEngineCtxFree(de_ctx); |
4336 | | return result; |
4337 | | } |
4338 | | |
4339 | | static int SigParseTestUnbalancedQuotes01(void) |
4340 | | { |
4341 | | DetectEngineCtx *de_ctx; |
4342 | | Signature *s; |
4343 | | |
4344 | | de_ctx = DetectEngineCtxInit(); |
4345 | | FAIL_IF_NULL(de_ctx); |
4346 | | de_ctx->flags |= DE_QUIET; |
4347 | | |
4348 | | s = SigInit(de_ctx, |
4349 | | "alert http any any -> any any (msg:\"SigParseTestUnbalancedQuotes01\"; " |
4350 | | "pcre:\"/\\/[a-z]+\\.php\\?[a-z]+?=\\d{7}&[a-z]+?=\\d{7,8}$/U\" " |
4351 | | "flowbits:set,et.exploitkitlanding; classtype:trojan-activity; sid:2017078; rev:5;)"); |
4352 | | FAIL_IF_NOT_NULL(s); |
4353 | | |
4354 | | PASS; |
4355 | | } |
4356 | | |
4357 | | static int SigParseTestContentGtDsize01(void) |
4358 | | { |
4359 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
4360 | | FAIL_IF_NULL(de_ctx); |
4361 | | de_ctx->flags |= DE_QUIET; |
4362 | | |
4363 | | Signature *s = SigInit(de_ctx, |
4364 | | "alert http any any -> any any (" |
4365 | | "dsize:21; content:\"0123456789001234567890|00 00|\"; " |
4366 | | "sid:1; rev:1;)"); |
4367 | | FAIL_IF_NOT_NULL(s); |
4368 | | |
4369 | | PASS; |
4370 | | } |
4371 | | |
4372 | | static int SigParseTestContentGtDsize02(void) |
4373 | | { |
4374 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
4375 | | FAIL_IF_NULL(de_ctx); |
4376 | | de_ctx->flags |= DE_QUIET; |
4377 | | |
4378 | | Signature *s = SigInit(de_ctx, |
4379 | | "alert http any any -> any any (" |
4380 | | "dsize:21; content:\"0123456789|00 00|\"; offset:10; " |
4381 | | "sid:1; rev:1;)"); |
4382 | | FAIL_IF_NOT_NULL(s); |
4383 | | |
4384 | | PASS; |
4385 | | } |
4386 | | |
4387 | | static int CountSigsWithSid(const DetectEngineCtx *de_ctx, const uint32_t sid) |
4388 | | { |
4389 | | int cnt = 0; |
4390 | | for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) { |
4391 | | if (sid == s->id) |
4392 | | cnt++; |
4393 | | } |
4394 | | return cnt; |
4395 | | } |
4396 | | |
4397 | | static int SigParseBidirWithSameSrcAndDest01(void) |
4398 | | { |
4399 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
4400 | | FAIL_IF_NULL(de_ctx); |
4401 | | de_ctx->flags |= DE_QUIET; |
4402 | | |
4403 | | Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any <> any any (sid:1;)"); |
4404 | | FAIL_IF_NULL(s); |
4405 | | FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 1); |
4406 | | FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC); |
4407 | | |
4408 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any [80, 81] <> any [81, 80] (sid:2;)"); |
4409 | | FAIL_IF_NULL(s); |
4410 | | FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 1); |
4411 | | FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC); |
4412 | | |
4413 | | s = DetectEngineAppendSig(de_ctx, |
4414 | | "alert tcp [1.2.3.4, 5.6.7.8] [80, 81] <> [5.6.7.8, 1.2.3.4] [81, 80] (sid:3;)"); |
4415 | | FAIL_IF_NULL(s); |
4416 | | FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 1); |
4417 | | FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC); |
4418 | | |
4419 | | DetectEngineCtxFree(de_ctx); |
4420 | | PASS; |
4421 | | } |
4422 | | |
4423 | | static int SigParseBidirWithSameSrcAndDest02(void) |
4424 | | { |
4425 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
4426 | | FAIL_IF_NULL(de_ctx); |
4427 | | de_ctx->flags |= DE_QUIET; |
4428 | | |
4429 | | // Source is a subset of destination |
4430 | | Signature *s = DetectEngineAppendSig( |
4431 | | de_ctx, "alert tcp 1.2.3.4 any <> [1.2.3.4, 5.6.7.8, ::1] any (sid:1;)"); |
4432 | | FAIL_IF_NULL(s); |
4433 | | FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 2); |
4434 | | FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC); |
4435 | | |
4436 | | // Source is a subset of destination |
4437 | | s = DetectEngineAppendSig( |
4438 | | de_ctx, "alert tcp [1.2.3.4, ::1] [80, 81, 82] <> [1.2.3.4, ::1] [80, 81] (sid:2;)"); |
4439 | | FAIL_IF_NULL(s); |
4440 | | FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 2); |
4441 | | FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC); |
4442 | | |
4443 | | // Source intersects with destination |
4444 | | s = DetectEngineAppendSig(de_ctx, |
4445 | | "alert tcp [1.2.3.4, ::1, ABCD:AAAA::1] [80] <> [1.2.3.4, ::1] [80, 81] (sid:3;)"); |
4446 | | FAIL_IF_NULL(s); |
4447 | | FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 2); |
4448 | | FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC); |
4449 | | |
4450 | | // mix in negation, these are the same |
4451 | | s = DetectEngineAppendSig( |
4452 | | de_ctx, "alert tcp [!1.2.3.4, 1.2.3.0/24] any <> [1.2.3.0/24, !1.2.3.4] any (sid:4;)"); |
4453 | | FAIL_IF_NULL(s); |
4454 | | FAIL_IF_NOT(CountSigsWithSid(de_ctx, 4) == 1); |
4455 | | FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC); |
4456 | | |
4457 | | // mix in negation, these are not the same |
4458 | | s = DetectEngineAppendSig( |
4459 | | de_ctx, "alert tcp [1.2.3.4, 1.2.3.0/24] any <> [1.2.3.0/24, !1.2.3.4] any (sid:5;)"); |
4460 | | FAIL_IF_NULL(s); |
4461 | | FAIL_IF_NOT(CountSigsWithSid(de_ctx, 5) == 2); |
4462 | | FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC); |
4463 | | |
4464 | | DetectEngineCtxFree(de_ctx); |
4465 | | PASS; |
4466 | | } |
4467 | | |
4468 | | static int SigParseTestActionReject(void) |
4469 | | { |
4470 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
4471 | | FAIL_IF_NULL(de_ctx); |
4472 | | |
4473 | | Signature *sig = DetectEngineAppendSig( |
4474 | | de_ctx, "reject tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)"); |
4475 | | #ifdef HAVE_LIBNET11 |
4476 | | FAIL_IF_NULL(sig); |
4477 | | FAIL_IF_NOT((sig->action & (ACTION_DROP | ACTION_REJECT)) == (ACTION_DROP | ACTION_REJECT)); |
4478 | | #else |
4479 | | FAIL_IF_NOT_NULL(sig); |
4480 | | #endif |
4481 | | |
4482 | | DetectEngineCtxFree(de_ctx); |
4483 | | PASS; |
4484 | | } |
4485 | | |
4486 | | static int SigParseTestActionDrop(void) |
4487 | | { |
4488 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
4489 | | FAIL_IF_NULL(de_ctx); |
4490 | | |
4491 | | Signature *sig = DetectEngineAppendSig( |
4492 | | de_ctx, "drop tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)"); |
4493 | | FAIL_IF_NULL(sig); |
4494 | | FAIL_IF_NOT(sig->action & ACTION_DROP); |
4495 | | |
4496 | | DetectEngineCtxFree(de_ctx); |
4497 | | PASS; |
4498 | | } |
4499 | | |
4500 | | #endif /* UNITTESTS */ |
4501 | | |
4502 | | #ifdef UNITTESTS |
4503 | | void DetectParseRegisterTests (void); |
4504 | | #include "tests/detect-parse.c" |
4505 | | #endif |
4506 | | |
4507 | | void SigParseRegisterTests(void) |
4508 | 0 | { |
4509 | | #ifdef UNITTESTS |
4510 | | DetectParseRegisterTests(); |
4511 | | |
4512 | | UtRegisterTest("SigParseTest01", SigParseTest01); |
4513 | | UtRegisterTest("SigParseTest02", SigParseTest02); |
4514 | | UtRegisterTest("SigParseTest03", SigParseTest03); |
4515 | | UtRegisterTest("SigParseTest04", SigParseTest04); |
4516 | | UtRegisterTest("SigParseTest05", SigParseTest05); |
4517 | | UtRegisterTest("SigParseTest06", SigParseTest06); |
4518 | | UtRegisterTest("SigParseTest07", SigParseTest07); |
4519 | | UtRegisterTest("SigParseTest08", SigParseTest08); |
4520 | | UtRegisterTest("SigParseTest09", SigParseTest09); |
4521 | | UtRegisterTest("SigParseTest10", SigParseTest10); |
4522 | | UtRegisterTest("SigParseTest11", SigParseTest11); |
4523 | | UtRegisterTest("SigParseTest12", SigParseTest12); |
4524 | | UtRegisterTest("SigParseTest13", SigParseTest13); |
4525 | | UtRegisterTest("SigParseTest14", SigParseTest14); |
4526 | | UtRegisterTest("SigParseTest15", SigParseTest15); |
4527 | | UtRegisterTest("SigParseTest16", SigParseTest16); |
4528 | | UtRegisterTest("SigParseTest17", SigParseTest17); |
4529 | | UtRegisterTest("SigParseTest18", SigParseTest18); |
4530 | | UtRegisterTest("SigParseTest19", SigParseTest19); |
4531 | | UtRegisterTest("SigParseTest20", SigParseTest20); |
4532 | | UtRegisterTest("SigParseTest21 -- address with space", SigParseTest21); |
4533 | | UtRegisterTest("SigParseTest22 -- address with space", SigParseTest22); |
4534 | | UtRegisterTest("SigParseTest23 -- carriage return", SigParseTest23); |
4535 | | |
4536 | | UtRegisterTest("SigParseBidirecTest06", SigParseBidirecTest06); |
4537 | | UtRegisterTest("SigParseBidirecTest07", SigParseBidirecTest07); |
4538 | | UtRegisterTest("SigParseBidirecTest08", SigParseBidirecTest08); |
4539 | | UtRegisterTest("SigParseBidirecTest09", SigParseBidirecTest09); |
4540 | | UtRegisterTest("SigParseBidirecTest10", SigParseBidirecTest10); |
4541 | | UtRegisterTest("SigParseBidirecTest11", SigParseBidirecTest11); |
4542 | | UtRegisterTest("SigParseBidirecTest12", SigParseBidirecTest12); |
4543 | | UtRegisterTest("SigParseBidirecTest13", SigParseBidirecTest13); |
4544 | | UtRegisterTest("SigParseBidirecTest14", SigParseBidirecTest14); |
4545 | | UtRegisterTest("SigTestBidirec01", SigTestBidirec01); |
4546 | | UtRegisterTest("SigTestBidirec02", SigTestBidirec02); |
4547 | | UtRegisterTest("SigTestBidirec03", SigTestBidirec03); |
4548 | | UtRegisterTest("SigTestBidirec04", SigTestBidirec04); |
4549 | | UtRegisterTest("SigParseTestNegation01", SigParseTestNegation01); |
4550 | | UtRegisterTest("SigParseTestNegation02", SigParseTestNegation02); |
4551 | | UtRegisterTest("SigParseTestNegation03", SigParseTestNegation03); |
4552 | | UtRegisterTest("SigParseTestNegation04", SigParseTestNegation04); |
4553 | | UtRegisterTest("SigParseTestNegation05", SigParseTestNegation05); |
4554 | | UtRegisterTest("SigParseTestNegation06", SigParseTestNegation06); |
4555 | | UtRegisterTest("SigParseTestNegation07", SigParseTestNegation07); |
4556 | | UtRegisterTest("SigParseTestNegation08", SigParseTestNegation08); |
4557 | | UtRegisterTest("SigParseTestMpm01", SigParseTestMpm01); |
4558 | | UtRegisterTest("SigParseTestMpm02", SigParseTestMpm02); |
4559 | | UtRegisterTest("SigParseTestAppLayerTLS01", SigParseTestAppLayerTLS01); |
4560 | | UtRegisterTest("SigParseTestAppLayerTLS02", SigParseTestAppLayerTLS02); |
4561 | | UtRegisterTest("SigParseTestAppLayerTLS03", SigParseTestAppLayerTLS03); |
4562 | | UtRegisterTest("SigParseTestUnbalancedQuotes01", SigParseTestUnbalancedQuotes01); |
4563 | | |
4564 | | UtRegisterTest("SigParseTestContentGtDsize01", |
4565 | | SigParseTestContentGtDsize01); |
4566 | | UtRegisterTest("SigParseTestContentGtDsize02", |
4567 | | SigParseTestContentGtDsize02); |
4568 | | |
4569 | | UtRegisterTest("SigParseBidirWithSameSrcAndDest01", |
4570 | | SigParseBidirWithSameSrcAndDest01); |
4571 | | UtRegisterTest("SigParseBidirWithSameSrcAndDest02", |
4572 | | SigParseBidirWithSameSrcAndDest02); |
4573 | | UtRegisterTest("SigParseTestActionReject", SigParseTestActionReject); |
4574 | | UtRegisterTest("SigParseTestActionDrop", SigParseTestActionDrop); |
4575 | | #endif /* UNITTESTS */ |
4576 | 0 | } |