diff --git a/doc/userguide/rules/ssh-keywords.rst b/doc/userguide/rules/ssh-keywords.rst index fe61d1464643..8e967e3d536b 100644 --- a/doc/userguide/rules/ssh-keywords.rst +++ b/doc/userguide/rules/ssh-keywords.rst @@ -6,6 +6,26 @@ Suricata has several rule keywords to match on different elements of SSH connections. +Frames +------ + +The SSH parser supports the following frames: + +* ssh.record_hdr +* ssh.record_data +* ssh.record_pdu + +These are header + data = pdu for SSH records, after the banner and before encryption. +The SSH record header is 6 bytes long : 4 bytes length, 1 byte passing, 1 byte message code. + +Example: + +.. container:: example-rule + + alert ssh any any -> any any (msg:"hdr frame new keys"; :example-rule-emphasis:`frame:ssh.record.hdr; content: "|15|"; endswith;` bsize: 6; sid:2;) + +This rule matches like Wireshark ``ssh.message_code == 0x15``. + ssh.proto --------- Match on the version of the SSH protocol used. ``ssh.proto`` is a sticky buffer, diff --git a/rust/src/enip/enip.rs b/rust/src/enip/enip.rs index 05ec13a670d9..31c9152e5cab 100644 --- a/rust/src/enip/enip.rs +++ b/rust/src/enip/enip.rs @@ -565,7 +565,6 @@ unsafe extern "C" fn rs_enip_tx_get_alstate_progress(tx: *mut c_void, direction: return 0; } -// app-layer-frame-documentation tag start: FrameType enum #[derive(AppLayerFrameType)] pub enum EnipFrameType { Hdr, diff --git a/rust/src/http2/detect.rs b/rust/src/http2/detect.rs index 7354d270da26..b7a43ec522dc 100644 --- a/rust/src/http2/detect.rs +++ b/rust/src/http2/detect.rs @@ -434,11 +434,11 @@ pub fn http2_frames_get_header_value_vec( vec.extend_from_slice(&block.value); found = 1; } else if found == 1 && Rc::strong_count(&block.name) <= 2 { - vec.extend_from_slice(&[b',', b' ']); + vec.extend_from_slice(b", "); vec.extend_from_slice(&block.value); found = 2; } else if Rc::strong_count(&block.name) <= 2 { - vec.extend_from_slice(&[b',', b' ']); + vec.extend_from_slice(b", "); vec.extend_from_slice(&block.value); } } @@ -474,11 +474,11 @@ fn http2_frames_get_header_value<'a>( if let Ok(s) = single { vec.extend_from_slice(s); } - vec.extend_from_slice(&[b',', b' ']); + vec.extend_from_slice(b", "); vec.extend_from_slice(&block.value); found = 2; } else if Rc::strong_count(&block.name) <= 2 { - vec.extend_from_slice(&[b',', b' ']); + vec.extend_from_slice(b", "); vec.extend_from_slice(&block.value); } } @@ -730,7 +730,7 @@ fn http2_escape_header(blocks: &[parser::HTTP2FrameHeaderBlock], i: u32) -> Vec< let normalsize = blocks[i as usize].value.len() + 2 + blocks[i as usize].name.len(); let mut vec = Vec::with_capacity(normalsize); vec.extend_from_slice(&blocks[i as usize].name); - vec.extend_from_slice(&[b':', b' ']); + vec.extend_from_slice(b": "); vec.extend_from_slice(&blocks[i as usize].value); return vec; } @@ -750,12 +750,12 @@ pub unsafe extern "C" fn rs_http2_tx_get_header_names( for block in blocks.iter() { // we do not escape linefeeds in headers names vec.extend_from_slice(&block.name); - vec.extend_from_slice(&[b'\r', b'\n']); + vec.extend_from_slice(b"\r\n"); } } } if vec.len() > 2 { - vec.extend_from_slice(&[b'\r', b'\n']); + vec.extend_from_slice(b"\r\n"); tx.escaped.push(vec); let idx = tx.escaped.len() - 1; let value = &tx.escaped[idx]; @@ -815,9 +815,9 @@ pub unsafe extern "C" fn rs_http2_tx_get_headers( if !http2_header_iscookie(direction.into(), &block.name) { // we do not escape linefeeds nor : in headers names vec.extend_from_slice(&block.name); - vec.extend_from_slice(&[b':', b' ']); + vec.extend_from_slice(b": "); vec.extend_from_slice(http2_header_trimspaces(&block.value)); - vec.extend_from_slice(&[b'\r', b'\n']); + vec.extend_from_slice(b"\r\n"); } } } @@ -848,9 +848,9 @@ pub unsafe extern "C" fn rs_http2_tx_get_headers_raw( for block in blocks.iter() { // we do not escape linefeeds nor : in headers names vec.extend_from_slice(&block.name); - vec.extend_from_slice(&[b':', b' ']); + vec.extend_from_slice(b": "); vec.extend_from_slice(&block.value); - vec.extend_from_slice(&[b'\r', b'\n']); + vec.extend_from_slice(b"\r\n"); } } } diff --git a/rust/src/ike/ikev2.rs b/rust/src/ike/ikev2.rs index a1be25ffb4a2..d0d1ab321fcd 100644 --- a/rust/src/ike/ikev2.rs +++ b/rust/src/ike/ikev2.rs @@ -186,24 +186,20 @@ fn add_proposals( // Rule 1: warn on weak or unknown transforms for xform in &transforms { match *xform { - IkeV2Transform::Encryption(ref enc) => { - match *enc { - IkeTransformEncType::ENCR_DES_IV64 - | IkeTransformEncType::ENCR_DES - | IkeTransformEncType::ENCR_3DES - | IkeTransformEncType::ENCR_RC5 - | IkeTransformEncType::ENCR_IDEA - | IkeTransformEncType::ENCR_CAST - | IkeTransformEncType::ENCR_BLOWFISH - | IkeTransformEncType::ENCR_3IDEA - | IkeTransformEncType::ENCR_DES_IV32 - | IkeTransformEncType::ENCR_NULL => { - SCLogDebug!("Weak Encryption: {:?}", enc); - // XXX send event only if direction == Direction::ToClient ? - tx.set_event(IkeEvent::WeakCryptoEnc); - } - _ => (), - } + IkeV2Transform::Encryption( + IkeTransformEncType::ENCR_DES_IV64 + | IkeTransformEncType::ENCR_DES + | IkeTransformEncType::ENCR_3DES + | IkeTransformEncType::ENCR_RC5 + | IkeTransformEncType::ENCR_IDEA + | IkeTransformEncType::ENCR_CAST + | IkeTransformEncType::ENCR_BLOWFISH + | IkeTransformEncType::ENCR_3IDEA + | IkeTransformEncType::ENCR_DES_IV32 + | IkeTransformEncType::ENCR_NULL, + ) => { + // XXX send event only if direction == Direction::ToClient ? + tx.set_event(IkeEvent::WeakCryptoEnc); } IkeV2Transform::PRF(ref prf) => match *prf { IkeTransformPRFType::PRF_NULL => { @@ -276,9 +272,9 @@ fn add_proposals( IkeV2Transform::Auth(_) => true, _ => false, }) && !transforms.iter().any(|x| match *x { - IkeV2Transform::Encryption(ref enc) => enc.is_aead(), - _ => false, - }) { + IkeV2Transform::Encryption(ref enc) => enc.is_aead(), + _ => false, + }) { SCLogDebug!("No integrity transform found"); tx.set_event(IkeEvent::WeakCryptoNoAuth); } diff --git a/rust/src/mime/smtp.rs b/rust/src/mime/smtp.rs index bca64855c038..10dbb572c0ab 100644 --- a/rust/src/mime/smtp.rs +++ b/rust/src/mime/smtp.rs @@ -759,7 +759,7 @@ fn mime_smtp_complete(ctx: &mut MimeStateSMTP) { ctx.md5_result = ctx.md5.finalize_reset(); } // look for url in the last unfinished line - mime_smtp_find_url_strings(ctx, &[b'\n']); + mime_smtp_find_url_strings(ctx, b"\n"); } #[no_mangle] diff --git a/rust/src/ssh/ssh.rs b/rust/src/ssh/ssh.rs index d5341a2cfb19..1d38a1bd50e1 100644 --- a/rust/src/ssh/ssh.rs +++ b/rust/src/ssh/ssh.rs @@ -21,6 +21,7 @@ use crate::core::*; use nom7::Err; use std::ffi::CString; use std::sync::atomic::{AtomicBool, Ordering}; +use crate::frames::Frame; static mut ALPROTO_SSH: AppProto = ALPROTO_UNKNOWN; static HASSH_ENABLED: AtomicBool = AtomicBool::new(false); @@ -29,6 +30,13 @@ fn hassh_is_enabled() -> bool { HASSH_ENABLED.load(Ordering::Relaxed) } +#[derive(AppLayerFrameType)] +pub enum SshFrameType { + RecordHdr, + RecordData, + RecordPdu, +} + #[derive(AppLayerEvent)] pub enum SSHEvent { InvalidBanner, @@ -109,6 +117,7 @@ impl SSHState { fn parse_record( &mut self, mut input: &[u8], resp: bool, pstate: *mut std::os::raw::c_void, + flow: *const Flow, stream_slice: &StreamSlice, ) -> AppLayerResult { let (hdr, ohdr) = if !resp { (&mut self.transaction.cli_hdr, &self.transaction.srv_hdr) @@ -149,6 +158,30 @@ impl SSHState { while !input.is_empty() { match parser::ssh_parse_record(input) { Ok((rem, head)) => { + let _pdu = Frame::new( + flow, + stream_slice, + input, + SSH_RECORD_HEADER_LEN as i64, + SshFrameType::RecordHdr as u8, + Some(0), + ); + let _pdu = Frame::new( + flow, + stream_slice, + &input[SSH_RECORD_HEADER_LEN..], + (head.pkt_len - 2) as i64, + SshFrameType::RecordData as u8, + Some(0), + ); + let _pdu = Frame::new( + flow, + stream_slice, + input, + (head.pkt_len + 4) as i64, + SshFrameType::RecordPdu as u8, + Some(0), + ); SCLogDebug!("SSH valid record {}", head); match head.msg_code { parser::MessageCode::Kexinit if hassh_is_enabled() => { @@ -180,6 +213,30 @@ impl SSHState { Err(Err::Incomplete(_)) => { match parser::ssh_parse_record_header(input) { Ok((rem, head)) => { + let _pdu = Frame::new( + flow, + stream_slice, + input, + SSH_RECORD_HEADER_LEN as i64, + SshFrameType::RecordHdr as u8, + Some(0), + ); + let _pdu = Frame::new( + flow, + stream_slice, + &input[SSH_RECORD_HEADER_LEN..], + (head.pkt_len - 2) as i64, + SshFrameType::RecordData as u8, + Some(0), + ); + let _pdu = Frame::new( + flow, + stream_slice, + input, + (head.pkt_len + 4) as i64, + SshFrameType::RecordPdu as u8, + Some(0), + ); SCLogDebug!("SSH valid record header {}", head); let remlen = rem.len() as u32; hdr.record_left = head.pkt_len - 2 - remlen; @@ -210,15 +267,12 @@ impl SSHState { } Err(Err::Incomplete(_)) => { //we may have consumed data from previous records - if input.len() < SSH_RECORD_HEADER_LEN { - //do not trust nom incomplete value - return AppLayerResult::incomplete( - (il - input.len()) as u32, - SSH_RECORD_HEADER_LEN as u32, - ); - } else { - panic!("SSH invalid length record header"); - } + debug_validate_bug_on!(input.len() >= SSH_RECORD_HEADER_LEN); + //do not trust nom incomplete value + return AppLayerResult::incomplete( + (il - input.len()) as u32, + SSH_RECORD_HEADER_LEN as u32, + ); } Err(_e) => { SCLogDebug!("SSH invalid record header {}", _e); @@ -239,6 +293,7 @@ impl SSHState { fn parse_banner( &mut self, input: &[u8], resp: bool, pstate: *mut std::os::raw::c_void, + flow: *const Flow, stream_slice: &StreamSlice, ) -> AppLayerResult { let hdr = if !resp { &mut self.transaction.cli_hdr @@ -248,7 +303,7 @@ impl SSHState { if hdr.flags == SSHConnectionState::SshStateBannerWaitEol { match parser::ssh_parse_line(input) { Ok((rem, _)) => { - let mut r = self.parse_record(rem, resp, pstate); + let mut r = self.parse_record(rem, resp, pstate, flow, stream_slice); if r.is_incomplete() { //adds bytes consumed by banner to incomplete result r.consumed += (input.len() - rem.len()) as u32; @@ -288,7 +343,7 @@ impl SSHState { ); self.set_event(SSHEvent::LongBanner); } - let mut r = self.parse_record(rem, resp, pstate); + let mut r = self.parse_record(rem, resp, pstate, flow, stream_slice); if r.is_incomplete() { //adds bytes consumed by banner to incomplete result r.consumed += (input.len() - rem.len()) as u32; @@ -352,7 +407,7 @@ pub extern "C" fn rs_ssh_state_tx_free(_state: *mut std::os::raw::c_void, _tx_id #[no_mangle] pub unsafe extern "C" fn rs_ssh_parse_request( - _flow: *const Flow, state: *mut std::os::raw::c_void, pstate: *mut std::os::raw::c_void, + flow: *const Flow, state: *mut std::os::raw::c_void, pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void ) -> AppLayerResult { @@ -360,15 +415,15 @@ pub unsafe extern "C" fn rs_ssh_parse_request( let buf = stream_slice.as_slice(); let hdr = &mut state.transaction.cli_hdr; if hdr.flags < SSHConnectionState::SshStateBannerDone { - return state.parse_banner(buf, false, pstate); + return state.parse_banner(buf, false, pstate, flow, &stream_slice); } else { - return state.parse_record(buf, false, pstate); + return state.parse_record(buf, false, pstate, flow, &stream_slice); } } #[no_mangle] pub unsafe extern "C" fn rs_ssh_parse_response( - _flow: *const Flow, state: *mut std::os::raw::c_void, pstate: *mut std::os::raw::c_void, + flow: *const Flow, state: *mut std::os::raw::c_void, pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void ) -> AppLayerResult { @@ -376,9 +431,9 @@ pub unsafe extern "C" fn rs_ssh_parse_response( let buf = stream_slice.as_slice(); let hdr = &mut state.transaction.srv_hdr; if hdr.flags < SSHConnectionState::SshStateBannerDone { - return state.parse_banner(buf, true, pstate); + return state.parse_banner(buf, true, pstate, flow, &stream_slice); } else { - return state.parse_record(buf, true, pstate); + return state.parse_record(buf, true, pstate, flow, &stream_slice); } } @@ -464,8 +519,8 @@ pub unsafe extern "C" fn rs_ssh_register_parser() { get_state_data: rs_ssh_get_state_data, apply_tx_config: None, flags: 0, - get_frame_id_by_name: None, - get_frame_name_by_id: None, + get_frame_id_by_name: Some(SshFrameType::ffi_id_from_name), + get_frame_name_by_id: Some(SshFrameType::ffi_name_from_id), }; let ip_proto_str = CString::new("tcp").unwrap(); diff --git a/rust/src/websocket/websocket.rs b/rust/src/websocket/websocket.rs index ebbe901a53b0..f686ad471b42 100644 --- a/rust/src/websocket/websocket.rs +++ b/rust/src/websocket/websocket.rs @@ -36,7 +36,6 @@ pub(super) static mut ALPROTO_WEBSOCKET: AppProto = ALPROTO_UNKNOWN; static mut WEBSOCKET_MAX_PAYLOAD_SIZE: u32 = 0xFFFF; -// app-layer-frame-documentation tag start: FrameType enum #[derive(AppLayerFrameType)] pub enum WebSocketFrameType { Header, diff --git a/src/Makefile.am b/src/Makefile.am index fc6d6f177357..f241b6a4e306 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1278,7 +1278,7 @@ if BUILD_FUZZTARGETS LDFLAGS_FUZZ = $(all_libraries) $(SECLDFLAGS) LDADD_FUZZ = $(LDADD_GENERIC) -fuzz_applayerprotodetectgetproto_SOURCES = tests/fuzz/fuzz_applayerprotodetectgetproto.c +fuzz_applayerprotodetectgetproto_SOURCES = tests/fuzz/fuzz_applayerprotodetectgetproto.c tests/fuzz/confyaml.c fuzz_applayerprotodetectgetproto_LDFLAGS = $(LDFLAGS_FUZZ) fuzz_applayerprotodetectgetproto_LDADD = $(LDADD_FUZZ) fuzz_applayerprotodetectgetproto_DEPENDENCIES = libsuricata_c.a $(RUST_SURICATA_LIB) @@ -1290,7 +1290,7 @@ endif # force usage of CXX for linker nodist_EXTRA_fuzz_applayerprotodetectgetproto_SOURCES = force-cxx-linking.cxx -fuzz_applayerparserparse_SOURCES = tests/fuzz/fuzz_applayerparserparse.c +fuzz_applayerparserparse_SOURCES = tests/fuzz/fuzz_applayerparserparse.c tests/fuzz/confyaml.c fuzz_applayerparserparse_LDFLAGS = $(LDFLAGS_FUZZ) fuzz_applayerparserparse_LDADD = $(LDADD_FUZZ) fuzz_applayerparserparse_DEPENDENCIES = libsuricata_c.a $(RUST_SURICATA_LIB) @@ -1338,7 +1338,7 @@ endif # force usage of CXX for linker nodist_EXTRA_fuzz_decodepcapfile_SOURCES = force-cxx-linking.cxx -fuzz_sigpcap_SOURCES = tests/fuzz/fuzz_sigpcap.c +fuzz_sigpcap_SOURCES = tests/fuzz/fuzz_sigpcap.c tests/fuzz/confyaml.c fuzz_sigpcap_LDFLAGS = $(LDFLAGS_FUZZ) fuzz_sigpcap_LDADD = $(LDADD_FUZZ) fuzz_sigpcap_DEPENDENCIES = libsuricata_c.a $(RUST_SURICATA_LIB) @@ -1351,7 +1351,7 @@ endif nodist_EXTRA_fuzz_sigpcap_SOURCES = force-cxx-linking.cxx if HAS_FUZZPCAP -fuzz_sigpcap_aware_SOURCES = tests/fuzz/fuzz_sigpcap_aware.c +fuzz_sigpcap_aware_SOURCES = tests/fuzz/fuzz_sigpcap_aware.c tests/fuzz/confyaml.c fuzz_sigpcap_aware_LDFLAGS = $(LDFLAGS_FUZZ) fuzz_sigpcap_aware_LDADD = $(LDADD_FUZZ) -lfuzzpcap fuzz_sigpcap_aware_DEPENDENCIES = libsuricata_c.a $(RUST_SURICATA_LIB) @@ -1363,7 +1363,7 @@ endif # force usage of CXX for linker nodist_EXTRA_fuzz_sigpcap_aware_SOURCES = force-cxx-linking.cxx -fuzz_predefpcap_aware_SOURCES = tests/fuzz/fuzz_predefpcap_aware.c +fuzz_predefpcap_aware_SOURCES = tests/fuzz/fuzz_predefpcap_aware.c tests/fuzz/confyaml.c fuzz_predefpcap_aware_LDFLAGS = $(LDFLAGS_FUZZ) fuzz_predefpcap_aware_LDADD = $(LDADD_FUZZ) -lfuzzpcap fuzz_predefpcap_aware_DEPENDENCIES = libsuricata_c.a $(RUST_SURICATA_LIB) diff --git a/src/detect.c b/src/detect.c index 0302a374b550..aeb2fb625c77 100644 --- a/src/detect.c +++ b/src/detect.c @@ -150,7 +150,13 @@ static void DetectRun(ThreadVars *th_v, goto end; } const TcpSession *ssn = p->flow->protoctx; - if (ssn && (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) == 0) { + bool setting_nopayload = p->flow->alparser && + AppLayerParserStateIssetFlag( + p->flow->alparser, APP_LAYER_PARSER_NO_INSPECTION) && + !(p->flags & PKT_NOPAYLOAD_INSPECTION); + // we may be right after disabling app-layer (ssh) + if (ssn && + ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) == 0 || setting_nopayload)) { // PACKET_PROFILING_DETECT_START(p, PROF_DETECT_TX); DetectRunFrames(th_v, de_ctx, det_ctx, p, pflow, &scratch); // PACKET_PROFILING_DETECT_END(p, PROF_DETECT_TX); diff --git a/src/log-cf-common.c b/src/log-cf-common.c index 077813501c32..43fc9e3a9d6a 100644 --- a/src/log-cf-common.c +++ b/src/log-cf-common.c @@ -123,7 +123,7 @@ int LogCustomFormatParse(LogCustomFormat *cf, const char *format) n = LOG_NODE_STRLEN-2; np = NULL; /* End */ }else{ - n = np-p; + n = (uint32_t)(np - p); } strlcpy(node->data,p,n+1); p = np; @@ -151,7 +151,7 @@ int LogCustomFormatParse(LogCustomFormat *cf, const char *format) np = strchr(p, '}'); if (np != NULL && np-p > 1 && np-p < LOG_NODE_STRLEN-2) { p++; - n = np-p; + n = (uint32_t)(np - p); strlcpy(node->data, p, n+1); p = np; } else { diff --git a/src/log-httplog.c b/src/log-httplog.c index 93b6e0da9179..ee561f5609ea 100644 --- a/src/log-httplog.c +++ b/src/log-httplog.c @@ -130,7 +130,7 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const SCTime_t { LogHttpFileCtx *httplog_ctx = aft->httplog_ctx; uint32_t i; - uint32_t datalen; + size_t datalen; char buf[128]; uint8_t *cvalue = NULL; @@ -251,9 +251,9 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const SCTime_t if (tx->request_headers != NULL) { h_request_hdr = htp_table_get_c(tx->request_headers, "Cookie"); if (h_request_hdr != NULL) { - cvalue_len = GetCookieValue((uint8_t *) bstr_ptr(h_request_hdr->value), - bstr_len(h_request_hdr->value), (char *) node->data, - &cvalue); + cvalue_len = GetCookieValue((uint8_t *)bstr_ptr(h_request_hdr->value), + (uint32_t)bstr_len(h_request_hdr->value), (char *)node->data, + &cvalue); } } if (cvalue_len > 0 && cvalue != NULL) { diff --git a/src/log-pcap.c b/src/log-pcap.c index c0b6ef7d00f4..253560961dd0 100644 --- a/src/log-pcap.c +++ b/src/log-pcap.c @@ -1466,7 +1466,7 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf) } else { lvl = 0; } - comp->lz4f_prefs.compressionLevel = lvl; + comp->lz4f_prefs.compressionLevel = (int)lvl; /* Allocate resources for lz4. */ diff --git a/src/log-tlslog.c b/src/log-tlslog.c index db886f7b1316..12e235c21ac0 100644 --- a/src/log-tlslog.c +++ b/src/log-tlslog.c @@ -91,9 +91,8 @@ typedef struct LogTlsLogThread_ { MemBuffer *buffer; } LogTlsLogThread; -int TLSGetIPInformations(const Packet *p, char* srcip, size_t srcip_len, - Port* sp, char* dstip, size_t dstip_len, Port* dp, - int ipproto) +int TLSGetIPInformations(const Packet *p, char *srcip, socklen_t srcip_len, Port *sp, char *dstip, + socklen_t dstip_len, Port *dp, int ipproto) { if ((PKT_IS_TOSERVER(p))) { switch (ipproto) { diff --git a/src/log-tlslog.h b/src/log-tlslog.h index fb01562842d4..4a224ff156ef 100644 --- a/src/log-tlslog.h +++ b/src/log-tlslog.h @@ -27,8 +27,7 @@ void LogTlsLogRegister(void); -int TLSGetIPInformations(const Packet *p, char* srcip, size_t srcip_len, - Port* sp, char* dstip, size_t dstip_len, - Port* dp, int ipproto); +int TLSGetIPInformations(const Packet *p, char *srcip, socklen_t srcip_len, Port *sp, char *dstip, + socklen_t dstip_len, Port *dp, int ipproto); #endif /* SURICATA_LOG_TLSLOG_H */ diff --git a/src/output-tx.c b/src/output-tx.c index 582477c16408..06c8c98c7357 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -61,7 +61,7 @@ typedef struct OutputTxLogger_ { void (*ThreadExitPrintStats)(ThreadVars *, void *); } OutputTxLogger; -static OutputTxLogger *list[ALPROTO_MAX] = { NULL }; +static OutputTxLogger **list = NULL; int OutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto, TxLogger LogFunc, @@ -71,6 +71,14 @@ int OutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto, ThreadDeinitFunc ThreadDeinit, void (*ThreadExitPrintStats)(ThreadVars *, void *)) { + if (list == NULL) { + list = SCCalloc(ALPROTO_MAX, sizeof(OutputTxLogger *)); + if (unlikely(list == NULL)) { + SCLogError("Failed to allocate OutputTx list"); + return -1; + } + } + if (alproto != ALPROTO_UNKNOWN && !(AppLayerParserIsEnabled(alproto))) { SCLogDebug( "%s logger not enabled: protocol %s is disabled", name, AppProtoToString(alproto)); @@ -666,12 +674,21 @@ static uint32_t OutputTxLoggerGetActiveCount(void) void OutputTxLoggerRegister (void) { + BUG_ON(list); + list = SCCalloc(ALPROTO_MAX, sizeof(OutputTxLogger *)); + if (unlikely(list == NULL)) { + FatalError("Failed to allocate OutputTx list"); + } OutputRegisterRootLogger(OutputTxLogThreadInit, OutputTxLogThreadDeinit, OutputTxLogExitPrintStats, OutputTxLog, OutputTxLoggerGetActiveCount); } void OutputTxShutdown(void) { + // called in different places because of unix socket mode, and engine-analysis mode + if (list == NULL) { + return; + } for (AppProto alproto = 0; alproto < ALPROTO_MAX; alproto++) { OutputTxLogger *logger = list[alproto]; while (logger) { @@ -681,4 +698,6 @@ void OutputTxShutdown(void) } list[alproto] = NULL; } + SCFree(list); + list = NULL; } diff --git a/src/output.c b/src/output.c index f5bd70f66ec8..6d24a8d498fb 100644 --- a/src/output.c +++ b/src/output.c @@ -669,6 +669,8 @@ OutputModule *OutputGetModuleByConfName(const char *conf_name) return NULL; } +static EveJsonSimpleAppLayerLogger *simple_json_applayer_loggers; + /** * \brief Deregister all modules. Useful for a memory clean exit. */ @@ -680,6 +682,8 @@ void OutputDeregisterAll(void) TAILQ_REMOVE(&output_modules, module, entries); SCFree(module); } + SCFree(simple_json_applayer_loggers); + simple_json_applayer_loggers = NULL; } static int drop_loggers = 0; @@ -895,11 +899,75 @@ void TmModuleLoggerRegister(void) OutputRegisterLoggers(); } +EveJsonSimpleAppLayerLogger *SCEveJsonSimpleGetLogger(AppProto alproto) +{ + if (alproto < ALPROTO_MAX) { + return &simple_json_applayer_loggers[alproto]; + } + return NULL; +} + +static void RegisterSimpleJsonApplayerLogger( + AppProto alproto, EveJsonSimpleTxLogFunc LogTx, const char *name) +{ + simple_json_applayer_loggers[alproto].LogTx = LogTx; + if (name) { + simple_json_applayer_loggers[alproto].name = name; + } else { + simple_json_applayer_loggers[alproto].name = AppProtoToString(alproto); + } +} + /** * \brief Register all root loggers. */ void OutputRegisterRootLoggers(void) { + simple_json_applayer_loggers = SCCalloc(ALPROTO_MAX, sizeof(EveJsonSimpleAppLayerLogger)); + if (unlikely(simple_json_applayer_loggers == NULL)) { + FatalError("Failed to allocate simple_json_applayer_loggers"); + } + // ALPROTO_HTTP1 special: uses some options flags + RegisterSimpleJsonApplayerLogger(ALPROTO_FTP, EveFTPLogCommand, NULL); + // ALPROTO_SMTP special: uses state + RegisterSimpleJsonApplayerLogger(ALPROTO_TLS, JsonTlsLogJSONExtended, NULL); + // no cast here but done in rust for SSHTransaction + RegisterSimpleJsonApplayerLogger(ALPROTO_SSH, rs_ssh_log_json, NULL); + // ALPROTO_SMB special: uses state + // ALPROTO_DCERPC special: uses state + RegisterSimpleJsonApplayerLogger(ALPROTO_DNS, AlertJsonDns, NULL); + // either need a cast here or in rust for ModbusTransaction, done here + RegisterSimpleJsonApplayerLogger( + ALPROTO_MODBUS, (EveJsonSimpleTxLogFunc)rs_modbus_to_json, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_ENIP, SCEnipLoggerLog, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_DNP3, AlertJsonDnp3, NULL); + // ALPROTO_NFS special: uses state + // underscore instead of dash for ftp_data + RegisterSimpleJsonApplayerLogger(ALPROTO_FTPDATA, EveFTPDataAddMetadata, "ftp_data"); + RegisterSimpleJsonApplayerLogger( + ALPROTO_TFTP, (EveJsonSimpleTxLogFunc)rs_tftp_log_json_request, NULL); + // ALPROTO_IKE special: uses state + RegisterSimpleJsonApplayerLogger( + ALPROTO_KRB5, (EveJsonSimpleTxLogFunc)rs_krb5_log_json_response, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_QUIC, rs_quic_to_json, NULL); + // ALPROTO_DHCP TODO missing + RegisterSimpleJsonApplayerLogger( + ALPROTO_SNMP, (EveJsonSimpleTxLogFunc)rs_snmp_log_json_response, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_SIP, (EveJsonSimpleTxLogFunc)rs_sip_log_json, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_RFB, rs_rfb_logger_log, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_MQTT, JsonMQTTAddMetadata, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_PGSQL, JsonPgsqlAddMetadata, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_WEBSOCKET, rs_websocket_logger_log, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_LDAP, rs_ldap_logger_log, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_DOH2, AlertJsonDoh2, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_TEMPLATE, rs_template_logger_log, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_RDP, (EveJsonSimpleTxLogFunc)rs_rdp_to_json, NULL); + // special case : http2 is logged in http object + RegisterSimpleJsonApplayerLogger(ALPROTO_HTTP2, rs_http2_log_json, "http"); + // underscore instead of dash for bittorrent_dht + RegisterSimpleJsonApplayerLogger( + ALPROTO_BITTORRENT_DHT, rs_bittorrent_dht_logger_log, "bittorrent_dht"); + OutputPacketLoggerRegister(); OutputFiledataLoggerRegister(); OutputFileLoggerRegister(); @@ -916,24 +984,7 @@ static int JsonGenericLogger(ThreadVars *tv, void *thread_data, const Packet *p, return TM_ECODE_FAILED; } - const char *name; - switch (al->proto) { - case ALPROTO_HTTP2: - // special case - name = "http"; - break; - case ALPROTO_FTPDATA: - // underscore instead of dash - name = "ftp_data"; - break; - case ALPROTO_BITTORRENT_DHT: - // underscore instead of dash - name = "bittorrent_dht"; - break; - default: - name = AppProtoToString(al->proto); - } - JsonBuilder *js = CreateEveHeader(p, dir, name, NULL, thread->ctx); + JsonBuilder *js = CreateEveHeader(p, dir, al->name, NULL, thread->ctx); if (unlikely(js == NULL)) { return TM_ECODE_FAILED; } @@ -1121,57 +1172,3 @@ void OutputRegisterLoggers(void) /* ARP JSON logger */ JsonArpLogRegister(); } - -static EveJsonSimpleAppLayerLogger simple_json_applayer_loggers[ALPROTO_MAX] = { - { ALPROTO_UNKNOWN, NULL }, - { ALPROTO_HTTP1, NULL }, // special: uses some options flags - { ALPROTO_FTP, EveFTPLogCommand }, - { ALPROTO_SMTP, NULL }, // special: uses state - { ALPROTO_TLS, JsonTlsLogJSONExtended }, - { ALPROTO_SSH, rs_ssh_log_json }, - { ALPROTO_IMAP, NULL }, // protocol detection only - { ALPROTO_JABBER, NULL }, // no parser, no logging - { ALPROTO_SMB, NULL }, // special: uses state - { ALPROTO_DCERPC, NULL }, // special: uses state - { ALPROTO_IRC, NULL }, // no parser, no logging - { ALPROTO_DNS, AlertJsonDns }, - { ALPROTO_MODBUS, (EveJsonSimpleTxLogFunc)rs_modbus_to_json }, - { ALPROTO_ENIP, SCEnipLoggerLog }, - { ALPROTO_DNP3, AlertJsonDnp3 }, - { ALPROTO_NFS, NULL }, // special: uses state - { ALPROTO_NTP, NULL }, // no logging - { ALPROTO_FTPDATA, EveFTPDataAddMetadata }, - { ALPROTO_TFTP, (EveJsonSimpleTxLogFunc)rs_tftp_log_json_request }, - { ALPROTO_IKE, NULL }, // special: uses state - { ALPROTO_KRB5, (EveJsonSimpleTxLogFunc)rs_krb5_log_json_response }, - { ALPROTO_QUIC, rs_quic_to_json }, - { ALPROTO_DHCP, NULL }, // TODO missing - { ALPROTO_SNMP, (EveJsonSimpleTxLogFunc)rs_snmp_log_json_response }, - { ALPROTO_SIP, (EveJsonSimpleTxLogFunc)rs_sip_log_json }, - { ALPROTO_RFB, rs_rfb_logger_log }, - { ALPROTO_MQTT, JsonMQTTAddMetadata }, - { ALPROTO_PGSQL, JsonPgsqlAddMetadata }, - { ALPROTO_TELNET, NULL }, // no logging - { ALPROTO_WEBSOCKET, rs_websocket_logger_log }, - { ALPROTO_LDAP, rs_ldap_logger_log }, - { ALPROTO_DOH2, AlertJsonDoh2 }, - { ALPROTO_TEMPLATE, rs_template_logger_log }, - { ALPROTO_RDP, (EveJsonSimpleTxLogFunc)rs_rdp_to_json }, - { ALPROTO_HTTP2, rs_http2_log_json }, - { ALPROTO_BITTORRENT_DHT, rs_bittorrent_dht_logger_log }, - { ALPROTO_POP3, NULL }, // protocol detection only - { ALPROTO_HTTP, NULL }, // signature protocol, not for app-layer logging - { ALPROTO_FAILED, NULL }, -#ifdef UNITTESTS - { ALPROTO_TEST, NULL }, -#endif /* UNITESTS */ -}; - -EveJsonSimpleAppLayerLogger *SCEveJsonSimpleGetLogger(AppProto alproto) -{ - if (alproto < ALPROTO_MAX) { - BUG_ON(simple_json_applayer_loggers[alproto].proto != alproto); - return &simple_json_applayer_loggers[alproto]; - } - return NULL; -} diff --git a/src/output.h b/src/output.h index 6c477547e66f..074d20bf5bf2 100644 --- a/src/output.h +++ b/src/output.h @@ -192,8 +192,8 @@ void OutputClearActiveLoggers(void); typedef bool (*EveJsonSimpleTxLogFunc)(void *, struct JsonBuilder *); typedef struct EveJsonSimpleAppLayerLogger { - AppProto proto; EveJsonSimpleTxLogFunc LogTx; + const char *name; } EveJsonSimpleAppLayerLogger; EveJsonSimpleAppLayerLogger *SCEveJsonSimpleGetLogger(AppProto alproto); diff --git a/src/runmodes.c b/src/runmodes.c index 4f84149001a8..0fc8285eb4ff 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -525,7 +525,6 @@ static void RunOutputFreeList(void) static int file_logger_count = 0; static int filedata_logger_count = 0; -static LoggerId logger_bits[ALPROTO_MAX]; int RunModeOutputFiledataEnabled(void) { @@ -596,7 +595,8 @@ static void AddOutputToFreeList(OutputModule *module, OutputCtx *output_ctx) } /** \brief Turn output into thread module */ -static void SetupOutput(const char *name, OutputModule *module, OutputCtx *output_ctx) +static void SetupOutput( + const char *name, OutputModule *module, OutputCtx *output_ctx, LoggerId *logger_bits) { /* flow logger doesn't run in the packet path */ if (module->FlowLogFunc) { @@ -657,7 +657,7 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu } } -static void RunModeInitializeEveOutput(ConfNode *conf, OutputCtx *parent_ctx) +static void RunModeInitializeEveOutput(ConfNode *conf, OutputCtx *parent_ctx, LoggerId *logger_bits) { ConfNode *types = ConfNodeLookupChild(conf, "types"); SCLogDebug("types %p", types); @@ -710,8 +710,7 @@ static void RunModeInitializeEveOutput(ConfNode *conf, OutputCtx *parent_ctx) } AddOutputToFreeList(sub_module, result.ctx); - SetupOutput(sub_module->name, sub_module, - result.ctx); + SetupOutput(sub_module->name, sub_module, result.ctx, logger_bits); } } @@ -724,7 +723,7 @@ static void RunModeInitializeEveOutput(ConfNode *conf, OutputCtx *parent_ctx) } } -static void RunModeInitializeLuaOutput(ConfNode *conf, OutputCtx *parent_ctx) +static void RunModeInitializeLuaOutput(ConfNode *conf, OutputCtx *parent_ctx, LoggerId *logger_bits) { OutputModule *lua_module = OutputGetModuleByConfName("lua"); BUG_ON(lua_module == NULL); @@ -752,7 +751,7 @@ static void RunModeInitializeLuaOutput(ConfNode *conf, OutputCtx *parent_ctx) } AddOutputToFreeList(m, result.ctx); - SetupOutput(m->name, m, result.ctx); + SetupOutput(m->name, m, result.ctx, logger_bits); } } @@ -775,8 +774,8 @@ void RunModeInitializeOutputs(void) char tls_log_enabled = 0; char tls_store_present = 0; - memset(&logger_bits, 0, sizeof(logger_bits)); - + // ALPROTO_MAX is set to its final value + LoggerId logger_bits[ALPROTO_MAX] = { 0 }; TAILQ_FOREACH(output, &outputs->head, next) { output_config = ConfNodeLookupChild(output, output->val); @@ -842,7 +841,7 @@ void RunModeInitializeOutputs(void) // TODO if module == parent, find it's children if (strcmp(output->val, "eve-log") == 0) { - RunModeInitializeEveOutput(output_config, output_ctx); + RunModeInitializeEveOutput(output_config, output_ctx, logger_bits); /* add 'eve-log' to free list as it's the owner of the * main output ctx from which the sub-modules share the @@ -852,11 +851,11 @@ void RunModeInitializeOutputs(void) SCLogDebug("handle lua"); if (output_ctx == NULL) continue; - RunModeInitializeLuaOutput(output_config, output_ctx); + RunModeInitializeLuaOutput(output_config, output_ctx, logger_bits); AddOutputToFreeList(module, output_ctx); } else { AddOutputToFreeList(module, output_ctx); - SetupOutput(module->name, module, output_ctx); + SetupOutput(module->name, module, output_ctx, logger_bits); } } if (count == 0) { @@ -895,7 +894,7 @@ void RunModeInitializeOutputs(void) } AddOutputToFreeList(module, output_ctx); - SetupOutput(module->name, module, output_ctx); + SetupOutput(module->name, module, output_ctx, logger_bits); } } } diff --git a/src/source-erf-file.c b/src/source-erf-file.c index f3102cebf3e7..5253ab660a0f 100644 --- a/src/source-erf-file.c +++ b/src/source-erf-file.c @@ -158,7 +158,7 @@ static inline TmEcode ReadErfRecord(ThreadVars *tv, Packet *p, void *data) ErfFileThreadVars *etv = (ErfFileThreadVars *)data; DagRecord dr; - int r = fread(&dr, sizeof(DagRecord), 1, etv->erf); + size_t r = fread(&dr, sizeof(DagRecord), 1, etv->erf); if (r < 1) { if (feof(etv->erf)) { SCLogInfo("End of ERF file reached"); diff --git a/src/source-pcap.c b/src/source-pcap.c index f916d69354c7..3ccc28b8c968 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -166,7 +166,7 @@ void TmModuleDecodePcapRegister (void) static inline void UpdatePcapStatsValue64(uint64_t *last, uint32_t current32) { /* uint64_t -> uint32_t is defined behaviour. It slices lower 32bits. */ - uint32_t last32 = *last; + uint32_t last32 = (uint32_t)*last; /* Branchless code as wrap-around is defined for unsigned */ *last += (uint32_t)(current32 - last32); diff --git a/src/suricata.c b/src/suricata.c index 13b48fe91770..a20b5f39cbcb 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -386,6 +386,7 @@ void GlobalsDestroy(void) AppLayerDeSetup(); DatasetsSave(); DatasetsDestroy(); + OutputTxShutdown(); TagDestroyCtx(); LiveDeviceListClean(); diff --git a/src/tests/fuzz/confyaml.c b/src/tests/fuzz/confyaml.c index d36e8e31339e..e67e40a34727 100644 --- a/src/tests/fuzz/confyaml.c +++ b/src/tests/fuzz/confyaml.c @@ -1,4 +1,4 @@ -const char configNoChecksum[] = "\ +const char *configNoChecksum = "\ %YAML 1.1\n\ ---\n\ pcap-file:\n\ diff --git a/src/tests/fuzz/fuzz_applayerparserparse.c b/src/tests/fuzz/fuzz_applayerparserparse.c index f12f814fd3f6..f20c566e399a 100644 --- a/src/tests/fuzz/fuzz_applayerparserparse.c +++ b/src/tests/fuzz/fuzz_applayerparserparse.c @@ -21,7 +21,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv); AppLayerParserThreadCtx *alp_tctx = NULL; -#include "confyaml.c" +extern const char *configNoChecksum; /* input buffer is structured this way : * 6 bytes header, diff --git a/src/tests/fuzz/fuzz_applayerprotodetectgetproto.c b/src/tests/fuzz/fuzz_applayerprotodetectgetproto.c index 86cf71d96fea..e30f729bc28f 100644 --- a/src/tests/fuzz/fuzz_applayerprotodetectgetproto.c +++ b/src/tests/fuzz/fuzz_applayerprotodetectgetproto.c @@ -18,7 +18,7 @@ //rule of thumb constant, so as not to timeout target #define PROTO_DETECT_MAX_LEN 1024 -#include "confyaml.c" +extern const char *configNoChecksum; int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); diff --git a/src/tests/fuzz/fuzz_predefpcap_aware.c b/src/tests/fuzz/fuzz_predefpcap_aware.c index f15641dc8317..6bcfa70755b3 100644 --- a/src/tests/fuzz/fuzz_predefpcap_aware.c +++ b/src/tests/fuzz/fuzz_predefpcap_aware.c @@ -42,7 +42,7 @@ void *fwd; SCInstance surifuzz; SC_ATOMIC_EXTERN(unsigned int, engine_stage); -#include "confyaml.c" +extern const char *configNoChecksum; char *filepath = NULL; diff --git a/src/tests/fuzz/fuzz_sigpcap.c b/src/tests/fuzz/fuzz_sigpcap.c index 99d05d6d98b6..63367fd2763e 100644 --- a/src/tests/fuzz/fuzz_sigpcap.c +++ b/src/tests/fuzz/fuzz_sigpcap.c @@ -42,7 +42,7 @@ void *fwd; SCInstance surifuzz; SC_ATOMIC_EXTERN(unsigned int, engine_stage); -#include "confyaml.c" +extern const char *configNoChecksum; int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { diff --git a/src/tests/fuzz/fuzz_sigpcap_aware.c b/src/tests/fuzz/fuzz_sigpcap_aware.c index c9ae3b6fa3bd..75efd5c651f9 100644 --- a/src/tests/fuzz/fuzz_sigpcap_aware.c +++ b/src/tests/fuzz/fuzz_sigpcap_aware.c @@ -42,7 +42,7 @@ void *fwd; SCInstance surifuzz; SC_ATOMIC_EXTERN(unsigned int, engine_stage); -#include "confyaml.c" +extern const char *configNoChecksum; static void SigGenerateAware(const uint8_t *data, size_t size, char *r, size_t *len) { diff --git a/src/util-print.c b/src/util-print.c index 65de27eb3899..16b66679f680 100644 --- a/src/util-print.c +++ b/src/util-print.c @@ -90,10 +90,9 @@ void PrintRawUriFp(FILE *fp, uint8_t *buf, uint32_t buflen) fprintf(fp, "%s", nbuf); } -void PrintRawUriBuf(char *retbuf, uint32_t *offset, uint32_t retbuflen, - uint8_t *buf, uint32_t buflen) +void PrintRawUriBuf(char *retbuf, uint32_t *offset, uint32_t retbuflen, uint8_t *buf, size_t buflen) { - for (uint32_t u = 0; u < buflen; u++) { + for (size_t u = 0; u < buflen; u++) { if (isprint(buf[u]) && buf[u] != '\"') { if (buf[u] == '\\') { PrintBufferData(retbuf, offset, retbuflen, diff --git a/src/util-print.h b/src/util-print.h index e33de781997f..c9f19b4cdb2d 100644 --- a/src/util-print.h +++ b/src/util-print.h @@ -41,7 +41,7 @@ void PrintBufferRawLineHex(char *, int *,int, const uint8_t *, uint32_t); void PrintRawUriFp(FILE *, uint8_t *, uint32_t); -void PrintRawUriBuf(char *, uint32_t *, uint32_t, uint8_t *, uint32_t); +void PrintRawUriBuf(char *, uint32_t *, uint32_t, uint8_t *, size_t); void PrintRawDataFp(FILE *, const uint8_t *, uint32_t); void PrintRawDataToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, const uint8_t *src_buf, uint32_t src_buf_len);