rust/nfs: convert parser to nom7 functions (NFS v3 and v4 records)

pull/6629/head
Pierre Chifflier 3 years ago committed by Victor Julien
parent c33cfed704
commit 0ffe123330

@ -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(_) => {

@ -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<Nfs3Handle>,
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<Nfs3Handle<'a>>,
}
named!(pub parse_nfs3_response_create<Nfs3ReplyCreate>,
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<Nfs3ReplyLookup>,
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<u8>,
}
named!(pub parse_nfs3_request_create<Nfs3RequestCreate>,
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<u8>,
}
named!(pub parse_nfs3_request_remove<Nfs3RequestRemove>,
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<u8>,
}
named!(pub parse_nfs3_request_rmdir<Nfs3RequestRmdir>,
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<u8>,
}
named!(pub parse_nfs3_request_mkdir<Nfs3RequestMkdir>,
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<u8>,
@ -175,212 +154,180 @@ pub struct Nfs3RequestRename<'a> {
pub to_name_vec: Vec<u8>,
}
named!(pub parse_nfs3_request_rename<Nfs3RequestRename>,
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<Nfs3RequestGetAttr>,
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<Nfs3RequestAccess>,
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<Nfs3RequestCommit>,
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<Nfs3RequestRead>,
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<u8>,
}
named!(pub parse_nfs3_request_lookup<Nfs3RequestLookup>,
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<u8>,
pub handle: Option<Nfs3Handle<'a>>,
}
named!(pub parse_nfs3_response_readdirplus_entry<Nfs3ResponseReaddirplusEntryC>,
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<Nfs3ResponseReaddirplusEntryC<'a>>,
}
named!(pub parse_nfs3_response_readdirplus_entry_cond<Nfs3ResponseReaddirplusEntry>,
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<Nfs3ResponseReaddirplus>,
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<Nfs3ResponseReaddirplusEntry<'a>>> {
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<Nfs3ResponseReaddirplusEntry<'a>>> {
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<Nfs3RequestReaddirplus>,
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<Nfs3RequestWrite>,
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<NfsReplyRead>,
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))
}

@ -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<u32>)
{
fn new_tx_v4<'b>(
&mut self, r: &RpcPacket<'b>, xidmap: &NFSRequestXidMap, procedure: u32,
_aux_opcodes: &Vec<u32>,
) {
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<u32> = 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<u32> = 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"<mount_root>".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);
},
}
};
}
}

File diff suppressed because it is too large Load Diff

@ -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<Vec<u32>>,
@ -43,122 +48,114 @@ pub struct RpcRequestCredsUnix<'a> {
// many0!(be_u32)
//);
named!(parse_rpc_request_creds_unix<RpcRequestCreds>,
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<RpcRequestCreds>,
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<RpcRequestCreds>,
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<RpcGssApiIntegrity>,
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<RpcPacketHeader>,
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<RpcRequestPacketPartial>,
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<RpcPacket>,
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<RpcReplyPacket>,
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<RpcPacketHeader>,
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<RpcPacket>,
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<RpcReplyPacket>,
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); }
}
}

Loading…
Cancel
Save