nfs: break out partial record handling

pull/7049/head
Victor Julien 5 years ago
parent fe76ab1803
commit bfb5ae867e

@ -983,6 +983,57 @@ impl NFSState {
return AppLayerResult::ok(); return AppLayerResult::ok();
} }
/// Handle partial records
fn parse_tcp_partial_data_ts<'b>(&mut self, base_input: &'b[u8], start_input: &'b[u8],
phdr: &RpcRequestPacketPartial, rec_size: usize) -> AppLayerResult {
let mut cur_i = start_input;
// special case: avoid buffering file write blobs
// as these can be large.
if rec_size >= 512 && cur_i.len() >= 44 {
// large record, likely file xfer
SCLogDebug!("large record {}, likely file xfer", rec_size);
// quick peek, are we in WRITE mode?
if phdr.procedure == NFSPROC3_WRITE {
SCLogDebug!("CONFIRMED WRITE: large record {}, file chunk xfer", rec_size);
// lets try to parse the RPC record. Might fail with Incomplete.
match parse_rpc(cur_i) {
Ok((remaining, ref hdr)) => {
match parse_nfs3_request_write(hdr.prog_data) {
Ok((_, ref w)) => {
// deal with the partial nfs write data
self.process_partial_write_request_record(hdr, w);
cur_i = remaining; // progress input past parsed record
}
_ => {
self.set_event(NFSEvent::MalformedData);
}
}
}
Err(Err::Incomplete(_)) => {
// we just size checked for the minimal record size above,
// so if options are used (creds/verifier), we can still
// have Incomplete data. Fall through to the buffer code
// and try again on our next iteration.
SCLogDebug!("TS data incomplete");
// fall through to the incomplete below
}
Err(Err::Error(_e)) | Err(Err::Failure(_e)) => {
self.set_event(NFSEvent::MalformedData);
SCLogDebug!("Parsing failed: {:?}", _e);
return AppLayerResult::err();
}
}
}
}
// make sure we pass a value higher than current input
// but lower than the record size
let n1 = cmp::max(cur_i.len(), 1024);
let n2 = cmp::min(n1, rec_size);
return AppLayerResult::incomplete((base_input.len() - cur_i.len()) as u32, n2 as u32);
}
/// Parsing function, handling TCP chunks fragmentation /// Parsing function, handling TCP chunks fragmentation
pub fn parse_tcp_data_ts<'b>(&mut self, i: &'b[u8]) -> AppLayerResult { pub fn parse_tcp_data_ts<'b>(&mut self, i: &'b[u8]) -> AppLayerResult {
let mut cur_i = i; let mut cur_i = i;
@ -1033,56 +1084,10 @@ impl NFSState {
match parse_rpc_request_partial(cur_i) { match parse_rpc_request_partial(cur_i) {
Ok((_, ref rpc_phdr)) => { Ok((_, ref rpc_phdr)) => {
let rec_size = (rpc_phdr.hdr.frag_len + 4) as usize; let rec_size = (rpc_phdr.hdr.frag_len + 4) as usize;
//SCLogDebug!("rec_size {}/{}", rec_size, cur_i.len());
//SCLogDebug!("cur_i {:?}", cur_i);
// Handle partial records
if rec_size > cur_i.len() { if rec_size > cur_i.len() {
// special case: avoid buffering file write blobs return self.parse_tcp_partial_data_ts(i, cur_i, rpc_phdr, rec_size);
// as these can be large.
if rec_size >= 512 && cur_i.len() >= 44 {
// large record, likely file xfer
SCLogDebug!("large record {}, likely file xfer", rec_size);
// quick peek, are in WRITE mode?
if rpc_phdr.procedure == NFSPROC3_WRITE {
SCLogDebug!("CONFIRMED WRITE: large record {}, file chunk xfer", rec_size);
// lets try to parse the RPC record. Might fail with Incomplete.
match parse_rpc(cur_i) {
Ok((remaining, ref rpc_record)) => {
match parse_nfs3_request_write(rpc_record.prog_data) {
Ok((_, ref nfs_request_write)) => {
// deal with the partial nfs write data
self.process_partial_write_request_record(rpc_record, nfs_request_write);
cur_i = remaining; // progress input past parsed record
},
_ => {
self.set_event(NFSEvent::MalformedData);
},
}
},
Err(Err::Incomplete(_)) => {
// we just size checked for the minimal record size above,
// so if options are used (creds/verifier), we can still
// have Incomplete data. Fall through to the buffer code
// and try again on our next iteration.
SCLogDebug!("TS data incomplete");
// fall through to the incomplete below
},
Err(Err::Error(_e)) |
Err(Err::Failure(_e)) => {
self.set_event(NFSEvent::MalformedData);
SCLogDebug!("Parsing failed: {:?}", _e);
return AppLayerResult::err();
},
}
}
}
// make sure we pass a value higher than current input
// but lower than the record size
let n1 = cmp::max(cur_i.len(), 1024);
let n2 = cmp::min(n1, rec_size);
return AppLayerResult::incomplete((i.len() - cur_i.len()) as u32, n2 as u32);
} }
// we have the full records size worth of data, // we have the full records size worth of data,
@ -1137,6 +1142,58 @@ impl NFSState {
AppLayerResult::ok() AppLayerResult::ok()
} }
/// Handle partial records
fn parse_tcp_partial_data_tc<'b>(&mut self, base_input: &'b[u8], start_input: &'b[u8],
phdr: &RpcPacketHeader, rec_size: usize) -> AppLayerResult {
let mut cur_i = start_input;
// special case: avoid buffering file read blobs
// as these can be large.
if rec_size >= 512 && cur_i.len() >= 128 {//36 {
// large record, likely file xfer
SCLogDebug!("large record {}, likely file xfer", rec_size);
// quick peek, are in READ mode?
if self.peek_reply_record(phdr) == NFSPROC3_READ {
SCLogDebug!("CONFIRMED large READ record {}, likely file chunk xfer", rec_size);
// we should have enough data to parse the RPC record
match parse_rpc_reply(cur_i) {
Ok((remaining, ref hdr)) => {
match parse_nfs3_reply_read(hdr.prog_data) {
Ok((_, ref r)) => {
// deal with the partial nfs read data
self.process_partial_read_reply_record(hdr, r);
cur_i = remaining; // progress input past parsed record
}
Err(Err::Incomplete(_)) => {
}
Err(Err::Error(_e)) | Err(Err::Failure(_e)) => {
self.set_event(NFSEvent::MalformedData);
SCLogDebug!("Parsing failed: {:?}", _e);
return AppLayerResult::err();
}
}
}
Err(Err::Incomplete(_)) => {
// size check was done for MINIMAL record size,
// so Incomplete is normal.
SCLogDebug!("TC data incomplete");
}
Err(Err::Error(_e)) | Err(Err::Failure(_e)) => {
self.set_event(NFSEvent::MalformedData);
SCLogDebug!("Parsing failed: {:?}", _e);
return AppLayerResult::err();
}
}
}
}
// make sure we pass a value higher than current input
// but lower than the record size
let n1 = cmp::max(cur_i.len(), 1024);
let n2 = cmp::min(n1, rec_size);
return AppLayerResult::incomplete((base_input.len() - cur_i.len()) as u32, n2 as u32);
}
/// Parsing function, handling TCP chunks fragmentation /// Parsing function, handling TCP chunks fragmentation
pub fn parse_tcp_data_tc<'b>(&mut self, i: &'b[u8]) -> AppLayerResult { pub fn parse_tcp_data_tc<'b>(&mut self, i: &'b[u8]) -> AppLayerResult {
let mut cur_i = i; let mut cur_i = i;
@ -1185,58 +1242,11 @@ impl NFSState {
while cur_i.len() > 0 { while cur_i.len() > 0 {
match parse_rpc_packet_header(cur_i) { match parse_rpc_packet_header(cur_i) {
Ok((_, ref rpc_hdr)) => { Ok((_, ref rpc_phdr)) => {
let rec_size = (rpc_hdr.frag_len + 4) as usize; let rec_size = (rpc_phdr.frag_len + 4) as usize;
// see if we have all data available // see if we have all data available
if rec_size > cur_i.len() { if rec_size > cur_i.len() {
// special case: avoid buffering file read blobs return self.parse_tcp_partial_data_tc(i, cur_i, rpc_phdr, rec_size);
// as these can be large.
if rec_size >= 512 && cur_i.len() >= 128 {//36 {
// large record, likely file xfer
SCLogDebug!("large record {}, likely file xfer", rec_size);
// quick peek, are in READ mode?
if self.peek_reply_record(rpc_hdr) == NFSPROC3_READ {
SCLogDebug!("CONFIRMED large READ record {}, likely file chunk xfer", rec_size);
// we should have enough data to parse the RPC record
match parse_rpc_reply(cur_i) {
Ok((remaining, ref rpc_record)) => {
match parse_nfs3_reply_read(rpc_record.prog_data) {
Ok((_, ref nfs_reply_read)) => {
// deal with the partial nfs read data
self.process_partial_read_reply_record(rpc_record, nfs_reply_read);
cur_i = remaining; // progress input past parsed record
},
Err(Err::Incomplete(_)) => {
},
Err(Err::Error(_e)) |
Err(Err::Failure(_e)) => {
self.set_event(NFSEvent::MalformedData);
SCLogDebug!("Parsing failed: {:?}", _e);
return AppLayerResult::err();
}
}
},
Err(Err::Incomplete(_)) => {
// size check was done for MINIMAL record size,
// so Incomplete is normal.
SCLogDebug!("TC data incomplete");
},
Err(Err::Error(_e)) |
Err(Err::Failure(_e)) => {
self.set_event(NFSEvent::MalformedData);
SCLogDebug!("Parsing failed: {:?}", _e);
return AppLayerResult::err();
}
}
}
}
// make sure we pass a value higher than current input
// but lower than the record size
let n1 = cmp::max(cur_i.len(), 1024);
let n2 = cmp::min(n1, rec_size);
return AppLayerResult::incomplete((i.len() - cur_i.len()) as u32, n2 as u32);
} }
// we have the full data of the record, lets parse // we have the full data of the record, lets parse

Loading…
Cancel
Save