@ -35,6 +35,7 @@
# include "app-layer-detect-proto.h"
# include "app-layer-protos.h"
# include "app-layer-parser.h"
# include "app-layer-frames.h"
# include "app-layer-smtp.h"
# include "util-enum.h"
@ -153,6 +154,43 @@ SCEnumCharMap smtp_decoder_event_table[] = {
{ NULL , - 1 } ,
} ;
enum SMTPFrameTypes {
SMTP_FRAME_COMMAND_LINE ,
SMTP_FRAME_DATA ,
SMTP_FRAME_RESPONSE_LINE ,
} ;
SCEnumCharMap smtp_frame_table [ ] = {
{
" command_line " ,
SMTP_FRAME_COMMAND_LINE ,
} ,
{
" data " ,
SMTP_FRAME_DATA ,
} ,
{
" response_line " ,
SMTP_FRAME_RESPONSE_LINE ,
} ,
{ NULL , - 1 } ,
} ;
static int SMTPGetFrameIdByName ( const char * frame_name )
{
int id = SCMapEnumNameToValue ( frame_name , smtp_frame_table ) ;
if ( id < 0 ) {
return - 1 ;
}
return id ;
}
static const char * SMTPGetFrameNameById ( const uint8_t frame_id )
{
const char * name = SCMapEnumValueToName ( frame_id , smtp_frame_table ) ;
return name ;
}
typedef struct SMTPThreadCtx_ {
MpmThreadCtx * smtp_mpm_thread_ctx ;
PrefilterRuleStore * pmq ;
@ -468,8 +506,8 @@ static void SMTPNewFile(SMTPTransaction *tx, File *file)
* \ retval - 1 Either when we don ' t have any new lines to supply anymore or
* on failure .
*/
static AppLayerResult SMTPGetLine (
SMTP State * state , SMTPInput * input , SMTP Line * line , uint16_t direction )
static AppLayerResult SMTPGetLine ( Flow * f , StreamSlice * slice , SMTPState * state , SMTPInput * input ,
SMTP Line * line , uint16_t direction )
{
SCEnter ( ) ;
@ -477,6 +515,26 @@ static AppLayerResult SMTPGetLine(
if ( input - > len < = 0 )
return APP_LAYER_ERROR ;
const uint8_t type = direction = = 0 ? SMTP_FRAME_COMMAND_LINE : SMTP_FRAME_RESPONSE_LINE ;
Frame * frame = AppLayerFrameGetLastOpenByType ( f , direction , type ) ;
if ( frame = = NULL ) {
if ( direction = = 0 & &
! ( state - > current_command = = SMTP_COMMAND_DATA & &
( state - > parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE ) ) ) {
frame = AppLayerFrameNewByPointer (
f , slice , input - > buf + input - > consumed , - 1 , 0 , SMTP_FRAME_COMMAND_LINE ) ;
/* can't set tx id before (possibly) creating it */
} else if ( direction = = 1 ) {
frame = AppLayerFrameNewByPointer (
f , slice , input - > buf + input - > consumed , - 1 , 1 , SMTP_FRAME_RESPONSE_LINE ) ;
if ( frame ! = NULL & & state - > curr_tx ) {
AppLayerFrameSetTxId ( frame , state - > curr_tx - > tx_id ) ;
}
}
}
SCLogDebug ( " frame %p " , frame ) ;
uint8_t * lf_idx = memchr ( input - > buf + input - > consumed , 0x0a , input - > len ) ;
bool discard_till_lf = ( direction = = 0 ) ? state - > discard_till_lf_ts : state - > discard_till_lf_tc ;
@ -503,6 +561,11 @@ static AppLayerResult SMTPGetLine(
input - > len - = line - > len ;
DEBUG_VALIDATE_BUG_ON ( ( input - > consumed + input - > len ) ! = input - > orig_len ) ;
line - > buf = input - > buf + o_consumed ;
if ( frame ! = NULL ) {
frame - > len = ( int64_t ) line - > len ;
}
if ( line - > len > = SMTP_LINE_BUFFER_LIMIT ) {
line - > len = SMTP_LINE_BUFFER_LIMIT ;
line - > delim_len = 0 ;
@ -1044,12 +1107,23 @@ static int NoNewTx(SMTPState *state, const SMTPLine *line)
* - 1 for errors and inconsistent states
* - 2 if MIME state could not be allocated
* */
static int SMTPProcessRequest (
SMTP State * state , Flow * f , AppLayerParserState * pstate , const SMTPLine * lin e)
static int SMTPProcessRequest ( SMTPState * state , Flow * f , AppLayerParserState * pstate ,
SMTP Input * input , const SMTPLine * line , const StreamSlice * slic e)
{
SCEnter ( ) ;
SMTPTransaction * tx = state - > curr_tx ;
Frame * frame = AppLayerFrameGetLastOpenByType ( f , 0 , SMTP_FRAME_COMMAND_LINE ) ;
if ( frame ) {
frame - > len = ( int64_t ) line - > len ;
} else {
if ( ! ( state - > current_command = = SMTP_COMMAND_DATA & &
( state - > parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE ) ) ) {
frame = AppLayerFrameNewByPointer (
f , slice , line - > buf , line - > len , 0 , SMTP_FRAME_COMMAND_LINE ) ;
}
}
/* If current input is to be discarded because it completes a long line,
* line ' s length and delimiter len are reset to 0. Skip processing this line .
* This line is only to get us out of the state where we should discard any
@ -1070,6 +1144,9 @@ static int SMTPProcessRequest(
StreamTcpReassemblySetMinInspectDepth ( f - > protoctx , STREAM_TOSERVER ,
smtp_config . content_inspect_min_size ) ;
}
if ( frame ! = NULL & & state - > curr_tx ) {
AppLayerFrameSetTxId ( frame , state - > curr_tx - > tx_id ) ;
}
state - > toserver_data_count + = ( line - > len + line - > delim_len ) ;
@ -1107,6 +1184,15 @@ static int SMTPProcessRequest(
}
}
state - > curr_tx - > is_data = true ;
Frame * data_frame = AppLayerFrameNewByPointer (
f , slice , input - > buf + input - > consumed , - 1 , 0 , SMTP_FRAME_DATA ) ;
if ( data_frame = = NULL ) {
SCLogDebug ( " data_frame %p - no data frame set up " , data_frame ) ;
} else {
AppLayerFrameSetTxId ( data_frame , state - > curr_tx - > tx_id ) ;
}
/* Enter immediately data mode without waiting for server reply */
if ( state - > parser_state & SMTP_PARSER_STATE_PIPELINING_SERVER ) {
state - > parser_state | = SMTP_PARSER_STATE_COMMAND_DATA_MODE ;
@ -1201,8 +1287,8 @@ static inline void ResetLine(SMTPLine *line)
* 1 for handing control over to GetLine
* - 1 for errors and inconsistent states
* */
static int SMTPPreProcessCommands (
S MTPState * state , Flow * f , AppLayerParserState * pstat e, SMTPInput * input , SMTPLine * line )
static int SMTPPreProcessCommands ( SMTPState * state , Flow * f , AppLayerParserState * pstate ,
S treamSlice * slic e, SMTPInput * input , SMTPLine * line )
{
DEBUG_VALIDATE_BUG_ON ( ( state - > parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE ) = = 0 ) ;
DEBUG_VALIDATE_BUG_ON ( line - > len ! = 0 ) ;
@ -1251,10 +1337,11 @@ static int SMTPPreProcessCommands(
if ( line - > len < 0 ) {
return - 1 ;
}
input - > consumed = total_consumed ;
input - > len - = current_line_consumed ;
DEBUG_VALIDATE_BUG_ON ( input - > consumed + input - > len ! = input - > orig_len ) ;
if ( SMTPProcessRequest ( state , f , pstate , line) = = - 1 ) {
if ( SMTPProcessRequest ( state , f , pstate , input, line, slic e) = = - 1 ) {
return - 1 ;
}
line_complete = false ;
@ -1263,8 +1350,13 @@ static int SMTPPreProcessCommands(
line - > delim_len = 0 ;
/* bail if `SMTPProcessRequest` ended the data mode */
if ( ( state - > parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE ) = = 0 )
if ( ( state - > parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE ) = = 0 ) {
Frame * data_frame = AppLayerFrameGetLastOpenByType ( f , 0 , SMTP_FRAME_DATA ) ;
if ( data_frame ) {
data_frame - > len = ( slice - > offset + input - > consumed ) - data_frame - > offset ;
}
break ;
}
}
}
return 0 ;
@ -1295,7 +1387,7 @@ static AppLayerResult SMTPParse(uint8_t direction, Flow *f, SMTPState *state,
if ( ( ( state - > current_command = = SMTP_COMMAND_DATA ) | |
( state - > current_command = = SMTP_COMMAND_BDAT ) ) & &
( state - > parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE ) ) {
int ret = SMTPPreProcessCommands ( state , f , pstate , & input, & line ) ;
int ret = SMTPPreProcessCommands ( state , f , pstate , & stream_slice, & input, & line ) ;
DEBUG_VALIDATE_BUG_ON ( ret ! = 0 & & ret ! = - 1 & & ret ! = 1 ) ;
if ( ret = = 0 & & input . consumed = = input . orig_len ) {
SCReturnStruct ( APP_LAYER_OK ) ;
@ -1303,9 +1395,9 @@ static AppLayerResult SMTPParse(uint8_t direction, Flow *f, SMTPState *state,
SCReturnStruct ( APP_LAYER_ERROR ) ;
}
}
AppLayerResult res = SMTPGetLine ( state, & input , & line , direction ) ;
AppLayerResult res = SMTPGetLine ( f, & stream_slice , state, & input , & line , direction ) ;
while ( res . status = = 0 ) {
int retval = SMTPProcessRequest ( state , f , pstate , & line) ;
int retval = SMTPProcessRequest ( state , f , pstate , & input, & line, & stream_slic e) ;
if ( retval ! = 0 )
SCReturnStruct ( APP_LAYER_ERROR ) ;
if ( line . delim_len = = 0 & & line . len = = SMTP_LINE_BUFFER_LIMIT ) {
@ -1326,7 +1418,7 @@ static AppLayerResult SMTPParse(uint8_t direction, Flow *f, SMTPState *state,
* In case of another boundary , the control should be passed to SMTPGetLine */
if ( ( input . len > 0 ) & & ( state - > current_command = = SMTP_COMMAND_DATA ) & &
( state - > parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE ) ) {
int ret = SMTPPreProcessCommands ( state , f , pstate , & input, & line ) ;
int ret = SMTPPreProcessCommands ( state , f , pstate , & stream_slice, & input, & line ) ;
DEBUG_VALIDATE_BUG_ON ( ret ! = 0 & & ret ! = - 1 & & ret ! = 1 ) ;
if ( ret = = 0 & & input . consumed = = input . orig_len ) {
SCReturnStruct ( APP_LAYER_OK ) ;
@ -1334,13 +1426,13 @@ static AppLayerResult SMTPParse(uint8_t direction, Flow *f, SMTPState *state,
SCReturnStruct ( APP_LAYER_ERROR ) ;
}
}
res = SMTPGetLine ( state, & input , & line , direction ) ;
res = SMTPGetLine ( f, & stream_slice , state, & input , & line , direction ) ;
}
if ( res . status = = 1 )
return res ;
/* toclient */
} else {
AppLayerResult res = SMTPGetLine ( state, & input , & line , direction ) ;
AppLayerResult res = SMTPGetLine ( f, & stream_slice , state, & input , & line , direction ) ;
while ( res . status = = 0 ) {
if ( SMTPProcessReply ( state , f , pstate , thread_data , & input , & line ) ! = 0 )
SCReturnStruct ( APP_LAYER_ERROR ) ;
@ -1352,7 +1444,7 @@ static AppLayerResult SMTPParse(uint8_t direction, Flow *f, SMTPState *state,
SMTPSetEvent ( state , SMTP_DECODER_EVENT_TRUNCATED_LINE ) ;
break ;
}
res = SMTPGetLine ( state, & input , & line , direction ) ;
res = SMTPGetLine ( f, & stream_slice , state, & input , & line , direction ) ;
}
if ( res . status = = 1 )
return res ;
@ -1752,6 +1844,8 @@ void RegisterSMTPParsers(void)
AppLayerParserRegisterTxDataFunc ( IPPROTO_TCP , ALPROTO_SMTP , SMTPGetTxData ) ;
AppLayerParserRegisterStateDataFunc ( IPPROTO_TCP , ALPROTO_SMTP , SMTPGetStateData ) ;
AppLayerParserRegisterStateProgressCompletionStatus ( ALPROTO_SMTP , 1 , 1 ) ;
AppLayerParserRegisterGetFrameFuncs (
IPPROTO_TCP , ALPROTO_SMTP , SMTPGetFrameIdByName , SMTPGetFrameNameById ) ;
} else {
SCLogInfo ( " Parser disabled for %s protocol. Protocol detection still on. " , proto_name ) ;
}