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);
HASSH_ENABLED.load(Ordering::Relaxed)
}
+#[derive(AppLayerFrameType)]
+pub enum SshFrameType {
+ RecordHdr,
+ RecordData,
+ RecordPdu,
+}
+
#[derive(AppLayerEvent)]
pub enum SSHEvent {
InvalidBanner,
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)
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() => {
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;
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
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;
);
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;
#[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 {
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 {
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);
}
}
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();