Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion rust/src/nfs/nfs2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,17 @@ impl NFSState {
self.set_event(NFSEvent::MalformedData);
}
};
} else if r.procedure == NFSPROC3_WRITE {
match parse_nfs2_request_write(r.prog_data) {
Ok((_, write_record)) => {
xidmap.chunk_offset = write_record.offset as u64;
xidmap.file_handle = write_record.handle.value.to_vec();
self.xidmap_handle2name(&mut xidmap);
}
_ => {
self.set_event(NFSEvent::MalformedData);
}
};
}

if !(r.procedure == NFSPROC3_COMMIT || // commit handled separately
Expand Down Expand Up @@ -103,7 +114,9 @@ impl NFSState {
self.requestmap.insert(r.hdr.xid, xidmap);
}

pub fn process_reply_record_v2(&mut self, flow: *mut Flow, r: &RpcReplyPacket, xidmap: &NFSRequestXidMap) {
pub fn process_reply_record_v2(
&mut self, flow: *mut Flow, r: &RpcReplyPacket, xidmap: &NFSRequestXidMap,
) {
let mut nfs_status = 0;
let resp_handle = Vec::new();

Expand All @@ -118,13 +131,25 @@ impl NFSState {
self.set_event(NFSEvent::MalformedData);
}
}
} else if xidmap.procedure == NFSPROC3_WRITE {
match parse_nfs2_reply_write(r.prog_data) {
Ok((_, ref reply)) => {
SCLogDebug!("NFSv2: WRITE reply record");
// TODO: forward to file tracking / logging
nfs_status = reply.status;
}
_ => {
self.set_event(NFSEvent::MalformedData);
}
}
} else {
let stat: u32 = match be_u32(r.prog_data) as IResult<&[u8], _> {
Ok((_, stat)) => stat,
_ => 0,
};
nfs_status = stat;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this extra line here?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oooh, that was a typo. will work on that.

SCLogDebug!(
"NFSv2: REPLY {} to procedure {} blob size {}",
r.hdr.xid,
Expand Down
77 changes: 77 additions & 0 deletions rust/src/nfs/nfs2_records.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,34 @@ pub fn parse_nfs2_request_read(i: &[u8]) -> IResult<&[u8], Nfs2RequestRead<'_>>
Ok((i, req))
}

#[derive(Debug, PartialEq, Eq)]
pub struct Nfs2RequestWrite<'a> {
pub handle: Nfs2Handle<'a>,
pub beginoffset: u32,
pub offset: u32,
pub totalcount: u32,
pub data: &'a [u8],
}

pub fn parse_nfs2_request_write(i: &[u8]) -> IResult<&[u8], Nfs2RequestWrite<'_>> {
let (i, handle) = parse_nfs2_handle(i)?;
let (i, beginoffset) = be_u32(i)?;
let (i, offset) = be_u32(i)?;
let (i, totalcount) = be_u32(i)?;
let (i, data_len) = be_u32(i)?; // XDR opaque length
let (i, data) = take(data_len)(i)?;
let fill_bytes = (4 - (data_len % 4)) % 4; // pad to 4-byte boundary
let (i, _) = cond(fill_bytes != 0, take(fill_bytes))(i)?;
let req = Nfs2RequestWrite {
handle,
beginoffset,
offset,
totalcount,
data,
};
Ok((i, req))
}

pub fn parse_nfs2_reply_read(i: &[u8]) -> IResult<&[u8], NfsReplyRead<'_>> {
let (i, status) = be_u32(i)?;
let (i, attr_blob) = take(68_usize)(i)?;
Expand All @@ -84,6 +112,31 @@ pub fn parse_nfs2_reply_read(i: &[u8]) -> IResult<&[u8], NfsReplyRead<'_>> {
Ok((i, reply))
}

#[derive(Debug, PartialEq, Eq)]
pub struct Nfs2ReplyWrite<'a> {
pub status: u32,
pub attr_blob: &'a [u8],
pub count: u32,
pub beginoffset: u32,
pub offset: u32,
}

pub fn parse_nfs2_reply_write(i: &[u8]) -> IResult<&[u8], Nfs2ReplyWrite<'_>> {
let (i, status) = be_u32(i)?;
let (i, attr_blob) = take(68_usize)(i)?;
let (i, count) = be_u32(i)?;
let (i, beginoffset) = be_u32(i)?;
let (i, offset) = be_u32(i)?;
let reply = Nfs2ReplyWrite {
status,
attr_blob,
count,
beginoffset,
offset,
};
Ok((i, reply))
}

#[derive(Debug, PartialEq, Eq)]
pub struct Nfs2Attributes {
pub atype: u32,
Expand Down Expand Up @@ -160,6 +213,30 @@ mod tests {
assert_eq!(request.offset, 0);
}

#[test]
fn test_nfs2_request_write_minimal() {
#[rustfmt::skip]
let buf: &[u8] = &[
// fake 32-byte handle
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
// beginoffset, offset, totalcount
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10,
0x00, 0x00, 0x00, 0x20,
// data_len + data
0x00, 0x00, 0x00, 0x04,
0xde, 0xad, 0xbe, 0xef,
];

let (_, req) = parse_nfs2_request_write(buf).unwrap();
assert_eq!(req.offset, 0x10);
assert_eq!(req.totalcount, 0x20);
assert_eq!(req.data, &[0xde, 0xad, 0xbe, 0xef]);
}

#[test]
fn test_nfs2_reply_read() {
#[rustfmt::skip]
Expand Down
Loading