use crate::direction::Direction;
use crate::nfs::nfs::*;
use crate::flow::Flow;
use crate::nfs::nfs3_records::*;
use crate::nfs::rpc_records::*;
use crate::nfs::types::*;
use nom7::number::streaming::be_u32;
use nom7::IResult;
impl NFSState {
pub fn process_request_record_v3(&mut self, flow: *mut Flow, r: &RpcPacket) {
SCLogDebug!(
"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);
let mut aux_file_name = Vec::new();
if self.nfs_version == 0 {
self.nfs_version = r.progver as u16;
}
if r.procedure == NFSPROC3_LOOKUP {
self.process_request_record_lookup(r, &mut xidmap);
} else if r.procedure == NFSPROC3_ACCESS {
if let Ok((_, rd)) = parse_nfs3_request_access(r.prog_data) {
xidmap.file_handle = rd.handle.value.to_vec();
self.xidmap_handle2name(&mut xidmap);
} else {
self.set_event(NFSEvent::MalformedData);
};
} else if r.procedure == NFSPROC3_GETATTR {
if let Ok((_, rd)) = parse_nfs3_request_getattr(r.prog_data) {
xidmap.file_handle = rd.handle.value.to_vec();
self.xidmap_handle2name(&mut xidmap);
} else {
self.set_event(NFSEvent::MalformedData);
};
} else if r.procedure == NFSPROC3_READDIRPLUS {
if let Ok((_, rd)) = parse_nfs3_request_readdirplus(r.prog_data) {
xidmap.file_handle = rd.handle.value.to_vec();
self.xidmap_handle2name(&mut xidmap);
} else {
self.set_event(NFSEvent::MalformedData);
};
} else if r.procedure == NFSPROC3_READ {
if let Ok((_, rd)) = parse_nfs3_request_read(r.prog_data) {
xidmap.chunk_offset = rd.offset;
xidmap.file_handle = rd.handle.value.to_vec();
self.xidmap_handle2name(&mut xidmap);
} else {
self.set_event(NFSEvent::MalformedData);
};
} else if r.procedure == NFSPROC3_WRITE {
if let Ok((_, rd)) = parse_nfs3_request_write(r.prog_data, true) {
self.process_write_record(flow, r, &rd);
} else {
self.set_event(NFSEvent::MalformedData);
}
} else if r.procedure == NFSPROC3_CREATE {
if let Ok((_, rd)) = parse_nfs3_request_create(r.prog_data) {
xidmap.file_handle = rd.handle.value.to_vec();
xidmap.file_name = rd.name_vec;
} else {
self.set_event(NFSEvent::MalformedData);
};
} else if r.procedure == NFSPROC3_REMOVE {
if let Ok((_, rd)) = parse_nfs3_request_remove(r.prog_data) {
xidmap.file_handle = rd.handle.value.to_vec();
xidmap.file_name = rd.name_vec;
} else {
self.set_event(NFSEvent::MalformedData);
};
} else if r.procedure == NFSPROC3_RENAME {
if let Ok((_, rd)) = parse_nfs3_request_rename(r.prog_data) {
xidmap.file_handle = rd.from_handle.value.to_vec();
xidmap.file_name = rd.from_name_vec;
aux_file_name = rd.to_name_vec;
} else {
self.set_event(NFSEvent::MalformedData);
};
} else if r.procedure == NFSPROC3_MKDIR {
if let Ok((_, rd)) = parse_nfs3_request_mkdir(r.prog_data) {
xidmap.file_handle = rd.handle.value.to_vec();
xidmap.file_name = rd.name_vec;
} else {
self.set_event(NFSEvent::MalformedData);
};
} else if r.procedure == NFSPROC3_RMDIR {
if let Ok((_, rd)) = parse_nfs3_request_rmdir(r.prog_data) {
xidmap.file_handle = rd.handle.value.to_vec();
xidmap.file_name = rd.name_vec;
} else {
self.set_event(NFSEvent::MalformedData);
};
} else if r.procedure == NFSPROC3_COMMIT {
SCLogDebug!("COMMIT, closing shop");
if let Ok((_, rd)) = parse_nfs3_request_commit(r.prog_data) {
let file_handle = rd.handle.value.to_vec();
if let Some(tx) = self.get_file_tx_by_handle(&file_handle, Direction::ToServer) {
if let Some(NFSTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
tdf.chunk_count += 1;
if tdf.file_additional_procs.is_empty() {
tdf.file_additional_procs.push(NFSPROC3_COMMIT);
}
filetracker_close(&mut tdf.file_tracker);
tdf.file_last_xid = r.hdr.xid;
tx.is_last = true;
tx.request_done = true;
tx.is_file_closed = true;
}
}
} else {
self.set_event(NFSEvent::MalformedData);
};
}
if !(r.procedure == NFSPROC3_COMMIT || r.procedure == NFSPROC3_WRITE || r.procedure == NFSPROC3_READ)
{
let mut tx = self.new_tx();
tx.xid = r.hdr.xid;
tx.procedure = r.procedure;
tx.request_done = true;
tx.file_name = xidmap.file_name.to_vec();
tx.nfs_version = r.progver as u16;
tx.file_handle = xidmap.file_handle.to_vec();
if r.procedure == NFSPROC3_RENAME {
tx.type_data = Some(NFSTransactionTypeData::RENAME(aux_file_name));
}
tx.auth_type = r.creds_flavor;
#[allow(clippy::single_match)]
match r.creds {
RpcRequestCreds::Unix(ref u) => {
tx.request_machine_name = u.machine_name_buf.to_vec();
tx.request_uid = u.uid;
tx.request_gid = u.gid;
}
_ => {}
}
SCLogDebug!(
"TX created: ID {} XID {} PROCEDURE {}",
tx.id,
tx.xid,
tx.procedure
);
self.transactions.push(tx);
} else if r.procedure == NFSPROC3_READ {
let found = self
.get_file_tx_by_handle(&xidmap.file_handle, Direction::ToClient)
.is_some();
if !found {
let tx =
self.new_file_tx(&xidmap.file_handle, &xidmap.file_name, Direction::ToClient);
tx.procedure = NFSPROC3_READ;
tx.xid = r.hdr.xid;
tx.is_first = true;
tx.nfs_version = r.progver as u16;
tx.auth_type = r.creds_flavor;
if let RpcRequestCreds::Unix(ref u) = r.creds {
tx.request_machine_name = u.machine_name_buf.to_vec();
tx.request_uid = u.uid;
tx.request_gid = u.gid;
}
}
}
self.requestmap.put(r.hdr.xid, xidmap);
}
pub fn process_reply_record_v3(&mut self, flow: *mut Flow, r: &RpcReplyPacket, xidmap: &mut NFSRequestXidMap) {
let mut nfs_status = 0;
let mut resp_handle = Vec::new();
if xidmap.procedure == NFSPROC3_LOOKUP {
if let Ok((_, rd)) = parse_nfs3_response_lookup(r.prog_data) {
SCLogDebug!("LOOKUP: {:?}", rd);
SCLogDebug!("RESPONSE LOOKUP file_name {:?}", xidmap.file_name);
nfs_status = rd.status;
SCLogDebug!("LOOKUP handle {:?}", rd.handle);
self.namemap
.put(rd.handle.value.to_vec(), xidmap.file_name.to_vec());
resp_handle = rd.handle.value.to_vec();
} else {
self.set_event(NFSEvent::MalformedData);
};
} else if xidmap.procedure == NFSPROC3_CREATE {
if let Ok((_, rd)) = parse_nfs3_response_create(r.prog_data) {
SCLogDebug!("nfs3_create_record: {:?}", rd);
SCLogDebug!("RESPONSE CREATE file_name {:?}", xidmap.file_name);
nfs_status = rd.status;
if let Some(h) = rd.handle {
SCLogDebug!("handle {:?}", h);
self.namemap
.put(h.value.to_vec(), xidmap.file_name.to_vec());
resp_handle = h.value.to_vec();
}
} else {
self.set_event(NFSEvent::MalformedData);
};
} else if xidmap.procedure == NFSPROC3_READ {
if let Ok((_, rd)) = parse_nfs3_reply_read(r.prog_data, true) {
self.process_read_record(flow, r, &rd, Some(xidmap));
nfs_status = rd.status;
} else {
self.set_event(NFSEvent::MalformedData);
}
} else if xidmap.procedure == NFSPROC3_READDIRPLUS {
if let Ok((_, rd)) = parse_nfs3_response_readdirplus(r.prog_data) {
nfs_status = rd.status;
let d = if rd.data.len() >= 4 {
&rd.data[..rd.data.len() - 4_usize]
} else {
rd.data
};
if let Ok((_, ref entries)) = many0_nfs3_response_readdirplus_entries(d) {
SCLogDebug!("READDIRPLUS ENTRIES reply {:?}", entries);
for ce in entries {
SCLogDebug!("ce {:?}", ce);
if let Some(ref e) = ce.entry {
SCLogDebug!("e {:?}", e);
if let Some(ref h) = e.handle {
SCLogDebug!("h {:?}", h);
self.namemap.put(h.value.to_vec(), e.name_vec.to_vec());
}
}
}
} else {
self.set_event(NFSEvent::MalformedData);
}
} else {
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;
}
SCLogDebug!(
"REPLY {} to procedure {} blob size {}",
r.hdr.xid,
xidmap.procedure,
r.prog_data.len()
);
if xidmap.procedure != NFSPROC3_READ {
self.mark_response_tx_done(flow, r.hdr.xid, r.reply_state, nfs_status, &resp_handle);
}
}
}