From: Victor Julien Date: Thu, 21 Mar 2019 12:57:50 +0000 (+0100) Subject: proto-detect: improve midstream support X-Git-Tag: suricata-5.0.0-beta1~106 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=422e4892cc724e2ec064a5672030220cbdcd5406;p=thirdparty%2Fsuricata.git proto-detect: improve midstream support When Suricata picks up a flow it assumes the first packet is toserver. In a perfect world without packet loss and where all sessions neatly start after Suricata itself started, this would be true. However, in reality we have to account for packet loss and Suricata starting to get packets for flows already active be for Suricata is (re)started. The protocol records on the wire would often be able to tell us more though. For example in SMB1 and SMB2 records there is a flag that indicates whether the record is a request or a response. This patch is enabling the procotol detection engine to utilize this information to 'reverse' the flow. There are three ways in which this is supported in this patch: 1. patterns for detection are registered per direction. If the proto was not recognized in the traffic direction, and midstream is enabled, the pattern set for the opposing direction is also evaluated. If that matches, the flow is considered to be in the wrong direction and is reversed. 2. probing parsers now have a way to feed back their understanding of the flow direction. They are now passed the direction as Suricata sees the traffic when calling the probing parsers. The parser can then see if its own observation matches that, and pass back it's own view to the caller. 3. a new pattern + probing parser set up: probing parsers can now be registered with a pattern, so that when the pattern matches the probing parser is called as well. The probing parser can then provide the protocol detection engine with the direction of the traffic. The process of reversing takes a multi step approach as well: a. reverse the current packets direction b. reverse most of the flows direction sensitive flags c. tag the flow as 'reversed'. This is because the 5 tuple is *not* reversed, since it is immutable after the flows creation. Most of the currently registered parsers benefit already: - HTTP/SMTP/FTP/TLS patterns are registered per direction already so they will benefit from the pattern midstream logic in (1) above. - the Rust based SMB parser uses a mix of pattern + probing parser as described in (3) above. - the NFS detection is purely done by probing parser and is updated to consider the direction in that parser. Other protocols, such as DNS, are still to do. Ticket: #2572 --- 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);