From 0ffe12333028894b6999a7e65b565a2782e90b53 Mon Sep 17 00:00:00 2001 From: Pierre Chifflier Date: Mon, 8 Nov 2021 16:38:17 +0100 Subject: [PATCH] rust/nfs: convert parser to nom7 functions (NFS v3 and v4 records) --- rust/src/nfs/nfs.rs | 78 +-- rust/src/nfs/nfs3_records.rs | 537 +++++++-------- rust/src/nfs/nfs4.rs | 216 +++--- rust/src/nfs/nfs4_records.rs | 1219 ++++++++++++++++------------------ rust/src/nfs/rpc_records.rs | 503 +++++++------- 5 files changed, 1210 insertions(+), 1343 deletions(-) diff --git a/rust/src/nfs/nfs.rs b/rust/src/nfs/nfs.rs index 444e785623..9b6db86a5f 100644 --- a/rust/src/nfs/nfs.rs +++ b/rust/src/nfs/nfs.rs @@ -19,10 +19,10 @@ use std; use std::cmp; -use std::collections::{HashMap}; +use std::collections::HashMap; use std::ffi::{CStr, CString}; -use nom; +use nom7::{Err, Needed}; use crate::applayer; use crate::applayer::*; @@ -250,9 +250,9 @@ pub struct NFSRequestXidMap { impl NFSRequestXidMap { pub fn new(progver: u32, procedure: u32, chunk_offset: u64) -> NFSRequestXidMap { NFSRequestXidMap { - progver:progver, - procedure:procedure, - chunk_offset:chunk_offset, + progver, + procedure, + chunk_offset, file_name:Vec::new(), file_handle:Vec::new(), gssapi_proc: 0, @@ -1068,7 +1068,7 @@ impl NFSState { }, } }, - Err(nom::Err::Incomplete(_)) => { + 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 @@ -1076,8 +1076,8 @@ impl NFSState { SCLogDebug!("TS data incomplete"); // fall through to the incomplete below }, - Err(nom::Err::Error(_e)) | - Err(nom::Err::Failure(_e)) => { + Err(Err::Error(_e)) | + Err(Err::Failure(_e)) => { self.set_event(NFSEvent::MalformedData); SCLogDebug!("Parsing failed: {:?}", _e); return AppLayerResult::err(); @@ -1099,7 +1099,7 @@ impl NFSState { cur_i = &cur_i[rec_size..]; self.process_request_record(rpc_record); }, - Err(nom::Err::Incomplete(_)) => { + Err(Err::Incomplete(_)) => { cur_i = &cur_i[rec_size..]; // progress input past parsed record // we shouldn't get incomplete as we have the full data @@ -1107,26 +1107,27 @@ impl NFSState { // bad. self.set_event(NFSEvent::MalformedData); }, - Err(nom::Err::Error(_e)) | - Err(nom::Err::Failure(_e)) => { + Err(Err::Error(_e)) | + Err(Err::Failure(_e)) => { self.set_event(NFSEvent::MalformedData); SCLogDebug!("Parsing failed: {:?}", _e); return AppLayerResult::err(); }, } }, - Err(nom::Err::Incomplete(needed)) => { - if let nom::Needed::Size(n) = needed { + Err(Err::Incomplete(needed)) => { + if let Needed::Size(n) = needed { SCLogDebug!("Not enough data for partial RPC header {:?}", needed); // 28 is the partial RPC header size parse_rpc_request_partial // looks for. + let n = usize::from(n); let need = if n > 28 { n } else { 28 }; return AppLayerResult::incomplete((i.len() - cur_i.len()) as u32, need as u32); } return AppLayerResult::err(); }, - Err(nom::Err::Error(_e)) | - Err(nom::Err::Failure(_e)) => { + Err(Err::Error(_e)) | + Err(Err::Failure(_e)) => { self.set_event(NFSEvent::MalformedData); SCLogDebug!("Parsing failed: {:?}", _e); return AppLayerResult::err(); @@ -1214,23 +1215,23 @@ impl NFSState { self.process_partial_read_reply_record(rpc_record, nfs_reply_read); cur_i = remaining; // progress input past parsed record }, - Err(nom::Err::Incomplete(_)) => { + Err(Err::Incomplete(_)) => { }, - Err(nom::Err::Error(_e)) | - Err(nom::Err::Failure(_e)) => { + Err(Err::Error(_e)) | + Err(Err::Failure(_e)) => { self.set_event(NFSEvent::MalformedData); SCLogDebug!("Parsing failed: {:?}", _e); return AppLayerResult::err(); } } }, - Err(nom::Err::Incomplete(_)) => { + Err(Err::Incomplete(_)) => { // size check was done for MINIMAL record size, // so Incomplete is normal. SCLogDebug!("TC data incomplete"); }, - Err(nom::Err::Error(_e)) | - Err(nom::Err::Failure(_e)) => { + Err(Err::Error(_e)) | + Err(Err::Failure(_e)) => { self.set_event(NFSEvent::MalformedData); SCLogDebug!("Parsing failed: {:?}", _e); return AppLayerResult::err(); @@ -1251,7 +1252,7 @@ impl NFSState { cur_i = &cur_i[rec_size..]; // progress input past parsed record self.process_reply_record(rpc_record); }, - Err(nom::Err::Incomplete(_)) => { + Err(Err::Incomplete(_)) => { cur_i = &cur_i[rec_size..]; // progress input past parsed record // we shouldn't get incomplete as we have the full data @@ -1259,26 +1260,27 @@ impl NFSState { // bad. self.set_event(NFSEvent::MalformedData); }, - Err(nom::Err::Error(_e)) | - Err(nom::Err::Failure(_e)) => { + Err(Err::Error(_e)) | + Err(Err::Failure(_e)) => { self.set_event(NFSEvent::MalformedData); SCLogDebug!("Parsing failed: {:?}", _e); return AppLayerResult::err(); } } }, - Err(nom::Err::Incomplete(needed)) => { - if let nom::Needed::Size(n) = needed { + Err(Err::Incomplete(needed)) => { + if let Needed::Size(n) = needed { SCLogDebug!("Not enough data for partial RPC header {:?}", needed); // 12 is the partial RPC header size parse_rpc_packet_header // looks for. + let n = usize::from(n); let need = if n > 12 { n } else { 12 }; return AppLayerResult::incomplete((i.len() - cur_i.len()) as u32, need as u32); } return AppLayerResult::err(); }, - Err(nom::Err::Error(_e)) | - Err(nom::Err::Failure(_e)) => { + Err(Err::Error(_e)) | + Err(Err::Failure(_e)) => { self.set_event(NFSEvent::MalformedData); SCLogDebug!("Parsing failed: {:?}", _e); return AppLayerResult::err(); @@ -1309,10 +1311,10 @@ impl NFSState { _ => { }, } }, - Err(nom::Err::Incomplete(_)) => { + Err(Err::Incomplete(_)) => { }, - Err(nom::Err::Error(_e)) | - Err(nom::Err::Failure(_e)) => { + Err(Err::Error(_e)) | + Err(Err::Failure(_e)) => { SCLogDebug!("Parsing failed: {:?}", _e); } } @@ -1329,10 +1331,10 @@ impl NFSState { self.is_udp = true; self.process_reply_record(rpc_record); }, - Err(nom::Err::Incomplete(_)) => { + Err(Err::Incomplete(_)) => { }, - Err(nom::Err::Error(_e)) | - Err(nom::Err::Failure(_e)) => { + Err(Err::Error(_e)) | + Err(Err::Failure(_e)) => { SCLogDebug!("Parsing failed: {:?}", _e); } } @@ -1649,7 +1651,7 @@ fn nfs_probe_dir(i: &[u8], rdir: *mut u8) -> i8 { unsafe { *rdir = dir as u8 }; return 1; }, - Err(nom::Err::Incomplete(_)) => { + Err(Err::Incomplete(_)) => { return 0; }, Err(_) => { @@ -1669,7 +1671,7 @@ pub fn nfs_probe(i: &[u8], direction: Direction) -> i32 { return -1; } }, - Err(nom::Err::Incomplete(_)) => { + Err(Err::Incomplete(_)) => { match parse_rpc_packet_header (i) { Ok((_, ref rpc_hdr)) => { if rpc_hdr.frag_len >= 24 && rpc_hdr.frag_len <= 35000 && rpc_hdr.xid != 0 && rpc_hdr.msgtype == 1 { @@ -1679,7 +1681,7 @@ pub fn nfs_probe(i: &[u8], direction: Direction) -> i32 { return -1; } }, - Err(nom::Err::Incomplete(_)) => { + Err(Err::Incomplete(_)) => { return 0; }, Err(_) => { @@ -1704,7 +1706,7 @@ pub fn nfs_probe(i: &[u8], direction: Direction) -> i32 { return -1; } }, - Err(nom::Err::Incomplete(_)) => { + Err(Err::Incomplete(_)) => { return 0; }, Err(_) => { diff --git a/rust/src/nfs/nfs3_records.rs b/rust/src/nfs/nfs3_records.rs index 2130063ba1..62e6a44ef4 100644 --- a/rust/src/nfs/nfs3_records.rs +++ b/rust/src/nfs/nfs3_records.rs @@ -17,157 +17,136 @@ //! Nom parsers for RPC & NFSv3 -use nom::IResult; -use nom::combinator::rest; -use nom::number::streaming::{be_u32, be_u64}; use crate::nfs::nfs_records::*; +use nom7::bytes::streaming::take; +use nom7::combinator::{complete, cond, rest}; +use nom7::multi::{length_data, many0}; +use nom7::number::streaming::{be_u32, be_u64}; +use nom7::IResult; -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct Nfs3Handle<'a> { pub len: u32, - pub value: &'a[u8], + pub value: &'a [u8], } -named!(pub parse_nfs3_handle, - do_parse!( - obj_len: be_u32 - >> obj: take!(obj_len) - >> ( - Nfs3Handle { - len:obj_len, - value:obj, - } - )) -); +pub fn parse_nfs3_handle(i: &[u8]) -> IResult<&[u8], Nfs3Handle> { + let (i, len) = be_u32(i)?; + let (i, value) = take(len as usize)(i)?; + let handle = Nfs3Handle { len, value }; + Ok((i, handle)) +} -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct Nfs3ReplyCreate<'a> { pub status: u32, pub handle: Option>, } -named!(pub parse_nfs3_response_create, - do_parse!( - status: be_u32 - >> handle_has_value: be_u32 - >> handle: cond!(handle_has_value == 1, parse_nfs3_handle) - >> ( - Nfs3ReplyCreate { - status:status, - handle:handle, - } - )) -); +pub fn parse_nfs3_response_create(i: &[u8]) -> IResult<&[u8], Nfs3ReplyCreate> { + let (i, status) = be_u32(i)?; + let (i, handle_has_value) = be_u32(i)?; + let (i, handle) = cond(handle_has_value == 1, parse_nfs3_handle)(i)?; + let reply = Nfs3ReplyCreate { status, handle }; + Ok((i, reply)) +} -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct Nfs3ReplyLookup<'a> { pub status: u32, pub handle: Nfs3Handle<'a>, } -named!(pub parse_nfs3_response_lookup, - do_parse!( - status: be_u32 - >> handle: parse_nfs3_handle - >> ( - Nfs3ReplyLookup { - status:status, - handle:handle, - } - )) -); +pub fn parse_nfs3_response_lookup(i: &[u8]) -> IResult<&[u8], Nfs3ReplyLookup> { + let (i, status) = be_u32(i)?; + let (i, handle) = parse_nfs3_handle(i)?; + let reply = Nfs3ReplyLookup { status, handle }; + Ok((i, reply)) +} -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct Nfs3RequestCreate<'a> { pub handle: Nfs3Handle<'a>, pub name_len: u32, pub create_mode: u32, - pub verifier: &'a[u8], + pub verifier: &'a [u8], pub name_vec: Vec, } -named!(pub parse_nfs3_request_create, - do_parse!( - handle: parse_nfs3_handle - >> name_len: be_u32 - >> name: take!(name_len) - >> create_mode: be_u32 - >> verifier: rest - >> ( - Nfs3RequestCreate { - handle:handle, - name_len:name_len, - create_mode:create_mode, - verifier:verifier, - name_vec:name.to_vec(), - } - )) -); +pub fn parse_nfs3_request_create(i: &[u8]) -> IResult<&[u8], Nfs3RequestCreate> { + let (i, handle) = parse_nfs3_handle(i)?; + let (i, name_len) = be_u32(i)?; + let (i, name) = take(name_len as usize)(i)?; + let (i, create_mode) = be_u32(i)?; + let (i, verifier) = rest(i)?; + let req = Nfs3RequestCreate { + handle, + name_len, + create_mode, + verifier, + name_vec: name.to_vec(), + }; + Ok((i, req)) +} -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct Nfs3RequestRemove<'a> { pub handle: Nfs3Handle<'a>, pub name_len: u32, pub name_vec: Vec, } -named!(pub parse_nfs3_request_remove, - do_parse!( - handle: parse_nfs3_handle - >> name_len: be_u32 - >> name: take!(name_len) - >> _fill_bytes: rest - >> ( - Nfs3RequestRemove { - handle:handle, - name_len:name_len, - name_vec:name.to_vec(), - } - )) -); +pub fn parse_nfs3_request_remove(i: &[u8]) -> IResult<&[u8], Nfs3RequestRemove> { + let (i, handle) = parse_nfs3_handle(i)?; + let (i, name_len) = be_u32(i)?; + let (i, name) = take(name_len as usize)(i)?; + let (i, _fill_bytes) = rest(i)?; + let req = Nfs3RequestRemove { + handle, + name_len, + name_vec: name.to_vec(), + }; + Ok((i, req)) +} -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct Nfs3RequestRmdir<'a> { pub handle: Nfs3Handle<'a>, pub name_vec: Vec, } -named!(pub parse_nfs3_request_rmdir, - do_parse!( - dir_handle: parse_nfs3_handle - >> name_len: be_u32 - >> name: take!(name_len) - >> _fill_bytes: cond!(name_len % 4 != 0, take!(4 - name_len % 4)) - >> ( - Nfs3RequestRmdir { - handle:dir_handle, - name_vec:name.to_vec(), - } - )) -); +pub fn parse_nfs3_request_rmdir(i: &[u8]) -> IResult<&[u8], Nfs3RequestRmdir> { + let (i, handle) = parse_nfs3_handle(i)?; + let (i, name_len) = be_u32(i)?; + let (i, name) = take(name_len as usize)(i)?; + let (i, _fill_bytes) = cond(name_len % 4 != 0, take(4 - (name_len % 4)))(i)?; + let req = Nfs3RequestRmdir { + handle, + name_vec: name.to_vec(), + }; + Ok((i, req)) +} -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct Nfs3RequestMkdir<'a> { pub handle: Nfs3Handle<'a>, pub name_vec: Vec, } -named!(pub parse_nfs3_request_mkdir, - do_parse!( - dir_handle: parse_nfs3_handle - >> name_len: be_u32 - >> name: take!(name_len) - >> _fill_bytes: cond!(name_len % 4 != 0, take!(4 - name_len % 4)) - >> _attributes: rest - >> ( - Nfs3RequestMkdir { - handle:dir_handle, - name_vec:name.to_vec(), - } - )) -); +pub fn parse_nfs3_request_mkdir(i: &[u8]) -> IResult<&[u8], Nfs3RequestMkdir> { + let (i, handle) = parse_nfs3_handle(i)?; + let (i, name_len) = be_u32(i)?; + let (i, name) = take(name_len as usize)(i)?; + let (i, _fill_bytes) = cond(name_len % 4 != 0, take(4 - (name_len % 4)))(i)?; + let (i, _attributes) = rest(i)?; + let req = Nfs3RequestMkdir { + handle, + name_vec: name.to_vec(), + }; + Ok((i, req)) +} -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct Nfs3RequestRename<'a> { pub from_handle: Nfs3Handle<'a>, pub from_name_vec: Vec, @@ -175,212 +154,180 @@ pub struct Nfs3RequestRename<'a> { pub to_name_vec: Vec, } -named!(pub parse_nfs3_request_rename, - do_parse!( - from_handle: parse_nfs3_handle - >> from_name_len: be_u32 - >> from_name: take!(from_name_len) - >> _from_fill_bytes: cond!(from_name_len % 4 != 0, take!(4 - from_name_len % 4)) - >> to_handle: parse_nfs3_handle - >> to_name_len: be_u32 - >> to_name: take!(to_name_len) - >> _to_fill_bytes: rest - >> ( - Nfs3RequestRename { - from_handle, - from_name_vec:from_name.to_vec(), - to_handle, - to_name_vec:to_name.to_vec(), - } - )) -); +pub fn parse_nfs3_request_rename(i: &[u8]) -> IResult<&[u8], Nfs3RequestRename> { + let (i, from_handle) = parse_nfs3_handle(i)?; + let (i, from_name_len) = be_u32(i)?; + let (i, from_name) = take(from_name_len as usize)(i)?; + let (i, _from_fill_bytes) = cond(from_name_len % 4 != 0, take(4 - (from_name_len % 4)))(i)?; + + let (i, to_handle) = parse_nfs3_handle(i)?; + let (i, to_name_len) = be_u32(i)?; + let (i, to_name) = take(to_name_len as usize)(i)?; + let (i, _from_fill_bytes) = rest(i)?; + let req = Nfs3RequestRename { + from_handle, + from_name_vec: from_name.to_vec(), + to_handle, + to_name_vec: to_name.to_vec(), + }; + Ok((i, req)) +} -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct Nfs3RequestGetAttr<'a> { pub handle: Nfs3Handle<'a>, } -named!(pub parse_nfs3_request_getattr, - do_parse!( - handle: parse_nfs3_handle - >> ( - Nfs3RequestGetAttr { - handle:handle, - } - )) -); +pub fn parse_nfs3_request_getattr(i: &[u8]) -> IResult<&[u8], Nfs3RequestGetAttr> { + let (i, handle) = parse_nfs3_handle(i)?; + Ok((i, Nfs3RequestGetAttr { handle })) +} -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct Nfs3RequestAccess<'a> { pub handle: Nfs3Handle<'a>, pub check_access: u32, } -named!(pub parse_nfs3_request_access, - do_parse!( - handle: parse_nfs3_handle - >> check_access: be_u32 - >> ( - Nfs3RequestAccess { - handle:handle, - check_access:check_access, - } - )) -); +pub fn parse_nfs3_request_access(i: &[u8]) -> IResult<&[u8], Nfs3RequestAccess> { + let (i, handle) = parse_nfs3_handle(i)?; + let (i, check_access) = be_u32(i)?; + let req = Nfs3RequestAccess { + handle, + check_access, + }; + Ok((i, req)) +} -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct Nfs3RequestCommit<'a> { pub handle: Nfs3Handle<'a>, } -named!(pub parse_nfs3_request_commit, - do_parse!( - handle: parse_nfs3_handle - >> _offset: be_u64 - >> _count: be_u32 - >> ( - Nfs3RequestCommit { - handle - } - )) -); +pub fn parse_nfs3_request_commit(i: &[u8]) -> IResult<&[u8], Nfs3RequestCommit> { + let (i, handle) = parse_nfs3_handle(i)?; + let (i, _offset) = be_u64(i)?; + let (i, _count) = be_u32(i)?; + Ok((i, Nfs3RequestCommit { handle })) +} -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct Nfs3RequestRead<'a> { pub handle: Nfs3Handle<'a>, pub offset: u64, } -named!(pub parse_nfs3_request_read, - do_parse!( - handle: parse_nfs3_handle - >> offset: be_u64 - >> _count: be_u32 - >> ( - Nfs3RequestRead { - handle, - offset - } - )) -); +pub fn parse_nfs3_request_read(i: &[u8]) -> IResult<&[u8], Nfs3RequestRead> { + let (i, handle) = parse_nfs3_handle(i)?; + let (i, offset) = be_u64(i)?; + let (i, _count) = be_u32(i)?; + Ok((i, Nfs3RequestRead { handle, offset })) +} -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct Nfs3RequestLookup<'a> { pub handle: Nfs3Handle<'a>, pub name_vec: Vec, } -named!(pub parse_nfs3_request_lookup, - do_parse!( - handle: parse_nfs3_handle - >> name_len: be_u32 - >> name_contents: take!(name_len) - >> _name_padding: rest - >> ( - Nfs3RequestLookup { - handle, - name_vec:name_contents.to_vec(), - } - )) -); - +pub fn parse_nfs3_request_lookup(i: &[u8]) -> IResult<&[u8], Nfs3RequestLookup> { + let (i, handle) = parse_nfs3_handle(i)?; + let (i, name_contents) = length_data(be_u32)(i)?; + let (i, _name_padding) = rest(i)?; + let req = Nfs3RequestLookup { + handle, + name_vec: name_contents.to_vec(), + }; + Ok((i, req)) +} -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct Nfs3ResponseReaddirplusEntryC<'a> { pub name_vec: Vec, pub handle: Option>, } -named!(pub parse_nfs3_response_readdirplus_entry, - do_parse!( - _file_id: be_u64 - >> name_len: be_u32 - >> name_content: take!(name_len) - >> _fill_bytes: cond!(name_len % 4 != 0, take!(4 - name_len % 4)) - >> _cookie: take!(8) - >> attr_value_follows: be_u32 - >> _attr: cond!(attr_value_follows==1, take!(84)) - >> handle_value_follows: be_u32 - >> handle: cond!(handle_value_follows==1, parse_nfs3_handle) - >> ( - Nfs3ResponseReaddirplusEntryC { - name_vec:name_content.to_vec(), - handle, - } - ) - ) -); +pub fn parse_nfs3_response_readdirplus_entry( + i: &[u8], +) -> IResult<&[u8], Nfs3ResponseReaddirplusEntryC> { + let (i, _file_id) = be_u64(i)?; + let (i, name_len) = be_u32(i)?; + let (i, name_contents) = take(name_len as usize)(i)?; + let (i, _fill_bytes) = cond(name_len % 4 != 0, take(4 - (name_len % 4)))(i)?; + let (i, _cookie) = take(8_usize)(i)?; + let (i, attr_value_follows) = be_u32(i)?; + let (i, _attr) = cond(attr_value_follows == 1, take(84_usize))(i)?; + let (i, handle_value_follows) = be_u32(i)?; + let (i, handle) = cond(handle_value_follows == 1, parse_nfs3_handle)(i)?; + let resp = Nfs3ResponseReaddirplusEntryC { + name_vec: name_contents.to_vec(), + handle, + }; + Ok((i, resp)) +} -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct Nfs3ResponseReaddirplusEntry<'a> { pub entry: Option>, } -named!(pub parse_nfs3_response_readdirplus_entry_cond, - do_parse!( - value_follows: be_u32 - >> entry: cond!(value_follows==1, parse_nfs3_response_readdirplus_entry) - >> ( - Nfs3ResponseReaddirplusEntry { - entry - } - )) -); +pub fn parse_nfs3_response_readdirplus_entry_cond( + i: &[u8], +) -> IResult<&[u8], Nfs3ResponseReaddirplusEntry> { + let (i, value_follows) = be_u32(i)?; + let (i, entry) = cond(value_follows == 1, parse_nfs3_response_readdirplus_entry)(i)?; + Ok((i, Nfs3ResponseReaddirplusEntry { entry })) +} -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct Nfs3ResponseReaddirplus<'a> { pub status: u32, - pub data: &'a[u8], + pub data: &'a [u8], } -named!(pub parse_nfs3_response_readdirplus, - do_parse!( - status: be_u32 - >> dir_attr_follows: be_u32 - >> _dir_attr: cond!(dir_attr_follows == 1, take!(84)) - >> _verifier: take!(8) - >> data: rest - - >> ( Nfs3ResponseReaddirplus { - status, - data - } )) -); +pub fn parse_nfs3_response_readdirplus(i: &[u8]) -> IResult<&[u8], Nfs3ResponseReaddirplus> { + let (i, status) = be_u32(i)?; + let (i, dir_attr_follows) = be_u32(i)?; + let (i, _dir_attr) = cond(dir_attr_follows == 1, take(84_usize))(i)?; + let (i, data) = rest(i)?; + let resp = Nfs3ResponseReaddirplus { status, data }; + Ok((i, resp)) +} -pub(crate) fn many0_nfs3_response_readdirplus_entries<'a>(input: &'a [u8]) -> IResult<&'a[u8], Vec>> { - many0!(input, complete!(parse_nfs3_response_readdirplus_entry_cond)) +pub(crate) fn many0_nfs3_response_readdirplus_entries<'a>( + input: &'a [u8], +) -> IResult<&'a [u8], Vec>> { + many0(complete(parse_nfs3_response_readdirplus_entry_cond))(input) } -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct Nfs3RequestReaddirplus<'a> { pub handle: Nfs3Handle<'a>, pub cookie: u32, - pub verifier: &'a[u8], + pub verifier: &'a [u8], pub dircount: u32, pub maxcount: u32, } -named!(pub parse_nfs3_request_readdirplus, - do_parse!( - handle: parse_nfs3_handle - >> cookie: be_u32 - >> verifier: take!(8) - >> dircount: be_u32 - >> maxcount: be_u32 - >> ( - Nfs3RequestReaddirplus { - handle:handle, - cookie:cookie, - verifier:verifier, - dircount:dircount, - maxcount:maxcount, - } - )) -); +pub fn parse_nfs3_request_readdirplus(i: &[u8]) -> IResult<&[u8], Nfs3RequestReaddirplus> { + let (i, handle) = parse_nfs3_handle(i)?; + let (i, cookie) = be_u32(i)?; + let (i, verifier) = take(8_usize)(i)?; + let (i, dircount) = be_u32(i)?; + let (i, maxcount) = be_u32(i)?; + let req = Nfs3RequestReaddirplus { + handle, + cookie, + verifier, + dircount, + maxcount, + }; + Ok((i, req)) +} -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct Nfs3RequestWrite<'a> { pub handle: Nfs3Handle<'a>, @@ -388,28 +335,26 @@ pub struct Nfs3RequestWrite<'a> { pub count: u32, pub stable: u32, pub file_len: u32, - pub file_data: &'a[u8], -} - -named!(pub parse_nfs3_request_write, - do_parse!( - handle: parse_nfs3_handle - >> offset: be_u64 - >> count: be_u32 - >> stable: be_u32 - >> file_len: be_u32 - >> file_data: rest // likely partial - >> ( - Nfs3RequestWrite { - handle:handle, - offset:offset, - count:count, - stable:stable, - file_len:file_len, - file_data:file_data, - } - )) -); + pub file_data: &'a [u8], +} + +pub fn parse_nfs3_request_write(i: &[u8]) -> IResult<&[u8], Nfs3RequestWrite> { + let (i, handle) = parse_nfs3_handle(i)?; + let (i, offset) = be_u64(i)?; + let (i, count) = be_u32(i)?; + let (i, stable) = be_u32(i)?; + let (i, file_len) = be_u32(i)?; + let (i, file_data) = rest(i)?; + let req = Nfs3RequestWrite { + handle, + offset, + count, + stable, + file_len, + file_data, + }; + Ok((i, req)) +} /* #[derive(Debug,PartialEq)] pub struct Nfs3ReplyRead<'a> { @@ -422,24 +367,22 @@ pub struct Nfs3ReplyRead<'a> { pub data: &'a[u8], // likely partial } */ -named!(pub parse_nfs3_reply_read, - do_parse!( - status: be_u32 - >> attr_follows: be_u32 - >> attr_blob: take!(84) // fixed size? - >> count: be_u32 - >> eof: be_u32 - >> data_len: be_u32 - >> data_contents: rest - >> ( - NfsReplyRead { - status:status, - attr_follows:attr_follows, - attr_blob:attr_blob, - count:count, - eof:eof != 0, - data_len:data_len, - data:data_contents, - } - )) -); +pub fn parse_nfs3_reply_read(i: &[u8]) -> IResult<&[u8], NfsReplyRead> { + let (i, status) = be_u32(i)?; + let (i, attr_follows) = be_u32(i)?; + let (i, attr_blob) = take(84_usize)(i)?; // fixed size? + let (i, count) = be_u32(i)?; + let (i, eof) = be_u32(i)?; + let (i, data_len) = be_u32(i)?; + let (i, data) = rest(i)?; + let reply = NfsReplyRead { + status, + attr_follows, + attr_blob, + count, + eof: eof != 0, + data_len, + data, + }; + Ok((i, reply)) +} diff --git a/rust/src/nfs/nfs4.rs b/rust/src/nfs/nfs4.rs index aec2ef8988..95924df98a 100644 --- a/rust/src/nfs/nfs4.rs +++ b/rust/src/nfs/nfs4.rs @@ -17,30 +17,31 @@ // written by Victor Julien -use nom; +use nom::bytes::streaming::take; use nom::number::streaming::be_u32; +use nom7::Err; use crate::core::*; use crate::nfs::nfs::*; -use crate::nfs::types::*; -use crate::nfs::rpc_records::*; -use crate::nfs::nfs_records::*; use crate::nfs::nfs4_records::*; +use crate::nfs::nfs_records::*; +use crate::nfs::rpc_records::*; +use crate::nfs::types::*; use crate::kerberos::{parse_kerberos5_request, Kerberos5Ticket, SecBlobError}; -named!(parse_req_gssapi<&[u8], Kerberos5Ticket, SecBlobError>, - do_parse!( - len: be_u32 - >> ap: flat_map!(take!(len), parse_kerberos5_request) - >> ( ap ) -)); +// use the old nom type until both SMB and NFS are migrated to nom 7 +fn parse_req_gssapi(i: &[u8]) -> nom::IResult<&[u8], Kerberos5Ticket, SecBlobError> { + let (i, len) = be_u32(i)?; + let (i, buf) = take(len as usize)(i)?; + let (_, ap) = parse_kerberos5_request(buf)?; + Ok((i, ap)) +} impl NFSState { /* normal write: PUTFH (file handle), WRITE (write opts/data). File handle * is not part of the write record itself so we pass it in here. */ - fn write_v4<'b>(&mut self, r: &RpcPacket<'b>, w: &Nfs4RequestWrite<'b>, fh: &'b[u8]) - { + fn write_v4<'b>(&mut self, r: &RpcPacket<'b>, w: &Nfs4RequestWrite<'b>, fh: &'b [u8]) { // for now assume that stable FILE_SYNC flags means a single chunk let is_last = if w.stable == 2 { true } else { false }; SCLogDebug!("is_last {}", is_last); @@ -63,9 +64,18 @@ impl NFSState { let found = match self.get_file_tx_by_handle(&file_handle, Direction::ToServer) { Some((tx, files, flags)) => { if let Some(NFSTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - filetracker_newchunk(&mut tdf.file_tracker, files, flags, - &file_name, w.data, w.offset, - w.write_len, fill_bytes as u8, is_last, &r.hdr.xid); + filetracker_newchunk( + &mut tdf.file_tracker, + files, + flags, + &file_name, + w.data, + w.offset, + w.write_len, + fill_bytes as u8, + is_last, + &r.hdr.xid, + ); tdf.chunk_count += 1; if is_last { tdf.file_last_xid = r.hdr.xid; @@ -74,15 +84,24 @@ impl NFSState { } } true - }, + } None => false, }; if !found { let (tx, files, flags) = self.new_file_tx(&file_handle, &file_name, Direction::ToServer); if let Some(NFSTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - filetracker_newchunk(&mut tdf.file_tracker, files, flags, - &file_name, w.data, w.offset, - w.write_len, fill_bytes as u8, is_last, &r.hdr.xid); + filetracker_newchunk( + &mut tdf.file_tracker, + files, + flags, + &file_name, + w.data, + w.offset, + w.write_len, + fill_bytes as u8, + is_last, + &r.hdr.xid, + ); tx.procedure = NFSPROC4_WRITE; tx.xid = r.hdr.xid; tx.is_first = true; @@ -100,17 +119,16 @@ impl NFSState { self.ts_chunk_left = w.write_len as u32 - file_data_len as u32; } - fn close_v4<'b>(&mut self, r: &RpcPacket<'b>, fh: &'b[u8]) - { + fn close_v4<'b>(&mut self, r: &RpcPacket<'b>, fh: &'b [u8]) { self.commit_v4(r, fh) } - fn commit_v4<'b>(&mut self, r: &RpcPacket<'b>, fh: &'b[u8]) - { + fn commit_v4<'b>(&mut self, r: &RpcPacket<'b>, fh: &'b [u8]) { SCLogDebug!("COMMIT, closing shop"); let file_handle = fh.to_vec(); - if let Some((tx, files, flags)) = self.get_file_tx_by_handle(&file_handle, Direction::ToServer) { + if let Some((tx, files, flags)) = self.get_file_tx_by_handle(&file_handle, Direction::ToServer) + { if let Some(NFSTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { tdf.file_tracker.close(files, flags); tdf.file_last_xid = r.hdr.xid; @@ -121,10 +139,10 @@ impl NFSState { } } - fn new_tx_v4<'b>(&mut self, r: &RpcPacket<'b>, - xidmap: &NFSRequestXidMap, procedure: u32, - _aux_opcodes: &Vec) - { + fn new_tx_v4<'b>( + &mut self, r: &RpcPacket<'b>, xidmap: &NFSRequestXidMap, procedure: u32, + _aux_opcodes: &Vec, + ) { let mut tx = self.new_tx(); tx.xid = r.hdr.xid; tx.procedure = procedure; @@ -139,24 +157,28 @@ impl NFSState { tx.request_machine_name = u.machine_name_buf.to_vec(); tx.request_uid = u.uid; tx.request_gid = u.gid; - }, - _ => { }, + } + _ => {} } - SCLogDebug!("NFSv4: TX created: ID {} XID {} PROCEDURE {}", - tx.id, tx.xid, tx.procedure); + SCLogDebug!( + "NFSv4: TX created: ID {} XID {} PROCEDURE {}", + tx.id, + tx.xid, + tx.procedure + ); self.transactions.push(tx); } /* A normal READ request looks like: PUTFH (file handle) READ (read opts). * We need the file handle for the READ. */ - fn compound_request<'b>(&mut self, r: &RpcPacket<'b>, - cr: &Nfs4RequestCompoundRecord<'b>, - xidmap: &mut NFSRequestXidMap) - { - let mut last_putfh : Option<&'b[u8]> = None; - let mut main_opcode : u32 = 0; - let mut aux_opcodes : Vec = Vec::new(); + fn compound_request<'b>( + &mut self, r: &RpcPacket<'b>, cr: &Nfs4RequestCompoundRecord<'b>, + xidmap: &mut NFSRequestXidMap, + ) { + let mut last_putfh: Option<&'b [u8]> = None; + let mut main_opcode: u32 = 0; + let mut aux_opcodes: Vec = Vec::new(); for c in &cr.commands { SCLogDebug!("c {:?}", c); @@ -213,12 +235,14 @@ impl NFSState { main_opcode = NFSPROC4_REMOVE; } &Nfs4RequestContent::SetClientId(ref _rd) => { - SCLogDebug!("SETCLIENTIDv4: client id {} r_netid {} r_addr {}", - String::from_utf8_lossy(&_rd.client_id), - String::from_utf8_lossy(&_rd.r_netid), - String::from_utf8_lossy(&_rd.r_addr)); + SCLogDebug!( + "SETCLIENTIDv4: client id {} r_netid {} r_addr {}", + String::from_utf8_lossy(&_rd.client_id), + String::from_utf8_lossy(&_rd.r_netid), + String::from_utf8_lossy(&_rd.r_addr) + ); } - &_ => { }, + &_ => {} } } @@ -229,8 +253,13 @@ impl NFSState { /// complete request record pub fn process_request_record_v4<'b>(&mut self, r: &RpcPacket<'b>) { - SCLogDebug!("NFSv4 REQUEST {} procedure {} ({}) blob size {}", - r.hdr.xid, r.procedure, self.requestmap.len(), r.prog_data.len()); + SCLogDebug!( + "NFSv4 REQUEST {} procedure {} ({}) blob size {}", + r.hdr.xid, + r.procedure, + self.requestmap.len(), + r.prog_data.len() + ); let mut xidmap = NFSRequestXidMap::new(r.progver, r.procedure, 0); @@ -245,7 +274,7 @@ impl NFSState { let mut data = r.prog_data; if let RpcRequestCreds::GssApi(ref creds) = r.creds { - if creds.procedure == 0 && creds.service == 2 { + if creds.procedure == 0 && creds.service == 2 { SCLogDebug!("GSS INTEGRITIY: {:?}", creds); match parse_rpc_gssapi_integrity(r.prog_data) { Ok((_rem, rec)) => { @@ -254,18 +283,20 @@ impl NFSState { // store proc and serv for the reply xidmap.gssapi_proc = creds.procedure; xidmap.gssapi_service = creds.service; - }, - Err(nom::Err::Incomplete(_n)) => { + } + Err(Err::Incomplete(_n)) => { SCLogDebug!("NFSPROC4_COMPOUND/GSS INTEGRITIY: INCOMPLETE {:?}", _n); self.set_event(NFSEvent::MalformedData); return; - }, - Err(nom::Err::Error(_e)) | - Err(nom::Err::Failure(_e)) => { - SCLogDebug!("NFSPROC4_COMPOUND/GSS INTEGRITIY: Parsing failed: {:?}", _e); + } + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { + SCLogDebug!( + "NFSPROC4_COMPOUND/GSS INTEGRITIY: Parsing failed: {:?}", + _e + ); self.set_event(NFSEvent::MalformedData); return; - }, + } } } } @@ -274,29 +305,28 @@ impl NFSState { Ok((_, rd)) => { SCLogDebug!("NFSPROC4_COMPOUND: {:?}", rd); self.compound_request(r, &rd, &mut xidmap); - }, - Err(nom::Err::Incomplete(_n)) => { + } + Err(Err::Incomplete(_n)) => { SCLogDebug!("NFSPROC4_COMPOUND: INCOMPLETE {:?}", _n); self.set_event(NFSEvent::MalformedData); - }, - Err(nom::Err::Error(_e)) | - Err(nom::Err::Failure(_e)) => { + } + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { SCLogDebug!("NFSPROC4_COMPOUND: Parsing failed: {:?}", _e); self.set_event(NFSEvent::MalformedData); - }, + } }; } self.requestmap.insert(r.hdr.xid, xidmap); } - fn compound_response<'b>(&mut self, r: &RpcReplyPacket<'b>, - cr: &Nfs4ResponseCompoundRecord<'b>, - xidmap: &mut NFSRequestXidMap) - { + fn compound_response<'b>( + &mut self, r: &RpcReplyPacket<'b>, cr: &Nfs4ResponseCompoundRecord<'b>, + xidmap: &mut NFSRequestXidMap, + ) { let mut insert_filename_with_getfh = false; - let mut main_opcode_status : u32 = 0; - let mut main_opcode_status_set : bool = false; + let mut main_opcode_status: u32 = 0; + let mut main_opcode_status_set: bool = false; for c in &cr.commands { SCLogDebug!("c {:?}", c); @@ -310,22 +340,26 @@ impl NFSState { SCLogDebug!("READDIRv4: dir {}", String::from_utf8_lossy(&_d.name)); } } - } } &Nfs4ResponseContent::Remove(s) => { SCLogDebug!("REMOVE4: status {}", s); main_opcode_status = s; main_opcode_status_set = true; - }, + } &Nfs4ResponseContent::Create(s) => { SCLogDebug!("CREATE4: status {}", s); main_opcode_status = s; main_opcode_status_set = true; - }, + } &Nfs4ResponseContent::Read(s, ref rd) => { if let &Some(ref rd) = rd { - SCLogDebug!("READ4: xidmap {:?} status {} data {}", xidmap, s, rd.data.len()); + SCLogDebug!( + "READ4: xidmap {:?} status {} data {}", + xidmap, + s, + rd.data.len() + ); // convert record to generic read reply let reply = NfsReplyRead { status: s, @@ -338,28 +372,28 @@ impl NFSState { }; self.process_read_record(r, &reply, Some(xidmap)); } - }, + } &Nfs4ResponseContent::Open(_s, ref rd) => { if let &Some(ref _rd) = rd { SCLogDebug!("OPENv4: status {} opendata {:?}", _s, _rd); insert_filename_with_getfh = true; } - }, + } &Nfs4ResponseContent::GetFH(_s, ref rd) => { if let &Some(ref rd) = rd { if insert_filename_with_getfh { - self.namemap.insert(rd.value.to_vec(), - xidmap.file_name.to_vec()); + self.namemap + .insert(rd.value.to_vec(), xidmap.file_name.to_vec()); } } - }, + } &Nfs4ResponseContent::PutRootFH(s) => { if s == NFS4_OK && xidmap.file_name.len() == 0 { xidmap.file_name = b"".to_vec(); SCLogDebug!("filename {:?}", xidmap.file_name); } - }, - &_ => { }, + } + &_ => {} } } @@ -369,45 +403,43 @@ impl NFSState { } } - pub fn process_reply_record_v4<'b>(&mut self, r: &RpcReplyPacket<'b>, - xidmap: &mut NFSRequestXidMap) { + pub fn process_reply_record_v4<'b>( + &mut self, r: &RpcReplyPacket<'b>, xidmap: &mut NFSRequestXidMap, + ) { if xidmap.procedure == NFSPROC4_COMPOUND { let mut data = r.prog_data; if xidmap.gssapi_proc == 0 && xidmap.gssapi_service == 2 { - SCLogDebug!("GSS INTEGRITIY as set by call: {:?}", xidmap); match parse_rpc_gssapi_integrity(r.prog_data) { Ok((_rem, rec)) => { SCLogDebug!("GSS INTEGRITIY wrapper: {:?}", rec); data = rec.data; - }, - Err(nom::Err::Incomplete(_n)) => { + } + Err(Err::Incomplete(_n)) => { SCLogDebug!("NFSPROC4_COMPOUND/GSS INTEGRITIY: INCOMPLETE {:?}", _n); self.set_event(NFSEvent::MalformedData); return; - }, - Err(nom::Err::Error(_e)) | - Err(nom::Err::Failure(_e)) => { + } + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { SCLogDebug!("NFSPROC4_COMPOUND/GSS INTEGRITIY: Parsing failed: {:?}", _e); self.set_event(NFSEvent::MalformedData); return; - }, + } } } match parse_nfs4_response_compound(data) { Ok((_, rd)) => { SCLogDebug!("COMPOUNDv4: {:?}", rd); self.compound_response(r, &rd, xidmap); - }, - Err(nom::Err::Incomplete(_)) => { + } + Err(Err::Incomplete(_)) => { self.set_event(NFSEvent::MalformedData); - }, - Err(nom::Err::Error(_e)) | - Err(nom::Err::Failure(_e)) => { + } + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { SCLogDebug!("Parsing failed: {:?}", _e); self.set_event(NFSEvent::MalformedData); - }, + } }; } } diff --git a/rust/src/nfs/nfs4_records.rs b/rust/src/nfs/nfs4_records.rs index e4f391f1e8..94248db01f 100644 --- a/rust/src/nfs/nfs4_records.rs +++ b/rust/src/nfs/nfs4_records.rs @@ -16,7 +16,12 @@ */ //! Nom parsers for NFSv4 records -use nom::number::streaming::{be_u32, be_u64}; +use nom7::bytes::streaming::{tag, take}; +use nom7::combinator::{complete, cond, map, peek}; +use nom7::error::{make_error, ErrorKind}; +use nom7::multi::{count, many_till}; +use nom7::number::streaming::{be_u32, be_u64}; +use nom7::{Err, IResult}; use crate::nfs::types::*; @@ -53,35 +58,34 @@ pub struct Nfs4Attr { attr_mask: u64, } -named!(nfs4_parse_attr_fields, - do_parse!( - len: be_u32 - >> take!(len) - >> (len) -)); - -named!(nfs4_parse_attrs, - do_parse!( - attr_cnt: be_u32 - >> attr_mask1: be_u32 - >> attr_mask2: cond!(attr_cnt >= 2, be_u32) - >> cond!(attr_cnt == 3, be_u32) - >> nfs4_parse_attr_fields - >> ( Nfs4Attr { - attr_mask: ((attr_mask1 as u64) << 32) | attr_mask2.unwrap_or(0) as u64, - } ) -)); - -named!(nfs4_parse_attrbits, - do_parse!( - attr_cnt: be_u32 - >> attr_mask1: be_u32 - >> attr_mask2: cond!(attr_cnt >= 2, be_u32) - >> cond!(attr_cnt == 3, be_u32) - >> ( Nfs4Attr { - attr_mask: ((attr_mask1 as u64) << 32) | attr_mask2.unwrap_or(0) as u64, - } ) -)); +fn nfs4_parse_attr_fields(i: &[u8]) -> IResult<&[u8], u32> { + let (i, len) = be_u32(i)?; + let (i, _) = take(len as usize)(i)?; + Ok((i, len)) +} + +fn nfs4_parse_attrs(i: &[u8]) -> IResult<&[u8], Nfs4Attr> { + let (i, attr_cnt) = be_u32(i)?; + let (i, attr_mask1) = be_u32(i)?; + let (i, attr_mask2) = cond(attr_cnt >= 2, be_u32)(i)?; + let (i, _) = cond(attr_cnt == 3, be_u32)(i)?; + let (i, _) = nfs4_parse_attr_fields(i)?; + let attr = Nfs4Attr { + attr_mask: ((attr_mask1 as u64) << 32) | attr_mask2.unwrap_or(0) as u64, + }; + Ok((i, attr)) +} + +fn nfs4_parse_attrbits(i: &[u8]) -> IResult<&[u8], Nfs4Attr> { + let (i, attr_cnt) = be_u32(i)?; + let (i, attr_mask1) = be_u32(i)?; + let (i, attr_mask2) = cond(attr_cnt >= 2, be_u32)(i)?; + let (i, _) = cond(attr_cnt == 3, be_u32)(i)?; + let attr = Nfs4Attr { + attr_mask: ((attr_mask1 as u64) << 32) | attr_mask2.unwrap_or(0) as u64, + }; + Ok((i, attr)) +} #[derive(Debug,PartialEq)] pub struct Nfs4StateId<'a> { @@ -89,16 +93,12 @@ pub struct Nfs4StateId<'a> { pub data: &'a[u8], } -named!(nfs4_parse_stateid, - do_parse!( - seqid: be_u32 - >> data: take!(12) - >> ( Nfs4StateId { - seqid: seqid, - data: data, - }) - ) -); +fn nfs4_parse_stateid(i: &[u8]) -> IResult<&[u8], Nfs4StateId> { + let (i, seqid) = be_u32(i)?; + let (i, data) = take(12_usize)(i)?; + let state = Nfs4StateId { seqid, data }; + Ok((i, state)) +} #[derive(Debug,PartialEq)] pub struct Nfs4Handle<'a> { @@ -106,29 +106,23 @@ pub struct Nfs4Handle<'a> { pub value: &'a[u8], } -named!(nfs4_parse_handle, - do_parse!( - obj_len: be_u32 - >> obj: take!(obj_len) - >> ( Nfs4Handle { - len: obj_len, - value: obj, - }) -)); - -named!(nfs4_parse_nfsstring<&[u8]>, - do_parse!( - len: be_u32 - >> data: take!(len) - >> _fill_bytes: cond!(len % 4 != 0, take!(4 - len % 4)) - >> ( data ) -)); - -named!(nfs4_req_putfh, - do_parse!( - h: nfs4_parse_handle - >> ( Nfs4RequestContent::PutFH(h) ) -)); +fn nfs4_parse_handle(i: &[u8]) -> IResult<&[u8], Nfs4Handle> { + let (i, len) = be_u32(i)?; + let (i, value) = take(len as usize)(i)?; + let handle = Nfs4Handle { len, value }; + Ok((i, handle)) +} + +fn nfs4_parse_nfsstring(i: &[u8]) -> IResult<&[u8], &[u8]> { + let (i, len) = be_u32(i)?; + let (i, data) = take(len as usize)(i)?; + let (i, _fill_bytes) = cond(len % 4 != 0, take(4 - (len % 4)))(i)?; + Ok((i, data)) +} + +fn nfs4_req_putfh(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + map(nfs4_parse_handle, Nfs4RequestContent::PutFH)(i) +} #[derive(Debug,PartialEq)] pub struct Nfs4RequestSetClientId<'a> { @@ -137,27 +131,26 @@ pub struct Nfs4RequestSetClientId<'a> { pub r_addr: &'a[u8], } -named!(nfs4_req_setclientid, - do_parse!( - _client_verifier: take!(8) - >> client_id: nfs4_parse_nfsstring - >> _cb_program: be_u32 - >> r_netid: nfs4_parse_nfsstring - >> r_addr: nfs4_parse_nfsstring - >> _cb_id: be_u32 - >> (Nfs4RequestContent::SetClientId(Nfs4RequestSetClientId { - client_id, - r_netid, - r_addr - })) -)); - -named!(nfs4_req_setclientid_confirm, - do_parse!( - _client_id: take!(8) - >> _verifier: take!(8) - >> (Nfs4RequestContent::SetClientIdConfirm) -)); +fn nfs4_req_setclientid(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + let (i, _client_verifier) = take(8_usize)(i)?; + let (i, client_id) = nfs4_parse_nfsstring(i)?; + let (i, _cb_program) = be_u32(i)?; + let (i, r_netid) = nfs4_parse_nfsstring(i)?; + let (i, r_addr) = nfs4_parse_nfsstring(i)?; + let (i, _cb_id) = be_u32(i)?; + let req = Nfs4RequestContent::SetClientId(Nfs4RequestSetClientId { + client_id, + r_netid, + r_addr + }); + Ok((i, req)) +} + +fn nfs4_req_setclientid_confirm(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + let (i, _client_id) = take(8_usize)(i)?; + let (i, _verifier) = take(8_usize)(i)?; + Ok((i, Nfs4RequestContent::SetClientIdConfirm)) +} #[derive(Debug,PartialEq)] pub struct Nfs4RequestCreate<'a> { @@ -166,19 +159,18 @@ pub struct Nfs4RequestCreate<'a> { pub link_content: &'a[u8], } -named!(nfs4_req_create, - do_parse!( - ftype4: be_u32 - >> link_content: cond!(ftype4 == 5, nfs4_parse_nfsstring) - >> filename: nfs4_parse_nfsstring - >> _attrs: nfs4_parse_attrs - >> ( Nfs4RequestContent::Create(Nfs4RequestCreate { - ftype4: ftype4, - filename: filename, - link_content: link_content.unwrap_or(&[]), - }) - )) -); +fn nfs4_req_create(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + let (i, ftype4) = be_u32(i)?; + let (i, link_content) = cond(ftype4 == 5, nfs4_parse_nfsstring)(i)?; + let (i, filename) = nfs4_parse_nfsstring(i)?; + let (i, _attrs) = nfs4_parse_attrs(i)?; + let req = Nfs4RequestContent::Create(Nfs4RequestCreate { + ftype4, + filename, + link_content: link_content.unwrap_or(&[]), + }); + Ok((i, req)) +} #[derive(Debug,PartialEq)] pub enum Nfs4OpenRequestContent<'a> { @@ -187,34 +179,29 @@ pub enum Nfs4OpenRequestContent<'a> { Guarded4(Nfs4Attr), } -named!(nfs4_req_open_unchecked4, - do_parse!( - attrs: nfs4_parse_attrs - >> ( Nfs4OpenRequestContent::Unchecked4(attrs) ) -)); +fn nfs4_req_open_unchecked4(i: &[u8]) -> IResult<&[u8], Nfs4OpenRequestContent> { + map(nfs4_parse_attrs, Nfs4OpenRequestContent::Unchecked4)(i) +} -named!(nfs4_req_open_guarded4, - do_parse!( - attrs: nfs4_parse_attrs - >> ( Nfs4OpenRequestContent::Guarded4(attrs) ) -)); +fn nfs4_req_open_guarded4(i: &[u8]) -> IResult<&[u8], Nfs4OpenRequestContent> { + map(nfs4_parse_attrs, Nfs4OpenRequestContent::Guarded4)(i) +} -named!(nfs4_req_open_exclusive4, - do_parse!( - ver: take!(8) - >> ( Nfs4OpenRequestContent::Exclusive4(ver) ) -)); +fn nfs4_req_open_exclusive4(i: &[u8]) -> IResult<&[u8], Nfs4OpenRequestContent> { + map(take(8_usize), Nfs4OpenRequestContent::Exclusive4)(i) +} -named!(nfs4_req_open_type, - do_parse!( - mode: be_u32 - >> data: switch!(value!(mode), - 0 => call!(nfs4_req_open_unchecked4) | - 1 => call!(nfs4_req_open_guarded4) | - 2 => call!(nfs4_req_open_exclusive4)) - >> ( data ) -)); +fn nfs4_req_open_type(i: &[u8]) -> IResult<&[u8], Nfs4OpenRequestContent> { + let (i, mode) = be_u32(i)?; + let (i, data) = match mode { + 0 => nfs4_req_open_unchecked4(i)?, + 1 => nfs4_req_open_guarded4(i)?, + 2 => nfs4_req_open_exclusive4(i)?, + _ => { return Err(Err::Error(make_error(i, ErrorKind::Switch))); } + }; + Ok((i, data)) +} #[derive(Debug,PartialEq)] pub struct Nfs4RequestOpen<'a> { @@ -223,36 +210,33 @@ pub struct Nfs4RequestOpen<'a> { pub open_data: Option>, } -named!(nfs4_req_open, - do_parse!( - _seqid: be_u32 - >> _share_access: be_u32 - >> _share_deny: be_u32 - >> _client_id: be_u64 - >> owner_len: be_u32 - >> cond!(owner_len > 0, take!(owner_len)) - >> open_type: be_u32 - >> open_data: cond!(open_type == 1, nfs4_req_open_type) - >> _claim_type: be_u32 - >> filename: nfs4_parse_nfsstring - >> ( Nfs4RequestContent::Open(Nfs4RequestOpen { - open_type, - filename, - open_data - }) - )) -); - -named!(nfs4_req_readdir, - do_parse!( - _cookie: be_u64 - >> _cookie_verf: be_u64 - >> _dir_cnt: be_u32 - >> _max_cnt: be_u32 - >> _attr: nfs4_parse_attrbits - >> ( Nfs4RequestContent::ReadDir ) - ) -); +fn nfs4_req_open(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + let (i, _seq_id) = be_u32(i)?; + let (i, _share_access) = be_u32(i)?; + let (i, _share_deny) = be_u32(i)?; + let (i, _client_id) = be_u64(i)?; + let (i, owner_len) = be_u32(i)?; + let (i, _) = cond(owner_len > 0, take(owner_len as usize))(i)?; + let (i, open_type) = be_u32(i)?; + let (i, open_data) = cond(open_type == 1, nfs4_req_open_type)(i)?; + let (i, _claim_type) = be_u32(i)?; + let (i, filename) = nfs4_parse_nfsstring(i)?; + let req = Nfs4RequestContent::Open(Nfs4RequestOpen { + open_type, + filename, + open_data + }); + Ok((i, req)) +} + +fn nfs4_req_readdir(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + let (i, _cookie) = be_u64(i)?; + let (i, _cookie_verf) = be_u64(i)?; + let (i, _dir_cnt) = be_u32(i)?; + let (i, _max_cnt) = be_u32(i)?; + let (i, _attr) = nfs4_parse_attrbits(i)?; + Ok((i, Nfs4RequestContent::ReadDir)) +} #[derive(Debug,PartialEq)] pub struct Nfs4RequestRename<'a> { @@ -260,57 +244,46 @@ pub struct Nfs4RequestRename<'a> { pub newname: &'a[u8], } -named!(nfs4_req_rename, - do_parse!( - oldname: nfs4_parse_nfsstring - >> newname: nfs4_parse_nfsstring - >> ( Nfs4RequestContent::Rename(Nfs4RequestRename { - oldname, - newname - }) - )) -); +fn nfs4_req_rename(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + let (i, oldname) = nfs4_parse_nfsstring(i)?; + let (i, newname) = nfs4_parse_nfsstring(i)?; + let req = Nfs4RequestContent::Rename(Nfs4RequestRename { + oldname, + newname + }); + Ok((i, req)) +} #[derive(Debug,PartialEq)] pub struct Nfs4RequestLookup<'a> { pub filename: &'a[u8], } -named!(nfs4_req_lookup, - do_parse!( - filename: nfs4_parse_nfsstring - >> ( Nfs4RequestContent::Lookup(Nfs4RequestLookup { - filename - }) - )) -); +fn nfs4_req_lookup(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + map(nfs4_parse_nfsstring, |filename| { + Nfs4RequestContent::Lookup(Nfs4RequestLookup { filename }) + })(i) +} -named!(nfs4_req_remove, - do_parse!( - filename: nfs4_parse_nfsstring - >> ( Nfs4RequestContent::Remove(filename) ) -)); +fn nfs4_req_remove(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + map(nfs4_parse_nfsstring, Nfs4RequestContent::Remove)(i) +} #[derive(Debug,PartialEq)] pub struct Nfs4RequestSetAttr<'a> { pub stateid: Nfs4StateId<'a>, } -named!(nfs4_req_setattr, - do_parse!( - stateid: nfs4_parse_stateid - >> _attrs: nfs4_parse_attrs - >> (Nfs4RequestContent::SetAttr(Nfs4RequestSetAttr { - stateid - })) -)); +fn nfs4_req_setattr(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + let (i, stateid) = nfs4_parse_stateid(i)?; + let (i, _attrs) = nfs4_parse_attrs(i)?; + let req = Nfs4RequestContent::SetAttr(Nfs4RequestSetAttr { stateid }); + Ok((i, req)) +} -named!(nfs4_req_getattr, - do_parse!( - attrs: nfs4_parse_attrbits - >> ( Nfs4RequestContent::GetAttr(attrs) ) - ) -); +fn nfs4_req_getattr(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + map(nfs4_parse_attrbits, Nfs4RequestContent::GetAttr)(i) +} #[derive(Debug,PartialEq)] pub struct Nfs4RequestWrite<'a> { @@ -321,22 +294,22 @@ pub struct Nfs4RequestWrite<'a> { pub data: &'a[u8], } -named!(nfs4_req_write, - do_parse!( - stateid: nfs4_parse_stateid - >> offset: be_u64 - >> stable: be_u32 - >> write_len: be_u32 - >> data: take!(write_len) - >> _padding: cond!(write_len % 4 != 0, take!(4 - write_len % 4)) - >> (Nfs4RequestContent::Write(Nfs4RequestWrite { - stateid: stateid, - offset: offset, - stable: stable, - write_len: write_len, - data: data, - })) -)); +fn nfs4_req_write(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + let (i, stateid) = nfs4_parse_stateid(i)?; + let (i, offset) = be_u64(i)?; + let (i, stable) = be_u32(i)?; + let (i, write_len) = be_u32(i)?; + let (i, data) = take(write_len as usize)(i)?; + let (i, _padding) = cond(write_len % 4 != 0, take(4 - (write_len % 4)))(i)?; + let req = Nfs4RequestContent::Write(Nfs4RequestWrite { + stateid, + offset, + stable, + write_len, + data, + }); + Ok((i, req)) +} #[derive(Debug,PartialEq)] pub struct Nfs4RequestRead<'a> { @@ -345,78 +318,67 @@ pub struct Nfs4RequestRead<'a> { pub count: u32, } -named!(nfs4_req_read, - do_parse!( - stateid: nfs4_parse_stateid - >> offset: be_u64 - >> count: be_u32 - >> ( Nfs4RequestContent::Read(Nfs4RequestRead { - stateid: stateid, - offset: offset, - count: count, - }) - )) -); - -named!(nfs4_req_close, - do_parse!( - _seqid: be_u32 - >> stateid: nfs4_parse_stateid - >> ( Nfs4RequestContent::Close(stateid) ) -)); +fn nfs4_req_read(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + let (i, stateid) = nfs4_parse_stateid(i)?; + let (i, offset) = be_u64(i)?; + let (i, count) = be_u32(i)?; + let req = Nfs4RequestContent::Read(Nfs4RequestRead { + stateid, + offset, + count, + }); + Ok((i, req)) +} + +fn nfs4_req_close(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + let (i, _seq_id) = be_u32(i)?; + let (i, stateid) = nfs4_parse_stateid(i)?; + Ok((i, Nfs4RequestContent::Close(stateid))) +} #[derive(Debug,PartialEq)] pub struct Nfs4RequestOpenConfirm<'a> { pub stateid: Nfs4StateId<'a>, } -named!(nfs4_req_open_confirm, - do_parse!( - stateid: nfs4_parse_stateid - >> _seqid: be_u32 - >> ( Nfs4RequestContent::OpenConfirm(Nfs4RequestOpenConfirm { - stateid - }) - )) -); - -named!(nfs4_req_delegreturn, - do_parse!( - a: nfs4_parse_stateid - >> ( Nfs4RequestContent::DelegReturn(a) ) - ) -); - -named!(nfs4_req_renew, - do_parse!( - a: be_u64 - >> ( Nfs4RequestContent::Renew(a) ) - ) -); - -named!(nfs4_req_getfh, - do_parse!( ( Nfs4RequestContent::GetFH ) )); - -named!(nfs4_req_savefh, - do_parse!( ( Nfs4RequestContent::SaveFH ) )); - -named!(nfs4_req_putrootfh, - do_parse!( ( Nfs4RequestContent::PutRootFH ) )); - -named!(nfs4_req_access, - do_parse!( - a: be_u32 - >> ( Nfs4RequestContent::Access(a) ) - ) -); - -named!(nfs4_req_commit, - do_parse!( - _offset: be_u64 - >> _count: be_u32 - >> ( Nfs4RequestContent::Commit ) - ) -); +fn nfs4_req_open_confirm(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + let (i, _seq_id) = be_u32(i)?; + let (i, stateid) = nfs4_parse_stateid(i)?; + let req = Nfs4RequestContent::OpenConfirm(Nfs4RequestOpenConfirm { + stateid + }); + Ok((i, req)) +} + +fn nfs4_req_delegreturn(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + map(nfs4_parse_stateid, Nfs4RequestContent::DelegReturn)(i) +} + +fn nfs4_req_renew(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + map(be_u64, Nfs4RequestContent::Renew)(i) +} + +fn nfs4_req_getfh(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + Ok((i, Nfs4RequestContent::GetFH)) +} + +fn nfs4_req_savefh(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + Ok((i, Nfs4RequestContent::SaveFH)) +} + +fn nfs4_req_putrootfh(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + Ok((i, Nfs4RequestContent::PutRootFH)) +} + +fn nfs4_req_access(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + map(be_u32, Nfs4RequestContent::Access)(i) +} + +fn nfs4_req_commit(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + let (i, _offset) = be_u64(i)?; + let (i, _count) = be_u32(i)?; + Ok((i, Nfs4RequestContent::Commit)) +} #[derive(Debug,PartialEq)] pub struct Nfs4RequestExchangeId<'a> { @@ -425,93 +387,86 @@ pub struct Nfs4RequestExchangeId<'a> { pub nii_name: &'a[u8], } -named!(nfs4_req_exchangeid, - do_parse!( - _verifier: take!(8) - >> eia_clientstring: nfs4_parse_nfsstring - >> _eia_clientflags: be_u32 - >> _eia_state_protect: be_u32 - >> _eia_client_impl_id: be_u32 - >> nii_domain: nfs4_parse_nfsstring - >> nii_name: nfs4_parse_nfsstring - >> _nii_data_sec: be_u64 - >> _nii_data_nsec: be_u32 - >> (Nfs4RequestContent::ExchangeId( - Nfs4RequestExchangeId { - client_string: eia_clientstring, - nii_domain, - nii_name - } - )) -)); +fn nfs4_req_exchangeid(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + let (i, _verifier) = take(8_usize)(i)?; + let (i, eia_clientstring) = nfs4_parse_nfsstring(i)?; + let (i, _eia_clientflags) = be_u32(i)?; + let (i, _eia_state_protect) = be_u32(i)?; + let (i, _eia_client_impl_id) = be_u32(i)?; + let (i, nii_domain) = nfs4_parse_nfsstring(i)?; + let (i, nii_name) = nfs4_parse_nfsstring(i)?; + let (i, _nii_data_sec) = be_u64(i)?; + let (i, _nii_data_nsec) = be_u32(i)?; + let req = Nfs4RequestContent::ExchangeId(Nfs4RequestExchangeId { + client_string: eia_clientstring, + nii_domain, + nii_name + }); + Ok((i, req)) +} #[derive(Debug,PartialEq)] pub struct Nfs4RequestSequence<'a> { pub ssn_id: &'a[u8], } -named!(nfs4_req_sequence, - do_parse!( - ssn_id: take!(16) - >> _seq_id: be_u32 - >> _slot_id: be_u32 - >> _high_slot_id: be_u32 - >> _cache_this: be_u32 - >> (Nfs4RequestContent::Sequence( - Nfs4RequestSequence { - ssn_id - } - )) -)); - -named!(parse_request_compound_command, - do_parse!( - cmd: be_u32 - >> cmd_data: switch!(value!(cmd), - NFSPROC4_PUTFH => call!(nfs4_req_putfh) | - NFSPROC4_READ => call!(nfs4_req_read) | - NFSPROC4_WRITE => call!(nfs4_req_write) | - NFSPROC4_GETFH => call!(nfs4_req_getfh) | - NFSPROC4_SAVEFH => call!(nfs4_req_savefh) | - NFSPROC4_OPEN => call!(nfs4_req_open) | - NFSPROC4_CLOSE => call!(nfs4_req_close) | - NFSPROC4_LOOKUP => call!(nfs4_req_lookup) | - NFSPROC4_ACCESS => call!(nfs4_req_access) | - NFSPROC4_COMMIT => call!(nfs4_req_commit) | - NFSPROC4_GETATTR => call!(nfs4_req_getattr) | - NFSPROC4_READDIR => call!(nfs4_req_readdir) | - NFSPROC4_RENEW => call!(nfs4_req_renew) | - NFSPROC4_OPEN_CONFIRM => call!(nfs4_req_open_confirm) | - NFSPROC4_REMOVE => call!(nfs4_req_remove) | - NFSPROC4_RENAME => call!(nfs4_req_rename) | - NFSPROC4_CREATE => call!(nfs4_req_create) | - NFSPROC4_DELEGRETURN => call!(nfs4_req_delegreturn) | - NFSPROC4_SETATTR => call!(nfs4_req_setattr) | - NFSPROC4_PUTROOTFH => call!(nfs4_req_putrootfh) | - NFSPROC4_SETCLIENTID => call!(nfs4_req_setclientid) | - NFSPROC4_SETCLIENTID_CONFIRM => call!(nfs4_req_setclientid_confirm) | - NFSPROC4_SEQUENCE => call!(nfs4_req_sequence) | - NFSPROC4_EXCHANGE_ID => call!(nfs4_req_exchangeid) - ) - >> ( cmd_data ) -)); +fn nfs4_req_sequence(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + let (i, ssn_id) = take(16_usize)(i)?; + let (i, _seq_id) = be_u32(i)?; + let (i, _slot_id) = be_u32(i)?; + let (i, _high_slot_id) = be_u32(i)?; + let (i, _cache_this) = be_u32(i)?; + let req = Nfs4RequestContent::Sequence(Nfs4RequestSequence { + ssn_id + }); + Ok((i, req)) +} + +fn parse_request_compound_command(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + let (i, cmd) = be_u32(i)?; + let (i, cmd_data) = match cmd { + NFSPROC4_PUTFH => nfs4_req_putfh(i)?, + NFSPROC4_READ => nfs4_req_read(i)?, + NFSPROC4_WRITE => nfs4_req_write(i)?, + NFSPROC4_GETFH => nfs4_req_getfh(i)?, + NFSPROC4_SAVEFH => nfs4_req_savefh(i)?, + NFSPROC4_OPEN => nfs4_req_open(i)?, + NFSPROC4_CLOSE => nfs4_req_close(i)?, + NFSPROC4_LOOKUP => nfs4_req_lookup(i)?, + NFSPROC4_ACCESS => nfs4_req_access(i)?, + NFSPROC4_COMMIT => nfs4_req_commit(i)?, + NFSPROC4_GETATTR => nfs4_req_getattr(i)?, + NFSPROC4_READDIR => nfs4_req_readdir(i)?, + NFSPROC4_RENEW => nfs4_req_renew(i)?, + NFSPROC4_OPEN_CONFIRM => nfs4_req_open_confirm(i)?, + NFSPROC4_REMOVE => nfs4_req_remove(i)?, + NFSPROC4_RENAME => nfs4_req_rename(i)?, + NFSPROC4_CREATE => nfs4_req_create(i)?, + NFSPROC4_DELEGRETURN => nfs4_req_delegreturn(i)?, + NFSPROC4_SETATTR => nfs4_req_setattr(i)?, + NFSPROC4_PUTROOTFH => nfs4_req_putrootfh(i)?, + NFSPROC4_SETCLIENTID => nfs4_req_setclientid(i)?, + NFSPROC4_SETCLIENTID_CONFIRM => nfs4_req_setclientid_confirm(i)?, + NFSPROC4_SEQUENCE => nfs4_req_sequence(i)?, + NFSPROC4_EXCHANGE_ID => nfs4_req_exchangeid(i)?, + _ => { return Err(Err::Error(make_error(i, ErrorKind::Switch))); } + }; + Ok((i, cmd_data)) +} #[derive(Debug,PartialEq)] pub struct Nfs4RequestCompoundRecord<'a> { pub commands: Vec>, } -named!(pub parse_nfs4_request_compound, - do_parse!( - tag_len: be_u32 - >> _tag: cond!(tag_len > 0, take!(tag_len)) - >> _min_ver: be_u32 - >> ops_cnt: be_u32 - >> commands: count!(parse_request_compound_command, ops_cnt as usize) - >> (Nfs4RequestCompoundRecord { - commands - }) -)); +pub fn parse_nfs4_request_compound(i: &[u8]) -> IResult<&[u8], Nfs4RequestCompoundRecord> { + let (i, tag_len) = be_u32(i)?; + let (i, _tag) = cond(tag_len > 0, take(tag_len as usize))(i)?; + let (i, _min_ver) = be_u32(i)?; + let (i, ops_cnt) = be_u32(i)?; + let (i, commands) = count(parse_request_compound_command, ops_cnt as usize)(i)?; + Ok((i, Nfs4RequestCompoundRecord { commands })) +} #[derive(Debug,PartialEq)] pub enum Nfs4ResponseContent<'a> { @@ -546,23 +501,18 @@ pub struct Nfs4ResponseWrite { pub committed: u32, } -named!(nfs4_res_write_ok, - do_parse!( - count: be_u32 - >> committed: be_u32 - >> _verifier: be_u64 - >> (Nfs4ResponseWrite { - count, - committed - }) -)); - -named!(nfs4_res_write, - do_parse!( - status: be_u32 - >> wd: cond!(status == 0, nfs4_res_write_ok) - >> (Nfs4ResponseContent::Write(status, wd) ) -)); +fn nfs4_res_write_ok(i: &[u8]) -> IResult<&[u8], Nfs4ResponseWrite> { + let (i, count) = be_u32(i)?; + let (i, committed) = be_u32(i)?; + let (i, _verifier) = be_u64(i)?; + Ok((i, Nfs4ResponseWrite { count, committed })) +} + +fn nfs4_res_write(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + let (i, status) = be_u32(i)?; + let (i, wd) = cond(status == 0, nfs4_res_write_ok)(i)?; + Ok((i, Nfs4ResponseContent::Write(status, wd))) +} #[derive(Debug,PartialEq)] pub struct Nfs4ResponseRead<'a> { @@ -571,24 +521,23 @@ pub struct Nfs4ResponseRead<'a> { pub data: &'a[u8], } -named!(nfs4_res_read_ok, - do_parse!( - eof: be_u32 - >> read_len: be_u32 - >> read_data: take!(read_len) - >> (Nfs4ResponseRead { - eof: eof==1, - count: read_len, - data: read_data, - }) -)); - -named!(nfs4_res_read, - do_parse!( - status: be_u32 - >> rd: cond!(status == 0, nfs4_res_read_ok) - >> (Nfs4ResponseContent::Read(status, rd) ) -)); +fn nfs4_res_read_ok(i: &[u8]) -> IResult<&[u8], Nfs4ResponseRead> { + let (i, eof) = be_u32(i)?; + let (i, read_len) = be_u32(i)?; + let (i, read_data) = take(read_len as usize)(i)?; + let resp = Nfs4ResponseRead { + eof: eof==1, + count: read_len, + data: read_data, + }; + Ok((i, resp)) +} + +fn nfs4_res_read(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + let (i, status) = be_u32(i)?; + let (i, rd) = cond(status == 0, nfs4_res_read_ok)(i)?; + Ok((i, Nfs4ResponseContent::Read(status, rd))) +} #[derive(Debug,PartialEq)] pub struct Nfs4ResponseOpen<'a> { @@ -603,42 +552,38 @@ pub struct Nfs4ResponseOpenDelegateRead<'a> { pub stateid: Nfs4StateId<'a>, } -named!(nfs4_res_open_ok_delegate_read, - do_parse!( - stateid: nfs4_parse_stateid - >> _recall: be_u32 - >> _ace_type: be_u32 - >> _ace_flags: be_u32 - >> _ace_mask: be_u32 - >> who_len: be_u32 - >> _who: take!(who_len) - >> (Nfs4ResponseOpenDelegateRead { - stateid - }) -)); - -named!(nfs4_res_open_ok, - do_parse!( - stateid: nfs4_parse_stateid - >> _change_info: take!(20) - >> result_flags: be_u32 - >> _attrs: nfs4_parse_attrbits - >> delegation_type: be_u32 - >> delegate_read: cond!(delegation_type == 1, nfs4_res_open_ok_delegate_read) - >> ( Nfs4ResponseOpen { - stateid, - result_flags, - delegation_type, - delegate_read - } ) -)); - -named!(nfs4_res_open, - do_parse!( - status: be_u32 - >> open_data: cond!(status == 0, nfs4_res_open_ok) - >> ( Nfs4ResponseContent::Open(status, open_data) ) -)); +fn nfs4_res_open_ok_delegate_read(i: &[u8]) -> IResult<&[u8], Nfs4ResponseOpenDelegateRead> { + let (i, stateid) = nfs4_parse_stateid(i)?; + let (i, _recall) = be_u32(i)?; + let (i, _ace_type) = be_u32(i)?; + let (i, _ace_flags) = be_u32(i)?; + let (i, _ace_mask) = be_u32(i)?; + let (i, who_len) = be_u32(i)?; + let (i, _who) = take(who_len as usize)(i)?; + Ok((i, Nfs4ResponseOpenDelegateRead { stateid })) +} + +fn nfs4_res_open_ok(i: &[u8]) -> IResult<&[u8], Nfs4ResponseOpen> { + let (i, stateid) = nfs4_parse_stateid(i)?; + let (i, _change_info) = take(20_usize)(i)?; + let (i, result_flags) = be_u32(i)?; + let (i, _attrs) = nfs4_parse_attrbits(i)?; + let (i, delegation_type) = be_u32(i)?; + let (i, delegate_read) = cond(delegation_type == 1, nfs4_res_open_ok_delegate_read)(i)?; + let resp = Nfs4ResponseOpen { + stateid, + result_flags, + delegation_type, + delegate_read + }; + Ok((i, resp)) +} + +fn nfs4_res_open(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + let (i, status) = be_u32(i)?; + let (i, open_data) = cond(status == 0, nfs4_res_open_ok)(i)?; + Ok((i, Nfs4ResponseContent::Open(status, open_data))) +} #[derive(Debug,PartialEq)] pub struct Nfs4ResponseReaddirEntry<'a> { @@ -651,171 +596,143 @@ pub struct Nfs4ResponseReaddir<'a> { pub listing: Vec>>, } -named!(nfs4_res_readdir_entry_do, - do_parse!( - _cookie: be_u64 - >> name: nfs4_parse_nfsstring - >> _attrs: nfs4_parse_attrs - >> ( Nfs4ResponseReaddirEntry { - name: name, - }) -)); - -named!(nfs4_res_readdir_entry>, - do_parse!( - value_follows: be_u32 - >> entry: cond!(value_follows == 1, nfs4_res_readdir_entry_do) - >> (entry) -)); - -named!(nfs4_res_readdir_ok, - do_parse!( - _verifier: be_u64 - // run parser until we find a 'value follows == 0' - >> listing: many_till!(complete!(call!(nfs4_res_readdir_entry)), peek!(tag!(b"\x00\x00\x00\x00"))) - // value follows == 0 checked by line above - >> _value_follows: be_u32 - >> eof: be_u32 - >> ( Nfs4ResponseReaddir { eof: eof==1, listing: listing.0 }) -)); - -named!(nfs4_res_readdir, - do_parse!( - status: be_u32 - >> rd: cond!(status == 0, nfs4_res_readdir_ok) - >> ( Nfs4ResponseContent::ReadDir(status, rd) ) -)); - -named!(nfs4_res_create_ok, - do_parse!( - _change_info: take!(20) - >> attrs: nfs4_parse_attrbits - >> ( attrs ) -)); - -named!(nfs4_res_create, - do_parse!( - status: be_u32 - >> _attrs: cond!(status == 0, nfs4_res_create_ok) - >> ( Nfs4ResponseContent::Create(status) ) -)); - -named!(nfs4_res_setattr_ok, - do_parse!( - attrs: nfs4_parse_attrbits - >> ( attrs ) -)); - -named!(nfs4_res_setattr, - do_parse!( - status: be_u32 - >> _attrs: cond!(status == 0, nfs4_res_setattr_ok) - >> ( Nfs4ResponseContent::SetAttr(status) ) -)); - -named!(nfs4_res_getattr_ok, - do_parse!( - attrs: nfs4_parse_attrs - >> ( attrs ) -)); - -named!(nfs4_res_getattr, - do_parse!( - status: be_u32 - >> attrs: cond!(status == 0, nfs4_res_getattr_ok) - >> ( Nfs4ResponseContent::GetAttr(status, attrs) ) -)); - -named!(nfs4_res_openconfirm, - do_parse!( - status: be_u32 - >> stateid: cond!(status == 0, nfs4_parse_stateid) - >> ( Nfs4ResponseContent::OpenConfirm(status, stateid) ) -)); - -named!(nfs4_res_close, - do_parse!( - status: be_u32 - >> stateid: cond!(status == 0, nfs4_parse_stateid) - >> ( Nfs4ResponseContent::Close(status, stateid) ) -)); - -named!(nfs4_res_remove, - do_parse!( - status: be_u32 - >> cond!(status == 0, take!(20)) // change_info - >> ( Nfs4ResponseContent::Remove(status) ) -)); - -named!(nfs4_res_rename, - do_parse!( - status: be_u32 - >> ( Nfs4ResponseContent::Rename(status) ) -)); - -named!(nfs4_res_savefh, - do_parse!( - status: be_u32 - >> ( Nfs4ResponseContent::SaveFH(status) ) -)); - -named!(nfs4_res_lookup, - do_parse!( - status: be_u32 - >> ( Nfs4ResponseContent::Lookup(status) ) -)); - -named!(nfs4_res_renew, - do_parse!( - status: be_u32 - >> ( Nfs4ResponseContent::Renew(status) ) -)); - -named!(nfs4_res_getfh, - do_parse!( - status: be_u32 - >> fh: cond!(status == 0, nfs4_parse_handle) - >> ( Nfs4ResponseContent::GetFH(status, fh) ) -)); - -named!(nfs4_res_putfh, - do_parse!( - status: be_u32 - >> ( Nfs4ResponseContent::PutFH(status) ) -)); - -named!(nfs4_res_putrootfh, - do_parse!( - status: be_u32 - >> ( Nfs4ResponseContent::PutRootFH(status) ) -)); - -named!(nfs4_res_delegreturn, - do_parse!( - status: be_u32 - >> ( Nfs4ResponseContent::DelegReturn(status) ) -)); - -named!(nfs4_res_setclientid, - do_parse!( - status: be_u32 - >> _client_id: be_u64 - >> _verifier: be_u32 - >> ( Nfs4ResponseContent::SetClientId(status) ) -)); - -named!(nfs4_res_setclientid_confirm, - do_parse!( - status: be_u32 - >> ( Nfs4ResponseContent::SetClientIdConfirm(status) ) -)); - -named!(nfs4_res_commit, - do_parse!( - status: be_u32 - >> _verifier: cond!(status == 0, take!(8)) - >> ( Nfs4ResponseContent::Commit(status)) -)); +fn nfs4_res_readdir_entry_do(i: &[u8]) -> IResult<&[u8], Nfs4ResponseReaddirEntry> { + let (i, _cookie) = be_u64(i)?; + let (i, name) = nfs4_parse_nfsstring(i)?; + let (i, _attrs) = nfs4_parse_attrs(i)?; + Ok((i, Nfs4ResponseReaddirEntry { name })) +} + +fn nfs4_res_readdir_entry(i: &[u8]) -> IResult<&[u8], Option> { + let (i, value_follows) = be_u32(i)?; + let (i, entry) = cond(value_follows == 1, nfs4_res_readdir_entry_do)(i)?; + Ok((i, entry)) +} + +fn nfs4_res_readdir_ok(i: &[u8]) -> IResult<&[u8], Nfs4ResponseReaddir> { + let (i, _verifier) = be_u64(i)?; + // run parser until we find a 'value follows == 0' + let (i, listing) = many_till( + complete(nfs4_res_readdir_entry), + peek(tag(b"\x00\x00\x00\x00")), + )(i)?; + // value follows == 0 checked by line above + let (i, _value_follows) = be_u32(i)?; + let (i, eof) = be_u32(i)?; + Ok(( + i, + Nfs4ResponseReaddir { + eof: eof == 1, + listing: listing.0, + }, + )) +} + +fn nfs4_res_readdir(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + let (i, status) = be_u32(i)?; + let (i, rd) = cond(status == 0, nfs4_res_readdir_ok)(i)?; + Ok((i, Nfs4ResponseContent::ReadDir(status, rd))) +} + +fn nfs4_res_create_ok(i: &[u8]) -> IResult<&[u8], Nfs4Attr> { + let (i, _change_info) = take(20_usize)(i)?; + nfs4_parse_attrbits(i) +} + +fn nfs4_res_create(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + let (i, status) = be_u32(i)?; + let (i, _attrs) = cond(status == 0, nfs4_res_create_ok)(i)?; + Ok((i, Nfs4ResponseContent::Create(status))) +} + +fn nfs4_res_setattr_ok(i: &[u8]) -> IResult<&[u8], Nfs4Attr> { + nfs4_parse_attrbits(i) +} + +fn nfs4_res_setattr(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + let (i, status) = be_u32(i)?; + let (i, _attrs) = cond(status == 0, nfs4_res_setattr_ok)(i)?; + Ok((i, Nfs4ResponseContent::SetAttr(status))) +} + +fn nfs4_res_getattr_ok(i: &[u8]) -> IResult<&[u8], Nfs4Attr> { + nfs4_parse_attrs(i) +} + +fn nfs4_res_getattr(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + let (i, status) = be_u32(i)?; + let (i, attrs) = cond(status == 0, nfs4_res_getattr_ok)(i)?; + Ok((i, Nfs4ResponseContent::GetAttr(status, attrs))) +} + +fn nfs4_res_openconfirm(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + let (i, status) = be_u32(i)?; + let (i, stateid) = cond(status == 0, nfs4_parse_stateid)(i)?; + Ok((i, Nfs4ResponseContent::OpenConfirm(status, stateid))) +} + +fn nfs4_res_close(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + let (i, status) = be_u32(i)?; + let (i, stateid) = cond(status == 0, nfs4_parse_stateid)(i)?; + Ok((i, Nfs4ResponseContent::Close(status, stateid))) +} + +fn nfs4_res_remove(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + let (i, status) = be_u32(i)?; + let (i, _) = cond(status == 0, take(20_usize))(i)?; + Ok((i, Nfs4ResponseContent::Remove(status))) +} + +fn nfs4_res_rename(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + map(be_u32, Nfs4ResponseContent::Rename)(i) +} + +fn nfs4_res_savefh(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + map(be_u32, Nfs4ResponseContent::SaveFH)(i) +} + +fn nfs4_res_lookup(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + map(be_u32, Nfs4ResponseContent::Lookup)(i) +} + +fn nfs4_res_renew(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + map(be_u32, Nfs4ResponseContent::Renew)(i) +} + +fn nfs4_res_getfh(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + let (i, status) = be_u32(i)?; + let (i, fh) = cond(status == 0, nfs4_parse_handle)(i)?; + Ok((i, Nfs4ResponseContent::GetFH(status, fh))) +} + +fn nfs4_res_putfh(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + map(be_u32, Nfs4ResponseContent::PutFH)(i) +} + +fn nfs4_res_putrootfh(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + map(be_u32, Nfs4ResponseContent::PutRootFH)(i) +} + +fn nfs4_res_delegreturn(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + map(be_u32, Nfs4ResponseContent::DelegReturn)(i) +} + +fn nfs4_res_setclientid(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + let (i, status) = be_u32(i)?; + let (i, _client_id) = be_u64(i)?; + let (i, _verifier) = be_u32(i)?; + Ok((i, Nfs4ResponseContent::SetClientId(status))) +} + +fn nfs4_res_setclientid_confirm(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + map(be_u32, Nfs4ResponseContent::SetClientIdConfirm)(i) +} + +fn nfs4_res_commit(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + let (i, status) = be_u32(i)?; + let (i, _verifier) = cond(status == 0, take(8_usize))(i)?; + Ok((i, Nfs4ResponseContent::Commit(status))) +} #[derive(Debug,PartialEq)] pub struct Nfs4ResponseAccess { @@ -823,76 +740,70 @@ pub struct Nfs4ResponseAccess { pub access_rights: u32, } -named!(nfs4_res_access_ok, - do_parse!( - s: be_u32 - >> a: be_u32 - >> (Nfs4ResponseAccess { - supported_types: s, - access_rights: a, - }) -)); - -named!(nfs4_res_access, - do_parse!( - status: be_u32 - >> ad: cond!(status == 0, nfs4_res_access_ok) - >> ( Nfs4ResponseContent::Access( - status, ad, )) -)); +fn nfs4_res_access_ok(i: &[u8]) -> IResult<&[u8], Nfs4ResponseAccess> { + let (i, supported_types) = be_u32(i)?; + let (i, access_rights) = be_u32(i)?; + let resp = Nfs4ResponseAccess { + supported_types, + access_rights + }; + Ok((i, resp)) +} +fn nfs4_res_access(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + let (i, status) = be_u32(i)?; + let (i, ad) = cond(status == 0, nfs4_res_access_ok)(i)?; + Ok((i, Nfs4ResponseContent::Access(status, ad))) +} #[derive(Debug,PartialEq)] pub struct Nfs4ResponseSequence<'a> { pub ssn_id: &'a[u8], } -named!(nfs4_res_sequence_ok, - do_parse!( - ssn_id: take!(16) - >> _slots: take!(12) - >> _flags: be_u32 - >> ( Nfs4ResponseSequence { - ssn_id: ssn_id, - }) -)); - -named!(nfs4_res_sequence, - do_parse!( - status: be_u32 - >> seq: cond!(status == 0, nfs4_res_sequence_ok) - >> ( Nfs4ResponseContent::Sequence(status, seq) ) -)); - -named!(nfs4_res_compound_command, - do_parse!( - cmd: be_u32 - >> cmd_data: switch!(value!(cmd), - NFSPROC4_READ => call!(nfs4_res_read) | - NFSPROC4_WRITE => call!(nfs4_res_write) | - NFSPROC4_ACCESS => call!(nfs4_res_access) | - NFSPROC4_COMMIT => call!(nfs4_res_commit) | - NFSPROC4_GETFH => call!(nfs4_res_getfh) | - NFSPROC4_PUTFH => call!(nfs4_res_putfh) | - NFSPROC4_SAVEFH => call!(nfs4_res_savefh) | - NFSPROC4_RENAME => call!(nfs4_res_rename) | - NFSPROC4_READDIR => call!(nfs4_res_readdir) | - NFSPROC4_GETATTR => call!(nfs4_res_getattr) | - NFSPROC4_SETATTR => call!(nfs4_res_setattr) | - NFSPROC4_LOOKUP => call!(nfs4_res_lookup) | - NFSPROC4_OPEN => call!(nfs4_res_open) | - NFSPROC4_OPEN_CONFIRM => call!(nfs4_res_openconfirm) | - NFSPROC4_CLOSE => call!(nfs4_res_close) | - NFSPROC4_REMOVE => call!(nfs4_res_remove) | - NFSPROC4_CREATE => call!(nfs4_res_create) | - NFSPROC4_DELEGRETURN => call!(nfs4_res_delegreturn) | - NFSPROC4_SETCLIENTID => call!(nfs4_res_setclientid) | - NFSPROC4_SETCLIENTID_CONFIRM => call!(nfs4_res_setclientid_confirm) | - NFSPROC4_PUTROOTFH => call!(nfs4_res_putrootfh) | - NFSPROC4_SEQUENCE => call!(nfs4_res_sequence) | - NFSPROC4_RENEW => call!(nfs4_res_renew)) - >> (cmd_data) -)); +fn nfs4_res_sequence_ok(i: &[u8]) -> IResult<&[u8], Nfs4ResponseSequence> { + let (i, ssn_id) = take(16_usize)(i)?; + let (i, _slots) = take(12_usize)(i)?; + let (i, _flags) = be_u32(i)?; + Ok((i, Nfs4ResponseSequence { ssn_id })) +} + +fn nfs4_res_sequence(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + let (i, status) = be_u32(i)?; + let (i, seq) = cond(status == 0, nfs4_res_sequence_ok)(i)?; + Ok((i, Nfs4ResponseContent::Sequence(status, seq))) +} + +fn nfs4_res_compound_command(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + let (i, cmd) = be_u32(i)?; + let (i, cmd_data) = match cmd { + NFSPROC4_READ => nfs4_res_read(i)?, + NFSPROC4_WRITE => nfs4_res_write(i)?, + NFSPROC4_ACCESS => nfs4_res_access(i)?, + NFSPROC4_COMMIT => nfs4_res_commit(i)?, + NFSPROC4_GETFH => nfs4_res_getfh(i)?, + NFSPROC4_PUTFH => nfs4_res_putfh(i)?, + NFSPROC4_SAVEFH => nfs4_res_savefh(i)?, + NFSPROC4_RENAME => nfs4_res_rename(i)?, + NFSPROC4_READDIR => nfs4_res_readdir(i)?, + NFSPROC4_GETATTR => nfs4_res_getattr(i)?, + NFSPROC4_SETATTR => nfs4_res_setattr(i)?, + NFSPROC4_LOOKUP => nfs4_res_lookup(i)?, + NFSPROC4_OPEN => nfs4_res_open(i)?, + NFSPROC4_OPEN_CONFIRM => nfs4_res_openconfirm(i)?, + NFSPROC4_CLOSE => nfs4_res_close(i)?, + NFSPROC4_REMOVE => nfs4_res_remove(i)?, + NFSPROC4_CREATE => nfs4_res_create(i)?, + NFSPROC4_DELEGRETURN => nfs4_res_delegreturn(i)?, + NFSPROC4_SETCLIENTID => nfs4_res_setclientid(i)?, + NFSPROC4_SETCLIENTID_CONFIRM => nfs4_res_setclientid_confirm(i)?, + NFSPROC4_PUTROOTFH => nfs4_res_putrootfh(i)?, + NFSPROC4_SEQUENCE => nfs4_res_sequence(i)?, + NFSPROC4_RENEW => nfs4_res_renew(i)?, + _ => { return Err(Err::Error(make_error(i, ErrorKind::Switch))); } + }; + Ok((i, cmd_data)) +} #[derive(Debug,PartialEq)] pub struct Nfs4ResponseCompoundRecord<'a> { @@ -900,15 +811,11 @@ pub struct Nfs4ResponseCompoundRecord<'a> { pub commands: Vec>, } -named!(pub parse_nfs4_response_compound, - do_parse!( - status: be_u32 - >> tag_len: be_u32 - >> _tag: cond!(tag_len > 0, take!(tag_len)) - >> ops_cnt: be_u32 - >> commands: count!(nfs4_res_compound_command, ops_cnt as usize) - >> (Nfs4ResponseCompoundRecord { - status: status, - commands: commands, - }) -)); +pub fn parse_nfs4_response_compound(i: &[u8]) -> IResult<&[u8], Nfs4ResponseCompoundRecord> { + let (i, status) = be_u32(i)?; + let (i, tag_len) = be_u32(i)?; + let (i, _tag) = cond(tag_len > 0, take(tag_len as usize))(i)?; + let (i, ops_cnt) = be_u32(i)?; + let (i, commands) = count(nfs4_res_compound_command, ops_cnt as usize)(i)?; + Ok((i, Nfs4ResponseCompoundRecord { status, commands })) +} diff --git a/rust/src/nfs/rpc_records.rs b/rust/src/nfs/rpc_records.rs index 2341be109a..933d2e0146 100644 --- a/rust/src/nfs/rpc_records.rs +++ b/rust/src/nfs/rpc_records.rs @@ -17,22 +17,27 @@ //! Nom parsers for RPCv2 -use nom::IResult; -use nom::combinator::rest; -use nom::number::streaming::be_u32; - -#[derive(Debug,PartialEq)] +use nom7::bits::{bits, streaming::take as take_bits}; +use nom7::bytes::streaming::take; +use nom7::combinator::cond; +use nom7::error::Error; +use nom7::multi::length_data; +use nom7::number::streaming::be_u32; +use nom7::sequence::tuple; +use nom7::IResult; + +#[derive(Debug, PartialEq)] pub enum RpcRequestCreds<'a> { Unix(RpcRequestCredsUnix<'a>), GssApi(RpcRequestCredsGssApi<'a>), - Unknown(&'a[u8]), + Unknown(&'a [u8]), } -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct RpcRequestCredsUnix<'a> { pub stamp: u32, pub machine_name_len: u32, - pub machine_name_buf: &'a[u8], + pub machine_name_buf: &'a [u8], pub uid: u32, pub gid: u32, pub aux_gids: Option>, @@ -43,122 +48,114 @@ pub struct RpcRequestCredsUnix<'a> { // many0!(be_u32) //); -named!(parse_rpc_request_creds_unix, - do_parse!( - stamp: be_u32 - >> machine_name_len: be_u32 - >> machine_name_buf: take!(machine_name_len) - >> uid: be_u32 - >> gid: be_u32 - //>>aux_gids: parse_rpc_creds_unix_aux_gids - >> (RpcRequestCreds::Unix(RpcRequestCredsUnix { - stamp:stamp, - machine_name_len:machine_name_len, - machine_name_buf:machine_name_buf, - uid:uid, - gid:gid, - aux_gids:None, - })) -)); - -#[derive(Debug,PartialEq)] +fn parse_rpc_request_creds_unix(i: &[u8]) -> IResult<&[u8], RpcRequestCreds> { + let (i, stamp) = be_u32(i)?; + let (i, machine_name_len) = be_u32(i)?; + let (i, machine_name_buf) = take(machine_name_len as usize)(i)?; + let (i, uid) = be_u32(i)?; + let (i, gid) = be_u32(i)?; + // let (i, aux_gids) = parse_rpc_creds_unix_aux_gids(i)?; + let creds = RpcRequestCreds::Unix(RpcRequestCredsUnix { + stamp, + machine_name_len, + machine_name_buf, + uid, + gid, + aux_gids: None, + }); + Ok((i, creds)) +} + +#[derive(Debug, PartialEq)] pub struct RpcRequestCredsGssApi<'a> { pub version: u32, pub procedure: u32, pub seq_num: u32, pub service: u32, - pub ctx: &'a[u8], + pub ctx: &'a [u8], } -named!(parse_rpc_request_creds_gssapi, - do_parse!( - version: be_u32 - >> procedure: be_u32 - >> seq_num: be_u32 - >> service: be_u32 - >> ctx_len: be_u32 - >> ctx: take!(ctx_len) - >> (RpcRequestCreds::GssApi(RpcRequestCredsGssApi { - version: version, - procedure: procedure, - seq_num: seq_num, - service: service, - ctx: ctx, - })) -)); - -named!(parse_rpc_request_creds_unknown, - do_parse!( - blob: rest - >> (RpcRequestCreds::Unknown(blob) ) -)); - -#[derive(Debug,PartialEq)] +fn parse_rpc_request_creds_gssapi(i: &[u8]) -> IResult<&[u8], RpcRequestCreds> { + let (i, version) = be_u32(i)?; + let (i, procedure) = be_u32(i)?; + let (i, seq_num) = be_u32(i)?; + let (i, service) = be_u32(i)?; + let (i, ctx) = length_data(be_u32)(i)?; + let creds = RpcRequestCreds::GssApi(RpcRequestCredsGssApi { + version, + procedure, + seq_num, + service, + ctx, + }); + Ok((i, creds)) +} + +fn parse_rpc_request_creds_unknown(i: &[u8]) -> IResult<&[u8], RpcRequestCreds> { + Ok((&[], RpcRequestCreds::Unknown(i))) +} + +#[derive(Debug, PartialEq)] pub struct RpcGssApiIntegrity<'a> { pub seq_num: u32, - pub data: &'a[u8], + pub data: &'a [u8], } // Parse the GSSAPI Integrity envelope to get to the // data we care about. -named!(pub parse_rpc_gssapi_integrity, - do_parse!( - len: be_u32 - >> seq_num: be_u32 - >> data: take!(len) - >> (RpcGssApiIntegrity { - seq_num: seq_num, - data: data, - }) -)); - -#[derive(Debug,PartialEq)] -pub struct RpcPacketHeader<> { +pub fn parse_rpc_gssapi_integrity(i: &[u8]) -> IResult<&[u8], RpcGssApiIntegrity> { + let (i, len) = be_u32(i)?; + let (i, seq_num) = be_u32(i)?; + let (i, data) = take(len as usize)(i)?; + let res = RpcGssApiIntegrity { seq_num, data }; + Ok((i, res)) +} + +#[derive(Debug, PartialEq)] +pub struct RpcPacketHeader { pub frag_is_last: bool, pub frag_len: u32, pub xid: u32, pub msgtype: u32, } -fn parse_bits(i:&[u8]) -> IResult<&[u8],(u8,u32)> { - bits!(i, - tuple!( - take_bits!(1u8), // is_last - take_bits!(31u32))) // len +fn parse_bits(i: &[u8]) -> IResult<&[u8], (u8, u32)> { + bits::<_, _, Error<(&[u8], usize)>, _, _>(tuple(( + take_bits(1u8), // is_last + take_bits(31u32), // len + )))(i) +} + +pub fn parse_rpc_packet_header(i: &[u8]) -> IResult<&[u8], RpcPacketHeader> { + let (i, fraghdr) = parse_bits(i)?; + let (i, xid) = be_u32(i)?; + let (i, msgtype) = be_u32(i)?; + let hdr = RpcPacketHeader { + frag_is_last: fraghdr.0 == 1, + frag_len: fraghdr.1, + xid, + msgtype, + }; + Ok((i, hdr)) } -named!(pub parse_rpc_packet_header, - do_parse!( - fraghdr: parse_bits - >> xid: be_u32 - >> msgtype: be_u32 - >> ( - RpcPacketHeader { - frag_is_last:fraghdr.0 == 1, - frag_len:fraghdr.1, - xid:xid, - msgtype:msgtype, - } - )) -); - -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct RpcReplyPacket<'a> { - pub hdr: RpcPacketHeader<>, + pub hdr: RpcPacketHeader, pub verifier_flavor: u32, pub verifier_len: u32, - pub verifier: Option<&'a[u8]>, + pub verifier: Option<&'a [u8]>, pub reply_state: u32, pub accept_state: u32, - pub prog_data: &'a[u8], + pub prog_data: &'a [u8], } // top of request packet, just to get to procedure -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct RpcRequestPacketPartial { pub hdr: RpcPacketHeader, @@ -168,27 +165,25 @@ pub struct RpcRequestPacketPartial { pub procedure: u32, } -named!(pub parse_rpc_request_partial, - do_parse!( - hdr: parse_rpc_packet_header - >> rpcver: be_u32 - >> program: be_u32 - >> progver: be_u32 - >> procedure: be_u32 - >> ( - RpcRequestPacketPartial { - hdr:hdr, - rpcver:rpcver, - program:program, - progver:progver, - procedure:procedure, - } - )) -); - -#[derive(Debug,PartialEq)] +pub fn parse_rpc_request_partial(i: &[u8]) -> IResult<&[u8], RpcRequestPacketPartial> { + let (i, hdr) = parse_rpc_packet_header(i)?; + let (i, rpcver) = be_u32(i)?; + let (i, program) = be_u32(i)?; + let (i, progver) = be_u32(i)?; + let (i, procedure) = be_u32(i)?; + let req = RpcRequestPacketPartial { + hdr, + rpcver, + program, + progver, + procedure, + }; + Ok((i, req)) +} + +#[derive(Debug, PartialEq)] pub struct RpcPacket<'a> { - pub hdr: RpcPacketHeader<>, + pub hdr: RpcPacketHeader, pub rpcver: u32, pub program: u32, @@ -200,177 +195,165 @@ pub struct RpcPacket<'a> { pub verifier_flavor: u32, pub verifier_len: u32, - pub verifier: &'a[u8], + pub verifier: &'a [u8], - pub prog_data: &'a[u8], + pub prog_data: &'a [u8], } -named!(pub parse_rpc, - do_parse!( - hdr: parse_rpc_packet_header - - >> rpcver: be_u32 - >> program: be_u32 - >> progver: be_u32 - >> procedure: be_u32 - - >> creds_flavor: be_u32 - >> creds_len: be_u32 - >> creds: flat_map!(take!(creds_len), switch!(value!(creds_flavor), - 1 => call!(parse_rpc_request_creds_unix) | - 6 => call!(parse_rpc_request_creds_gssapi) | - _ => call!(parse_rpc_request_creds_unknown) )) - - >> verifier_flavor: be_u32 - >> verifier_len: be_u32 - >> verifier: take!(verifier_len as usize) - - >> pl: rest - - >> ( - RpcPacket { - hdr:hdr, - - rpcver:rpcver, - program:program, - progver:progver, - procedure:procedure, - - creds_flavor:creds_flavor, - creds:creds, - - verifier_flavor:verifier_flavor, - verifier_len:verifier_len, - verifier:verifier, - - prog_data:pl, - } - )) -); +pub fn parse_rpc(i: &[u8]) -> IResult<&[u8], RpcPacket> { + let (i, hdr) = parse_rpc_packet_header(i)?; + + let (i, rpcver) = be_u32(i)?; + let (i, program) = be_u32(i)?; + let (i, progver) = be_u32(i)?; + let (i, procedure) = be_u32(i)?; + + let (i, creds_flavor) = be_u32(i)?; + let (i, creds_len) = be_u32(i)?; + let (i, creds_buf) = take(creds_len as usize)(i)?; + let (_, creds) = match creds_flavor { + 1 => parse_rpc_request_creds_unix(creds_buf)?, + 6 => parse_rpc_request_creds_gssapi(creds_buf)?, + _ => parse_rpc_request_creds_unknown(creds_buf)?, + }; + + let (i, verifier_flavor) = be_u32(i)?; + let (i, verifier_len) = be_u32(i)?; + let (i, verifier) = take(verifier_len as usize)(i)?; + + let (i, prog_data) = (&[], i); + let packet = RpcPacket { + hdr, + + rpcver, + program, + progver, + procedure, + + creds_flavor, + creds, + + verifier_flavor, + verifier_len, + verifier, + + prog_data, + }; + Ok((i, packet)) +} // to be called with data <= hdr.frag_len + 4. Sending more data is undefined. -named!(pub parse_rpc_reply, - do_parse!( - hdr: parse_rpc_packet_header - - >> reply_state: be_u32 - - >> verifier_flavor: be_u32 - >> verifier_len: be_u32 - >> verifier: cond!(verifier_len > 0, take!(verifier_len as usize)) - - >> accept_state: be_u32 - - >> pl: rest - - >> ( - RpcReplyPacket { - hdr:hdr, - - verifier_flavor:verifier_flavor, - verifier_len:verifier_len, - verifier:verifier, - - reply_state:reply_state, - accept_state:accept_state, - - prog_data:pl, - } - )) -); +pub fn parse_rpc_reply(i: &[u8]) -> IResult<&[u8], RpcReplyPacket> { + let (i, hdr) = parse_rpc_packet_header(i)?; -named!(pub parse_rpc_udp_packet_header, - do_parse!( - xid: be_u32 - >> msgtype: be_u32 - >> ( - RpcPacketHeader { - frag_is_last:false, - frag_len:0, + let (i, reply_state) = be_u32(i)?; - xid:xid, - msgtype:msgtype, - } - )) -); + let (i, verifier_flavor) = be_u32(i)?; + let (i, verifier_len) = be_u32(i)?; + let (i, verifier) = cond(verifier_len > 0, take(verifier_len as usize))(i)?; -named!(pub parse_rpc_udp_request, - do_parse!( - hdr: parse_rpc_udp_packet_header + let (i, accept_state) = be_u32(i)?; + let (i, prog_data) = (&[], i); + let packet = RpcReplyPacket { + hdr, - >> rpcver: be_u32 - >> program: be_u32 - >> progver: be_u32 - >> procedure: be_u32 + verifier_flavor, + verifier_len, + verifier, - >> creds_flavor: be_u32 - >> creds_len: be_u32 - >> creds: flat_map!(take!(creds_len), switch!(value!(creds_flavor), - 1 => call!(parse_rpc_request_creds_unix) | - 6 => call!(parse_rpc_request_creds_gssapi) | - _ => call!(parse_rpc_request_creds_unknown) )) + reply_state, + accept_state, - >> verifier_flavor: be_u32 - >> verifier_len: be_u32 - >> verifier: take!(verifier_len as usize) - - >> pl: rest - - >> ( - RpcPacket { - hdr:hdr, - - rpcver:rpcver, - program:program, - progver:progver, - procedure:procedure, - - creds_flavor:creds_flavor, - creds:creds, - - verifier_flavor:verifier_flavor, - verifier_len:verifier_len, - verifier:verifier, - - prog_data:pl, - } - )) -); + prog_data, + }; + Ok((i, packet)) +} -named!(pub parse_rpc_udp_reply, - do_parse!( - hdr: parse_rpc_udp_packet_header +pub fn parse_rpc_udp_packet_header(i: &[u8]) -> IResult<&[u8], RpcPacketHeader> { + let (i, xid) = be_u32(i)?; + let (i, msgtype) = be_u32(i)?; + let hdr = RpcPacketHeader { + frag_is_last: false, + frag_len: 0, + + xid, + msgtype, + }; + Ok((i, hdr)) +} - >> verifier_flavor: be_u32 - >> verifier_len: be_u32 - >> verifier: cond!(verifier_len > 0, take!(verifier_len as usize)) +pub fn parse_rpc_udp_request(i: &[u8]) -> IResult<&[u8], RpcPacket> { + let (i, hdr) = parse_rpc_udp_packet_header(i)?; + + let (i, rpcver) = be_u32(i)?; + let (i, program) = be_u32(i)?; + let (i, progver) = be_u32(i)?; + let (i, procedure) = be_u32(i)?; + + let (i, creds_flavor) = be_u32(i)?; + let (i, creds_len) = be_u32(i)?; + let (i, creds_buf) = take(creds_len as usize)(i)?; + let (_, creds) = match creds_flavor { + 1 => parse_rpc_request_creds_unix(creds_buf)?, + 6 => parse_rpc_request_creds_gssapi(creds_buf)?, + _ => parse_rpc_request_creds_unknown(creds_buf)?, + }; + + let (i, verifier_flavor) = be_u32(i)?; + let (i, verifier_len) = be_u32(i)?; + let (i, verifier) = take(verifier_len as usize)(i)?; + + let (i, prog_data) = (&[], i); + let packet = RpcPacket { + hdr, + + rpcver, + program, + progver, + procedure, + + creds_flavor, + creds, + + verifier_flavor, + verifier_len, + verifier, + + prog_data, + }; + Ok((i, packet)) +} - >> reply_state: be_u32 - >> accept_state: be_u32 +pub fn parse_rpc_udp_reply(i: &[u8]) -> IResult<&[u8], RpcReplyPacket> { + let (i, hdr) = parse_rpc_udp_packet_header(i)?; - >> pl: rest + let (i, verifier_flavor) = be_u32(i)?; + let (i, verifier_len) = be_u32(i)?; + let (i, verifier) = cond(verifier_len > 0, take(verifier_len as usize))(i)?; - >> ( - RpcReplyPacket { - hdr:hdr, + let (i, reply_state) = be_u32(i)?; + let (i, accept_state) = be_u32(i)?; + let (i, prog_data) = (&[], i); + let packet = RpcReplyPacket { + hdr, - verifier_flavor:verifier_flavor, - verifier_len:verifier_len, - verifier:verifier, + verifier_flavor, + verifier_len, + verifier, - reply_state:reply_state, - accept_state:accept_state, + reply_state, + accept_state, - prog_data:pl, - } - )) -); + prog_data, + }; + Ok((i, packet)) +} #[cfg(test)] mod tests { use crate::nfs::rpc_records::*; - use nom::Err::Incomplete; - use nom::Needed::Size; + use nom7::Err::Incomplete; + use nom7::Needed; #[test] fn test_partial_input_too_short() { @@ -381,7 +364,7 @@ mod tests { let r = parse_rpc_request_partial(buf); match r { - Err(Incomplete(s)) => { assert_eq!(s, Size(4)); }, + Err(Incomplete(s)) => { assert_eq!(s, Needed::new(4)); }, _ => { panic!("failed {:?}",r); } } }