diff --git a/rust/src/applayertemplate/template.rs b/rust/src/applayertemplate/template.rs index 2c96a29f7a..fdfab3cd5a 100644 --- a/rust/src/applayertemplate/template.rs +++ b/rust/src/applayertemplate/template.rs @@ -257,8 +257,10 @@ export_tx_set_detect_state!( #[no_mangle] pub extern "C" fn rs_template_probing_parser( _flow: *const Flow, + _direction: u8, input: *const libc::uint8_t, input_len: u32, + _rdir: *mut u8 ) -> AppProto { // Need at least 2 bytes. if input_len > 1 && input != std::ptr::null_mut() { diff --git a/rust/src/dhcp/dhcp.rs b/rust/src/dhcp/dhcp.rs index 5139ec6a02..5f22f8c2bc 100644 --- a/rust/src/dhcp/dhcp.rs +++ b/rust/src/dhcp/dhcp.rs @@ -219,8 +219,11 @@ impl DHCPState { #[no_mangle] pub extern "C" fn rs_dhcp_probing_parser(_flow: *const Flow, + _direction: u8, input: *const libc::uint8_t, - input_len: u32) -> AppProto { + input_len: u32, + _rdir: *mut u8) -> AppProto +{ if input_len < DHCP_MIN_FRAME_LEN { return ALPROTO_UNKNOWN; } diff --git a/rust/src/ikev2/ikev2.rs b/rust/src/ikev2/ikev2.rs index dfff4f10b5..dcbf581f26 100644 --- a/rust/src/ikev2/ikev2.rs +++ b/rust/src/ikev2/ikev2.rs @@ -624,7 +624,11 @@ pub extern "C" fn rs_ikev2_state_get_event_info(event_name: *const libc::c_char, static mut ALPROTO_IKEV2 : AppProto = ALPROTO_UNKNOWN; #[no_mangle] -pub extern "C" fn rs_ikev2_probing_parser(_flow: *const Flow, input:*const libc::uint8_t, input_len: u32) -> AppProto { +pub extern "C" fn rs_ikev2_probing_parser(_flow: *const Flow, + _direction: u8, + input:*const libc::uint8_t, input_len: u32, + _rdir: *mut u8) -> AppProto +{ let slice = build_slice!(input,input_len as usize); let alproto = unsafe{ ALPROTO_IKEV2 }; match parse_ikev2_header(slice) { diff --git a/rust/src/krb/krb5.rs b/rust/src/krb/krb5.rs index 65d3a4ce51..bab1e584ec 100644 --- a/rust/src/krb/krb5.rs +++ b/rust/src/krb/krb5.rs @@ -405,7 +405,11 @@ pub extern "C" fn rs_krb5_state_get_event_info(event_name: *const libc::c_char, static mut ALPROTO_KRB5 : AppProto = ALPROTO_UNKNOWN; #[no_mangle] -pub extern "C" fn rs_krb5_probing_parser(_flow: *const Flow, input:*const libc::uint8_t, input_len: u32) -> AppProto { +pub extern "C" fn rs_krb5_probing_parser(_flow: *const Flow, + _direction: u8, + input:*const libc::uint8_t, input_len: u32, + _rdir: *mut u8) -> AppProto +{ let slice = build_slice!(input,input_len as usize); let alproto = unsafe{ ALPROTO_KRB5 }; if slice.len() <= 10 { return unsafe{ALPROTO_FAILED}; } @@ -439,14 +443,19 @@ pub extern "C" fn rs_krb5_probing_parser(_flow: *const Flow, input:*const libc:: } #[no_mangle] -pub extern "C" fn rs_krb5_probing_parser_tcp(_flow: *const Flow, input:*const libc::uint8_t, input_len: u32) -> AppProto { +pub extern "C" fn rs_krb5_probing_parser_tcp(_flow: *const Flow, + direction: u8, + input:*const libc::uint8_t, input_len: u32, + rdir: *mut u8) -> AppProto +{ let slice = build_slice!(input,input_len as usize); if slice.len() <= 14 { return unsafe{ALPROTO_FAILED}; } match be_u32(slice) { Ok((rem, record_mark)) => { // protocol implementations forbid very large requests if record_mark > 16384 { return unsafe{ALPROTO_FAILED}; } - return rs_krb5_probing_parser(_flow, rem.as_ptr(), rem.len() as u32); + return rs_krb5_probing_parser(_flow, direction, + rem.as_ptr(), rem.len() as u32, rdir); }, Err(nom::Err::Incomplete(_)) => { return ALPROTO_UNKNOWN; diff --git a/rust/src/nfs/nfs.rs b/rust/src/nfs/nfs.rs index bf9efb1866..d50162deb2 100644 --- a/rust/src/nfs/nfs.rs +++ b/rust/src/nfs/nfs.rs @@ -1681,6 +1681,26 @@ pub extern "C" fn rs_nfs_init(context: &'static mut SuricataFileContext) } } +fn nfs_probe_dir(i: &[u8], rdir: *mut u8) -> i8 { + match parse_rpc_packet_header(i) { + Ok((_, ref hdr)) => { + let dir = if hdr.msgtype == 0 { + STREAM_TOSERVER + } else { + STREAM_TOCLIENT + }; + unsafe { *rdir = dir }; + return 1; + }, + Err(nom::Err::Incomplete(_)) => { + return 0; + }, + Err(_) => { + return -1; + }, + } +} + pub fn nfs_probe(i: &[u8], direction: u8) -> i8 { if direction == STREAM_TOCLIENT { match parse_rpc_reply(i) { @@ -1772,6 +1792,33 @@ pub fn nfs_probe_udp(i: &[u8], direction: u8) -> i8 { } } +/// MIDSTREAM +#[no_mangle] +pub extern "C" fn rs_nfs_probe_ms(input: *const libc::uint8_t, + len: libc::uint32_t, rdir: *mut u8) -> libc::int8_t +{ + let slice: &[u8] = unsafe { + std::slice::from_raw_parts(input as *mut u8, len as usize) + }; + let mut direction : u8 = 0; + match nfs_probe_dir(slice, &mut direction) { + 1 => { + let r = nfs_probe(slice, direction); + if r == 1 { + unsafe { *rdir = direction; } + return 1; + } + return r; + }, + 0 => { + return 0; + }, + _ => { + return -1; + } + } +} + /// TOSERVER probe function #[no_mangle] pub extern "C" fn rs_nfs_probe_ts(input: *const libc::uint8_t, len: libc::uint32_t) diff --git a/rust/src/ntp/ntp.rs b/rust/src/ntp/ntp.rs index aeda23512c..0d449f3f95 100644 --- a/rust/src/ntp/ntp.rs +++ b/rust/src/ntp/ntp.rs @@ -343,7 +343,11 @@ pub extern "C" fn rs_ntp_state_get_event_info(event_name: *const libc::c_char, static mut ALPROTO_NTP : AppProto = ALPROTO_UNKNOWN; #[no_mangle] -pub extern "C" fn ntp_probing_parser(_flow: *const Flow, input:*const u8, input_len: u32) -> AppProto { +pub extern "C" fn ntp_probing_parser(_flow: *const Flow, + _direction: u8, + input:*const u8, input_len: u32, + _rdir: *mut u8) -> AppProto +{ let slice: &[u8] = unsafe { std::slice::from_raw_parts(input as *mut u8, input_len as usize) }; let alproto = unsafe{ ALPROTO_NTP }; match parse_ntp(slice) { diff --git a/rust/src/parser.rs b/rust/src/parser.rs index 90964b9695..ab2efec695 100644 --- a/rust/src/parser.rs +++ b/rust/src/parser.rs @@ -125,7 +125,7 @@ pub type ParseFn = extern "C" fn (flow: *const Flow, input_len: u32, data: *const c_void, flags: u8) -> i32; -pub type ProbeFn = extern "C" fn (flow: *const Flow,input:*const u8, input_len: u32) -> AppProto; +pub type ProbeFn = extern "C" fn (flow: *const Flow,direction: u8,input:*const u8, input_len: u32, rdir: *mut u8) -> AppProto; pub type StateAllocFn = extern "C" fn () -> *mut c_void; pub type StateFreeFn = extern "C" fn (*mut c_void); pub type StateTxFreeFn = extern "C" fn (*mut c_void, u64); diff --git a/rust/src/smb/smb.rs b/rust/src/smb/smb.rs index 6752aa3752..6242d512ef 100644 --- a/rust/src/smb/smb.rs +++ b/rust/src/smb/smb.rs @@ -1870,17 +1870,68 @@ pub extern "C" fn rs_smb_parse_response_tcp_gap( // probing parser // return 1 if found, 0 is not found #[no_mangle] -pub extern "C" fn rs_smb_probe_tcp(input: *const libc::uint8_t, len: libc::uint32_t) - -> libc::int8_t +pub extern "C" fn rs_smb_probe_tcp(direction: libc::uint8_t, + input: *const libc::uint8_t, len: libc::uint32_t, + rdir: *mut libc::uint8_t) + -> libc::int8_t { let slice = build_slice!(input, len as usize); match search_smb_record(slice) { - Ok((_, _)) => { + Ok((_, ref data)) => { SCLogDebug!("smb found"); - return 1; + match parse_smb_version(data) { + Ok((_, ref smb)) => { + SCLogDebug!("SMB {:?}", smb); + if smb.version == 0xff_u8 { // SMB1 + SCLogDebug!("SMBv1 record"); + match parse_smb_record(data) { + Ok((_, ref smb_record)) => { + if smb_record.flags & 0x80 != 0 { + SCLogDebug!("RESPONSE {:02x}", smb_record.flags); + if direction & STREAM_TOSERVER != 0 { + unsafe { *rdir = STREAM_TOCLIENT; } + } + } else { + SCLogDebug!("REQUEST {:02x}", smb_record.flags); + if direction & STREAM_TOCLIENT != 0 { + unsafe { *rdir = STREAM_TOSERVER; } + } + } + return 1; + }, + _ => { }, + } + } else if smb.version == 0xfe_u8 { // SMB2 + SCLogDebug!("SMB2 record"); + match parse_smb2_record_direction(data) { + Ok((_, ref smb_record)) => { + if direction & STREAM_TOSERVER != 0 { + SCLogDebug!("direction STREAM_TOSERVER smb_record {:?}", smb_record); + if !smb_record.request { + unsafe { *rdir = STREAM_TOCLIENT; } + } + } else { + SCLogDebug!("direction STREAM_TOCLIENT smb_record {:?}", smb_record); + if smb_record.request { + unsafe { *rdir = STREAM_TOSERVER; } + } + } + }, + _ => {}, + } + } + else if smb.version == 0xfd_u8 { // SMB3 transform + SCLogDebug!("SMB3 record"); + } + return 1; + }, + _ => { + SCLogDebug!("smb not found in {:?}", slice); + }, + } }, _ => { - SCLogDebug!("smb not found in {:?}", slice); + SCLogDebug!("no dice"); }, } match parse_nbss_record_partial(slice) { diff --git a/rust/src/smb/smb2_records.rs b/rust/src/smb/smb2_records.rs index 910bc0a49f..cf4dd0680a 100644 --- a/rust/src/smb/smb2_records.rs +++ b/rust/src/smb/smb2_records.rs @@ -32,6 +32,21 @@ named!(pub parse_smb2_sec_blob, }) )); +#[derive(Debug,PartialEq)] +pub struct Smb2RecordDir<> { + pub request: bool, +} + +named!(pub parse_smb2_record_direction, + do_parse!( + _server_component: tag!(b"\xfeSMB") + >> _skip: take!(12) + >> flags: le_u8 + >> (Smb2RecordDir { + request: flags & 0x01 == 0, + }) +)); + #[derive(Debug,PartialEq)] pub struct Smb2Record<'a> { pub direction: u8, // 0 req, 1 res diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index afd4ee83d6..84b671ce4a 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -110,14 +110,18 @@ typedef struct AppLayerProtoDetectProbingParser_ { typedef struct AppLayerProtoDetectPMSignature_ { AppProto alproto; + uint8_t direction; /**< direction for midstream */ SigIntId id; /* \todo Change this into a non-pointer */ DetectContentData *cd; + uint16_t pp_min_depth; + uint16_t pp_max_depth; + ProbingParserFPtr PPFunc; struct AppLayerProtoDetectPMSignature_ *next; } AppLayerProtoDetectPMSignature; typedef struct AppLayerProtoDetectPMCtx_ { - uint16_t max_len; + uint16_t pp_max_len; uint16_t min_len; MpmCtx mpm_ctx; @@ -176,87 +180,105 @@ static void AppLayerProtoDetectPEGetIpprotos(AppProto alproto, /***** Static Internal Calls: Protocol Retrieval *****/ /** \internal - * \brief Handle SPM search for Signature */ -static AppProto AppLayerProtoDetectPMMatchSignature(const AppLayerProtoDetectPMSignature *s, - AppLayerProtoDetectThreadCtx *tctx, - uint8_t *buf, uint16_t buflen, - uint8_t ipproto) + * \brief Handle SPM search for Signature + * \param buflen full size of the input buffer + * \param searchlen pattern matching portion of buffer */ +static AppProto AppLayerProtoDetectPMMatchSignature( + const AppLayerProtoDetectPMSignature *s, + AppLayerProtoDetectThreadCtx *tctx, + Flow *f, uint8_t direction, + uint8_t *buf, uint16_t buflen, uint16_t searchlen, + bool *rflow) { SCEnter(); - AppProto proto = ALPROTO_UNKNOWN; - uint8_t *found = NULL; - if (s->cd->offset > buflen) { - SCLogDebug("s->co->offset (%"PRIu16") > buflen (%"PRIu16")", - s->cd->offset, buflen); - goto end; + if (s->cd->offset > searchlen) { + SCLogDebug("s->co->offset (%"PRIu16") > searchlen (%"PRIu16")", + s->cd->offset, searchlen); + SCReturnUInt(ALPROTO_UNKNOWN); } - - if (s->cd->depth > buflen) { - SCLogDebug("s->co->depth (%"PRIu16") > buflen (%"PRIu16")", - s->cd->depth, buflen); - goto end; + if (s->cd->depth > searchlen) { + SCLogDebug("s->co->depth (%"PRIu16") > searchlen (%"PRIu16")", + s->cd->depth, searchlen); + SCReturnUInt(ALPROTO_UNKNOWN); } uint8_t *sbuf = buf + s->cd->offset; - uint16_t sbuflen = s->cd->depth - s->cd->offset; + uint16_t ssearchlen = s->cd->depth - s->cd->offset; SCLogDebug("s->co->offset (%"PRIu16") s->cd->depth (%"PRIu16")", s->cd->offset, s->cd->depth); - found = SpmScan(s->cd->spm_ctx, tctx->spm_thread_ctx, sbuf, sbuflen); - if (found != NULL) - proto = s->alproto; - - end: - SCReturnUInt(proto); -} - -/** \internal - * \brief Run Pattern Sigs against buffer - * \param pm_results[out] AppProto array of size ALPROTO_MAX */ -static AppProto AppLayerProtoDetectPMGetProto(AppLayerProtoDetectThreadCtx *tctx, - Flow *f, - uint8_t *buf, uint16_t buflen, - uint8_t direction, - uint8_t ipproto, - AppProto *pm_results) -{ - SCEnter(); - - pm_results[0] = ALPROTO_UNKNOWN; - - AppLayerProtoDetectPMCtx *pm_ctx; - MpmThreadCtx *mpm_tctx; - uint16_t pm_matches = 0; - uint8_t cnt; - uint16_t searchlen; - - if (f->protomap >= FLOW_PROTO_DEFAULT) - return ALPROTO_UNKNOWN; + uint8_t *found = SpmScan(s->cd->spm_ctx, tctx->spm_thread_ctx, + sbuf, ssearchlen); + if (found == NULL) { + SCReturnUInt(ALPROTO_UNKNOWN); + } - if (direction & STREAM_TOSERVER) { - pm_ctx = &alpd_ctx.ctx_ipp[f->protomap].ctx_pm[0]; - mpm_tctx = &tctx->mpm_tctx[f->protomap][0]; + SCLogDebug("matching, s->direction %s, our dir %s", + (s->direction & STREAM_TOSERVER) ? "toserver" : "toclient", + (direction & STREAM_TOSERVER) ? "toserver" : "toclient"); + if (s->PPFunc == NULL) { + if ((direction & (STREAM_TOSERVER|STREAM_TOCLIENT)) == s->direction) { + SCLogDebug("direction is correct"); + } else { + SCLogDebug("direction is wrong, rflow = true"); + *rflow = true; + } + /* validate using Probing Parser */ } else { - pm_ctx = &alpd_ctx.ctx_ipp[f->protomap].ctx_pm[1]; - mpm_tctx = &tctx->mpm_tctx[f->protomap][1]; + if (s->pp_min_depth > buflen) { + SCLogDebug("PP can't be run yet as pp_min_depth %u > buflen %u", + s->pp_min_depth, buflen); + SCReturnInt(ALPROTO_UNKNOWN); + } + + uint8_t rdir = 0; + AppProto r = s->PPFunc(f, direction, buf, buflen, &rdir); + if (r == s->alproto) { + SCLogDebug("found %s/%u, rdir %02x reverse_flow? %s", + AppProtoToString(r), r, rdir, + (rdir && direction != rdir) ? "true" : "false"); + *rflow = (rdir && direction != rdir); + SCReturnUInt(s->alproto); + } else if (r == ALPROTO_FAILED) { + SCReturnUInt(ALPROTO_FAILED); + } else { + /* unknown: lets see if we will try again later */ + if (s->pp_max_depth < buflen) { + SCLogDebug("depth reached and answer inconclusive: fail"); + SCReturnUInt(ALPROTO_FAILED); + } + SCReturnUInt(ALPROTO_UNKNOWN); + } } - if (pm_ctx->mpm_ctx.pattern_cnt == 0) - goto end; + SCReturnUInt(s->alproto); +} - searchlen = buflen; - if (searchlen > pm_ctx->max_len) - searchlen = pm_ctx->max_len; +/** + * \retval 0 no matches + * \retval -1 no matches, mpm depth reached + */ +static inline int PMGetProtoInspect( + AppLayerProtoDetectThreadCtx *tctx, + AppLayerProtoDetectPMCtx *pm_ctx, + MpmThreadCtx *mpm_tctx, + Flow *f, uint8_t *buf, uint16_t buflen, + uint8_t direction, AppProto *pm_results, bool *rflow) +{ + int pm_matches = 0; - uint32_t search_cnt = 0; + uint16_t searchlen = MIN(buflen, pm_ctx->mpm_ctx.maxdepth); + SCLogDebug("searchlen %u buflen %u", searchlen, buflen); /* do the mpm search */ - search_cnt = mpm_table[pm_ctx->mpm_ctx.mpm_type].Search(&pm_ctx->mpm_ctx, - mpm_tctx, - &tctx->pmq, - buf, searchlen); - if (search_cnt == 0) - goto end; + uint32_t search_cnt = mpm_table[pm_ctx->mpm_ctx.mpm_type].Search( + &pm_ctx->mpm_ctx, mpm_tctx, &tctx->pmq, + buf, searchlen); + if (search_cnt == 0) { + if (buflen >= pm_ctx->mpm_ctx.maxdepth) + return -1; + return 0; + } /* alproto bit field */ uint8_t pm_results_bf[(ALPROTO_MAX / 8) + 1]; @@ -265,14 +287,14 @@ static AppProto AppLayerProtoDetectPMGetProto(AppLayerProtoDetectThreadCtx *tctx /* loop through unique pattern id's. Can't use search_cnt here, * as that contains all matches, tctx->pmq.pattern_id_array_cnt * contains only *unique* matches. */ - for (cnt = 0; cnt < tctx->pmq.rule_id_array_cnt; cnt++) { + for (uint32_t cnt = 0; cnt < tctx->pmq.rule_id_array_cnt; cnt++) { const AppLayerProtoDetectPMSignature *s = pm_ctx->map[tctx->pmq.rule_id_array[cnt]]; while (s != NULL) { AppProto proto = AppLayerProtoDetectPMMatchSignature(s, - tctx, buf, searchlen, ipproto); + tctx, f, direction, buf, buflen, searchlen, rflow); /* store each unique proto once */ - if (proto != ALPROTO_UNKNOWN && + if (AppProtoIsValid(proto) && !(pm_results_bf[proto / 8] & (1 << (proto % 8))) ) { pm_results[pm_matches++] = proto; @@ -281,12 +303,99 @@ static AppProto AppLayerProtoDetectPMGetProto(AppLayerProtoDetectThreadCtx *tctx s = s->next; } } - - end: + if (pm_matches == 0 && buflen >= pm_ctx->pp_max_len) { + pm_matches = -2; + } PmqReset(&tctx->pmq); - if (buflen >= pm_ctx->max_len) + return pm_matches; +} + +/** \internal + * \brief Run Pattern Sigs against buffer + * \param direction direction for the patterns + * \param pm_results[out] AppProto array of size ALPROTO_MAX */ +static AppProto AppLayerProtoDetectPMGetProto( + AppLayerProtoDetectThreadCtx *tctx, + Flow *f, uint8_t *buf, uint16_t buflen, + uint8_t direction, AppProto *pm_results, bool *rflow) +{ + SCEnter(); + + pm_results[0] = ALPROTO_UNKNOWN; + + AppLayerProtoDetectPMCtx *pm_ctx; + MpmThreadCtx *mpm_tctx; + int m = -1; + + if (f->protomap >= FLOW_PROTO_DEFAULT) + return ALPROTO_FAILED; + + if (direction & STREAM_TOSERVER) { + pm_ctx = &alpd_ctx.ctx_ipp[f->protomap].ctx_pm[0]; + mpm_tctx = &tctx->mpm_tctx[f->protomap][0]; + } else { + pm_ctx = &alpd_ctx.ctx_ipp[f->protomap].ctx_pm[1]; + mpm_tctx = &tctx->mpm_tctx[f->protomap][1]; + } + if (likely(pm_ctx->mpm_ctx.pattern_cnt > 0)) { + m = PMGetProtoInspect(tctx, + pm_ctx, mpm_tctx, + f, buf, buflen, direction, + pm_results, rflow); + + } + /* pattern found, yay */ + if (m > 0) { FLOW_SET_PM_DONE(f, direction); - SCReturnUInt(pm_matches); + SCReturnUInt((uint16_t)m); + + /* handle non-found in non-midstream case */ + } else if (!stream_config.midstream) { + /* we can give up if mpm gave no results and its search depth + * was reached. */ + if (m < 0) { + FLOW_SET_PM_DONE(f, direction); + SCReturnUInt(0); + } else if (m == 0) { + SCReturnUInt(0); + } + SCReturnUInt((uint16_t)m); + + /* handle non-found in midstream case */ + } else if (m <= 0) { + if (direction & STREAM_TOSERVER) { + pm_ctx = &alpd_ctx.ctx_ipp[f->protomap].ctx_pm[1]; + mpm_tctx = &tctx->mpm_tctx[f->protomap][1]; + } else { + pm_ctx = &alpd_ctx.ctx_ipp[f->protomap].ctx_pm[0]; + mpm_tctx = &tctx->mpm_tctx[f->protomap][0]; + } + SCLogDebug("no matches and in midstream mode, lets try the " + "*patterns for the other side"); + + int om = -1; + if (likely(pm_ctx->mpm_ctx.pattern_cnt > 0)) { + om = PMGetProtoInspect(tctx, + pm_ctx, mpm_tctx, + f, buf, buflen, direction, + pm_results, rflow); + } + /* found! */ + if (om > 0) { + FLOW_SET_PM_DONE(f, direction); + SCReturnUInt((uint16_t)om); + + /* both sides failed */ + } else if (om < 0 && m && m < 0) { + FLOW_SET_PM_DONE(f, direction); + SCReturnUInt(0); + + /* one side still uncertain */ + } else if (om == 0 || m == 0) { + SCReturnUInt(0); + } + } + SCReturnUInt(0); } static AppLayerProtoDetectProbingParserPort *AppLayerProtoDetectGetProbingParsers(AppLayerProtoDetectProbingParser *pp, @@ -343,8 +452,9 @@ static AppProto AppLayerProtoDetectPEGetProto(Flow *f, uint8_t ipproto, * */ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, - uint8_t *buf, uint32_t buflen, - uint8_t ipproto, uint8_t direction) + uint8_t *buf, uint32_t buflen, + uint8_t ipproto, uint8_t direction, + bool *reverse_flow) { const AppLayerProtoDetectProbingParserPort *pp_port_dp = NULL; const AppLayerProtoDetectProbingParserPort *pp_port_sp = NULL; @@ -411,6 +521,7 @@ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, } /* run the parser(s) */ + uint8_t rdir = 0; pe = pe1; while (pe != NULL) { if ((buflen < pe->min_depth) || @@ -420,9 +531,9 @@ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, } if (direction & STREAM_TOSERVER && pe->ProbingParserTs != NULL) { - alproto = pe->ProbingParserTs(f, buf, buflen); + alproto = pe->ProbingParserTs(f, direction, buf, buflen, &rdir); } else if (pe->ProbingParserTc != NULL) { - alproto = pe->ProbingParserTc(f, buf, buflen); + alproto = pe->ProbingParserTc(f, direction, buf, buflen, &rdir); } if (alproto != ALPROTO_UNKNOWN && alproto != ALPROTO_FAILED) goto end; @@ -441,9 +552,9 @@ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, } if (direction & STREAM_TOSERVER && pe->ProbingParserTs != NULL) { - alproto = pe->ProbingParserTs(f, buf, buflen); + alproto = pe->ProbingParserTs(f, direction, buf, buflen, &rdir); } else if (pe->ProbingParserTc != NULL) { - alproto = pe->ProbingParserTc(f, buf, buflen); + alproto = pe->ProbingParserTc(f, direction, buf, buflen, &rdir); } if (alproto != ALPROTO_UNKNOWN && alproto != ALPROTO_FAILED) goto end; @@ -472,6 +583,12 @@ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, } end: + if (alproto != ALPROTO_FAILED && alproto != ALPROTO_UNKNOWN && + rdir == (direction & (STREAM_TOSERVER|STREAM_TOCLIENT))) { + SCLogDebug("PP found %u, is reverse flow", alproto); + *reverse_flow = true; + } + SCLogDebug("%s, mask is now %08x", (direction & STREAM_TOSERVER) ? "toserver":"toclient", alproto_masks[0]); SCReturnUInt(alproto); @@ -1269,45 +1386,46 @@ static void AppLayerProtoDetectPMFreeSignature(AppLayerProtoDetectPMSignature *s } static int AppLayerProtoDetectPMAddSignature(AppLayerProtoDetectPMCtx *ctx, DetectContentData *cd, - AppProto alproto) + AppProto alproto, uint8_t direction, + ProbingParserFPtr PPFunc, + uint16_t pp_min_depth, uint16_t pp_max_depth) { SCEnter(); - int ret = 0; - AppLayerProtoDetectPMSignature *s = SCMalloc(sizeof(*s)); + AppLayerProtoDetectPMSignature *s = SCCalloc(1, sizeof(*s)); if (unlikely(s == NULL)) - goto error; - memset(s, 0, sizeof(*s)); + SCReturnInt(-1); s->alproto = alproto; + s->direction = direction; s->cd = cd; + s->PPFunc = PPFunc; + s->pp_min_depth = pp_min_depth; + s->pp_max_depth = pp_max_depth; /* prepend to the list */ s->next = ctx->head; ctx->head = s; - goto end; - error: - ret = -1; - end: - SCReturnInt(ret); + SCReturnInt(0); } static int AppLayerProtoDetectPMRegisterPattern(uint8_t ipproto, AppProto alproto, const char *pattern, uint16_t depth, uint16_t offset, uint8_t direction, - uint8_t is_cs) + uint8_t is_cs, + ProbingParserFPtr PPFunc, + uint16_t pp_min_depth, uint16_t pp_max_depth) { SCEnter(); AppLayerProtoDetectCtxIpproto *ctx_ipp = &alpd_ctx.ctx_ipp[FlowGetProtoMapping(ipproto)]; AppLayerProtoDetectPMCtx *ctx_pm = NULL; - DetectContentData *cd; int ret = 0; - cd = DetectContentParseEncloseQuotes(alpd_ctx.spm_global_thread_ctx, - pattern); + DetectContentData *cd = DetectContentParseEncloseQuotes( + alpd_ctx.spm_global_thread_ctx, pattern); if (cd == NULL) goto error; cd->depth = depth; @@ -1330,13 +1448,14 @@ static int AppLayerProtoDetectPMRegisterPattern(uint8_t ipproto, AppProto alprot else ctx_pm = (AppLayerProtoDetectPMCtx *)&ctx_ipp->ctx_pm[1]; - if (depth > ctx_pm->max_len) - ctx_pm->max_len = depth; + if (pp_max_depth > ctx_pm->pp_max_len) + ctx_pm->pp_max_len = pp_max_depth; if (depth < ctx_pm->min_len) ctx_pm->min_len = depth; /* Finally turn it into a signature and add to the ctx. */ - AppLayerProtoDetectPMAddSignature(ctx_pm, cd, alproto); + AppLayerProtoDetectPMAddSignature(ctx_pm, cd, alproto, direction, + PPFunc, pp_min_depth, pp_max_depth); goto end; error: @@ -1350,7 +1469,8 @@ static int AppLayerProtoDetectPMRegisterPattern(uint8_t ipproto, AppProto alprot AppProto AppLayerProtoDetectGetProto(AppLayerProtoDetectThreadCtx *tctx, Flow *f, uint8_t *buf, uint32_t buflen, - uint8_t ipproto, uint8_t direction) + uint8_t ipproto, uint8_t direction, + bool *reverse_flow) { SCEnter(); SCLogDebug("buflen %u for %s direction", buflen, @@ -1362,10 +1482,8 @@ AppProto AppLayerProtoDetectGetProto(AppLayerProtoDetectThreadCtx *tctx, if (!FLOW_IS_PM_DONE(f, direction)) { AppProto pm_results[ALPROTO_MAX]; uint16_t pm_matches = AppLayerProtoDetectPMGetProto(tctx, f, - buf, buflen, - direction, - ipproto, - pm_results); + buf, buflen, direction, + pm_results, reverse_flow); if (pm_matches > 0) { alproto = pm_results[0]; @@ -1381,10 +1499,15 @@ AppProto AppLayerProtoDetectGetProto(AppLayerProtoDetectThreadCtx *tctx, } if (!FLOW_IS_PP_DONE(f, direction)) { + bool rflow = false; alproto = AppLayerProtoDetectPPGetProto(f, buf, buflen, - ipproto, direction); + ipproto, direction, + &rflow); if (alproto != ALPROTO_UNKNOWN) goto end; + if (rflow) { + *reverse_flow = true; + } } /* Look if flow can be found in expectation list */ @@ -1582,12 +1705,24 @@ int AppLayerProtoDetectPMRegisterPatternCS(uint8_t ipproto, AppProto alproto, uint8_t direction) { SCEnter(); - int r = 0; - r = AppLayerProtoDetectPMRegisterPattern(ipproto, alproto, - pattern, - depth, offset, - direction, - 1 /* case-sensitive */); + int r = AppLayerProtoDetectPMRegisterPattern(ipproto, alproto, + pattern, depth, offset, + direction, 1 /* case-sensitive */, + NULL, 0, 0); + SCReturnInt(r); +} + +int AppLayerProtoDetectPMRegisterPatternCSwPP(uint8_t ipproto, AppProto alproto, + const char *pattern, uint16_t depth, uint16_t offset, + uint8_t direction, + ProbingParserFPtr PPFunc, + uint16_t pp_min_depth, uint16_t pp_max_depth) +{ + SCEnter(); + int r = AppLayerProtoDetectPMRegisterPattern(ipproto, alproto, + pattern, depth, offset, + direction, 1 /* case-sensitive */, + PPFunc, pp_min_depth, pp_max_depth); SCReturnInt(r); } @@ -1597,12 +1732,10 @@ int AppLayerProtoDetectPMRegisterPatternCI(uint8_t ipproto, AppProto alproto, uint8_t direction) { SCEnter(); - int r = 0; - r = AppLayerProtoDetectPMRegisterPattern(ipproto, alproto, - pattern, - depth, offset, - direction, - 0 /* !case-sensitive */); + int r = AppLayerProtoDetectPMRegisterPattern(ipproto, alproto, + pattern, depth, offset, + direction, 0 /* !case-sensitive */, + NULL, 0, 0); SCReturnInt(r); } @@ -1983,32 +2116,18 @@ static int AppLayerProtoDetectTest01(void) AppLayerProtoDetectUnittestCtxBackup(); AppLayerProtoDetectSetup(); - const char *buf; - int r = 0; - - buf = "HTTP"; + const char *buf = "HTTP"; AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); buf = "GET"; AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOSERVER); AppLayerProtoDetectPrepareState(); - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 1) { - printf("Failure - " - "alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 1\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1) { - printf("Failure - " - "alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1\n"); - goto end; - } + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 1); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1); - r = 1; - - end: AppLayerProtoDetectDeSetup(); AppLayerProtoDetectUnittestCtxRestore(); - return r; + PASS; } static int AppLayerProtoDetectTest02(void) @@ -2016,47 +2135,24 @@ static int AppLayerProtoDetectTest02(void) AppLayerProtoDetectUnittestCtxBackup(); AppLayerProtoDetectSetup(); - int r = 0; - const char *buf = "HTTP"; AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); buf = "ftp"; AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT); AppLayerProtoDetectPrepareState(); - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2\n"); - goto end; - } - - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map != NULL\n"); - goto end; - } + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2); - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_FTP) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0].alproto != ALPROTO_FTP\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1]->alproto != ALPROTO_HTTP) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1].alproto != ALPROTO_HTTP\n"); - goto end; - } + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL); - r = 1; + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_FTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1]->alproto != ALPROTO_HTTP); - end: AppLayerProtoDetectDeSetup(); AppLayerProtoDetectUnittestCtxRestore(); - return r; + PASS; } static int AppLayerProtoDetectTest03(void) @@ -2065,18 +2161,14 @@ static int AppLayerProtoDetectTest03(void) AppLayerProtoDetectSetup(); uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\n"; - const char *buf; - int r = 0; - Flow f; AppProto pm_results[ALPROTO_MAX]; - AppLayerProtoDetectThreadCtx *alpd_tctx; - + memset(pm_results, 0, sizeof(pm_results)); + Flow f; memset(&f, 0x00, sizeof(f)); f.protomap = FlowGetProtoMapping(IPPROTO_TCP); - memset(pm_results, 0, sizeof(pm_results)); - buf = "HTTP"; + const char *buf = "HTTP"; AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); buf = "220 "; AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT); @@ -2084,54 +2176,28 @@ static int AppLayerProtoDetectTest03(void) AppLayerProtoDetectPrepareState(); /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since * it sets internal structures which depends on the above function. */ - alpd_tctx = AppLayerProtoDetectGetCtxThread(); - - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2\n"); - goto end; - } + AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread(); + FAIL_IF_NULL(alpd_tctx); - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map != NULL\n"); - goto end; - } - - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_FTP) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0].alproto != ALPROTO_FTP\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1]->alproto != ALPROTO_HTTP) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1].alproto != ALPROTO_HTTP\n"); - goto end; - } + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_FTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1]->alproto != ALPROTO_HTTP); + bool rflow = false; uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, - l7data, sizeof(l7data), + &f, l7data, sizeof(l7data), STREAM_TOCLIENT, - IPPROTO_TCP, - pm_results); - if (cnt != 1 && pm_results[0] != ALPROTO_HTTP) { - printf("cnt != 1 && pm_results[0] != AlPROTO_HTTP\n"); - goto end; - } - - r = 1; + pm_results, &rflow); + FAIL_IF(cnt != 1); + FAIL_IF(pm_results[0] != ALPROTO_HTTP); - end: - if (alpd_tctx != NULL) - AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + AppLayerProtoDetectDestroyCtxThread(alpd_tctx); AppLayerProtoDetectDeSetup(); AppLayerProtoDetectUnittestCtxRestore(); - return r; + PASS; } static int AppLayerProtoDetectTest04(void) @@ -2140,67 +2206,38 @@ static int AppLayerProtoDetectTest04(void) AppLayerProtoDetectSetup(); uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\n"; - const char *buf; - int r = 0; Flow f; - AppProto pm_results[ALPROTO_MAX]; - AppLayerProtoDetectThreadCtx *alpd_tctx; - memset(&f, 0x00, sizeof(f)); - f.protomap = FlowGetProtoMapping(IPPROTO_TCP); - + AppProto pm_results[ALPROTO_MAX]; memset(pm_results, 0, sizeof(pm_results)); + f.protomap = FlowGetProtoMapping(IPPROTO_TCP); - buf = "200 "; + const char *buf = "200 "; AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, buf, 13, 0, STREAM_TOCLIENT); AppLayerProtoDetectPrepareState(); /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since * it sets internal structures which depends on the above function. */ - alpd_tctx = AppLayerProtoDetectGetCtxThread(); + AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread(); + FAIL_IF_NULL(alpd_tctx); - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2\n"); - goto end; - } - - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map != NULL\n"); - goto end; - } - - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0].alproto != ALPROTO_HTTP\n"); - goto end; - } + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP); + bool rdir = false; uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, - l7data, sizeof(l7data), - STREAM_TOCLIENT, - IPPROTO_TCP, - pm_results); - if (cnt != 1 && pm_results[0] != ALPROTO_HTTP) { - printf("cnt != 1 && pm_results[0] != AlPROTO_HTTP\n"); - goto end; - } + &f, l7data, sizeof(l7data), STREAM_TOCLIENT, + pm_results, &rdir); + FAIL_IF(cnt != 1); + FAIL_IF(pm_results[0] != ALPROTO_HTTP); - r = 1; - - end: - if (alpd_tctx != NULL) - AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + AppLayerProtoDetectDestroyCtxThread(alpd_tctx); AppLayerProtoDetectDeSetup(); AppLayerProtoDetectUnittestCtxRestore(); - return r; + PASS; } static int AppLayerProtoDetectTest05(void) @@ -2209,18 +2246,13 @@ static int AppLayerProtoDetectTest05(void) AppLayerProtoDetectSetup(); uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\nBlahblah"; - const char *buf; - int r = 0; - Flow f; AppProto pm_results[ALPROTO_MAX]; - AppLayerProtoDetectThreadCtx *alpd_tctx; - + memset(pm_results, 0, sizeof(pm_results)); + Flow f; memset(&f, 0x00, sizeof(f)); f.protomap = FlowGetProtoMapping(IPPROTO_TCP); - memset(pm_results, 0, sizeof(pm_results)); - - buf = "HTTP"; + const char *buf = "HTTP"; AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); buf = "220 "; AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT); @@ -2228,54 +2260,28 @@ static int AppLayerProtoDetectTest05(void) AppLayerProtoDetectPrepareState(); /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since * it sets internal structures which depends on the above function. */ - alpd_tctx = AppLayerProtoDetectGetCtxThread(); + AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread(); + FAIL_IF_NULL(alpd_tctx); - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2\n"); - goto end; - } - - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map != NULL\n"); - goto end; - } - - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_FTP) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0].alproto != ALPROTO_FTP\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1]->alproto != ALPROTO_HTTP) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1].alproto != ALPROTO_HTTP\n"); - goto end; - } + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_FTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1]->alproto != ALPROTO_HTTP); + bool rdir = false; uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, - l7data, sizeof(l7data), - STREAM_TOCLIENT, - IPPROTO_TCP, - pm_results); - if (cnt != 1 && pm_results[0] != ALPROTO_HTTP) { - printf("cnt != 1 && pm_results[0] != AlPROTO_HTTP\n"); - goto end; - } + &f, l7data, sizeof(l7data), + STREAM_TOCLIENT, + pm_results, &rdir); + FAIL_IF(cnt != 1); + FAIL_IF(pm_results[0] != ALPROTO_HTTP); - r = 1; - - end: - if (alpd_tctx != NULL) - AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + AppLayerProtoDetectDestroyCtxThread(alpd_tctx); AppLayerProtoDetectDeSetup(); AppLayerProtoDetectUnittestCtxRestore(); - return r; + PASS; } static int AppLayerProtoDetectTest06(void) @@ -2284,16 +2290,13 @@ static int AppLayerProtoDetectTest06(void) AppLayerProtoDetectSetup(); uint8_t l7data[] = "220 Welcome to the OISF FTP server\r\n"; - const char *buf; - int r = 0; - Flow f; AppProto pm_results[ALPROTO_MAX]; - AppLayerProtoDetectThreadCtx *alpd_tctx; - + memset(pm_results, 0, sizeof(pm_results)); + Flow f; memset(&f, 0x00, sizeof(f)); f.protomap = FlowGetProtoMapping(IPPROTO_TCP); - buf = "HTTP"; + const char *buf = "HTTP"; AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); buf = "220 "; AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT); @@ -2301,54 +2304,27 @@ static int AppLayerProtoDetectTest06(void) AppLayerProtoDetectPrepareState(); /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since * it sets internal structures which depends on the above function. */ - alpd_tctx = AppLayerProtoDetectGetCtxThread(); - - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2\n"); - goto end; - } + AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread(); + FAIL_IF_NULL(alpd_tctx); - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map != NULL\n"); - goto end; - } - - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_FTP) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0].alproto != ALPROTO_FTP\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1]->alproto != ALPROTO_HTTP) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1].alproto != ALPROTO_HTTP\n"); - goto end; - } + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_FTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1]->alproto != ALPROTO_HTTP); + bool rdir = false; uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, - l7data, sizeof(l7data), - STREAM_TOCLIENT, - IPPROTO_TCP, - pm_results); - if (cnt != 1 && pm_results[0] != ALPROTO_FTP) { - printf("cnt != 1 && pm_results[0] != AlPROTO_FTP\n"); - goto end; - } + &f, l7data, sizeof(l7data), STREAM_TOCLIENT, + pm_results, &rdir); + FAIL_IF(cnt != 1); + FAIL_IF(pm_results[0] != ALPROTO_FTP); - r = 1; - - end: - if (alpd_tctx != NULL) - AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + AppLayerProtoDetectDestroyCtxThread(alpd_tctx); AppLayerProtoDetectDeSetup(); AppLayerProtoDetectUnittestCtxRestore(); - return r; + PASS; } static int AppLayerProtoDetectTest07(void) @@ -2357,67 +2333,36 @@ static int AppLayerProtoDetectTest07(void) AppLayerProtoDetectSetup(); uint8_t l7data[] = "220 Welcome to the OISF HTTP/FTP server\r\n"; - const char *buf; - int r = 0; Flow f; - AppProto pm_results[ALPROTO_MAX]; - AppLayerProtoDetectThreadCtx *alpd_tctx; - memset(&f, 0x00, sizeof(f)); f.protomap = FlowGetProtoMapping(IPPROTO_TCP); - + AppProto pm_results[ALPROTO_MAX]; memset(pm_results, 0, sizeof(pm_results)); - buf = "HTTP"; + const char *buf = "HTTP"; AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); AppLayerProtoDetectPrepareState(); /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since * it sets internal structures which depends on the above function. */ - alpd_tctx = AppLayerProtoDetectGetCtxThread(); - - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2\n"); - goto end; - } + AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread(); - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map != NULL\n"); - goto end; - } - - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0].alproto != ALPROTO_HTTP\n"); - goto end; - } + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP); + bool rdir = false; uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, - l7data, sizeof(l7data), - STREAM_TOCLIENT, - IPPROTO_TCP, - pm_results); - if (cnt != 0) { - printf("cnt != 0\n"); - goto end; - } + &f, l7data, sizeof(l7data), STREAM_TOCLIENT, + pm_results, &rdir); + FAIL_IF(cnt != 0); - r = 1; - - end: - if (alpd_tctx != NULL) - AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + AppLayerProtoDetectDestroyCtxThread(alpd_tctx); AppLayerProtoDetectDeSetup(); AppLayerProtoDetectUnittestCtxRestore(); - return r; + PASS; } static int AppLayerProtoDetectTest08(void) @@ -2445,67 +2390,38 @@ static int AppLayerProtoDetectTest08(void) 0x20, 0x4c, 0x4d, 0x20, 0x30, 0x2e, 0x31, 0x32, 0x00 }; - const char *buf; - int r = 0; - Flow f; AppProto pm_results[ALPROTO_MAX]; - AppLayerProtoDetectThreadCtx *alpd_tctx; - + memset(pm_results, 0, sizeof(pm_results)); + Flow f; memset(&f, 0x00, sizeof(f)); f.protomap = FlowGetProtoMapping(IPPROTO_TCP); - memset(pm_results, 0, sizeof(pm_results)); - - buf = "|ff|SMB"; + const char *buf = "|ff|SMB"; AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB, buf, 8, 4, STREAM_TOCLIENT); AppLayerProtoDetectPrepareState(); /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since * it sets internal structures which depends on the above function. */ - alpd_tctx = AppLayerProtoDetectGetCtxThread(); + AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread(); + FAIL_IF_NULL(alpd_tctx); - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2\n"); - goto end; - } - - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map != NULL\n"); - goto end; - } - - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_SMB) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0].alproto != ALPROTO_SMB\n"); - goto end; - } + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_SMB); + bool rdir = false; uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, - l7data, sizeof(l7data), - STREAM_TOCLIENT, - IPPROTO_TCP, - pm_results); - if (cnt != 1 && pm_results[0] != ALPROTO_SMB) { - printf("cnt != 1 && pm_results[0] != AlPROTO_SMB\n"); - goto end; - } + &f, l7data, sizeof(l7data), STREAM_TOCLIENT, + pm_results, &rdir); + FAIL_IF(cnt != 1); + FAIL_IF(pm_results[0] != ALPROTO_SMB); - r = 1; - - end: - if (alpd_tctx != NULL) - AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + AppLayerProtoDetectDestroyCtxThread(alpd_tctx); AppLayerProtoDetectDeSetup(); AppLayerProtoDetectUnittestCtxRestore(); - return r; + PASS; } static int AppLayerProtoDetectTest09(void) @@ -2529,67 +2445,38 @@ static int AppLayerProtoDetectTest09(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02 }; - const char *buf; - int r = 0; - Flow f; AppProto pm_results[ALPROTO_MAX]; - AppLayerProtoDetectThreadCtx *alpd_tctx; - + memset(pm_results, 0, sizeof(pm_results)); + Flow f; memset(&f, 0x00, sizeof(f)); f.protomap = FlowGetProtoMapping(IPPROTO_TCP); - memset(pm_results, 0, sizeof(pm_results)); - - buf = "|fe|SMB"; + const char *buf = "|fe|SMB"; AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB2, buf, 8, 4, STREAM_TOCLIENT); AppLayerProtoDetectPrepareState(); /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since * it sets internal structures which depends on the above function. */ - alpd_tctx = AppLayerProtoDetectGetCtxThread(); - - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2\n"); - goto end; - } - - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map != NULL\n"); - goto end; - } + AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread(); + FAIL_IF_NULL(alpd_tctx); - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_SMB2) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0].alproto != ALPROTO_SMB2\n"); - goto end; - } + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_SMB2); + bool rdir = false; uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, - l7data, sizeof(l7data), - STREAM_TOCLIENT, - IPPROTO_TCP, - pm_results); - if (cnt != 1 && pm_results[0] != ALPROTO_SMB2) { - printf("cnt != 1 && pm_results[0] != AlPROTO_SMB2\n"); - goto end; - } - - r = 1; + &f, l7data, sizeof(l7data), STREAM_TOCLIENT, + pm_results, &rdir); + FAIL_IF(cnt != 1); + FAIL_IF(pm_results[0] != ALPROTO_SMB2); - end: - if (alpd_tctx != NULL) - AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + AppLayerProtoDetectDestroyCtxThread(alpd_tctx); AppLayerProtoDetectDeSetup(); AppLayerProtoDetectUnittestCtxRestore(); - return r; + PASS; } static int AppLayerProtoDetectTest10(void) @@ -2608,67 +2495,38 @@ static int AppLayerProtoDetectTest10(void) 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; - const char *buf; - int r = 0; - Flow f; AppProto pm_results[ALPROTO_MAX]; - AppLayerProtoDetectThreadCtx *alpd_tctx; - + memset(pm_results, 0, sizeof(pm_results)); + Flow f; memset(&f, 0x00, sizeof(f)); f.protomap = FlowGetProtoMapping(IPPROTO_TCP); - memset(pm_results, 0, sizeof(pm_results)); - - buf = "|05 00|"; + const char *buf = "|05 00|"; AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_DCERPC, buf, 4, 0, STREAM_TOCLIENT); AppLayerProtoDetectPrepareState(); /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since * it sets internal structures which depends on the above function. */ - alpd_tctx = AppLayerProtoDetectGetCtxThread(); + AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread(); + FAIL_IF_NULL(alpd_tctx); - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2\n"); - goto end; - } - - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map != NULL\n"); - goto end; - } - - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_DCERPC) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0].alproto != ALPROTO_DCERPC\n"); - goto end; - } + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_DCERPC); + bool rdir = false; uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, - l7data, sizeof(l7data), - STREAM_TOCLIENT, - IPPROTO_TCP, - pm_results); - if (cnt != 1 && pm_results[0] != ALPROTO_DCERPC) { - printf("cnt != 1 && pm_results[0] != AlPROTO_DCERPC\n"); - goto end; - } + &f, l7data, sizeof(l7data), STREAM_TOCLIENT, + pm_results, &rdir); + FAIL_IF(cnt != 1); + FAIL_IF(pm_results[0] != ALPROTO_DCERPC); - r = 1; - - end: - if (alpd_tctx != NULL) - AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + AppLayerProtoDetectDestroyCtxThread(alpd_tctx); AppLayerProtoDetectDeSetup(); AppLayerProtoDetectUnittestCtxRestore(); - return r; + PASS; } /** @@ -2682,16 +2540,12 @@ static int AppLayerProtoDetectTest11(void) uint8_t l7data[] = "CONNECT www.ssllabs.com:443 HTTP/1.0\r\n"; uint8_t l7data_resp[] = "HTTP/1.1 405 Method Not Allowed\r\n"; - int r = 0; - Flow f; AppProto pm_results[ALPROTO_MAX]; - AppLayerProtoDetectThreadCtx *alpd_tctx; - + memset(pm_results, 0, sizeof(pm_results)); + Flow f; memset(&f, 0x00, sizeof(f)); f.protomap = FlowGetProtoMapping(IPPROTO_TCP); - memset(pm_results, 0, sizeof(pm_results)); - AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, "HTTP", 4, 0, STREAM_TOSERVER); AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, "GET", 3, 0, STREAM_TOSERVER); AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, "PUT", 3, 0, STREAM_TOSERVER); @@ -2704,71 +2558,41 @@ static int AppLayerProtoDetectTest11(void) AppLayerProtoDetectPrepareState(); /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since * it sets internal structures which depends on the above function. */ - alpd_tctx = AppLayerProtoDetectGetCtxThread(); - - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 7) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 7\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1\n"); - goto end; - } - - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map == NULL) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map != NULL\n"); - goto end; - } - - if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[0]->alproto != ALPROTO_HTTP || - alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[1]->alproto != ALPROTO_HTTP || - alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[2]->alproto != ALPROTO_HTTP || - alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[3]->alproto != ALPROTO_HTTP || - alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[4]->alproto != ALPROTO_HTTP || - alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[5]->alproto != ALPROTO_HTTP || - alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[6]->alproto != ALPROTO_HTTP || - alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP) - { - printf("failure 1\n"); - goto end; - } - - memset(pm_results, 0, sizeof(pm_results)); + AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread(); + FAIL_IF_NULL(alpd_tctx); + + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 7); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map == NULL); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL); + + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[0]->alproto != ALPROTO_HTTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[1]->alproto != ALPROTO_HTTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[2]->alproto != ALPROTO_HTTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[3]->alproto != ALPROTO_HTTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[4]->alproto != ALPROTO_HTTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[5]->alproto != ALPROTO_HTTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[6]->alproto != ALPROTO_HTTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP); + + bool rdir = false; uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, - l7data, sizeof(l7data), - STREAM_TOSERVER, - IPPROTO_TCP, - pm_results); - if (cnt != 1 && pm_results[0] != ALPROTO_HTTP) { - printf("l7data - cnt != 1 && pm_results[0] != AlPROTO_HTTP\n"); - goto end; - } + &f, l7data, sizeof(l7data), STREAM_TOSERVER, + pm_results, &rdir); + FAIL_IF(cnt != 1); + FAIL_IF(pm_results[0] != ALPROTO_HTTP); memset(pm_results, 0, sizeof(pm_results)); cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, - l7data_resp, sizeof(l7data_resp), - STREAM_TOCLIENT, - IPPROTO_TCP, - pm_results); - if (cnt != 1 && pm_results[0] != ALPROTO_HTTP) { - printf("l7data_resp - cnt != 1 && pm_results[0] != AlPROTO_HTTP\n"); - goto end; - } + &f, l7data_resp, sizeof(l7data_resp), STREAM_TOCLIENT, + pm_results, &rdir); + FAIL_IF(cnt != 1); + FAIL_IF(pm_results[0] != ALPROTO_HTTP); - r = 1; - - end: - if (alpd_tctx != NULL) - AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + AppLayerProtoDetectDestroyCtxThread(alpd_tctx); AppLayerProtoDetectDeSetup(); AppLayerProtoDetectUnittestCtxRestore(); - return r; + PASS; } /** @@ -2832,12 +2656,9 @@ static int AppLayerProtoDetectTest13(void) uint8_t l7data[] = "CONNECT www.ssllabs.com:443 HTTP/1.0\r\n"; uint8_t l7data_resp[] = "HTTP/1.1 405 Method Not Allowed\r\n"; - int r = 0; - Flow f; AppProto pm_results[ALPROTO_MAX]; - AppLayerProtoDetectThreadCtx *alpd_tctx; - uint32_t cnt; + Flow f; memset(&f, 0x00, sizeof(f)); f.protomap = FlowGetProtoMapping(IPPROTO_TCP); @@ -2853,62 +2674,37 @@ static int AppLayerProtoDetectTest13(void) AppLayerProtoDetectPrepareState(); /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since * it sets internal structures which depends on the above function. */ - alpd_tctx = AppLayerProtoDetectGetCtxThread(); + AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread(); - if (alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].max_pat_id != 7) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].max_pat_id != 7\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[1].max_pat_id != 1) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[1].max_pat_id != 1\n"); - goto end; - } + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].max_pat_id != 7); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[1].max_pat_id != 1); - if (alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[0]->alproto != ALPROTO_HTTP || - alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[1]->alproto != ALPROTO_HTTP || - alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[2]->alproto != ALPROTO_HTTP || - alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[3]->alproto != ALPROTO_HTTP || - alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[4]->alproto != ALPROTO_HTTP || - alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[5]->alproto != ALPROTO_HTTP || - alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[6]->alproto != ALPROTO_HTTP || - alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP) - { - printf("failure 1\n"); - goto end; - } + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[0]->alproto != ALPROTO_HTTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[1]->alproto != ALPROTO_HTTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[2]->alproto != ALPROTO_HTTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[3]->alproto != ALPROTO_HTTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[4]->alproto != ALPROTO_HTTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[5]->alproto != ALPROTO_HTTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[6]->alproto != ALPROTO_HTTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP); memset(pm_results, 0, sizeof(pm_results)); - cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, - l7data, sizeof(l7data), - STREAM_TOSERVER, - IPPROTO_TCP, - pm_results); - if (cnt != 0) { - printf("l7data - cnt != 0\n"); - goto end; - } + bool rdir = false; + uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, + &f, l7data, sizeof(l7data), STREAM_TOSERVER, + pm_results, &rdir); + FAIL_IF(cnt != 0); memset(pm_results, 0, sizeof(pm_results)); cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, - l7data_resp, sizeof(l7data_resp), - STREAM_TOCLIENT, - IPPROTO_TCP, - pm_results); - if (cnt != 0) { - printf("l7data_resp - cnt != 0\n"); - goto end; - } + &f, l7data_resp, sizeof(l7data_resp), STREAM_TOCLIENT, + pm_results, &rdir); + FAIL_IF(cnt != 0); - r = 1; - - end: - if (alpd_tctx != NULL) - AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + AppLayerProtoDetectDestroyCtxThread(alpd_tctx); AppLayerProtoDetectDeSetup(); AppLayerProtoDetectUnittestCtxRestore(); - return r; + PASS; } /** @@ -2923,12 +2719,9 @@ static int AppLayerProtoDetectTest14(void) uint8_t l7data[] = "CONNECT www.ssllabs.com:443 HTTP/1.0\r\n"; uint8_t l7data_resp[] = "HTTP/1.1 405 Method Not Allowed\r\n"; - int r = 0; - Flow f; AppProto pm_results[ALPROTO_MAX]; - AppLayerProtoDetectThreadCtx *alpd_tctx; uint32_t cnt; - + Flow f; memset(&f, 0x00, sizeof(f)); f.protomap = FlowGetProtoMapping(IPPROTO_UDP); @@ -2944,62 +2737,40 @@ static int AppLayerProtoDetectTest14(void) AppLayerProtoDetectPrepareState(); /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since * it sets internal structures which depends on the above function. */ - alpd_tctx = AppLayerProtoDetectGetCtxThread(); + AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread(); + FAIL_IF_NULL(alpd_tctx); - if (alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].max_pat_id != 7) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].max_pat_id != 7\n"); - goto end; - } - if (alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[1].max_pat_id != 1) { - printf("alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[1].max_pat_id != 1\n"); - goto end; - } + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].max_pat_id != 7); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[1].max_pat_id != 1); - if (alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[0]->alproto != ALPROTO_HTTP || - alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[1]->alproto != ALPROTO_HTTP || - alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[2]->alproto != ALPROTO_HTTP || - alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[3]->alproto != ALPROTO_HTTP || - alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[4]->alproto != ALPROTO_HTTP || - alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[5]->alproto != ALPROTO_HTTP || - alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[6]->alproto != ALPROTO_HTTP || - alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP) - { - printf("failure 1\n"); - goto end; - } + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[0]->alproto != ALPROTO_HTTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[1]->alproto != ALPROTO_HTTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[2]->alproto != ALPROTO_HTTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[3]->alproto != ALPROTO_HTTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[4]->alproto != ALPROTO_HTTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[5]->alproto != ALPROTO_HTTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[6]->alproto != ALPROTO_HTTP); + FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP); memset(pm_results, 0, sizeof(pm_results)); + bool rdir = false; cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, - l7data, sizeof(l7data), - STREAM_TOSERVER, - IPPROTO_UDP, - pm_results); - if (cnt != 1 && pm_results[0] != ALPROTO_HTTP) { - printf("l7data - cnt != 0\n"); - goto end; - } + &f, l7data, sizeof(l7data), STREAM_TOSERVER, + pm_results, &rdir); + FAIL_IF(cnt != 1); + FAIL_IF(pm_results[0] != ALPROTO_HTTP); memset(pm_results, 0, sizeof(pm_results)); cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, - l7data_resp, sizeof(l7data_resp), - STREAM_TOCLIENT, - IPPROTO_UDP, - pm_results); - if (cnt != 1 && pm_results[0] != ALPROTO_HTTP) { - printf("l7data_resp - cnt != 0\n"); - goto end; - } + &f, l7data_resp, sizeof(l7data_resp), STREAM_TOCLIENT, + pm_results, &rdir); + FAIL_IF(cnt != 1); + FAIL_IF(pm_results[0] != ALPROTO_HTTP); - r = 1; - - end: - if (alpd_tctx != NULL) - AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + AppLayerProtoDetectDestroyCtxThread(alpd_tctx); AppLayerProtoDetectDeSetup(); AppLayerProtoDetectUnittestCtxRestore(); - return r; + PASS; } typedef struct AppLayerProtoDetectPPTestDataElement_ { @@ -3121,9 +2892,9 @@ static int AppLayerProtoDetectPPTestData(AppLayerProtoDetectProbingParser *pp, return result; } -static uint16_t ProbingParserDummyForTesting(Flow *f, +static uint16_t ProbingParserDummyForTesting(Flow *f, uint8_t direction, uint8_t *input, - uint32_t input_len) + uint32_t input_len, uint8_t *rdir) { return 0; } diff --git a/src/app-layer-detect-proto.h b/src/app-layer-detect-proto.h index 0f0e3a97d5..779f50a883 100644 --- a/src/app-layer-detect-proto.h +++ b/src/app-layer-detect-proto.h @@ -27,8 +27,9 @@ typedef struct AppLayerProtoDetectThreadCtx_ AppLayerProtoDetectThreadCtx; -typedef AppProto (*ProbingParserFPtr)(Flow *f, - uint8_t *input, uint32_t input_len); +typedef AppProto (*ProbingParserFPtr)(Flow *f, uint8_t dir, + uint8_t *input, uint32_t input_len, + uint8_t *rdir); /***** Protocol Retrieval *****/ @@ -41,13 +42,15 @@ typedef AppProto (*ProbingParserFPtr)(Flow *f, * \param buflen The length of the above buffer. * \param ipproto The ip protocol. * \param direction The direction bitfield - STREAM_TOSERVER/STREAM_TOCLIENT. + * \param[out] reverse_flow true if flow is detected to be reversed * * \retval The app layer protocol. */ AppProto AppLayerProtoDetectGetProto(AppLayerProtoDetectThreadCtx *tctx, Flow *f, uint8_t *buf, uint32_t buflen, - uint8_t ipproto, uint8_t direction); + uint8_t ipproto, uint8_t direction, + bool *reverse_flow); /***** State Preparation *****/ @@ -84,9 +87,14 @@ int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, * \brief Registers a case-sensitive pattern for protocol detection. */ int AppLayerProtoDetectPMRegisterPatternCS(uint8_t ipproto, AppProto alproto, - const char *pattern, - uint16_t depth, uint16_t offset, - uint8_t direction); + const char *pattern, uint16_t depth, uint16_t offset, + uint8_t direction); +int AppLayerProtoDetectPMRegisterPatternCSwPP(uint8_t ipproto, AppProto alproto, + const char *pattern, uint16_t depth, uint16_t offset, + uint8_t direction, + ProbingParserFPtr PPFunc, + uint16_t pp_min_depth, uint16_t pp_max_depth); + /** * \brief Registers a case-insensitive pattern for protocol detection. */ diff --git a/src/app-layer-dnp3.c b/src/app-layer-dnp3.c index 61945a4046..7f27ce4f54 100644 --- a/src/app-layer-dnp3.c +++ b/src/app-layer-dnp3.c @@ -264,7 +264,9 @@ static int DNP3ContainsBanner(const uint8_t *input, uint32_t len) /** * \brief DNP3 probing parser. */ -static uint16_t DNP3ProbingParser(Flow *f, uint8_t *input, uint32_t len) +static uint16_t DNP3ProbingParser(Flow *f, uint8_t direction, + uint8_t *input, uint32_t len, + uint8_t *rdir) { DNP3LinkHeader *hdr = (DNP3LinkHeader *)input; @@ -2041,27 +2043,28 @@ static int DNP3ProbingParserTest(void) 0x05, 0x64, 0x05, 0xc9, 0x03, 0x00, 0x04, 0x00, 0xbd, 0x71 }; + uint8_t rdir = 0; /* Valid frame. */ - FAIL_IF(DNP3ProbingParser(NULL, pkt, sizeof(pkt)) != ALPROTO_DNP3); + FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, pkt, sizeof(pkt), &rdir) != ALPROTO_DNP3); /* Send too little bytes. */ - FAIL_IF(DNP3ProbingParser(NULL, pkt, sizeof(DNP3LinkHeader) - 1) != ALPROTO_UNKNOWN); + FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, pkt, sizeof(DNP3LinkHeader) - 1, &rdir) != ALPROTO_UNKNOWN); /* Bad start bytes. */ pkt[0] = 0x06; - FAIL_IF(DNP3ProbingParser(NULL, pkt, sizeof(pkt)) != ALPROTO_FAILED); + FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, pkt, sizeof(pkt), &rdir) != ALPROTO_FAILED); /* Restore start byte. */ pkt[0] = 0x05; /* Set the length to a value less than the minimum length of 5. */ pkt[2] = 0x03; - FAIL_IF(DNP3ProbingParser(NULL, pkt, sizeof(pkt)) != ALPROTO_FAILED); + FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, pkt, sizeof(pkt), &rdir) != ALPROTO_FAILED); /* Send a banner. */ char mybanner[] = "Welcome to DNP3 SCADA."; - FAIL_IF(DNP3ProbingParser(NULL, (uint8_t *)mybanner, sizeof(mybanner)) != ALPROTO_DNP3); + FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, (uint8_t *)mybanner, sizeof(mybanner), &rdir) != ALPROTO_DNP3); PASS; } diff --git a/src/app-layer-dns-tcp-rust.c b/src/app-layer-dns-tcp-rust.c index 1ecb34a04b..85e4c61a30 100644 --- a/src/app-layer-dns-tcp-rust.c +++ b/src/app-layer-dns-tcp-rust.c @@ -52,7 +52,8 @@ static int RustDNSTCPParseResponse(Flow *f, void *state, local_data); } -static uint16_t RustDNSTCPProbe(Flow *f, uint8_t *input, uint32_t len) +static uint16_t RustDNSTCPProbe(Flow *f, uint8_t direction, + uint8_t *input, uint32_t len, uint8_t *rdir) { SCLogDebug("RustDNSTCPProbe"); if (len == 0 || len < sizeof(DNSHeader)) { diff --git a/src/app-layer-dns-tcp.c b/src/app-layer-dns-tcp.c index 8492de6b44..fcc477ee29 100644 --- a/src/app-layer-dns-tcp.c +++ b/src/app-layer-dns-tcp.c @@ -63,7 +63,9 @@ struct DNSTcpHeader_ { } __attribute__((__packed__)); typedef struct DNSTcpHeader_ DNSTcpHeader; -static uint16_t DNSTcpProbingParser(Flow *f, uint8_t *input, uint32_t ilen); +static uint16_t DNSTcpProbingParser(Flow *f, uint8_t direction, + uint8_t *input, uint32_t ilen, + uint8_t *rdir); /** \internal * \param input_len at least enough for the DNSTcpHeader @@ -317,7 +319,8 @@ static int DNSTCPRequestParse(Flow *f, void *dstate, /* Clear gap state. */ if (dns_state->gap_ts) { - if (DNSTcpProbingParser(f, input, input_len) == ALPROTO_DNS) { + if (DNSTcpProbingParser(f, STREAM_TOSERVER, + input, input_len, NULL) == ALPROTO_DNS) { SCLogDebug("New data probed as DNS, clearing gap state."); BufferReset(dns_state); dns_state->gap_ts = 0; @@ -557,7 +560,8 @@ static int DNSTCPResponseParse(Flow *f, void *dstate, /* Clear gap state. */ if (dns_state->gap_tc) { - if (DNSTcpProbingParser(f, input, input_len) == ALPROTO_DNS) { + if (DNSTcpProbingParser(f, STREAM_TOCLIENT, + input, input_len, NULL) == ALPROTO_DNS) { SCLogDebug("New data probed as DNS, clearing gap state."); BufferReset(dns_state); dns_state->gap_tc = 0; @@ -639,7 +643,9 @@ bad_data: SCReturnInt(-1); } -static uint16_t DNSTcpProbingParser(Flow *f, uint8_t *input, uint32_t ilen) +static uint16_t DNSTcpProbingParser(Flow *f, uint8_t direction, + uint8_t *input, uint32_t ilen, + uint8_t *rdir) { if (ilen == 0 || ilen < sizeof(DNSTcpHeader)) { SCLogDebug("ilen too small, hoped for at least %"PRIuMAX, (uintmax_t)sizeof(DNSTcpHeader)); @@ -679,7 +685,9 @@ static uint16_t DNSTcpProbingParser(Flow *f, uint8_t *input, uint32_t ilen) * This is a minimal parser that just checks that the input contains enough * data for a TCP DNS response. */ -static uint16_t DNSTcpProbeResponse(Flow *f, uint8_t *input, uint32_t len) +static uint16_t DNSTcpProbeResponse(Flow *f, uint8_t direction, + uint8_t *input, uint32_t len, + uint8_t *rdir) { if (len == 0 || len < sizeof(DNSTcpHeader)) { return ALPROTO_UNKNOWN; diff --git a/src/app-layer-dns-udp-rust.c b/src/app-layer-dns-udp-rust.c index 0411b9febb..b3e5c08ab2 100644 --- a/src/app-layer-dns-udp-rust.c +++ b/src/app-layer-dns-udp-rust.c @@ -50,7 +50,8 @@ static int RustDNSUDPParseResponse(Flow *f, void *state, local_data); } -static uint16_t DNSUDPProbe(Flow *f, uint8_t *input, uint32_t len) +static uint16_t DNSUDPProbe(Flow *f, uint8_t direction, + uint8_t *input, uint32_t len, uint8_t *rdir) { if (len == 0 || len < sizeof(DNSHeader)) { return ALPROTO_UNKNOWN; diff --git a/src/app-layer-dns-udp.c b/src/app-layer-dns-udp.c index 9c59e63e1b..4e28133002 100644 --- a/src/app-layer-dns-udp.c +++ b/src/app-layer-dns-udp.c @@ -331,7 +331,8 @@ insufficient_data: SCReturnInt(-1); } -static uint16_t DNSUdpProbingParser(Flow *f, uint8_t *input, uint32_t ilen) +static uint16_t DNSUdpProbingParser(Flow *f, uint8_t direction, + uint8_t *input, uint32_t ilen, uint8_t *rdir) { if (ilen == 0 || ilen < sizeof(DNSHeader)) { SCLogDebug("ilen too small, hoped for at least %"PRIuMAX, (uintmax_t)sizeof(DNSHeader)); diff --git a/src/app-layer-enip.c b/src/app-layer-enip.c index 743a84b262..6a377f2f28 100644 --- a/src/app-layer-enip.c +++ b/src/app-layer-enip.c @@ -359,7 +359,8 @@ static int ENIPParse(Flow *f, void *state, AppLayerParserState *pstate, -static uint16_t ENIPProbingParser(Flow *f, uint8_t *input, uint32_t input_len) +static uint16_t ENIPProbingParser(Flow *f, uint8_t direction, + uint8_t *input, uint32_t input_len, uint8_t *rdir) { // SCLogDebug("ENIPProbingParser %d", input_len); if (input_len < sizeof(ENIPEncapHdr)) diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index c945b4c579..8e660de2c0 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -1427,8 +1427,10 @@ static void ModbusStateFree(void *state) } static uint16_t ModbusProbingParser(Flow *f, + uint8_t direction, uint8_t *input, - uint32_t input_len) + uint32_t input_len, + uint8_t *rdir) { ModbusHeader *header = (ModbusHeader *) input; diff --git a/src/app-layer-nfs-tcp.c b/src/app-layer-nfs-tcp.c index abd816b3ea..45dbaa5a90 100644 --- a/src/app-layer-nfs-tcp.c +++ b/src/app-layer-nfs-tcp.c @@ -112,30 +112,21 @@ static AppLayerDecoderEvents *NFSTCPGetEvents(void *state, uint64_t id) * \retval ALPROTO_NFS if it looks like echo, otherwise * ALPROTO_UNKNOWN. */ -static AppProto NFSTCPProbingParserTS(Flow *f, uint8_t *input, uint32_t input_len) +static AppProto NFSTCPProbingParser(Flow *f, + uint8_t direction, + uint8_t *input, uint32_t input_len, + uint8_t *rdir) { if (input_len < NFSTCP_MIN_FRAME_LEN) { return ALPROTO_UNKNOWN; } - int8_t r = rs_nfs_probe_ts(input, input_len); - if (r == 1) { - return ALPROTO_NFS; - } else if (r == -1) { - return ALPROTO_FAILED; - } - - SCLogDebug("Protocol not detected as ALPROTO_NFS."); - return ALPROTO_UNKNOWN; -} - -static AppProto NFSTCPProbingParserTC(Flow *f, uint8_t *input, uint32_t input_len) -{ - if (input_len < NFSTCP_MIN_FRAME_LEN) { - return ALPROTO_UNKNOWN; + int8_t r = 0; + if (direction & STREAM_TOSERVER) { + r = rs_nfs_probe_ts(input, input_len); + } else { + r = rs_nfs_probe_tc(input, input_len); } - - int8_t r = rs_nfs_probe_tc(input, input_len); if (r == 1) { return ALPROTO_NFS; } else if (r == -1) { @@ -287,21 +278,22 @@ void RegisterNFSTCPParsers(void) SCLogDebug("Unittest mode, registering default configuration."); AppLayerProtoDetectPPRegister(IPPROTO_TCP, NFSTCP_DEFAULT_PORT, ALPROTO_NFS, 0, NFSTCP_MIN_FRAME_LEN, STREAM_TOSERVER, - NFSTCPProbingParserTS, NFSTCPProbingParserTC); + NFSTCPProbingParser, NFSTCPProbingParser); } else { if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, proto_name, ALPROTO_NFS, 0, NFSTCP_MIN_FRAME_LEN, - NFSTCPProbingParserTS, NFSTCPProbingParserTC)) { + NFSTCPProbingParser, NFSTCPProbingParser)) { SCLogDebug("No NFSTCP app-layer configuration, enabling NFSTCP" " detection TCP detection on port %s.", NFSTCP_DEFAULT_PORT); + /* register 'midstream' probing parsers if midstream is enabled. */ AppLayerProtoDetectPPRegister(IPPROTO_TCP, NFSTCP_DEFAULT_PORT, ALPROTO_NFS, 0, NFSTCP_MIN_FRAME_LEN, STREAM_TOSERVER, - NFSTCPProbingParserTS, NFSTCPProbingParserTC); + NFSTCPProbingParser, NFSTCPProbingParser); } } diff --git a/src/app-layer-nfs-udp.c b/src/app-layer-nfs-udp.c index 50cce89790..5cc58965a3 100644 --- a/src/app-layer-nfs-udp.c +++ b/src/app-layer-nfs-udp.c @@ -109,7 +109,8 @@ static AppLayerDecoderEvents *NFSGetEvents(void *state, uint64_t id) * \retval ALPROTO_NFS if it looks like echo, otherwise * ALPROTO_UNKNOWN. */ -static AppProto NFSProbingParserTS(Flow *f, uint8_t *input, uint32_t input_len) +static AppProto NFSProbingParser(Flow *f, uint8_t direction, + uint8_t *input, uint32_t input_len, uint8_t *rdir) { SCLogDebug("probing"); if (input_len < NFS_MIN_FRAME_LEN) { @@ -117,28 +118,12 @@ static AppProto NFSProbingParserTS(Flow *f, uint8_t *input, uint32_t input_len) return ALPROTO_UNKNOWN; } - int8_t r = rs_nfs_probe_udp_ts(input, input_len); - if (r == 1) { - SCLogDebug("nfs"); - return ALPROTO_NFS; - } else if (r == -1) { - SCLogDebug("failed"); - return ALPROTO_FAILED; - } - - SCLogDebug("Protocol not detected as ALPROTO_NFS."); - return ALPROTO_UNKNOWN; -} - -static AppProto NFSProbingParserTC(Flow *f, uint8_t *input, uint32_t input_len) -{ - SCLogDebug("probing"); - if (input_len < NFS_MIN_FRAME_LEN) { - SCLogDebug("unknown"); - return ALPROTO_UNKNOWN; - } + int8_t r = 0; + if (direction & STREAM_TOSERVER) + r = rs_nfs_probe_udp_ts(input, input_len); + else + r = rs_nfs_probe_udp_tc(input, input_len); - int8_t r = rs_nfs_probe_tc(input, input_len); if (r == 1) { SCLogDebug("nfs"); return ALPROTO_NFS; @@ -280,21 +265,21 @@ void RegisterNFSUDPParsers(void) SCLogDebug("Unittest mode, registering default configuration."); AppLayerProtoDetectPPRegister(IPPROTO_UDP, NFS_DEFAULT_PORT, ALPROTO_NFS, 0, NFS_MIN_FRAME_LEN, STREAM_TOSERVER, - NFSProbingParserTS, NFSProbingParserTC); + NFSProbingParser, NFSProbingParser); } else { if (!AppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP, proto_name, ALPROTO_NFS, 0, NFS_MIN_FRAME_LEN, - NFSProbingParserTS, NFSProbingParserTC)) { + NFSProbingParser, NFSProbingParser)) { SCLogDebug("No NFS app-layer configuration, enabling NFS" " detection TCP detection on port %s.", NFS_DEFAULT_PORT); AppLayerProtoDetectPPRegister(IPPROTO_UDP, NFS_DEFAULT_PORT, ALPROTO_NFS, 0, NFS_MIN_FRAME_LEN, STREAM_TOSERVER, - NFSProbingParserTS, NFSProbingParserTC); + NFSProbingParser, NFSProbingParser); } } diff --git a/src/app-layer-protos.h b/src/app-layer-protos.h index 855a1b3397..0d1d8bff6b 100644 --- a/src/app-layer-protos.h +++ b/src/app-layer-protos.h @@ -68,6 +68,11 @@ enum AppProtoEnum { /* not using the enum as that is a unsigned int, so 4 bytes */ typedef uint16_t AppProto; +static inline bool AppProtoIsValid(AppProto a) +{ + return ((a > ALPROTO_UNKNOWN && a < ALPROTO_FAILED)); +} + /** * \brief Maps the ALPROTO_*, to its string equivalent. * diff --git a/src/app-layer-smb-tcp-rust.c b/src/app-layer-smb-tcp-rust.c index 3681c124be..176af62e9a 100644 --- a/src/app-layer-smb-tcp-rust.c +++ b/src/app-layer-smb-tcp-rust.c @@ -78,8 +78,8 @@ static int RustSMBTCPParseResponse(Flow *f, void *state, return res; } -static uint16_t RustSMBTCPProbe(Flow *f, - uint8_t *input, uint32_t len) +static uint16_t RustSMBTCPProbe(Flow *f, uint8_t direction, + uint8_t *input, uint32_t len, uint8_t *rdir) { SCLogDebug("RustSMBTCPProbe"); @@ -87,7 +87,7 @@ static uint16_t RustSMBTCPProbe(Flow *f, return ALPROTO_UNKNOWN; } - const int r = rs_smb_probe_tcp(input, len); + const int r = rs_smb_probe_tcp(direction, input, len, rdir); switch (r) { case 1: return ALPROTO_SMB; @@ -184,22 +184,28 @@ static int RustSMBRegisterPatternsForProtocolDetection(void) { int r = 0; /* SMB1 */ - r |= AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB, - "|ff|SMB", 8, 4, STREAM_TOSERVER); - r |= AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB, - "|ff|SMB", 8, 4, STREAM_TOCLIENT); + r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB, + "|ff|SMB", 8, 4, STREAM_TOSERVER, RustSMBTCPProbe, + MIN_REC_SIZE, MIN_REC_SIZE); + r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB, + "|ff|SMB", 8, 4, STREAM_TOCLIENT, RustSMBTCPProbe, + MIN_REC_SIZE, MIN_REC_SIZE); /* SMB2/3 */ - r |= AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB, - "|fe|SMB", 8, 4, STREAM_TOSERVER); - r |= AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB, - "|fe|SMB", 8, 4, STREAM_TOCLIENT); + r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB, + "|fe|SMB", 8, 4, STREAM_TOSERVER, RustSMBTCPProbe, + MIN_REC_SIZE, MIN_REC_SIZE); + r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB, + "|fe|SMB", 8, 4, STREAM_TOCLIENT, RustSMBTCPProbe, + MIN_REC_SIZE, MIN_REC_SIZE); /* SMB3 encrypted records */ - r |= AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB, - "|fd|SMB", 8, 4, STREAM_TOSERVER); - r |= AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB, - "|fd|SMB", 8, 4, STREAM_TOCLIENT); + r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB, + "|fd|SMB", 8, 4, STREAM_TOSERVER, RustSMBTCPProbe, + MIN_REC_SIZE, MIN_REC_SIZE); + r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB, + "|fd|SMB", 8, 4, STREAM_TOCLIENT, RustSMBTCPProbe, + MIN_REC_SIZE, MIN_REC_SIZE); return r == 0 ? 0 : -1; } diff --git a/src/app-layer-smb.c b/src/app-layer-smb.c index 994d7a25e7..3fb3dc3e7d 100644 --- a/src/app-layer-smb.c +++ b/src/app-layer-smb.c @@ -1512,7 +1512,8 @@ static int SMBGetAlstateProgress(void *tx, uint8_t direction) #define SMB_PROBING_PARSER_MIN_DEPTH 8 -static uint16_t SMBProbingParser(Flow *f, uint8_t *input, uint32_t ilen) +static uint16_t SMBProbingParser(Flow *f, uint8_t direction, + uint8_t *input, uint32_t ilen, uint8_t *rdir) { int32_t len; int32_t input_len = ilen; @@ -2298,10 +2299,11 @@ static int SMBParserTest05(void) AppLayerProtoDetectPrepareState(); alpd_tctx = AppLayerProtoDetectGetCtxThread(); + bool reverse_flow = false; alproto = AppLayerProtoDetectGetProto(alpd_tctx, &f, smbbuf1, smblen1, - IPPROTO_TCP, STREAM_TOSERVER); + IPPROTO_TCP, STREAM_TOSERVER, &reverse_flow); if (alproto != ALPROTO_UNKNOWN) { printf("alproto is %"PRIu16 ". Should be ALPROTO_UNKNOWN\n", alproto); @@ -2311,7 +2313,7 @@ static int SMBParserTest05(void) alproto = AppLayerProtoDetectGetProto(alpd_tctx, &f, smbbuf2, smblen2, - IPPROTO_TCP, STREAM_TOSERVER); + IPPROTO_TCP, STREAM_TOSERVER, &reverse_flow); if (alproto != ALPROTO_SMB) { printf("alproto is %"PRIu16 ". Should be ALPROTO_SMB\n", alproto); @@ -2382,10 +2384,11 @@ static int SMBParserTest06(void) AppLayerProtoDetectPrepareState(); alpd_tctx = AppLayerProtoDetectGetCtxThread(); + bool reverse_flow = false; alproto = AppLayerProtoDetectGetProto(alpd_tctx, &f, smbbuf1, smblen1, - IPPROTO_TCP, STREAM_TOSERVER); + IPPROTO_TCP, STREAM_TOSERVER, &reverse_flow); if (alproto != ALPROTO_UNKNOWN) { printf("alproto is %"PRIu16 ". Should be ALPROTO_UNKNOWN\n", alproto); @@ -2395,7 +2398,7 @@ static int SMBParserTest06(void) alproto = AppLayerProtoDetectGetProto(alpd_tctx, &f, smbbuf2, smblen2, - IPPROTO_TCP, STREAM_TOSERVER); + IPPROTO_TCP, STREAM_TOSERVER, &reverse_flow); if (alproto != ALPROTO_SMB) { printf("alproto is %"PRIu16 ". Should be ALPROTO_SMB\n", alproto); diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index 94c1e86dd7..d73658b64d 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -2624,7 +2624,8 @@ static void SSLStateTransactionFree(void *state, uint64_t tx_id) /* do nothing */ } -static uint16_t SSLProbingParser(Flow *f, uint8_t *input, uint32_t ilen) +static AppProto SSLProbingParser(Flow *f, uint8_t direction, + uint8_t *input, uint32_t ilen, uint8_t *rdir) { /* probably a rst/fin sending an eof */ if (ilen == 0) diff --git a/src/app-layer-template.c b/src/app-layer-template.c index 22f9628c83..299b1ee778 100644 --- a/src/app-layer-template.c +++ b/src/app-layer-template.c @@ -194,7 +194,8 @@ static AppLayerDecoderEvents *TemplateGetEvents(void *statev, uint64_t tx_id) * \retval ALPROTO_TEMPLATE if it looks like template, otherwise * ALPROTO_UNKNOWN. */ -static AppProto TemplateProbingParser(Flow *f, uint8_t *input, uint32_t input_len) +static AppProto TemplateProbingParser(Flow *f, uint8_t direction, + uint8_t *input, uint32_t input_len, uint8_t *rdir) { /* Very simple test - if there is input, this is template. */ if (input_len >= TEMPLATE_MIN_FRAME_LEN) { diff --git a/src/app-layer-tftp.c b/src/app-layer-tftp.c index 733baadbed..737205c47b 100644 --- a/src/app-layer-tftp.c +++ b/src/app-layer-tftp.c @@ -112,7 +112,8 @@ static AppLayerDecoderEvents *TFTPGetEvents(void *state, uint64_t tx_id) * \retval ALPROTO_TFTP if it looks like echo, otherwise * ALPROTO_UNKNOWN. */ -static AppProto TFTPProbingParser(Flow *f, uint8_t *input, uint32_t input_len) +static AppProto TFTPProbingParser(Flow *f, uint8_t direction, + uint8_t *input, uint32_t input_len, uint8_t *rdir) { /* Very simple test - if there is input, this is tftp. * Also check if it's starting by a zero */ diff --git a/src/app-layer.c b/src/app-layer.c index 7de157cf43..761f9497b7 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -323,11 +323,13 @@ static int TCPProtoDetect(ThreadVars *tv, } #endif + bool reverse_flow = false; PACKET_PROFILING_APP_PD_START(app_tctx); *alproto = AppLayerProtoDetectGetProto(app_tctx->alpd_tctx, f, data, data_len, - IPPROTO_TCP, flags); + IPPROTO_TCP, flags, &reverse_flow); PACKET_PROFILING_APP_PD_END(app_tctx); + SCLogDebug("alproto %u rev %s", *alproto, reverse_flow ? "true" : "false"); if (*alproto != ALPROTO_UNKNOWN) { if (*alproto_otherdir != ALPROTO_UNKNOWN && *alproto_otherdir != *alproto) { @@ -353,6 +355,15 @@ static int TCPProtoDetect(ThreadVars *tv, TcpSessionSetReassemblyDepth(ssn, AppLayerParserGetStreamDepth(f)); FlagPacketFlow(p, f, flags); + /* if protocol detection indicated that we need to reverse + * the direction of the flow, do it now. We flip the flow, + * packet and the direction flags */ + if (reverse_flow) { + SCLogDebug("reversing flow after proto detect told us so"); + PacketSwap(p); + FlowSwap(f); + SWAP_FLAGS(flags, STREAM_TOSERVER, STREAM_TOCLIENT); + } /* account flow if we have both sides */ if (*alproto_otherdir != ALPROTO_UNKNOWN) { @@ -680,15 +691,23 @@ int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow * SCLogDebug("Detecting AL proto on udp mesg (len %" PRIu32 ")", p->payload_len); + bool reverse_flow = false; PACKET_PROFILING_APP_PD_START(tctx); f->alproto = AppLayerProtoDetectGetProto(tctx->alpd_tctx, f, p->payload, p->payload_len, - IPPROTO_UDP, flags); + IPPROTO_UDP, flags, &reverse_flow); PACKET_PROFILING_APP_PD_END(tctx); if (f->alproto != ALPROTO_UNKNOWN) { AppLayerIncFlowCounter(tv, f); + if (reverse_flow) { + SCLogDebug("reversing flow after proto detect told us so"); + PacketSwap(p); + FlowSwap(f); + SWAP_FLAGS(flags, STREAM_TOSERVER, STREAM_TOCLIENT); + } + PACKET_PROFILING_APP_START(tctx, f->alproto); r = AppLayerParserParse(tv, tctx->alp_tctx, f, f->alproto, flags, p->payload, p->payload_len);