From: Sam Muhammed Date: Sun, 20 Feb 2022 15:45:14 +0000 (+0200) Subject: rust/nfs4: Add NFSPROC4_LAYOUTGET op parsers X-Git-Tag: suricata-7.0.0-beta1~815 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ff54a6d9d5795f7a249eb77ca32c5b3b7afc163e;p=thirdparty%2Fsuricata.git rust/nfs4: Add NFSPROC4_LAYOUTGET op parsers Also add respective response/request unittests test_nfs4_response_layoutget() test_nfs4_request_layoutget() --- diff --git a/rust/src/nfs/nfs4_records.rs b/rust/src/nfs/nfs4_records.rs index e49e8e3bc1..b2c80a3128 100644 --- a/rust/src/nfs/nfs4_records.rs +++ b/rust/src/nfs/nfs4_records.rs @@ -65,6 +65,7 @@ pub enum Nfs4RequestContent<'a> { CreateSession(Nfs4RequestCreateSession<'a>), ReclaimComplete(u32), SecInfoNoName(u32), + LayoutGet(Nfs4RequestLayoutGet<'a>), } #[derive(Debug,PartialEq)] @@ -429,6 +430,32 @@ fn nfs4_req_reclaim_complete(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { map(verify(be_u32, |&v| v <= 1), Nfs4RequestContent::ReclaimComplete) (i) } +#[derive(Debug, PartialEq)] +pub struct Nfs4RequestLayoutGet<'a> { + pub layout_type: u32, + pub length: u64, + pub min_length: u64, + pub stateid: Nfs4StateId<'a>, +} + +fn nfs4_req_layoutget(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + let (i, _layout_available) = verify(be_u32, |&v| v <= 1)(i)?; + let (i, layout_type) = be_u32(i)?; + let (i, _iq_mode) = be_u32(i)?; + let (i, _offset) = be_u64(i)?; + let (i, length) = be_u64(i)?; + let (i, min_length) = be_u64(i)?; + let (i, stateid) = nfs4_parse_stateid(i)?; + let (i, _maxcount) = be_u32(i)?; + let req = Nfs4RequestContent::LayoutGet(Nfs4RequestLayoutGet { + layout_type, + length, + min_length, + stateid, + }); + Ok((i, req)) +} + #[derive(Debug,PartialEq)] pub struct Nfs4RequestExchangeId<'a> { pub client_string: &'a[u8], @@ -501,6 +528,7 @@ fn parse_request_compound_command(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent NFSPROC4_CREATE_SESSION => nfs4_req_create_session(i)?, NFSPROC4_RECLAIM_COMPLETE => nfs4_req_reclaim_complete(i)?, NFSPROC4_SECINFO_NO_NAME => nfs4_req_secinfo_no_name(i)?, + NFSPROC4_LAYOUTGET => nfs4_req_layoutget(i)?, _ => { return Err(Err::Error(make_error(i, ErrorKind::Switch))); } }; Ok((i, cmd_data)) @@ -552,6 +580,7 @@ pub enum Nfs4ResponseContent<'a> { CreateSession(u32, Option>), ReclaimComplete(u32), SecInfoNoName(u32), + LayoutGet(u32, Option>), } #[derive(Debug, PartialEq)] @@ -747,6 +776,46 @@ fn nfs4_res_open(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { Ok((i, Nfs4ResponseContent::Open(status, open_data))) } +/*https://datatracker.ietf.org/doc/html/rfc5661#section-13.1*/ +// in case of multiple file handles, return handles in a vector +#[derive(Debug, PartialEq)] +pub struct Nfs4ResponseLayoutGet<'a> { + pub stateid: Nfs4StateId<'a>, + pub length: u64, + pub layout_type: u32, + pub device_id: &'a[u8], + pub file_handles: Vec>, +} + +fn nfs4_parse_res_layoutget(i: &[u8]) -> IResult<&[u8], Nfs4ResponseLayoutGet> { + let (i, _return_on_close) = verify(be_u32, |&v| v <= 1)(i)?; + let (i, stateid) = nfs4_parse_stateid(i)?; + let (i, _layout_seg) = be_u32(i)?; + let (i, _offset) = be_u64(i)?; + let (i, length) = be_u64(i)?; + let (i, _lo_mode) = be_u32(i)?; + let (i, layout_type) = be_u32(i)?; + let (i, _) = be_u32(i)?; + let (i, device_id) = take(16_usize)(i)?; + let (i, _nfl_util) = be_u32(i)?; + let (i, _strip_index) = be_u32(i)?; + let (i, _offset) = be_u64(i)?; + let (i, fh_handles) = be_u32(i)?; + let (i, file_handles) = count(nfs4_parse_handle, fh_handles as usize)(i)?; + Ok((i, Nfs4ResponseLayoutGet { + stateid, + length, + layout_type, + device_id, + file_handles, + })) +} + +fn nfs4_res_layoutget(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + let (i, status) = be_u32(i)?; + let (i, lyg_data) = cond(status == 0, nfs4_parse_res_layoutget)(i)?; + Ok((i, Nfs4ResponseContent::LayoutGet( status, lyg_data ))) +} // #[derive(Debug, PartialEq)] // pub struct Nfs4FlavorRpcSecGss<'a> { @@ -995,6 +1064,7 @@ fn nfs4_res_compound_command(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { NFSPROC4_CREATE_SESSION => nfs4_res_create_session(i)?, NFSPROC4_RECLAIM_COMPLETE => nfs4_res_reclaim_complete(i)?, NFSPROC4_SECINFO_NO_NAME => nfs4_res_secinfo_no_name(i)?, + NFSPROC4_LAYOUTGET => nfs4_res_layoutget(i)?, _ => { return Err(Err::Error(make_error(i, ErrorKind::Switch))); } }; Ok((i, cmd_data)) @@ -1336,6 +1406,33 @@ mod tests { } } + #[test] + fn test_nfs4_request_layoutget() { + let buf: &[u8] = &[ + 0x00, 0x00, 0x00, 0x32, /*opcode*/ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // layoutget + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x82, 0x14, 0xe0, 0x5b, 0x00, 0x89, 0xd9, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + ]; + + let (_, stateid_buf) = nfs4_parse_stateid(&buf[40..56]).unwrap(); + assert_eq!(stateid_buf.seqid, 0); + + let (_, request) = nfs4_req_layoutget(&buf[4..]).unwrap(); + match request { + Nfs4RequestContent::LayoutGet( lyg_data ) => { + assert_eq!(lyg_data.layout_type, 1); + assert_eq!(lyg_data.min_length, 4096); + assert_eq!(lyg_data.stateid, stateid_buf); + } + _ => { panic!("Failure"); } + } + } + #[test] fn test_nfs4_attrs() { #[rustfmt::skip] @@ -1704,4 +1801,46 @@ mod tests { } } + #[test] + fn test_nfs4_response_layoutget() { + let buf: &[u8] = &[ + 0x00, 0x00, 0x00, 0x32, /*opcode*/ + 0x00, 0x00, 0x00, 0x00, /*status*/ + // layoutget + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x03, 0x82, 0x14, 0xe0, 0x5b, 0x00, 0x89, 0xd9, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x58, 0x01, 0x01, 0x00, 0x00, + 0x00, 0xf2, 0xfa, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x30, 0x01, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x84, 0x72, 0x00, 0x00, 0x23, 0xa6, 0xc0, 0x12, + 0x00, 0xf2, 0xfa, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x00, 0xf2, 0xfa, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, + ]; + + let (_, stateid) = nfs4_parse_stateid(&buf[12..28]).unwrap(); + + let (_, lyg_data) = nfs4_parse_res_layoutget(&buf[8..]).unwrap(); + assert_eq!(lyg_data.stateid, stateid); + assert_eq!(lyg_data.layout_type, 1); + assert_eq!(lyg_data.device_id, &buf[60..76]); + + let (_, response) = nfs4_res_layoutget(&buf[4..]).unwrap(); + match response { + Nfs4ResponseContent::LayoutGet( status, lyg ) => { + assert_eq!(status, 0); + assert_eq!(lyg, Some(lyg_data)); + } + _ => { panic!("Failure"); } + } + } } diff --git a/rust/src/nfs/types.rs b/rust/src/nfs/types.rs index acee8a4d3b..d2f4c0707d 100644 --- a/rust/src/nfs/types.rs +++ b/rust/src/nfs/types.rs @@ -275,6 +275,7 @@ pub const NFSPROC4_WRITE: u32 = 38; pub const NFSPROC4_RELEASE_LOCKOWNER: u32 = 39; pub const NFSPROC4_EXCHANGE_ID: u32 = 42; pub const NFSPROC4_CREATE_SESSION: u32 = 43; +pub const NFSPROC4_LAYOUTGET: u32 = 50; pub const NFSPROC4_SECINFO_NO_NAME: u32 = 52; pub const NFSPROC4_SEQUENCE: u32 = 53; pub const NFSPROC4_RECLAIM_COMPLETE: u32 = 58;