From 8fe32f943b8e45ed973e6d2e43d9d60a682bd28d Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 10 Jun 2017 14:58:06 +0200 Subject: [PATCH] nfs3: search for next record if needed after GAP --- rust/src/nfs/nfs3.rs | 123 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 1 deletion(-) diff --git a/rust/src/nfs/nfs3.rs b/rust/src/nfs/nfs3.rs index 3772a91f44..4eddbbeadd 100644 --- a/rust/src/nfs/nfs3.rs +++ b/rust/src/nfs/nfs3.rs @@ -286,6 +286,9 @@ pub struct NFS3State { ts_ssn_gap: bool, tc_ssn_gap: bool, + ts_gap: bool, // last TS update was gap + tc_gap: bool, // last TC update was gap + /// tx counter for assigning incrementing id's to tx's tx_id: u64, @@ -313,6 +316,8 @@ impl NFS3State { tc_chunk_left:0, ts_ssn_gap:false, tc_ssn_gap:false, + ts_gap:false, + tc_gap:false, tx_id:0, de_state_count:0, //ts_txs_updated:false, @@ -1024,6 +1029,7 @@ impl NFS3State { panic!("consumed more than GAP size: {} > {}", consumed, gap_size); } self.ts_ssn_gap = true; + self.ts_gap = true; return 0 } @@ -1037,6 +1043,7 @@ impl NFS3State { panic!("consumed more than GAP size: {} > {}", consumed, gap_size); } self.tc_ssn_gap = true; + self.tc_gap = true; return 0 } @@ -1073,6 +1080,35 @@ impl NFS3State { if consumed > cur_i.len() as u32 { panic!("BUG consumed more than we gave it"); } cur_i = &cur_i[consumed as usize..]; } + if self.ts_gap { + SCLogDebug!("TS trying to catch up after GAP (input {})", cur_i.len()); + + let mut cnt = 0; + while cur_i.len() > 0 { + cnt += 1; + match nfs3_probe(cur_i, STREAM_TOSERVER) { + 1 => { + SCLogDebug!("expected data found"); + self.ts_gap = false; + break; + }, + 0 => { + SCLogDebug!("incomplete, queue and retry with the next block (input {}). Looped {} times.", cur_i.len(), cnt); + self.tcp_buffer_tc.extend_from_slice(cur_i); + return 0; + }, + -1 => { + cur_i = &cur_i[1..]; + if cur_i.len() == 0 { + SCLogDebug!("all post-GAP data in this chunk was bad. Looped {} times.", cnt); + } + }, + _ => { panic!("hell just froze over"); }, + } + } + SCLogDebug!("TS GAP handling done (input {})", cur_i.len()); + } + while cur_i.len() > 0 { // min record size match parse_rpc_request_partial(cur_i) { IResult::Done(_, ref rpc_phdr) => { @@ -1172,7 +1208,7 @@ impl NFS3State { v.as_slice() }, }; - SCLogDebug!("tcp_buffer ({})",tcp_buffer.len()); + SCLogDebug!("TC tcp_buffer ({}), input ({})",tcp_buffer.len(), i.len()); let mut cur_i = tcp_buffer; if cur_i.len() > 100000 { @@ -1186,6 +1222,35 @@ impl NFS3State { if consumed > cur_i.len() as u32 { panic!("BUG consumed more than we gave it"); } cur_i = &cur_i[consumed as usize..]; } + if self.tc_gap { + SCLogDebug!("TC trying to catch up after GAP (input {})", cur_i.len()); + + let mut cnt = 0; + while cur_i.len() > 0 { + cnt += 1; + match nfs3_probe(cur_i, STREAM_TOCLIENT) { + 1 => { + SCLogDebug!("expected data found"); + self.tc_gap = false; + break; + }, + 0 => { + SCLogDebug!("incomplete, queue and retry with the next block (input {}). Looped {} times.", cur_i.len(), cnt); + self.tcp_buffer_tc.extend_from_slice(cur_i); + return 0; + }, + -1 => { + cur_i = &cur_i[1..]; + if cur_i.len() == 0 { + SCLogDebug!("all post-GAP data in this chunk was bad. Looped {} times.", cnt); + } + }, + _ => { panic!("hell just froze over"); }, + } + } + SCLogDebug!("TC GAP handling done (input {})", cur_i.len()); + } + while cur_i.len() > 0 { match parse_rpc_packet_header(cur_i) { IResult::Done(_, ref rpc_hdr) => { @@ -1525,6 +1590,59 @@ pub extern "C" fn rs_nfs3_init(context: &'static mut SuricataFileContext) } } +pub fn nfs3_probe(i: &[u8], direction: u8) -> i8 { + if direction == STREAM_TOCLIENT { + match parse_rpc_reply(i) { + IResult::Done(_, ref rpc) => { + if rpc.hdr.frag_len >= 24 && rpc.hdr.frag_len <= 35000 && rpc.hdr.msgtype == 1 && rpc.reply_state == 0 && rpc.accept_state == 0 { + SCLogNotice!("TC PROBE LEN {} XID {} TYPE {}", rpc.hdr.frag_len, rpc.hdr.xid, rpc.hdr.msgtype); + return 1; + } else { + return -1; + } + }, + IResult::Incomplete(_) => { + match parse_rpc_packet_header (i) { + IResult::Done(_, ref rpc_hdr) => { + if rpc_hdr.frag_len >= 24 && rpc_hdr.frag_len <= 35000 && rpc_hdr.xid != 0 && rpc_hdr.msgtype == 1 { + SCLogNotice!("TC PROBE LEN {} XID {} TYPE {}", rpc_hdr.frag_len, rpc_hdr.xid, rpc_hdr.msgtype); + return 1; + } else { + return -1; + } + }, + IResult::Incomplete(_) => { }, + IResult::Error(_) => { + return -1; + }, + } + + + return 0; + }, + IResult::Error(_) => { + return -1; + }, + } + } else { + match parse_rpc(i) { + IResult::Done(_, ref rpc) => { + if rpc.hdr.frag_len >= 40 && rpc.hdr.frag_len <= 35000 && rpc.hdr.msgtype == 0 && rpc.progver == 3 && rpc.program == 100003 { + return 1; + } else { + return -1; + } + }, + IResult::Incomplete(_) => { + return 0; + }, + IResult::Error(_) => { + return -1; + }, + } + } +} + /// TOSERVER probe function #[no_mangle] pub extern "C" fn rs_nfs_probe(input: *const libc::uint8_t, len: libc::uint32_t) @@ -1533,6 +1651,8 @@ pub extern "C" fn rs_nfs_probe(input: *const libc::uint8_t, len: libc::uint32_t) let slice: &[u8] = unsafe { std::slice::from_raw_parts(input as *mut u8, len as usize) }; + return nfs3_probe(slice, STREAM_TOSERVER); +/* match parse_rpc(slice) { IResult::Done(_, ref rpc_hdr) => { if rpc_hdr.progver == 3 && rpc_hdr.program == 100003 { @@ -1548,6 +1668,7 @@ pub extern "C" fn rs_nfs_probe(input: *const libc::uint8_t, len: libc::uint32_t) return -1; }, } +*/ } #[no_mangle]