1 /* Copyright (C) 2007-2020 Open Information Security Foundation
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
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.
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
21 * \author Victor Julien <victor@inliniac.net>
25 #include "suricata-common.h"
31 #include "detect-parse.h"
33 #include "detect-engine.h"
34 #include "detect-engine-mpm.h"
35 #include "detect-engine-state.h"
36 #include "detect-engine-prefilter.h"
37 #include "detect-engine-content-inspection.h"
38 #include "detect-file-data.h"
40 #include "app-layer-parser.h"
41 #include "app-layer-htp.h"
42 #include "app-layer-smtp.h"
46 #include "flow-util.h"
48 #include "util-debug.h"
49 #include "util-spm-bm.h"
50 #include "util-unittest.h"
51 #include "util-unittest-helper.h"
52 #include "util-file-decompression.h"
54 static int DetectFiledataSetup (DetectEngineCtx
*, Signature
*, const char *);
56 static void DetectFiledataRegisterTests(void);
58 static void DetectFiledataSetupCallback(const DetectEngineCtx
*de_ctx
,
60 static int g_file_data_buffer_id
= 0;
62 static inline HtpBody
*GetResponseBody(htp_tx_t
*tx
);
65 static InspectionBuffer
*HttpServerBodyGetDataCallback(DetectEngineThreadCtx
*det_ctx
,
66 const DetectEngineTransforms
*transforms
,
67 Flow
*f
, const uint8_t flow_flags
,
68 void *txv
, const int list_id
);
71 static int DetectEngineInspectFiledata(
72 DetectEngineCtx
*de_ctx
, DetectEngineThreadCtx
*det_ctx
,
73 const DetectEngineAppInspectionEngine
*engine
,
75 Flow
*f
, uint8_t flags
, void *alstate
, void *txv
, uint64_t tx_id
);
76 int PrefilterMpmFiledataRegister(DetectEngineCtx
*de_ctx
,
77 SigGroupHead
*sgh
, MpmCtx
*mpm_ctx
,
78 const DetectBufferMpmRegistery
*mpm_reg
, int list_id
);
80 static int DetectEngineInspectBufferHttpBody(DetectEngineCtx
*de_ctx
,
81 DetectEngineThreadCtx
*det_ctx
, const DetectEngineAppInspectionEngine
*engine
,
82 const Signature
*s
, Flow
*f
, uint8_t flags
, void *alstate
, void *txv
, uint64_t tx_id
);
85 * \brief Registration function for keyword: file_data
87 void DetectFiledataRegister(void)
89 sigmatch_table
[DETECT_FILE_DATA
].name
= "file.data";
90 sigmatch_table
[DETECT_FILE_DATA
].alias
= "file_data";
91 sigmatch_table
[DETECT_FILE_DATA
].desc
= "make content keywords match on file data";
92 sigmatch_table
[DETECT_FILE_DATA
].url
= "/rules/http-keywords.html#file-data";
93 sigmatch_table
[DETECT_FILE_DATA
].Setup
= DetectFiledataSetup
;
95 sigmatch_table
[DETECT_FILE_DATA
].RegisterTests
= DetectFiledataRegisterTests
;
97 sigmatch_table
[DETECT_FILE_DATA
].flags
= SIGMATCH_NOOPT
;
99 DetectAppLayerMpmRegister2("file_data", SIG_FLAG_TOSERVER
, 2,
100 PrefilterMpmFiledataRegister
, NULL
,
102 DetectAppLayerMpmRegister2("file_data", SIG_FLAG_TOCLIENT
, 2,
103 PrefilterGenericMpmRegister
,
104 HttpServerBodyGetDataCallback
,
105 ALPROTO_HTTP
, HTP_RESPONSE_BODY
);
106 DetectAppLayerMpmRegister2("file_data", SIG_FLAG_TOSERVER
, 2,
107 PrefilterMpmFiledataRegister
, NULL
,
109 DetectAppLayerMpmRegister2("file_data", SIG_FLAG_TOCLIENT
, 2,
110 PrefilterMpmFiledataRegister
, NULL
,
112 DetectAppLayerMpmRegister2("file_data", SIG_FLAG_TOSERVER
, 2,
113 PrefilterMpmFiledataRegister
, NULL
,
114 ALPROTO_HTTP2
, HTTP2StateDataClient
);
115 DetectAppLayerMpmRegister2("file_data", SIG_FLAG_TOCLIENT
, 2,
116 PrefilterMpmFiledataRegister
, NULL
,
117 ALPROTO_HTTP2
, HTTP2StateDataServer
);
119 DetectAppLayerInspectEngineRegister2("file_data", ALPROTO_HTTP
, SIG_FLAG_TOCLIENT
,
120 HTP_RESPONSE_BODY
, DetectEngineInspectBufferHttpBody
, HttpServerBodyGetDataCallback
);
121 DetectAppLayerInspectEngineRegister2("file_data",
122 ALPROTO_SMTP
, SIG_FLAG_TOSERVER
, 0,
123 DetectEngineInspectFiledata
, NULL
);
124 DetectBufferTypeRegisterSetupCallback("file_data",
125 DetectFiledataSetupCallback
);
126 DetectAppLayerInspectEngineRegister2("file_data",
127 ALPROTO_SMB
, SIG_FLAG_TOSERVER
, 0,
128 DetectEngineInspectFiledata
, NULL
);
129 DetectAppLayerInspectEngineRegister2("file_data",
130 ALPROTO_SMB
, SIG_FLAG_TOCLIENT
, 0,
131 DetectEngineInspectFiledata
, NULL
);
132 DetectAppLayerInspectEngineRegister2("file_data",
133 ALPROTO_HTTP2
, SIG_FLAG_TOSERVER
, HTTP2StateDataClient
,
134 DetectEngineInspectFiledata
, NULL
);
135 DetectAppLayerInspectEngineRegister2("file_data",
136 ALPROTO_HTTP2
, SIG_FLAG_TOCLIENT
, HTTP2StateDataServer
,
137 DetectEngineInspectFiledata
, NULL
);
139 DetectBufferTypeSetDescriptionByName("file_data",
140 "http response body, smb files or smtp attachments data");
142 g_file_data_buffer_id
= DetectBufferTypeGetByName("file_data");
145 #define FILEDATA_CONTENT_LIMIT 100000
146 #define FILEDATA_CONTENT_INSPECT_MIN_SIZE 32768
147 #define FILEDATA_CONTENT_INSPECT_WINDOW 4096
149 static void SetupDetectEngineConfig(DetectEngineCtx
*de_ctx
) {
150 if (de_ctx
->filedata_config_initialized
)
153 /* initialize default */
154 for (int i
= 0; i
< (int)ALPROTO_MAX
; i
++) {
155 de_ctx
->filedata_config
[i
].content_limit
= FILEDATA_CONTENT_LIMIT
;
156 de_ctx
->filedata_config
[i
].content_inspect_min_size
= FILEDATA_CONTENT_INSPECT_MIN_SIZE
;
157 de_ctx
->filedata_config
[i
].content_inspect_window
= FILEDATA_CONTENT_INSPECT_WINDOW
;
160 /* add protocol specific settings here */
163 de_ctx
->filedata_config
[ALPROTO_SMTP
].content_limit
= smtp_config
.content_limit
;
164 de_ctx
->filedata_config
[ALPROTO_SMTP
].content_inspect_min_size
= smtp_config
.content_inspect_min_size
;
165 de_ctx
->filedata_config
[ALPROTO_SMTP
].content_inspect_window
= smtp_config
.content_inspect_window
;
167 de_ctx
->filedata_config_initialized
= true;
170 static int DetectEngineInspectBufferHttpBody(DetectEngineCtx
*de_ctx
,
171 DetectEngineThreadCtx
*det_ctx
, const DetectEngineAppInspectionEngine
*engine
,
172 const Signature
*s
, Flow
*f
, uint8_t flags
, void *alstate
, void *txv
, uint64_t tx_id
)
174 const int list_id
= engine
->sm_list
;
175 const InspectionBuffer
*buffer
= InspectionBufferGet(det_ctx
, list_id
);
177 if (buffer
->inspect
== NULL
) {
178 SCLogDebug("running inspect on %d", list_id
);
180 eof
= (AppLayerParserGetStateProgress(f
->proto
, f
->alproto
, txv
, flags
) > engine
->progress
);
182 SCLogDebug("list %d mpm? %s transforms %p", engine
->sm_list
, engine
->mpm
? "true" : "false",
183 engine
->v2
.transforms
);
185 /* if prefilter didn't already run, we need to consider transformations */
186 const DetectEngineTransforms
*transforms
= NULL
;
188 transforms
= engine
->v2
.transforms
;
191 buffer
= engine
->v2
.GetData(det_ctx
, transforms
, f
, flags
, txv
, list_id
);
192 if (unlikely(buffer
== NULL
)) {
193 return eof
? DETECT_ENGINE_INSPECT_SIG_CANT_MATCH
: DETECT_ENGINE_INSPECT_SIG_NO_MATCH
;
197 const uint32_t data_len
= buffer
->inspect_len
;
198 const uint8_t *data
= buffer
->inspect
;
199 const uint64_t offset
= buffer
->inspect_offset
;
201 uint8_t ci_flags
= eof
? DETECT_CI_FLAGS_END
: 0;
202 ci_flags
|= (offset
== 0 ? DETECT_CI_FLAGS_START
: 0);
203 ci_flags
|= buffer
->flags
;
205 det_ctx
->discontinue_matching
= 0;
206 det_ctx
->buffer_offset
= 0;
207 det_ctx
->inspection_recursion_counter
= 0;
209 /* Inspect all the uricontents fetched on each
210 * transaction at the app layer */
211 int r
= DetectEngineContentInspection(de_ctx
, det_ctx
, s
, engine
->smd
, NULL
, f
, (uint8_t *)data
,
212 data_len
, offset
, ci_flags
, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE
);
214 /* move inspected tracker to end of the data. HtpBodyPrune will consider
215 * the window sizes when freeing data */
217 HtpBody
*body
= GetResponseBody(tx
);
218 body
->body_inspected
= body
->content_len_so_far
;
219 SCLogDebug("body->body_inspected now: %" PRIu64
, body
->body_inspected
);
222 return DETECT_ENGINE_INSPECT_SIG_MATCH
;
225 if (flags
& STREAM_TOSERVER
) {
226 if (AppLayerParserGetStateProgress(IPPROTO_TCP
, ALPROTO_HTTP
, txv
, flags
) >
228 return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH
;
230 if (AppLayerParserGetStateProgress(IPPROTO_TCP
, ALPROTO_HTTP
, txv
, flags
) >
232 return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH
;
234 return DETECT_ENGINE_INSPECT_SIG_NO_MATCH
;
238 * \brief this function is used to parse filedata options
239 * \brief into the current signature
241 * \param de_ctx pointer to the Detection Engine Context
242 * \param s pointer to the Current Signature
243 * \param str pointer to the user provided "filestore" option
245 * \retval 0 on Success
246 * \retval -1 on Failure
248 static int DetectFiledataSetup (DetectEngineCtx
*de_ctx
, Signature
*s
, const char *str
)
252 if (!DetectProtoContainsProto(&s
->proto
, IPPROTO_TCP
) ||
253 (s
->alproto
!= ALPROTO_UNKNOWN
&& s
->alproto
!= ALPROTO_HTTP
&&
254 s
->alproto
!= ALPROTO_SMTP
&& s
->alproto
!= ALPROTO_SMB
&&
255 s
->alproto
!= ALPROTO_HTTP2
)) {
256 SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS
, "rule contains conflicting keywords.");
260 if (s
->alproto
== ALPROTO_HTTP
&& (s
->init_data
->init_flags
& SIG_FLAG_INIT_FLOW
) &&
261 (s
->flags
& SIG_FLAG_TOSERVER
) && !(s
->flags
& SIG_FLAG_TOCLIENT
)) {
262 SCLogError(SC_ERR_INVALID_SIGNATURE
, "Can't use file_data with "
263 "flow:to_server or flow:from_client with http.");
267 if (s
->alproto
== ALPROTO_SMTP
&& (s
->init_data
->init_flags
& SIG_FLAG_INIT_FLOW
) &&
268 !(s
->flags
& SIG_FLAG_TOSERVER
) && (s
->flags
& SIG_FLAG_TOCLIENT
)) {
269 SCLogError(SC_ERR_INVALID_SIGNATURE
, "Can't use file_data with "
270 "flow:to_client or flow:from_server with smtp.");
274 if (DetectBufferSetActiveList(s
, DetectBufferTypeGetByName("file_data")) < 0)
277 s
->init_data
->init_flags
|= SIG_FLAG_INIT_FILEDATA
;
278 SetupDetectEngineConfig(de_ctx
);
282 static void DetectFiledataSetupCallback(const DetectEngineCtx
*de_ctx
,
285 if (s
->alproto
== ALPROTO_HTTP
|| s
->alproto
== ALPROTO_UNKNOWN
) {
286 AppLayerHtpEnableResponseBodyCallback();
290 /* server body needs to be inspected in sync with stream if possible */
291 s
->init_data
->init_flags
|= SIG_FLAG_INIT_NEED_FLUSH
;
293 SCLogDebug("callback invoked by %u", s
->id
);
296 /* HTTP based detection */
298 static inline HtpBody
*GetResponseBody(htp_tx_t
*tx
)
300 HtpTxUserData
*htud
= (HtpTxUserData
*)htp_tx_get_user_data(tx
);
302 SCLogDebug("no htud");
306 return &htud
->response_body
;
309 static InspectionBuffer
*HttpServerBodyGetDataCallback(DetectEngineThreadCtx
*det_ctx
,
310 const DetectEngineTransforms
*transforms
,
311 Flow
*f
, const uint8_t flow_flags
,
312 void *txv
, const int list_id
)
316 InspectionBuffer
*buffer
= InspectionBufferGet(det_ctx
, list_id
);
317 if (buffer
->inspect
!= NULL
)
321 HtpState
*htp_state
= f
->alstate
;
322 const uint8_t flags
= flow_flags
;
324 HtpBody
*body
= GetResponseBody(tx
);
330 if (body
->body_inspected
== body
->content_len_so_far
) {
331 SCLogDebug("no new data");
335 HtpBodyChunk
*cur
= body
->first
;
337 SCLogDebug("No http chunks to inspect for this transaction");
341 SCLogDebug("response.body_limit %u response_body.content_len_so_far %"PRIu64
342 ", response.inspect_min_size %"PRIu32
", EOF %s, progress > body? %s",
343 htp_state
->cfg
->response
.body_limit
,
344 body
->content_len_so_far
,
345 htp_state
->cfg
->response
.inspect_min_size
,
346 flags
& STREAM_EOF
? "true" : "false",
347 (AppLayerParserGetStateProgress(IPPROTO_TCP
, ALPROTO_HTTP
, tx
, flags
) > HTP_RESPONSE_BODY
) ? "true" : "false");
349 if (!htp_state
->cfg
->http_body_inline
) {
350 /* inspect the body if the transfer is complete or we have hit
351 * our body size limit */
352 if ((htp_state
->cfg
->response
.body_limit
== 0 ||
353 body
->content_len_so_far
< htp_state
->cfg
->response
.body_limit
) &&
354 body
->content_len_so_far
< htp_state
->cfg
->response
.inspect_min_size
&&
355 !(AppLayerParserGetStateProgress(IPPROTO_TCP
, ALPROTO_HTTP
, tx
, flags
) > HTP_RESPONSE_BODY
) &&
356 !(flags
& STREAM_EOF
)) {
357 SCLogDebug("we still haven't seen the entire response body. "
358 "Let's defer body inspection till we see the "
364 /* get the inspect buffer
366 * make sure that we have at least the configured inspect_win size.
367 * If we have more, take at least 1/4 of the inspect win size before
371 if (body
->body_inspected
> htp_state
->cfg
->response
.inspect_min_size
) {
372 BUG_ON(body
->content_len_so_far
< body
->body_inspected
);
373 uint64_t inspect_win
= body
->content_len_so_far
- body
->body_inspected
;
374 SCLogDebug("inspect_win %"PRIu64
, inspect_win
);
375 if (inspect_win
< htp_state
->cfg
->response
.inspect_window
) {
376 uint64_t inspect_short
= htp_state
->cfg
->response
.inspect_window
- inspect_win
;
377 if (body
->body_inspected
< inspect_short
)
380 offset
= body
->body_inspected
- inspect_short
;
382 offset
= body
->body_inspected
- (htp_state
->cfg
->response
.inspect_window
/ 4);
389 StreamingBufferGetDataAtOffset(body
->sb
,
390 &data
, &data_len
, offset
);
391 InspectionBufferSetup(buffer
, data
, data_len
);
392 buffer
->inspect_offset
= offset
;
394 /* built-in 'transformation' */
395 if (htp_state
->cfg
->swf_decompression_enabled
) {
396 int swf_file_type
= FileIsSwfFile(data
, data_len
);
397 if (swf_file_type
== FILE_SWF_ZLIB_COMPRESSION
||
398 swf_file_type
== FILE_SWF_LZMA_COMPRESSION
)
400 (void)FileSwfDecompression(data
, data_len
,
403 htp_state
->cfg
->swf_compression_type
,
404 htp_state
->cfg
->swf_decompress_depth
,
405 htp_state
->cfg
->swf_compress_depth
);
409 InspectionBufferApplyTransforms(buffer
, transforms
);
411 SCReturnPtr(buffer
, "InspectionBuffer");
414 /* file API based inspection */
416 static InspectionBuffer
*FiledataGetDataCallback(DetectEngineThreadCtx
*det_ctx
,
417 const DetectEngineTransforms
*transforms
,
418 Flow
*f
, uint8_t flow_flags
, File
*cur_file
,
419 int list_id
, int local_file_id
, bool first
)
423 InspectionBufferMultipleForList
*fb
= InspectionBufferGetMulti(det_ctx
, list_id
);
424 InspectionBuffer
*buffer
= InspectionBufferMultipleForListGet(fb
, local_file_id
);
427 if (!first
&& buffer
->inspect
!= NULL
)
430 const uint64_t file_size
= FileDataSize(cur_file
);
431 const DetectEngineCtx
*de_ctx
= det_ctx
->de_ctx
;
432 const uint32_t content_limit
= de_ctx
->filedata_config
[f
->alproto
].content_limit
;
433 const uint32_t content_inspect_min_size
= de_ctx
->filedata_config
[f
->alproto
].content_inspect_min_size
;
434 // TODO this is unused, is that right?
435 //const uint32_t content_inspect_window = de_ctx->filedata_config[f->alproto].content_inspect_window;
437 SCLogDebug("[list %d] first: %d, content_limit %u, content_inspect_min_size %u", list_id
,
438 first
? 1 : 0, content_limit
, content_inspect_min_size
);
440 SCLogDebug("[list %d] file %p size %" PRIu64
", state %d", list_id
, cur_file
, file_size
,
444 if (cur_file
->content_inspected
== file_size
) {
445 SCLogDebug("no new data");
449 if (file_size
== 0) {
450 SCLogDebug("no data to inspect for this transaction");
454 if ((content_limit
== 0 || file_size
< content_limit
) &&
455 file_size
< content_inspect_min_size
&&
456 !(flow_flags
& STREAM_EOF
) && !(cur_file
->state
> FILE_STATE_OPENED
)) {
457 SCLogDebug("we still haven't seen the entire content. "
458 "Let's defer content inspection till we see the "
466 StreamingBufferGetDataAtOffset(cur_file
->sb
,
468 cur_file
->content_inspected
);
469 InspectionBufferSetup(buffer
, data
, data_len
);
470 SCLogDebug("[list %d] [before] buffer offset %" PRIu64
"; buffer len %" PRIu32
471 "; data_len %" PRIu32
"; file_size %" PRIu64
,
472 list_id
, buffer
->inspect_offset
, buffer
->inspect_len
, data_len
, file_size
);
473 buffer
->inspect_offset
= cur_file
->content_inspected
;
474 InspectionBufferApplyTransforms(buffer
, transforms
);
475 SCLogDebug("[list %d] [after] buffer offset %" PRIu64
"; buffer len %" PRIu32
, list_id
,
476 buffer
->inspect_offset
, buffer
->inspect_len
);
478 SCLogDebug("[list %d] content_inspected %" PRIu64
, list_id
, cur_file
->content_inspected
);
480 SCLogDebug("[list %d] file_data buffer %p, data %p len %u offset %" PRIu64
, list_id
, buffer
,
481 buffer
->inspect
, buffer
->inspect_len
, buffer
->inspect_offset
);
483 SCReturnPtr(buffer
, "InspectionBuffer");
486 static int DetectEngineInspectFiledata(
487 DetectEngineCtx
*de_ctx
, DetectEngineThreadCtx
*det_ctx
,
488 const DetectEngineAppInspectionEngine
*engine
,
490 Flow
*f
, uint8_t flags
, void *alstate
, void *txv
, uint64_t tx_id
)
495 const DetectEngineTransforms
*transforms
= NULL
;
497 transforms
= engine
->v2
.transforms
;
500 FileContainer
*ffc
= AppLayerParserGetFiles(f
, flags
);
502 return DETECT_ENGINE_INSPECT_SIG_NO_MATCH
;
505 int local_file_id
= 0;
506 File
*file
= ffc
->head
;
507 for (; file
!= NULL
; file
= file
->next
) {
508 if (file
->txid
!= tx_id
)
511 InspectionBuffer
*buffer
= FiledataGetDataCallback(det_ctx
,
512 transforms
, f
, flags
, file
, engine
->sm_list
, local_file_id
, false);
516 bool eof
= (file
->state
== FILE_STATE_CLOSED
);
517 uint8_t ciflags
= eof
? DETECT_CI_FLAGS_END
: 0;
518 if (buffer
->inspect_offset
== 0)
519 ciflags
|= DETECT_CI_FLAGS_START
;
521 det_ctx
->buffer_offset
= 0;
522 det_ctx
->discontinue_matching
= 0;
523 det_ctx
->inspection_recursion_counter
= 0;
524 match
= DetectEngineContentInspection(de_ctx
, det_ctx
, s
, engine
->smd
,
526 (uint8_t *)buffer
->inspect
,
528 buffer
->inspect_offset
, ciflags
,
529 DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE
);
530 /* update inspected tracker */
531 file
->content_inspected
= buffer
->inspect_len
+ buffer
->inspect_offset
;
540 return DETECT_ENGINE_INSPECT_SIG_MATCH
;
542 return DETECT_ENGINE_INSPECT_SIG_NO_MATCH
;
545 typedef struct PrefilterMpmFiledata
{
547 const MpmCtx
*mpm_ctx
;
548 const DetectEngineTransforms
*transforms
;
549 } PrefilterMpmFiledata
;
551 /** \brief Filedata Filedata Mpm prefilter callback
553 * \param det_ctx detection engine thread ctx
554 * \param pectx inspection context
555 * \param p packet to inspect
556 * \param f flow to inspect
557 * \param txv tx to inspect
558 * \param idx transaction id
559 * \param flags STREAM_* flags including direction
561 static void PrefilterTxFiledata(DetectEngineThreadCtx
*det_ctx
,
563 Packet
*p
, Flow
*f
, void *txv
,
564 const uint64_t idx
, const uint8_t flags
)
568 const PrefilterMpmFiledata
*ctx
= (const PrefilterMpmFiledata
*)pectx
;
569 const MpmCtx
*mpm_ctx
= ctx
->mpm_ctx
;
570 const int list_id
= ctx
->list_id
;
572 FileContainer
*ffc
= AppLayerParserGetFiles(f
, flags
);
573 int local_file_id
= 0;
575 File
*file
= ffc
->head
;
576 for (; file
!= NULL
; file
= file
->next
) {
577 if (file
->txid
!= idx
)
580 InspectionBuffer
*buffer
= FiledataGetDataCallback(det_ctx
,
581 ctx
->transforms
, f
, flags
, file
, list_id
, local_file_id
, true);
585 if (buffer
->inspect_len
>= mpm_ctx
->minlen
) {
586 (void)mpm_table
[mpm_ctx
->mpm_type
].Search(mpm_ctx
,
587 &det_ctx
->mtcu
, &det_ctx
->pmq
,
588 buffer
->inspect
, buffer
->inspect_len
);
595 static void PrefilterMpmFiledataFree(void *ptr
)
600 int PrefilterMpmFiledataRegister(DetectEngineCtx
*de_ctx
,
601 SigGroupHead
*sgh
, MpmCtx
*mpm_ctx
,
602 const DetectBufferMpmRegistery
*mpm_reg
, int list_id
)
604 PrefilterMpmFiledata
*pectx
= SCCalloc(1, sizeof(*pectx
));
607 pectx
->list_id
= list_id
;
608 pectx
->mpm_ctx
= mpm_ctx
;
609 pectx
->transforms
= &mpm_reg
->transforms
;
611 return PrefilterAppendTxEngine(de_ctx
, sgh
, PrefilterTxFiledata
,
612 mpm_reg
->app_v2
.alproto
, mpm_reg
->app_v2
.tx_min_progress
,
613 pectx
, PrefilterMpmFiledataFree
, mpm_reg
->pname
);
617 #include "tests/detect-file-data.c"