From: Victor Julien Date: Tue, 23 May 2017 08:10:57 +0000 (+0200) Subject: rust/nfs: add more record types X-Git-Tag: suricata-4.0.0-beta1~18 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=de7e0614fad242154d62ed1259afcd60093b88e3;p=thirdparty%2Fsuricata.git rust/nfs: add more record types --- diff --git a/rust/src/nfs/log.rs b/rust/src/nfs/log.rs index bf98781807..116ed58a8f 100644 --- a/rust/src/nfs/log.rs +++ b/rust/src/nfs/log.rs @@ -36,6 +36,22 @@ pub extern "C" fn rs_nfs3_tx_logging_is_filtered(tx: &mut NFS3Transaction) return 0; } +fn nfs3_rename_object(tx: &NFS3Transaction) -> Json +{ + let js = Json::object(); + let from_str = String::from_utf8_lossy(&tx.file_name); + js.set_string("from", &from_str); + + let to_vec = match tx.type_data { + Some(NFS3TransactionTypeData::RENAME(ref x)) => { x.to_vec() }, + _ => { Vec::new() } + }; + + let to_str = String::from_utf8_lossy(&to_vec); + js.set_string("to", &to_str); + return js; +} + fn nfs3_creds_object(tx: &NFS3Transaction) -> Json { let js = Json::object(); @@ -100,10 +116,12 @@ pub extern "C" fn rs_nfs3_log_json_response(tx: &mut NFS3Transaction) -> *mut Js if tx.procedure == NFSPROC3_READ { let read_js = nfs3_read_object(tx); js.set("read", read_js); - } - if tx.procedure == NFSPROC3_WRITE { + } else if tx.procedure == NFSPROC3_WRITE { let write_js = nfs3_write_object(tx); js.set("write", write_js); + } else if tx.procedure == NFSPROC3_RENAME { + let rename_js = nfs3_rename_object(tx); + js.set("rename", rename_js); } return js.unwrap(); diff --git a/rust/src/nfs/nfs3.rs b/rust/src/nfs/nfs3.rs index 9401970577..a582a1b188 100644 --- a/rust/src/nfs/nfs3.rs +++ b/rust/src/nfs/nfs3.rs @@ -90,12 +90,18 @@ pub static mut suricata_nfs3_file_config: Option<&'static SuricataFileContext> = * Transaction lookup. */ +#[derive(Debug)] +pub enum NFS3TransactionTypeData { + RENAME(Vec), +} #[derive(Debug)] pub struct NFS3Transaction { pub id: u64, /// internal id pub xid: u32, /// nfs3 req/reply pair id pub procedure: u32, + /// file name of the object we're dealing with. In case of RENAME + /// this is the 'from' or original name. pub file_name: Vec, pub request_machine_name: Vec, @@ -120,6 +126,8 @@ pub struct NFS3Transaction { pub file_tx_direction: u8, // STREAM_TOCLIENT or STREAM_TOSERVER pub file_handle: Vec, + pub type_data: Option, + /// additional procedures part of a single file transfer. Currently /// only COMMIT on WRITEs. pub file_additional_procs: Vec, @@ -155,6 +163,7 @@ impl NFS3Transaction { is_file_tx: false, file_tx_direction: 0, file_handle:Vec::new(), + type_data: None, file_additional_procs:Vec::new(), file_last_xid: 0, file_tracker: None, @@ -391,32 +400,54 @@ impl NFS3State { }; } + fn xidmap_handle2name(&mut self, xidmap: &mut NFS3RequestXidMap) { + match self.namemap.get(&xidmap.file_handle) { + Some(n) => { + SCLogDebug!("xidmap_handle2name: name {:?}", n); + xidmap.file_name = n.to_vec(); + }, + _ => { + SCLogDebug!("xidmap_handle2name: object {:?} not found", + xidmap.file_handle); + }, + } + } + /// complete request record fn process_request_record<'b>(&mut self, r: &RpcPacket<'b>) -> u32 { SCLogDebug!("REQUEST {} procedure {} ({}) blob size {}", r.hdr.xid, r.procedure, self.requestmap.len(), r.prog_data.len()); let mut xidmap = NFS3RequestXidMap::new(r.procedure, 0); + let mut aux_file_name = Vec::new(); if r.procedure == NFSPROC3_LOOKUP { self.process_request_record_lookup(r, &mut xidmap); + } else if r.procedure == NFSPROC3_ACCESS { + match parse_nfs3_request_access(r.prog_data) { + IResult::Done(_, ar) => { + xidmap.file_handle = ar.handle.value.to_vec(); + self.xidmap_handle2name(&mut xidmap); + }, + IResult::Incomplete(_) => { panic!("WEIRD"); }, + IResult::Error(e) => { panic!("Parsing failed: {:?}",e); }, + }; + } else if r.procedure == NFSPROC3_GETATTR { + match parse_nfs3_request_getattr(r.prog_data) { + IResult::Done(_, gar) => { + xidmap.file_handle = gar.handle.value.to_vec(); + self.xidmap_handle2name(&mut xidmap); + }, + IResult::Incomplete(_) => { panic!("WEIRD"); }, + IResult::Error(e) => { panic!("Parsing failed: {:?}",e); }, + }; } else if r.procedure == NFSPROC3_READ { match parse_nfs3_request_read(r.prog_data) { IResult::Done(_, nfs3_read_record) => { xidmap.chunk_offset = nfs3_read_record.offset; xidmap.file_handle = nfs3_read_record.handle.value.to_vec(); - - match self.namemap.get(nfs3_read_record.handle.value) { - Some(n) => { - SCLogDebug!("READ name {:?}", n); - xidmap.file_name = n.to_vec(); - }, - _ => { - SCLogDebug!("READ object {:?} not found", - nfs3_read_record.handle.value); - }, - } + self.xidmap_handle2name(&mut xidmap); }, IResult::Incomplete(_) => { panic!("WEIRD"); }, IResult::Error(e) => { panic!("Parsing failed: {:?}",e); }, @@ -432,12 +463,34 @@ impl NFS3State { } else if r.procedure == NFSPROC3_CREATE { match parse_nfs3_request_create(r.prog_data) { IResult::Done(_, nfs3_create_record) => { + xidmap.file_handle = nfs3_create_record.handle.value.to_vec(); xidmap.file_name = nfs3_create_record.name_vec; }, IResult::Incomplete(_) => { panic!("WEIRD"); }, IResult::Error(e) => { panic!("Parsing failed: {:?}",e); }, }; + } else if r.procedure == NFSPROC3_REMOVE { + match parse_nfs3_request_remove(r.prog_data) { + IResult::Done(_, rr) => { + xidmap.file_handle = rr.handle.value.to_vec(); + xidmap.file_name = rr.name_vec; + }, + IResult::Incomplete(_) => { panic!("WEIRD"); }, + IResult::Error(e) => { panic!("Parsing failed: {:?}",e); }, + }; + + } else if r.procedure == NFSPROC3_RENAME { + match parse_nfs3_request_rename(r.prog_data) { + IResult::Done(_, rr) => { + xidmap.file_handle = rr.from_handle.value.to_vec(); + xidmap.file_name = rr.from_name_vec; + aux_file_name = rr.to_name_vec; + }, + IResult::Incomplete(_) => { panic!("WEIRD"); }, + IResult::Error(e) => { panic!("Parsing failed: {:?}",e); }, + }; + } else if r.procedure == NFSPROC3_COMMIT { SCLogDebug!("COMMIT, closing shop"); @@ -476,6 +529,10 @@ impl NFS3State { tx.file_name = xidmap.file_name.to_vec(); //self.ts_txs_updated = true; + if r.procedure == NFSPROC3_RENAME { + tx.type_data = Some(NFS3TransactionTypeData::RENAME(aux_file_name)); + } + match &r.creds_unix { &Some(ref u) => { tx.request_machine_name = u.machine_name_buf.to_vec(); diff --git a/rust/src/nfs/parser.rs b/rust/src/nfs/parser.rs index 4f67cd0203..3e886a8145 100644 --- a/rust/src/nfs/parser.rs +++ b/rust/src/nfs/parser.rs @@ -137,6 +137,71 @@ named!(pub parse_nfs3_request_create, )) ); +#[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(), + } + )) +); + +#[derive(Debug,PartialEq)] +pub struct Nfs3RequestRename<'a> { + pub from_handle: Nfs3Handle<'a>, + pub from_name_vec: Vec, + pub to_handle: Nfs3Handle<'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_handle, + from_name_vec:from_name.to_vec(), + to_handle:to_handle, + to_name_vec:to_name.to_vec(), + } + )) +); + +#[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, + } + )) +); + #[derive(Debug,PartialEq)] pub struct Nfs3RequestAccess<'a> { pub handle: Nfs3Handle<'a>,