use std;
use std::mem::transmute;
use std::collections::{HashMap};
+use std::ffi::CStr;
use nom;
use nom::IResult;
* Transaction lookup.
*/
+#[repr(u32)]
+pub enum NFSEvent {
+ MalformedData = 0,
+ /* remove 'Padding' when more events are added. Rustc 1.7 won't
+ * accept a single field enum with repr(u32) */
+ Padding,
+}
+
#[derive(Debug)]
pub enum NFSTransactionTypeData {
RENAME(Vec<u8>),
pub nfs_version: u16,
+ pub events: u16,
+
/// tx counter for assigning incrementing id's to tx's
tx_id: u64,
tc_gap:false,
is_udp:false,
nfs_version:0,
+ events:0,
tx_id:0,
de_state_count:0,
//ts_txs_updated:false,
return None;
}
+ /// Set an event. The event is set on the most recent transaction.
+ pub fn set_event(&mut self, event: NFSEvent) {
+ let len = self.transactions.len();
+ if len == 0 {
+ return;
+ }
+
+ let mut tx = &mut self.transactions[len - 1];
+ sc_app_layer_decoder_events_set_event_raw(&mut tx.events, event as u8);
+ self.events += 1;
+ }
+
// TODO maybe not enough users to justify a func
fn mark_response_tx_done(&mut self, xid: u32, rpc_status: u32, nfs_status: u32, resp_handle: &Vec<u8>)
{
SCLogDebug!("LOOKUP {:?}", lookup);
xidmap.file_name = lookup.name_vec;
},
- IResult::Incomplete(_) => { panic!("WEIRD: parse_nfs3_request_lookup said: incomplete"); },
+ IResult::Incomplete(_) => {
+ self.set_event(NFSEvent::MalformedData);
+ },
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
}
xidmap.file_handle = ar.handle.value.to_vec();
self.xidmap_handle2name(&mut xidmap);
},
- IResult::Incomplete(_) => { panic!("WEIRD"); },
+ IResult::Incomplete(_) => {
+ self.set_event(NFSEvent::MalformedData);
+ },
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
} else if r.procedure == NFSPROC3_GETATTR {
xidmap.file_handle = gar.handle.value.to_vec();
self.xidmap_handle2name(&mut xidmap);
},
- IResult::Incomplete(_) => { panic!("WEIRD"); },
+ IResult::Incomplete(_) => {
+ self.set_event(NFSEvent::MalformedData);
+ },
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
} else if r.procedure == NFSPROC3_READDIRPLUS {
xidmap.file_handle = rdp.handle.value.to_vec();
self.xidmap_handle2name(&mut xidmap);
},
- IResult::Incomplete(_) => { panic!("WEIRD"); },
+ IResult::Incomplete(_) => {
+ self.set_event(NFSEvent::MalformedData);
+ },
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
} else if r.procedure == NFSPROC3_READ {
xidmap.file_handle = nfs3_read_record.handle.value.to_vec();
self.xidmap_handle2name(&mut xidmap);
},
- IResult::Incomplete(_) => { panic!("WEIRD"); },
+ IResult::Incomplete(_) => {
+ self.set_event(NFSEvent::MalformedData);
+ },
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
} else if r.procedure == NFSPROC3_WRITE {
IResult::Done(_, w) => {
self.process_write_record(r, &w);
},
- IResult::Incomplete(_) => { panic!("WEIRD"); },
+ IResult::Incomplete(_) => {
+ self.set_event(NFSEvent::MalformedData);
+ },
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
}
} else if r.procedure == NFSPROC3_CREATE {
xidmap.file_handle = nfs3_create_record.handle.value.to_vec();
xidmap.file_name = nfs3_create_record.name_vec;
},
- IResult::Incomplete(_) => { panic!("WEIRD"); },
+ IResult::Incomplete(_) => {
+ self.set_event(NFSEvent::MalformedData);
+ },
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
xidmap.file_handle = rr.handle.value.to_vec();
xidmap.file_name = rr.name_vec;
},
- IResult::Incomplete(_) => { panic!("WEIRD"); },
+ IResult::Incomplete(_) => {
+ self.set_event(NFSEvent::MalformedData);
+ },
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
xidmap.file_name = rr.from_name_vec;
aux_file_name = rr.to_name_vec;
},
- IResult::Incomplete(_) => { panic!("WEIRD"); },
+ IResult::Incomplete(_) => {
+ self.set_event(NFSEvent::MalformedData);
+ },
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
} else if r.procedure == NFSPROC3_MKDIR {
xidmap.file_handle = mr.handle.value.to_vec();
xidmap.file_name = mr.name_vec;
},
- IResult::Incomplete(_) => { panic!("WEIRD"); },
+ IResult::Incomplete(_) => {
+ self.set_event(NFSEvent::MalformedData);
+ },
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
} else if r.procedure == NFSPROC3_RMDIR {
xidmap.file_handle = rr.handle.value.to_vec();
xidmap.file_name = rr.name_vec;
},
- IResult::Incomplete(_) => { panic!("WEIRD"); },
+ IResult::Incomplete(_) => {
+ self.set_event(NFSEvent::MalformedData);
+ },
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
} else if r.procedure == NFSPROC3_COMMIT {
}
//self.ts_txs_updated = true;
},
- IResult::Incomplete(_) => { panic!("WEIRD"); },
+ IResult::Incomplete(_) => {
+ self.set_event(NFSEvent::MalformedData);
+ },
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
}
xidmap.file_handle = ar.handle.value.to_vec();
self.xidmap_handle2name(&mut xidmap);
},
- IResult::Incomplete(_) => { panic!("WEIRD"); },
+ IResult::Incomplete(_) => {
+ self.set_event(NFSEvent::MalformedData);
+ },
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
} else if r.procedure == NFSPROC3_READ {
xidmap.file_handle = read_record.handle.value.to_vec();
self.xidmap_handle2name(&mut xidmap);
},
- IResult::Incomplete(_) => { panic!("WEIRD"); },
+ IResult::Incomplete(_) => {
+ self.set_event(NFSEvent::MalformedData);
+ },
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
}
}
fn process_reply_record_v3<'b>(&mut self, r: &RpcReplyPacket<'b>, xidmap: &mut NFSRequestXidMap) -> u32 {
- let nfs_status;
+ let mut nfs_status = 0;
let mut resp_handle = Vec::new();
if xidmap.procedure == NFSPROC3_LOOKUP {
self.namemap.insert(lookup.handle.value.to_vec(), xidmap.file_name.to_vec());
resp_handle = lookup.handle.value.to_vec();
},
- IResult::Incomplete(_) => { panic!("WEIRD"); },
+ IResult::Incomplete(_) => {
+ self.set_event(NFSEvent::MalformedData);
+ },
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
} else if xidmap.procedure == NFSPROC3_CREATE {
}
},
- IResult::Incomplete(_) => { panic!("WEIRD"); },
+ IResult::Incomplete(_) => {
+ self.set_event(NFSEvent::MalformedData);
+ },
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
} else if xidmap.procedure == NFSPROC3_READ {
self.process_read_record(r, reply, Some(&xidmap));
nfs_status = reply.status;
},
- IResult::Incomplete(_) => { panic!("Incomplete!"); },
+ IResult::Incomplete(_) => {
+ self.set_event(NFSEvent::MalformedData);
+ },
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
}
} else if xidmap.procedure == NFSPROC3_READDIRPLUS {
SCLogDebug!("READDIRPLUS ENTRIES reply {:?}", entries);
},
- IResult::Incomplete(_) => { panic!("Incomplete!"); },
+ IResult::Incomplete(_) => {
+ self.set_event(NFSEvent::MalformedData);
+ },
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
}
},
- IResult::Incomplete(_) => { panic!("Incomplete!"); },
+ IResult::Incomplete(_) => {
+ self.set_event(NFSEvent::MalformedData);
+ },
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
}
}
}
fn process_reply_record_v2<'b>(&mut self, r: &RpcReplyPacket<'b>, xidmap: &NFSRequestXidMap) -> u32 {
- let nfs_status;
+ let mut nfs_status = 0;
let resp_handle = Vec::new();
if xidmap.procedure == NFSPROC3_READ {
self.process_read_record(r, reply, Some(&xidmap));
nfs_status = reply.status;
},
- IResult::Incomplete(_) => { panic!("Incomplete!"); },
+ IResult::Incomplete(_) => {
+ self.set_event(NFSEvent::MalformedData);
+ },
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
}
} else {
cur_i = remaining; // progress input past parsed record
},
IResult::Incomplete(_) => {
- SCLogDebug!("TS WRITE record incomplete");
+ self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
}
cur_i = &cur_i[rec_size..];
status |= self.process_request_record(rpc_record);
},
- IResult::Incomplete(x) => {
- // should be unreachable unless our rec_size calc is off
- panic!("TS data incomplete while we checked for rec_size? BUG {:?}", x);
- //self.tcp_buffer_ts.extend_from_slice(cur_i);
- //break;
+ IResult::Incomplete(_) => {
+ cur_i = &cur_i[rec_size..]; // progress input past parsed record
+
+ // we shouldn't get incomplete as we have the full data
+ // so if we got incomplete anyway it's the data that is
+ // bad.
+ self.set_event(NFSEvent::MalformedData);
+
+ status = 1;
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); //break
},
cur_i = remaining; // progress input past parsed record
},
IResult::Incomplete(_) => {
- SCLogDebug!("TS WRITE record incomplete");
+ self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
}
status |= self.process_reply_record(rpc_record);
},
IResult::Incomplete(_) => {
+ cur_i = &cur_i[rec_size..]; // progress input past parsed record
+
// we shouldn't get incomplete as we have the full data
- panic!("TC data incomplete, BUG!");
- //self.tcp_buffer_tc.extend_from_slice(cur_i);
- //break;
+ // so if we got incomplete anyway it's the data that is
+ // bad.
+ self.set_event(NFSEvent::MalformedData);
+
+ status = 1;
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); //break
},
}
}
+#[no_mangle]
+pub extern "C" fn rs_nfs_state_has_events(state: &mut NFSState) -> u8 {
+ if state.events > 0 {
+ return 1;
+ }
+ return 0;
+}
+
+#[no_mangle]
+pub extern "C" fn rs_nfs_state_get_events(state: &mut NFSState,
+ tx_id: libc::uint64_t)
+ -> *mut AppLayerDecoderEvents
+{
+ match state.get_tx_by_id(tx_id) {
+ Some(tx) => {
+ return tx.events;
+ }
+ _ => {
+ return std::ptr::null_mut();
+ }
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn rs_nfs_state_get_event_info(event_name: *const libc::c_char,
+ event_id: *mut libc::c_int,
+ event_type: *mut AppLayerEventType)
+ -> i8
+{
+ if event_name == std::ptr::null() {
+ return -1;
+ }
+ let c_event_name: &CStr = unsafe { CStr::from_ptr(event_name) };
+ let event = match c_event_name.to_str() {
+ Ok(s) => {
+ match s {
+ "malformed_data" => NFSEvent::MalformedData as i32,
+ _ => -1, // unknown event
+ }
+ },
+ Err(_) => -1, // UTF-8 conversion failed
+ };
+ unsafe{
+ *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
+ *event_id = event as libc::c_int;
+ };
+ 0
+}
+
/// return procedure(s) in the tx. At 0 return the main proc,
/// otherwise get procs from the 'file_additional_procs'.
/// Keep calling until 0 is returned.
rs_nfs3_state_tx_free(state, tx_id);
}
-#if 0
static int NFSTCPStateGetEventInfo(const char *event_name, int *event_id,
AppLayerEventType *event_type)
{
- *event_id = SCMapEnumNameToValue(event_name, nfs_decoder_event_table);
- if (*event_id == -1) {
- SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in "
- "nfs enum map table.", event_name);
- /* This should be treated as fatal. */
- return -1;
- }
-
- *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
-
- return 0;
+ return rs_nfs_state_get_event_info(event_name, event_id, event_type);
}
-static AppLayerDecoderEvents *NFSTCPGetEvents(void *state, uint64_t tx_id)
+static int NFSTCPHasEvents(void *state)
{
- NFSTCPState *nfs_state = state;
- NFSTCPTransaction *tx;
-
- TAILQ_FOREACH(tx, &nfs_state->tx_list, next) {
- if (tx->tx_id == tx_id) {
- return tx->decoder_events;
- }
- }
-
- return NULL;
+ return rs_nfs_state_has_events(state);
}
-static int NFSTCPHasEvents(void *state)
+static AppLayerDecoderEvents *NFSTCPGetEvents(void *state, uint64_t id)
{
- NFSTCPState *echo = state;
- return echo->events;
+ return rs_nfs_state_get_events(state, id);
}
-#endif
/**
* \brief Probe the input to see if it looks like echo.
AppLayerParserRegisterGetFilesFunc(IPPROTO_TCP, ALPROTO_NFS, NFSTCPGetFiles);
/* Application layer event handling. */
-// AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_NFS,
-// NFSTCPHasEvents);
+ AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_NFS,
+ NFSTCPHasEvents);
/* What is this being registered for? */
AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_NFS,
NULL, NFSTCPGetTxDetectState, NFSTCPSetTxDetectState);
-// AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_NFS,
-// NFSTCPStateGetEventInfo);
-// AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_NFS,
-// NFSTCPGetEvents);
+ AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_NFS,
+ NFSTCPStateGetEventInfo);
+ AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_NFS,
+ NFSTCPGetEvents);
/* This parser accepts gaps. */
AppLayerParserRegisterOptionFlags(IPPROTO_TCP, ALPROTO_NFS,
rs_nfs3_state_tx_free(state, tx_id);
}
-#if 0
static int NFSStateGetEventInfo(const char *event_name, int *event_id,
AppLayerEventType *event_type)
{
- *event_id = SCMapEnumNameToValue(event_name, nfs_decoder_event_table);
- if (*event_id == -1) {
- SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in "
- "nfs enum map table.", event_name);
- /* This should be treated as fatal. */
- return -1;
- }
-
- *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
-
- return 0;
+ return rs_nfs_state_get_event_info(event_name, event_id, event_type);
}
-static AppLayerDecoderEvents *NFSGetEvents(void *state, uint64_t tx_id)
+static int NFSHasEvents(void *state)
{
- NFSState *nfs_state = state;
- NFSTransaction *tx;
-
- TAILQ_FOREACH(tx, &nfs3_state->tx_list, next) {
- if (tx->tx_id == tx_id) {
- return tx->decoder_events;
- }
- }
-
- return NULL;
+ return rs_nfs_state_has_events(state);
}
-static int NFSHasEvents(void *state)
+static AppLayerDecoderEvents *NFSGetEvents(void *state, uint64_t id)
{
- NFSState *echo = state;
- return echo->events;
+ return rs_nfs_state_get_events(state, id);
}
-#endif
/**
* \brief Probe the input to see if it looks like echo.
AppLayerParserRegisterGetFilesFunc(IPPROTO_UDP, ALPROTO_NFS, NFSGetFiles);
/* Application layer event handling. */
-// AppLayerParserRegisterHasEventsFunc(IPPROTO_UDP, ALPROTO_NFS,
-// NFSHasEvents);
+ AppLayerParserRegisterHasEventsFunc(IPPROTO_UDP, ALPROTO_NFS,
+ NFSHasEvents);
/* What is this being registered for? */
AppLayerParserRegisterDetectStateFuncs(IPPROTO_UDP, ALPROTO_NFS,
NULL, NFSGetTxDetectState, NFSSetTxDetectState);
-// AppLayerParserRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_NFS,
-// NFSStateGetEventInfo);
-// AppLayerParserRegisterGetEventsFunc(IPPROTO_UDP, ALPROTO_NFS,
-// NFSGetEvents);
+ AppLayerParserRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_NFS,
+ NFSStateGetEventInfo);
+ AppLayerParserRegisterGetEventsFunc(IPPROTO_UDP, ALPROTO_NFS,
+ NFSGetEvents);
}
else {
SCLogNotice("NFS protocol parsing disabled.");