@ -1,4 +1,4 @@
/* Copyright (C) 2021 Open Information Security Foundation
/* Copyright (C) 2021 -2023 Open Information Security Foundation
*
* You can copy , redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
@ -40,12 +40,38 @@
# include "util-validate.h"
# include "util-print.h"
static InspectionBuffer * DetectFrame2InspectBuffer ( DetectEngineThreadCtx * det_ctx ,
const DetectEngineTransforms * transforms , Packet * p , const Frames * frames ,
const Frame * frame , const int list_id , const uint32_t idx , const bool first ) ;
struct FrameStreamData {
// shared between prefilter and inspect
DetectEngineThreadCtx * det_ctx ;
const DetectEngineTransforms * transforms ;
const Frame * frame ;
int list_id ;
uint32_t idx ; /**< multi buffer idx, incremented for each stream chunk */
// inspection only
const DetectEngineFrameInspectionEngine * inspect_engine ;
const Signature * s ;
int inspect_result ; // DETECT_ENGINE_INSPECT_SIG_MATCH / DETECT_ENGINE_INSPECT_SIG_NO_MATCH
Packet * p ;
// prefilter only
const MpmCtx * mpm_ctx ;
uint64_t requested_stream_offset ;
} ;
static bool SetupStreamCallbackData ( struct FrameStreamData * dst , const TcpSession * ssn ,
const TcpStream * stream , DetectEngineThreadCtx * det_ctx ,
const DetectEngineTransforms * transforms , const Frames * _frames , const Frame * frame ,
const int list_id , const bool eof ) ;
static bool BufferSetup ( struct FrameStreamData * fsd , InspectionBuffer * buffer , const uint8_t * input ,
const uint32_t input_len , const uint64_t input_offset ) ;
static void BufferSetupUdp ( InspectionBuffer * buffer , const Frame * frame , const Packet * p ,
const DetectEngineTransforms * transforms ) ;
void DetectRunPrefilterFrame ( DetectEngineThreadCtx * det_ctx , const SigGroupHead * sgh , Packet * p ,
const Frames * frames , const Frame * frame , const AppProto alproto , const uint32_t idx )
const Frames * frames , const Frame * frame , const AppProto alproto )
{
SCLogDebug ( " pcap_cnt % " PRIu64 , p - > pcap_cnt ) ;
PrefilterEngine * engine = sgh - > frame_engines ;
@ -54,7 +80,7 @@ void DetectRunPrefilterFrame(DetectEngineThreadCtx *det_ctx, const SigGroupHead
if ( engine - > alproto = = alproto & & engine - > ctx . frame_type = = frame - > type ) {
SCLogDebug ( " frame %p engine %p " , frame , engine ) ;
PREFILTER_PROFILING_START ( det_ctx ) ;
engine - > cb . PrefilterFrame ( det_ctx , engine - > pectx , p , frames , frame , idx );
engine - > cb . PrefilterFrame ( det_ctx , engine - > pectx , p , frames , frame );
PREFILTER_PROFILING_END ( det_ctx , engine - > gid ) ;
}
if ( engine - > is_last )
@ -72,6 +98,41 @@ typedef struct PrefilterMpmFrameCtx {
const DetectEngineTransforms * transforms ;
} PrefilterMpmFrameCtx ;
static int FrameStreamDataPrefilterFunc (
void * cb_data , const uint8_t * input , const uint32_t input_len , const uint64_t input_offset )
{
struct FrameStreamData * fsd = cb_data ;
SCLogDebug ( " prefilter: fsd %p { det_ctx:%p, transforms:%p, frame:%p, list_id:%d, idx:%u, "
" data_offset:% " PRIu64 " }, input: %p, input_len:%u, input_offset:% " PRIu64 ,
fsd , fsd - > det_ctx , fsd - > transforms , fsd - > frame , fsd - > list_id , fsd - > idx ,
fsd - > requested_stream_offset , input , input_len , input_offset ) ;
// PrintRawDataFp(stdout, input, input_len);
InspectionBuffer * buffer =
InspectionBufferMultipleForListGet ( fsd - > det_ctx , fsd - > list_id , fsd - > idx + + ) ;
if ( buffer = = NULL ) {
return 0 ;
}
SCLogDebug ( " buffer %p idx %u " , buffer , fsd - > idx ) ;
const int more_chunks = BufferSetup ( fsd , buffer , input , input_len , input_offset ) ;
const uint32_t data_len = buffer - > inspect_len ;
const uint8_t * data = buffer - > inspect ;
DetectEngineThreadCtx * det_ctx = fsd - > det_ctx ;
const MpmCtx * mpm_ctx = fsd - > mpm_ctx ;
if ( data ! = NULL & & data_len > = mpm_ctx - > minlen ) {
// PrintRawDataFp(stdout, data, data_len);
( void ) mpm_table [ mpm_ctx - > mpm_type ] . Search (
mpm_ctx , & det_ctx - > mtcu , & det_ctx - > pmq , data , data_len ) ;
SCLogDebug ( " det_ctx->pmq.rule_id_array_cnt %u " , det_ctx - > pmq . rule_id_array_cnt ) ;
PREFILTER_PROFILING_ADD_BYTES ( det_ctx , data_len ) ;
}
return more_chunks ;
}
/** \brief Generic Mpm prefilter callback
*
* \ param det_ctx detection engine thread ctx
@ -80,34 +141,62 @@ typedef struct PrefilterMpmFrameCtx {
* \ param pectx inspection context
*/
static void PrefilterMpmFrame ( DetectEngineThreadCtx * det_ctx , const void * pectx , Packet * p ,
const Frames * frames , const Frame * frame , const uint32_t idx )
const Frames * frames , const Frame * frame )
{
SCEnter ( ) ;
const PrefilterMpmFrameCtx * ctx = ( const PrefilterMpmFrameCtx * ) pectx ;
const MpmCtx * mpm_ctx = ctx - > mpm_ctx ;
SCLogDebug ( " running on list %d -> frame field type %u " , ctx - > list_id , frame - > type ) ;
// BUG_ON(frame->type != ctx->type);
InspectionBuffer * buffer = DetectFrame2InspectBuffer (
det_ctx , ctx - > transforms , p , frames , frame , ctx - > list_id , idx , true ) ;
if ( buffer = = NULL )
return ;
DEBUG_VALIDATE_BUG_ON ( frame - > len > = 0 & & buffer - > orig_len > frame - > len ) ;
const uint32_t data_len = buffer - > inspect_len ;
const uint8_t * data = buffer - > inspect ;
SCLogDebug ( " packet:% " PRIu64 " , prefilter running on list %d -> frame field type %u " ,
p - > pcap_cnt , ctx - > list_id , frame - > type ) ;
if ( p - > proto = = IPPROTO_UDP ) {
// TODO can we use single here? Could it conflict with TCP?
InspectionBuffer * buffer = InspectionBufferMultipleForListGet ( det_ctx , ctx - > list_id , 0 ) ;
if ( buffer = = NULL )
return ;
DEBUG_VALIDATE_BUG_ON ( frame - > offset > = p - > payload_len ) ;
if ( frame - > offset > = p - > payload_len )
return ;
BufferSetupUdp ( buffer , frame , p , ctx - > transforms ) ;
const uint32_t data_len = buffer - > inspect_len ;
const uint8_t * data = buffer - > inspect ;
// PrintRawDataFp(stdout, data, data_len);
if ( data ! = NULL & & data_len > = mpm_ctx - > minlen ) {
( void ) mpm_table [ mpm_ctx - > mpm_type ] . Search (
mpm_ctx , & det_ctx - > mtcu , & det_ctx - > pmq , data , data_len ) ;
SCLogDebug ( " det_ctx->pmq.rule_id_array_cnt %u " , det_ctx - > pmq . rule_id_array_cnt ) ;
PREFILTER_PROFILING_ADD_BYTES ( det_ctx , data_len ) ;
}
} else if ( p - > proto = = IPPROTO_TCP ) {
BUG_ON ( p - > flow - > protoctx = = NULL ) ;
TcpSession * ssn = p - > flow - > protoctx ;
TcpStream * stream ;
if ( PKT_IS_TOSERVER ( p ) ) {
stream = & ssn - > client ;
} else {
stream = & ssn - > server ;
}
const bool eof = ssn - > state = = TCP_CLOSED | | PKT_IS_PSEUDOPKT ( p ) ;
SCLogDebug ( " mpm'ing buffer: " ) ;
SCLogDebug ( " frame: %p " , frame ) ;
// PrintRawDataFp(stdout, data, MIN(32, data_len));
struct FrameStreamData fsd ;
memset ( & fsd , 0 , sizeof ( fsd ) ) ;
fsd . mpm_ctx = mpm_ctx ;
if ( data ! = NULL & & data_len > = mpm_ctx - > minlen ) {
( void ) mpm_table [ mpm_ctx - > mpm_type ] . Search (
mpm_ctx , & det_ctx - > mtcu , & det_ctx - > pmq , data , data_len ) ;
SCLogDebug ( " det_ctx->pmq.rule_id_array_cnt %u " , det_ctx - > pmq . rule_id_array_cnt ) ;
PREFILTER_PROFILING_ADD_BYTES ( det_ctx , data_len ) ;
if ( SetupStreamCallbackData ( & fsd , ssn , stream , det_ctx , ctx - > transforms , frames , frame ,
ctx - > list_id , eof ) = = true ) {
StreamReassembleForFrame ( ssn , stream , FrameStreamDataPrefilterFunc , & fsd ,
fsd . requested_stream_offset , eof ) ;
}
} else {
DEBUG_VALIDATE_BUG_ON ( 1 ) ;
}
SCLogDebug ( " packet:% " PRIu64
" , prefilter done running on list %d -> frame field type %u; have %u matches " ,
p - > pcap_cnt , ctx - > list_id , frame - > type , det_ctx - > pmq . rule_id_array_cnt ) ;
}
static void PrefilterMpmFrameFree ( void * ptr )
@ -136,7 +225,7 @@ int PrefilterGenericMpmFrameRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
}
int DetectRunFrameInspectRule ( ThreadVars * tv , DetectEngineThreadCtx * det_ctx , const Signature * s ,
Flow * f , Packet * p , const Frames * frames , const Frame * frame , const uint32_t idx )
Flow * f , Packet * p , const Frames * frames , const Frame * frame )
{
BUG_ON ( s - > frame_inspect = = NULL ) ;
@ -149,7 +238,7 @@ int DetectRunFrameInspectRule(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, co
// TODO there should be only one inspect engine for this frame, ever?
if ( e - > v1 . Callback ( det_ctx , e , s , p , frames , frame , idx ) = = true ) {
if ( e - > v1 . Callback ( det_ctx , e , s , p , frames , frame ) = = true ) {
SCLogDebug ( " sid %u: e %p Callback returned true " , s - > id , e ) ;
return true ;
}
@ -162,18 +251,9 @@ int DetectRunFrameInspectRule(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, co
return false ;
}
/** \internal
* \ brief setup buffer based on frame in UDP payload
*/
static InspectionBuffer * DetectFrame2InspectBufferUdp ( DetectEngineThreadCtx * det_ctx ,
const DetectEngineTransforms * transforms , Packet * p , InspectionBuffer * buffer ,
const Frames * frames , const Frame * frame , const int list_id , const uint32_t idx ,
const bool first )
static void BufferSetupUdp ( InspectionBuffer * buffer , const Frame * frame , const Packet * p ,
const DetectEngineTransforms * transforms )
{
DEBUG_VALIDATE_BUG_ON ( frame - > offset > = p - > payload_len ) ;
if ( frame - > offset > = p - > payload_len )
return NULL ;
uint8_t ci_flags = DETECT_CI_FLAGS_START ;
uint32_t frame_len ;
if ( frame - > len = = - 1 ) {
@ -194,43 +274,64 @@ static InspectionBuffer *DetectFrame2InspectBufferUdp(DetectEngineThreadCtx *det
p - > pcap_cnt , frame , frame - > id ,
AppLayerParserGetFrameNameById ( p - > flow - > proto , p - > flow - > alproto , frame - > type ) ,
frame - > offset , frame - > type , frame - > len ) ;
// PrintRawDataFp(stdout, data, MIN(64,data_len));
InspectionBufferSetupMulti ( buffer , transforms , data , data_len ) ;
buffer - > inspect_offset = 0 ;
buffer - > flags = ci_flags ;
return buffer ;
}
struct FrameStreamData {
DetectEngineThreadCtx * det_ctx ;
const DetectEngineTransforms * transforms ;
const Frame * frame ;
int list_id ;
uint32_t idx ;
uint64_t data_offset ;
uint64_t frame_offset ;
/** buffer is set if callback was successful */
InspectionBuffer * buffer ;
} ;
static int FrameStreamDataFunc (
void * cb_data , const uint8_t * input , const uint32_t input_len , const uint64_t offset )
/** \internal
* \ brief setup buffer based on frame in UDP payload
*/
static int DetectFrameInspectUdp ( DetectEngineThreadCtx * det_ctx ,
const DetectEngineFrameInspectionEngine * engine , const Signature * s ,
const DetectEngineTransforms * transforms , Packet * p , const Frames * _frames ,
const Frame * frame , const int list_id )
{
struct FrameStreamData * fsd = cb_data ;
SCLogDebug ( " fsd %p { det_ctx:%p, transforms:%p, frame:%p, list_id:%d, idx:%u, "
" data_offset:% " PRIu64 " , frame_offset:% " PRIu64
" }, input: %p, input_len:%u, offset:% " PRIu64 ,
fsd , fsd - > det_ctx , fsd - > transforms , fsd - > frame , fsd - > list_id , fsd - > idx ,
fsd - > data_offset , fsd - > frame_offset , input , input_len , offset ) ;
// PrintRawDataFp(stdout, input, input_len);
SCLogDebug ( " packet:% " PRIu64 " , inspect: s:%p s->id:%u, transforms:%p " , p - > pcap_cnt , s , s - > id ,
transforms ) ;
InspectionBuffer * buffer =
InspectionBufferMultipleForListGet ( fsd - > det_ctx , fsd - > list_id , fsd - > idx ) ;
BUG_ON ( buffer = = NULL ) ;
SCLogDebug ( " buffer %p " , buffer ) ;
// TODO can we use single here? Could it conflict with TCP?
InspectionBuffer * buffer = InspectionBufferMultipleForListGet ( det_ctx , list_id , 0 ) ;
if ( buffer = = NULL )
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH ;
DEBUG_VALIDATE_BUG_ON ( frame - > offset > = p - > payload_len ) ;
if ( frame - > offset > = p - > payload_len )
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH ;
if ( ! buffer - > initialized )
BufferSetupUdp ( buffer , frame , p , transforms ) ;
DEBUG_VALIDATE_BUG_ON ( ! buffer - > initialized ) ;
if ( buffer - > inspect = = NULL )
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH ;
const uint32_t data_len = buffer - > inspect_len ;
const uint8_t * data = buffer - > inspect ;
// PrintRawDataFp(stdout, data, data_len);
int r = DetectEngineContentInspection ( det_ctx - > de_ctx , det_ctx , s , engine - > smd , p , p - > flow ,
( uint8_t * ) data , data_len , 0 , buffer - > flags ,
DETECT_ENGINE_CONTENT_INSPECTION_MODE_FRAME ) ;
if ( r = = 1 ) {
SCLogDebug ( " match! " ) ;
return DETECT_ENGINE_INSPECT_SIG_MATCH ;
} else {
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH ;
}
}
/**
* \ retval bool true if callback should run again */
static bool BufferSetup ( struct FrameStreamData * fsd , InspectionBuffer * buffer , const uint8_t * input ,
const uint32_t input_len , const uint64_t input_offset )
{
const Frame * frame = fsd - > frame ;
/* so: relative to start of stream */
const uint64_t so_input_re = input_offset + input_len ;
const uint64_t so_frame_re =
frame - > offset + ( uint64_t ) frame - > len ; // TODO if eof, set to available data?
SCLogDebug ( " frame offset:% " PRIu64 , frame - > offset ) ;
const uint8_t * data = input ;
uint8_t ci_flags = 0 ;
@ -239,7 +340,7 @@ static int FrameStreamDataFunc(
/* fo: frame offset; offset relative to start of the frame */
uint64_t fo_inspect_offset = 0 ;
if ( frame - > offset = = 0 & & offset = = 0 ) {
if ( frame - > offset = = 0 & & input_ offset = = 0 ) {
ci_flags | = DETECT_CI_FLAGS_START ;
SCLogDebug ( " have frame data start " ) ;
@ -254,10 +355,10 @@ static int FrameStreamDataFunc(
}
} else {
const uint64_t so_frame_inspect_offset = frame - > inspect_progress + frame - > offset ;
const uint64_t so_inspect_offset = MAX ( offset, so_frame_inspect_offset ) ;
const uint64_t so_inspect_offset = MAX ( input_ offset, so_frame_inspect_offset ) ;
fo_inspect_offset = so_inspect_offset - frame - > offset ;
if ( frame - > offset > = offset) {
if ( frame - > offset > = input_ offset) {
ci_flags | = DETECT_CI_FLAGS_START ;
SCLogDebug ( " have frame data start " ) ;
}
@ -265,17 +366,12 @@ static int FrameStreamDataFunc(
if ( fo_inspect_offset > = ( uint64_t ) frame - > len ) {
SCLogDebug ( " data entirely past frame (% " PRIu64 " > % " PRIi64 " ) " ,
fo_inspect_offset , frame - > len ) ;
return 1 ;
return false ;
}
/* so: relative to start of stream */
const uint64_t so_frame_offset = frame - > offset ;
const uint64_t so_frame_re = so_frame_offset + ( uint64_t ) frame - > len ;
const uint64_t so_input_re = offset + input_len ;
/* in: relative to start of input data */
BUG_ON ( so_inspect_offset < offset) ;
const uint32_t in_data_offset = so_inspect_offset - offset;
BUG_ON ( so_inspect_offset < input_offset ) ;
const uint32_t in_data_offset = so_inspect_offset - input_offset ;
data + = in_data_offset ;
uint32_t in_data_excess = 0 ;
@ -287,58 +383,127 @@ static int FrameStreamDataFunc(
data_len = input_len - in_data_offset - in_data_excess ;
} else {
/* in: relative to start of input data */
BUG_ON ( so_inspect_offset < offset) ;
const uint32_t in_data_offset = so_inspect_offset - offset;
BUG_ON ( so_inspect_offset < input_ offset) ;
const uint32_t in_data_offset = so_inspect_offset - input_ offset;
data + = in_data_offset ;
data_len = input_len - in_data_offset ;
}
}
// PrintRawDataFp(stdout, data, data_len);
SCLogDebug ( " fsd->transforms %p " , fsd - > transforms ) ;
InspectionBufferSetupMulti ( buffer , fsd - > transforms , data , data_len ) ;
SCLogDebug ( " inspect_offset % " PRIu64 , fo_inspect_offset ) ;
buffer - > inspect_offset = fo_inspect_offset ;
buffer - > flags = ci_flags ;
fsd - > buffer = buffer ;
fsd - > det_ctx - > frame_inspect_progress =
MAX ( fo_inspect_offset + data_len , fsd - > det_ctx - > frame_inspect_progress ) ;
return 1 ; // for now only the first chunk
if ( frame - > len > = 0 & & so_input_re > = so_frame_re ) {
SCLogDebug ( " have the full frame, we can set progress accordingly (% " PRIu64 " > % " PRIu64
" ) " ,
so_input_re , so_frame_re ) ;
fsd - > det_ctx - > frame_inspect_progress =
MAX ( fo_inspect_offset + data_len , fsd - > det_ctx - > frame_inspect_progress ) ;
} else {
fsd - > det_ctx - > frame_inspect_progress =
MAX ( fo_inspect_offset + data_len , fsd - > det_ctx - > frame_inspect_progress ) ;
/* in IPS mode keep a sliding window */
const bool ips = StreamTcpInlineMode ( ) ;
if ( ips ) {
if ( fsd - > det_ctx - > frame_inspect_progress < 2500 )
fsd - > det_ctx - > frame_inspect_progress = 0 ;
else
fsd - > det_ctx - > frame_inspect_progress - = 2500 ;
}
SCLogDebug ( " ips %s inspect_progress % " PRIu64 , BOOL2STR ( ips ) ,
fsd - > det_ctx - > frame_inspect_progress ) ;
}
/* keep going as long as there is possibly still data for this frame */
const bool ret = ( frame - > len > = 0 & & so_input_re > = so_frame_re ) ;
SCLogDebug ( " buffer set up, more to do: %s " , BOOL2STR ( ret ) ) ;
return ret ;
}
static InspectionBuffer * DetectFrame2InspectBuffer ( DetectEngineThreadCtx * det_ctx ,
const DetectEngineTransforms * transforms , Packet * p , const Frames * frames ,
const Frame * frame , const int list_id , const uint32_t idx , const bool first )
static int FrameStreamDataInspectFunc (
void * cb_data , const uint8_t * input , const uint32_t input_len , const uint64_t input_offset )
{
// TODO do we really need multiple buffer support here?
InspectionBuffer * buffer = InspectionBufferMultipleForListGet ( det_ctx , list_id , idx ) ;
if ( buffer = = NULL )
return NULL ;
if ( ! first & & buffer - > inspect ! = NULL )
return buffer ;
struct FrameStreamData * fsd = cb_data ;
SCLogDebug ( " inspect: fsd %p { det_ctx:%p, transforms:%p, s:%p, s->id:%u, frame:%p, list_id:%d, "
" idx:%u, "
" requested_stream_offset:% " PRIu64
" }, input: %p, input_len:%u, input_offset:% " PRIu64 ,
fsd , fsd - > det_ctx , fsd - > transforms , fsd - > s , fsd - > s - > id , fsd - > frame , fsd - > list_id ,
fsd - > idx , fsd - > requested_stream_offset , input , input_len , input_offset ) ;
// PrintRawDataFp(stdout, input, input_len);
BUG_ON ( p - > flow = = NULL ) ;
InspectionBuffer * buffer =
InspectionBufferMultipleForListGet ( fsd - > det_ctx , fsd - > list_id , fsd - > idx + + ) ;
if ( buffer = = NULL ) {
return 0 ;
}
SCLogDebug ( " buffer %p idx %u " , buffer , fsd - > idx ) ;
if ( p - > proto = = IPPROTO_UDP ) {
return DetectFrame2InspectBufferUdp (
det_ctx , transforms , p , buffer , frames , frame , list_id , idx , first ) ;
/* if we've not done so already, set up the buffer */
int more_chunks = 1 ;
if ( ! buffer - > initialized ) {
more_chunks = BufferSetup ( fsd , buffer , input , input_len , input_offset ) ;
}
DEBUG_VALIDATE_BUG_ON ( ! buffer - > initialized ) ;
if ( buffer - > inspect = = NULL ) {
return more_chunks ;
}
BUG_ON ( p - > flow - > protoctx = = NULL ) ;
TcpSession * ssn = p - > flow - > protoctx ;
TcpStream * stream ;
if ( PKT_IS_TOSERVER ( p ) ) {
stream = & ssn - > client ;
const uint32_t data_len = buffer - > inspect_len ;
const uint8_t * data = buffer - > inspect ;
const uint64_t data_offset = buffer - > inspect_offset ;
DetectEngineThreadCtx * det_ctx = fsd - > det_ctx ;
det_ctx - > discontinue_matching = 0 ;
det_ctx - > buffer_offset = 0 ;
det_ctx - > inspection_recursion_counter = 0 ;
const DetectEngineFrameInspectionEngine * engine = fsd - > inspect_engine ;
const Signature * s = fsd - > s ;
Packet * p = fsd - > p ;
# ifdef DEBUG
const uint8_t ci_flags = buffer - > flags ;
SCLogDebug ( " frame %p offset % " PRIu64 " type %u len % " PRIi64
" ci_flags %02x (start:%s, end:%s) " ,
fsd - > frame , fsd - > frame - > offset , fsd - > frame - > type , fsd - > frame - > len , ci_flags ,
( ci_flags & DETECT_CI_FLAGS_START ) ? " true " : " false " ,
( ci_flags & DETECT_CI_FLAGS_END ) ? " true " : " false " ) ;
SCLogDebug ( " buffer %p offset % " PRIu64 " len %u ci_flags %02x (start:%s, end:%s) " , buffer ,
buffer - > inspect_offset , buffer - > inspect_len , ci_flags ,
( ci_flags & DETECT_CI_FLAGS_START ) ? " true " : " false " ,
( ci_flags & DETECT_CI_FLAGS_END ) ? " true " : " false " ) ;
// PrintRawDataFp(stdout, data, data_len);
// PrintRawDataFp(stdout, data, MIN(64, data_len));
# endif
BUG_ON ( fsd - > frame - > len > 0 & & ( int64_t ) data_len > fsd - > frame - > len ) ;
int r = DetectEngineContentInspection ( det_ctx - > de_ctx , det_ctx , s , engine - > smd , p , p - > flow ,
( uint8_t * ) data , data_len , data_offset , buffer - > flags ,
DETECT_ENGINE_CONTENT_INSPECTION_MODE_FRAME ) ;
if ( r = = 1 ) {
SCLogDebug ( " DETECT_ENGINE_INSPECT_SIG_MATCH " ) ;
fsd - > inspect_result = DETECT_ENGINE_INSPECT_SIG_MATCH ;
} else {
stream = & ssn - > server ;
SCLogDebug ( " DETECT_ENGINE_INSPECT_SIG_NO_MATCH " ) ;
}
return more_chunks ;
}
SCLogDebug ( " frame % " PRIi64 " , len % " PRIi64 " , offset % " PRIu64 , frame - > id , frame - > len ,
frame - > offset ) ;
static bool SetupStreamCallbackData ( struct FrameStreamData * dst , const TcpSession * ssn ,
const TcpStream * stream , DetectEngineThreadCtx * det_ctx ,
const DetectEngineTransforms * transforms , const Frames * _frames , const Frame * frame ,
const int list_id , const bool eof )
{
SCLogDebug ( " frame % " PRIi64 " , len % " PRIi64 " , offset % " PRIu64 " , inspect_progress % " PRIu64 ,
frame - > id , frame - > len , frame - > offset , frame - > inspect_progress ) ;
const uint64_t frame_offset = frame - > offset ;
const bool eof = ssn - > state = = TCP_CLOSED | | PKT_IS_PSEUDOPKT ( p ) ;
const uint64_t usable = StreamTcpGetUsable ( stream , eof ) ;
const uint64_t usable = StreamDataRightEdge ( stream , eof ) ;
if ( usable < = frame_offset )
return NULL ;
return false ;
uint64_t want = frame - > inspect_progress ;
if ( frame - > len = = - 1 ) {
@ -356,26 +521,31 @@ static InspectionBuffer *DetectFrame2InspectBuffer(DetectEngineThreadCtx *det_ct
}
}
const bool ips = StreamTcpInlineMode ( ) ;
const uint64_t have = usable ;
if ( have < want ) {
if ( ! ips & & have < want ) {
SCLogDebug ( " wanted % " PRIu64 " bytes, got % " PRIu64 , want , have ) ;
return NULL ;
return false ;
}
const uint64_t available_data = usable - STREAM_BASE_OFFSET ( stream ) ;
SCLogDebug ( " check inspection for having 2500 bytes: % " PRIu64 , available_data ) ;
if ( ! eof & & available_data < 2500 & & ( frame - > len < 0 | | frame - > len > ( int64_t ) available_data ) ) {
if ( ! ips & & ! eof & & available_data < 2500 & &
( frame - > len < 0 | | frame - > len > ( int64_t ) available_data ) ) {
SCLogDebug ( " skip inspection until we have 2500 bytes (have % " PRIu64 " ) " , available_data ) ;
return NULL ;
return false ;
}
const uint64_t offset = MAX ( STREAM_BASE_OFFSET ( stream ) , frame - > offset ) ;
struct FrameStreamData fsd = { det_ctx , transforms , frame , list_id , idx ,
STREAM_BASE_OFFSET ( stream ) , MAX ( frame - > inspect_progress , frame - > offset ) , NULL } ;
StreamReassembleForFrame ( ssn , stream , FrameStreamDataFunc , & fsd , offset , eof ) ;
const uint64_t offset =
MAX ( STREAM_BASE_OFFSET ( stream ) , frame - > offset + frame - > inspect_progress ) ;
return fsd . buffer ;
dst - > det_ctx = det_ctx ;
dst - > transforms = transforms ;
dst - > frame = frame ;
dst - > list_id = list_id ;
dst - > requested_stream_offset = offset ;
return true ;
}
/**
@ -392,56 +562,48 @@ static InspectionBuffer *DetectFrame2InspectBuffer(DetectEngineThreadCtx *det_ct
*/
int DetectEngineInspectFrameBufferGeneric ( DetectEngineThreadCtx * det_ctx ,
const DetectEngineFrameInspectionEngine * engine , const Signature * s , Packet * p ,
const Frames * frames , const Frame * frame , const uint32_t idx )
const Frames * frames , const Frame * frame )
{
const int list_id = engine - > sm_list ;
SCLogDebug ( " running inspect on %d " , list_id ) ;
SCLogDebug ( " list %d transforms %p " , engine - > sm_list , engine - > v1 . transforms ) ;
/* if prefilter didn't already run, we need to consider transformations */
const DetectEngineTransforms * transforms = NULL ;
if ( ! engine - > mpm ) {
transforms = engine - > v1 . transforms ;
}
const int list_id = engine - > sm_list ;
SCLogDebug ( " running inspect on %d " , list_id ) ;
const InspectionBuffer * buffer =
DetectFrame2InspectBuffer ( det_ctx , transforms , p , frames , frame , list_id , idx , false ) ;
if ( unlikely ( buffer = = NULL ) ) {
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH ;
if ( p - > proto = = IPPROTO_UDP ) {
return DetectFrameInspectUdp ( det_ctx , engine , s , transforms , p , frames , frame , list_id ) ;
}
DEBUG_VALIDATE_BUG_ON ( p - > proto ! = IPPROTO_TCP ) ;
const uint32_t data_len = buffer - > inspect_len ;
const uint8_t * data = buffer - > inspect ;
const uint64_t offset = buffer - > inspect_offset ;
SCLogDebug ( " packet:% " PRIu64 " , frame->id:% " PRIu64
" , list:%d, transforms:%p, s:%p, s->id:%u, engine:%p " ,
p - > pcap_cnt , frame - > id , engine - > sm_list , engine - > v1 . transforms , s , s - > id , engine ) ;
det_ctx - > discontinue_matching = 0 ;
det_ctx - > buffer_offset = 0 ;
det_ctx - > inspection_recursion_counter = 0 ;
# ifdef DEBUG
const uint8_t ci_flags = buffer - > flags ;
SCLogDebug ( " frame %p offset % " PRIu64 " type %u len % " PRIi64
" ci_flags %02x (start:%s, end:%s) " ,
frame , frame - > offset , frame - > type , frame - > len , ci_flags ,
( ci_flags & DETECT_CI_FLAGS_START ) ? " true " : " false " ,
( ci_flags & DETECT_CI_FLAGS_END ) ? " true " : " false " ) ;
SCLogDebug ( " buffer %p offset % " PRIu64 " len %u ci_flags %02x (start:%s, end:%s) " , buffer ,
buffer - > inspect_offset , buffer - > inspect_len , ci_flags ,
( ci_flags & DETECT_CI_FLAGS_START ) ? " true " : " false " ,
( ci_flags & DETECT_CI_FLAGS_END ) ? " true " : " false " ) ;
// PrintRawDataFp(stdout, data, data_len);
// PrintRawDataFp(stdout, data, MIN(64, data_len));
# endif
BUG_ON ( frame - > len > 0 & & ( int64_t ) data_len > frame - > len ) ;
// TODO don't call if matching needs frame end and DETECT_CI_FLAGS_END not set
// TODO same for start
int r = DetectEngineContentInspection ( det_ctx - > de_ctx , det_ctx , s , engine - > smd , p , p - > flow ,
( uint8_t * ) data , data_len , offset , buffer - > flags ,
DETECT_ENGINE_CONTENT_INSPECTION_MODE_FRAME ) ;
if ( r = = 1 ) {
return DETECT_ENGINE_INSPECT_SIG_MATCH ;
BUG_ON ( p - > flow - > protoctx = = NULL ) ;
TcpSession * ssn = p - > flow - > protoctx ;
TcpStream * stream ;
if ( PKT_IS_TOSERVER ( p ) ) {
stream = & ssn - > client ;
} else {
stream = & ssn - > server ;
}
const bool eof = ssn - > state = = TCP_CLOSED | | PKT_IS_PSEUDOPKT ( p ) ;
struct FrameStreamData fsd ;
memset ( & fsd , 0 , sizeof ( fsd ) ) ;
fsd . inspect_engine = engine ;
fsd . s = s ;
fsd . inspect_result = DETECT_ENGINE_INSPECT_SIG_NO_MATCH ;
fsd . p = p ;
if ( SetupStreamCallbackData (
& fsd , ssn , stream , det_ctx , transforms , frames , frame , list_id , eof ) = = false ) {
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH ;
}
StreamReassembleForFrame (
ssn , stream , FrameStreamDataInspectFunc , & fsd , fsd . requested_stream_offset , eof ) ;
return fsd . inspect_result ;
}