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) {
+ match parse_rpc(cur_i, false) {
Ok((remaining, ref rpc_record)) => {
match parse_nfs3_request_write(rpc_record.prog_data, false) {
Ok((_, ref nfs_request_write)) => {
// we have the full records size worth of data,
// let's parse it
- match parse_rpc(&cur_i[..rec_size]) {
+ match parse_rpc(cur_i, true) {
Ok((_, ref rpc_record)) => {
- cur_i = &cur_i[rec_size..];
status |= self.process_request_record(rpc_record);
},
Err(nom::Err::Incomplete(_)) => {
- cur_i = &cur_i[rec_size..]; // progress input past parsed record
-
- // we shouldn't get incomplete as we have the full data
- // so if we got incomplete anyway it's the data that is
- // bad.
self.set_event(NFSEvent::MalformedData);
status = 1;
return 1;
},
}
+ cur_i = &cur_i[rec_size..];
},
Err(nom::Err::Incomplete(_)) => {
SCLogDebug!("Fragmentation required (TCP level) 2");
self.tcp_buffer_ts.extend_from_slice(cur_i);
break;
},
+ /* This error is fatal. If we failed to parse the RPC hdr we don't
+ * have a length and we don't know where the next record starts. */
Err(nom::Err::Error(_e)) |
Err(nom::Err::Failure(_e)) => {
self.set_event(NFSEvent::MalformedData);
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) {
+ match parse_rpc_reply(cur_i, false) {
Ok((remaining, ref rpc_record)) => {
match parse_nfs3_reply_read(rpc_record.prog_data, false) {
Ok((_, ref nfs_reply_read)) => {
}
// we have the full data of the record, lets parse
- match parse_rpc_reply(&cur_i[..rec_size]) {
+ match parse_rpc_reply(cur_i, true) {
Ok((_, ref rpc_record)) => {
- cur_i = &cur_i[rec_size..]; // progress input past parsed record
status |= self.process_reply_record(rpc_record);
},
Err(nom::Err::Incomplete(_)) => {
- cur_i = &cur_i[rec_size..]; // progress input past parsed record
-
// we shouldn't get incomplete as we have the full data
// so if we got incomplete anyway it's the data that is
// bad.
return 1;
}
}
+ cur_i = &cur_i[rec_size..]; // progress input past parsed record
},
Err(nom::Err::Incomplete(_)) => {
SCLogDebug!("REPLY: insufficient data for HDR");
self.tcp_buffer_tc.extend_from_slice(cur_i);
break;
},
+ /* This error is fatal. If we failed to parse the RPC hdr we don't
+ * have a length and we don't know where the next record starts. */
Err(nom::Err::Error(_e)) |
Err(nom::Err::Failure(_e)) => {
self.set_event(NFSEvent::MalformedData);
pub fn nfs_probe(i: &[u8], direction: u8) -> i8 {
if direction == STREAM_TOCLIENT {
- match parse_rpc_reply(i) {
+ match parse_rpc_reply(i, false) {
Ok((_, 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 {
SCLogDebug!("TC PROBE LEN {} XID {} TYPE {}", rpc.hdr.frag_len, rpc.hdr.xid, rpc.hdr.msgtype);
},
}
} else {
- match parse_rpc(i) {
+ match parse_rpc(i, false) {
Ok((_, ref rpc)) => {
if rpc.hdr.frag_len >= 40 && rpc.hdr.msgtype == 0 &&
rpc.rpcver == 2 && (rpc.progver == 3 || rpc.progver == 4) &&
//! Nom parsers for RPCv2
-use nom::{be_u32, rest};
+use nom::{be_u32, rest, rest_len};
use nom::IResult;
pub const RPC_MAX_MACHINE_SIZE: u32 = 256; // Linux kernel defines 64.
pub reply_state: u32,
pub accept_state: u32,
+ pub prog_data_size: u32,
pub prog_data: &'a[u8],
}
pub verifier_len: u32,
pub verifier: &'a[u8],
+ pub prog_data_size: u32,
pub prog_data: &'a[u8],
}
-pub fn parse_rpc(start_i: &[u8]) -> IResult<&[u8], RpcPacket> {
+/// Parse request RPC record.
+///
+/// Can be called from 2 paths:
+/// 1. we have all data -> do full parsing
+/// 2. we have partial data (large records) -> allow partial prog_data parsing
+///
+/// Arguments:
+/// * `complete`:
+/// type: bool
+/// description: do full parsing, including of `prog_data`
+///
+pub fn parse_rpc(start_i: &[u8], complete: bool) -> IResult<&[u8], RpcPacket> {
let (i, hdr) = parse_rpc_packet_header(start_i)?;
let rec_size = hdr.frag_len as usize + 4;
if consumed > rec_size as usize {
return Err(nom::Err::Error(error_position!(i, nom::ErrorKind::LengthValue)));
}
-
- let (i, prog_data) = rest(i)?;
+ let data_size: u32 = (rec_size as usize - consumed) as u32;
+ let (i, prog_data) = if !complete {
+ rest(i)?
+ } else {
+ take!(i, data_size)?
+ };
Ok((i, RpcPacket {
hdr,
verifier_flavor,
verifier_len,
verifier,
+ prog_data_size: data_size,
prog_data,
}))
}
-// to be called with data <= hdr.frag_len + 4. Sending more data is undefined.
-pub fn parse_rpc_reply(start_i: &[u8]) -> IResult<&[u8], RpcReplyPacket> {
+/// Parse reply RPC record.
+///
+/// Can be called from 2 paths:
+/// 1. we have all data -> do full parsing
+/// 2. we have partial data (large records) -> allow partial prog_data parsing
+///
+/// Arguments:
+/// * `complete`:
+/// type: bool
+/// description: do full parsing, including of `prog_data`
+///
+pub fn parse_rpc_reply(start_i: &[u8], complete: bool) -> IResult<&[u8], RpcReplyPacket> {
let (i, hdr) = parse_rpc_packet_header(start_i)?;
let rec_size = hdr.frag_len + 4;
return Err(nom::Err::Error(error_position!(i, nom::ErrorKind::LengthValue)));
}
- let (i, prog_data) = rest(i)?;
+ let data_size: u32 = (rec_size as usize - consumed) as u32;
+ let (i, prog_data) = if !complete {
+ rest(i)?
+ } else {
+ take!(i, data_size)?
+ };
let packet = RpcReplyPacket {
hdr,
reply_state,
accept_state,
- //prog_data_size: data_size,
+ prog_data_size: data_size,
prog_data,
};
Ok((i, packet))
>> verifier_len: verify!(be_u32, |size| size < RPC_MAX_VERIFIER_SIZE)
>> verifier: take!(verifier_len as usize)
+ >> prog_data_size: rest_len
>> pl: rest
>> (
verifier_len:verifier_len,
verifier:verifier,
+ prog_data_size: prog_data_size as u32,
prog_data:pl,
}
))
>> reply_state: verify!(be_u32, |v| v <= 1)
>> accept_state: be_u32
+ >> data_size: rest_len
>> pl: rest
>> (
reply_state:reply_state,
accept_state:accept_state,
+ prog_data_size: data_size as u32,
prog_data:pl,
}
))