diff --git a/experimental/src/generic/mod.rs b/experimental/src/generic/mod.rs index 5df6026a3..4db00551b 100644 --- a/experimental/src/generic/mod.rs +++ b/experimental/src/generic/mod.rs @@ -2,7 +2,7 @@ extern crate serde; extern crate serde_json; use serde::Deserialize; -use snmp::{r_snmp_bulk_get, r_snmp_bulk_walk, SnmpResult, SnmpValue}; +use snmp::{snmp_bulk_get, snmp_bulk_walk, SnmpResult, SnmpValue}; use std::collections::BTreeMap; @@ -71,6 +71,7 @@ pub struct Snmp { name: String, oid: String, query: QueryType, + labels: Option>, } #[derive(Deserialize, Debug)] @@ -188,7 +189,7 @@ impl Command { for s in self.collect.snmp.iter() { match s.query { QueryType::Walk => { - let r = r_snmp_bulk_walk(target, version, community, &s.oid); + let r = snmp_bulk_walk(target, version, community, &s.oid); match r.variables.len() { 1 => { let result = r.variables.get(0).unwrap(); @@ -212,7 +213,7 @@ impl Command { } } if !to_get.is_empty() { - let r = r_snmp_bulk_get(target, version, community, 1, 1, &to_get); + let r = snmp_bulk_get(target, version, community, 1, 1, &to_get); for (idx, result) in r.variables.iter().enumerate() { if let SnmpValue::Integer(v) = result.value { res.insert(get_name[idx].to_string(), v); @@ -231,7 +232,7 @@ impl Command { // QueryType::Walk => { // res = Some(( // &query.name, - // r_snmp_bulk_walk(target, version, community, &query.oid), + // snmp_bulk_walk(target, version, community, &query.oid), // )); // } // }, diff --git a/experimental/src/snmp/mod.rs b/experimental/src/snmp/mod.rs index b2a4643a6..6e327b67e 100644 --- a/experimental/src/snmp/mod.rs +++ b/experimental/src/snmp/mod.rs @@ -4,7 +4,6 @@ extern crate rasn_smi; extern crate rasn_snmp; use log::{info, trace, warn}; -use rasn::types::IntegerType; use rasn::types::ObjectIdentifier; use rasn_snmp::v2::Pdus; use rasn_snmp::v2::VarBind; @@ -12,18 +11,21 @@ use rasn_snmp::v2::VarBindValue; use rasn_snmp::v2::{BulkPdu, Pdu}; use rasn_snmp::v2::{GetBulkRequest, GetNextRequest, GetRequest}; use rasn_snmp::v2c::Message; +use std::collections::BTreeMap; use std::convert::TryInto; -use std::ffi::CStr; -use std::ffi::CString; use std::net::UdpSocket; -use std::os::raw::{c_char, c_void}; #[derive(Debug, PartialEq)] -pub struct SnmpResult { +pub struct SnmpSubResult<'a> { + pub label: &'a str, + pub value: &'a str, pub variables: Vec, } -type CSnmpVariable = c_void; +#[derive(Debug, PartialEq)] +pub struct SnmpResult<'a> { + pub labels: Vec>, +} #[derive(Debug, PartialEq)] pub enum SnmpValue { @@ -43,234 +45,163 @@ impl SnmpVariable { } } -type CSnmpResult = c_void; - -impl SnmpResult { - fn new() -> SnmpResult { - SnmpResult { - variables: Vec::new(), +impl<'a> SnmpResult<'a> { + fn new(labels: &'a BTreeMap) -> SnmpResult<'a> { + let mut retval: Vec = Vec::new(); + retval.reserve(labels.len()); + for (label, value) in labels.iter() { + let item = SnmpSubResult { + label: &label, + value: &value, + variables: Vec::new(), + }; + retval.push(item); } + SnmpResult { labels: retval } } - fn add_variable(&mut self, name: String, value: SnmpValue) { - self.variables.push(SnmpVariable::new(name, value)); + fn new_simple() -> SnmpResult<'a> { + let label = SnmpSubResult{label: "", value: "", variables: Vec::new() }; + SnmpResult { labels: vec![label], } } - fn concat(&mut self, other: SnmpResult) { - self.variables.extend(other.variables); + fn add_variable(&mut self, idx: usize, name: String, value: SnmpValue) { + self.labels[idx].variables.push(SnmpVariable::new(name, value)); } -} -//#[allow(non_snake_case)] -//#[no_mangle] -//pub extern "C" fn snmpresult_DESTROY(p: *mut CSnmpResult) { -// unsafe { Box::from_raw(p as *mut SnmpResult) }; -//} - -//#[allow(non_snake_case)] -//#[no_mangle] -//pub extern "C" fn snmpresult_get_variable(p: *mut CSnmpResult, index: usize) -> *mut CSnmpVariable { -// trace!("snmpresult_get_variable {}", index); -// let p = p as *mut SnmpResult; -// let p = unsafe { &mut *p }; -// if index >= p.variables.len() { -// return Box::into_raw(Box::new(SnmpVariable::new("".to_string(), "".to_string()))) -// as *mut CSnmpVariable; -// } -// let v = &p.variables[index]; -// Box::into_raw(Box::new(SnmpVariable { -// name: v.name.clone(), -// value: v.value.clone(), -// })) as *mut CSnmpVariable -//} -// -//#[allow(non_snake_case)] -//#[no_mangle] -//pub extern "C" fn snmpresult_variables_count(p: *mut CSnmpResult) -> usize { -// let p = p as *mut SnmpResult; -// let p = unsafe { &mut *p }; -// p.variables.len() -//} -// -//#[allow(non_snake_case)] -//#[no_mangle] -//pub extern "C" fn snmpvariable_DESTROY(p: *mut CSnmpVariable) { -// unsafe { Box::from_raw(p as *mut SnmpVariable) }; -//} - -//#[allow(non_snake_case)] -//#[no_mangle] -//pub extern "C" fn snmpvariable_get_name(p: *mut CSnmpVariable) -> *mut c_char { -// let p = p as *mut SnmpVariable; -// let p = unsafe { &mut *p }; -// let c = CString::new(p.name.clone()).unwrap(); -// c.into_raw() -//} -// -//#[allow(non_snake_case)] -//#[no_mangle] -//pub extern "C" fn snmpvariable_get_value(p: *mut CSnmpVariable) -> *mut c_char { -// let p = p as *mut SnmpVariable; -// let p = unsafe { &mut *p }; -// let c = CString::new(p.value.clone()).unwrap(); -// c.into_raw() -//} - -//#[no_mangle] -//pub extern "C" fn snmp_get(target: *const c_char, oid: *const c_char) -> *mut CSnmpResult { -// if target.is_null() { -// return Box::into_raw(Box::new(SnmpResult::new())) as *mut CSnmpResult; -// } -// let target = unsafe { CStr::from_ptr(target) }; -// let target = match target.to_str() { -// Ok(s) => s, -// Err(_) => "", -// }; -// -// if oid.is_null() { -// return Box::into_raw(Box::new(SnmpResult::new())) as *mut CSnmpResult; -// } -// let oid = unsafe { CStr::from_ptr(oid) }; -// let oid = match oid.to_str() { -// Ok(s) => s, -// Err(_) => "", -// }; -// -// Box::into_raw(Box::new(r_snmp_get(target, oid, "public"))) as *mut CSnmpResult -//} - -pub fn r_snmp_get(target: &str, oid: &str, community: &str) -> SnmpResult { - let oid_tab = oid - .split('.') - .map(|x| x.parse::().unwrap()) - .collect::>(); - - let request_id = 1; - - let variable_bindings = vec![VarBind { - name: ObjectIdentifier::new_unchecked(oid_tab.into()), - value: VarBindValue::Unspecified, - }]; - - let pdu = Pdu { - request_id, - error_status: 0, - error_index: 0, - variable_bindings, - }; - - let get_request = GetRequest(pdu); - - let message: rasn_snmp::v2c::Message = Message { - version: 1.into(), - community: community.to_string().into(), - data: get_request.into(), - }; - - // Send the message through an UDP socket - let socket = UdpSocket::bind("0.0.0.0:0").unwrap(); - socket.connect(target).expect("connect function failed"); - let duration = std::time::Duration::from_millis(1000); - socket.set_read_timeout(Some(duration)).unwrap(); - - let encoded = rasn::der::encode(&message).unwrap(); - let res = socket.send(&encoded).unwrap(); - assert!(res == encoded.len()); - - let mut buf = [0; 1024]; - let resp = socket.recv_from(buf.as_mut_slice()).unwrap(); - - trace!("Received {} bytes", resp.0); - assert!(resp.0 > 0); - let decoded: Message = rasn::ber::decode(&buf[0..resp.0]).unwrap(); - build_response(decoded, "", false).0 -} - -//#[no_mangle] -//pub extern "C" fn snmp_walk(target: *const c_char, oid: *const c_char) -> *mut CSnmpResult { -// if target.is_null() { -// return Box::into_raw(Box::new(SnmpResult::new())) as *mut CSnmpResult; -// } -// let target = unsafe { CStr::from_ptr(target) }; -// let target = match target.to_str() { -// Ok(s) => s, -// Err(_) => "", -// }; -// -// if oid.is_null() { -// return Box::into_raw(Box::new(SnmpResult::new())) as *mut CSnmpResult; -// } -// let oid = unsafe { CStr::from_ptr(oid) }; -// let oid = match oid.to_str() { -// Ok(s) => s, -// Err(_) => "", -// }; -// Box::into_raw(Box::new(r_snmp_walk(target, oid))) as *mut CSnmpResult -//} - -pub fn r_snmp_walk(target: &str, oid: &str) -> SnmpResult { - let community = "public"; - let oid_tab = oid - .split('.') - .map(|x| x.parse::().unwrap()) - .collect::>(); - - let mut retval = SnmpResult::new(); - let mut request_id: i32 = 1; - - let create_next_request = |id: i32, oid: &[u32]| -> Message { - let variable_bindings = vec![VarBind { - name: ObjectIdentifier::new_unchecked(oid.to_vec().into()), - value: VarBindValue::Unspecified, - }]; - - let pdu = Pdu { - request_id: id, - error_status: 0, - error_index: 0, - variable_bindings, - }; - let get_request: GetNextRequest = GetNextRequest(pdu); - - Message { - version: 1.into(), - community: community.into(), - data: get_request.into(), + fn get_last_oid(&self, idx: usize) -> &str { + if self.labels.is_empty() { + return ""; } - }; + let last = self.labels[idx].variables.iter().last().unwrap(); + if last.name.is_empty() { + return ""; + } + last.name.as_str() + } - let mut message = create_next_request(request_id, &oid_tab); - // Send the message through an UDP socket - let socket = UdpSocket::bind("0.0.0.0:0").unwrap(); - socket.connect(target).expect("connect function failed"); - let duration = std::time::Duration::from_millis(1000); - socket.set_read_timeout(Some(duration)).unwrap(); - - loop { - let encoded: Vec = rasn::der::encode(&message).unwrap(); - let res: usize = socket.send(&encoded).unwrap(); - assert!(res == encoded.len()); - - let mut buf: [u8; 1024] = [0; 1024]; - let resp: (usize, std::net::SocketAddr) = socket.recv_from(buf.as_mut_slice()).unwrap(); - - trace!("Received {} bytes", resp.0); - assert!(resp.0 > 0); - let decoded: Message = rasn::ber::decode(&buf[0..resp.0]).unwrap(); - if let Pdus::Response(resp) = &decoded.data { - let resp_oid = &resp.0.variable_bindings[0].name; - let n = resp_oid.len() - 1; - if resp_oid[0..n] != oid_tab[0..n] { - break; + fn concat(&mut self, mut other: SnmpResult) { + for v in other.labels.iter_mut() { + for vv in self.labels.iter_mut() { + if v.label == vv.label { + vv.variables.extend(v.variables); + break; + } } - message = create_next_request(request_id, &resp_oid); } - retval.concat(build_response(decoded, &oid, true).0); - request_id += 1; } - retval } +//pub fn snmp_get(target: &str, oid: &str, community: &str) -> SnmpResult { +// let oid_tab = oid +// .split('.') +// .map(|x| x.parse::().unwrap()) +// .collect::>(); +// +// let request_id = 1; +// +// let variable_bindings = vec![VarBind { +// name: ObjectIdentifier::new_unchecked(oid_tab.into()), +// value: VarBindValue::Unspecified, +// }]; +// +// let pdu = Pdu { +// request_id, +// error_status: 0, +// error_index: 0, +// variable_bindings, +// }; +// +// let get_request = GetRequest(pdu); +// +// let message: rasn_snmp::v2c::Message = Message { +// version: 1.into(), +// community: community.to_string().into(), +// data: get_request.into(), +// }; +// +// // Send the message through an UDP socket +// let socket = UdpSocket::bind("0.0.0.0:0").unwrap(); +// socket.connect(target).expect("connect function failed"); +// let duration = std::time::Duration::from_millis(1000); +// socket.set_read_timeout(Some(duration)).unwrap(); +// +// let encoded = rasn::der::encode(&message).unwrap(); +// let res = socket.send(&encoded).unwrap(); +// assert!(res == encoded.len()); +// +// let mut buf = [0; 1024]; +// let resp = socket.recv_from(buf.as_mut_slice()).unwrap(); +// +// trace!("Received {} bytes", resp.0); +// assert!(resp.0 > 0); +// let decoded: Message = rasn::ber::decode(&buf[0..resp.0]).unwrap(); +// build_response(decoded, "", {}, false).0 +//} + +//pub fn snmp_walk(target: &str, oid: &str) -> SnmpResult { +// let community = "public"; +// let oid_tab = oid +// .split('.') +// .map(|x| x.parse::().unwrap()) +// .collect::>(); +// +// let mut retval = SnmpResult::new(); +// let mut request_id: i32 = 1; +// +// let create_next_request = |id: i32, oid: &[u32]| -> Message { +// let variable_bindings = vec![VarBind { +// name: ObjectIdentifier::new_unchecked(oid.to_vec().into()), +// value: VarBindValue::Unspecified, +// }]; +// +// let pdu = Pdu { +// request_id: id, +// error_status: 0, +// error_index: 0, +// variable_bindings, +// }; +// let get_request: GetNextRequest = GetNextRequest(pdu); +// +// Message { +// version: 1.into(), +// community: community.into(), +// data: get_request.into(), +// } +// }; +// +// let mut message = create_next_request(request_id, &oid_tab); +// // Send the message through an UDP socket +// let socket = UdpSocket::bind("0.0.0.0:0").unwrap(); +// socket.connect(target).expect("connect function failed"); +// let duration = std::time::Duration::from_millis(1000); +// socket.set_read_timeout(Some(duration)).unwrap(); +// +// loop { +// let encoded: Vec = rasn::der::encode(&message).unwrap(); +// let res: usize = socket.send(&encoded).unwrap(); +// assert!(res == encoded.len()); +// +// let mut buf: [u8; 1024] = [0; 1024]; +// let resp: (usize, std::net::SocketAddr) = socket.recv_from(buf.as_mut_slice()).unwrap(); +// +// trace!("Received {} bytes", resp.0); +// assert!(resp.0 > 0); +// let decoded: Message = rasn::ber::decode(&buf[0..resp.0]).unwrap(); +// if let Pdus::Response(resp) = &decoded.data { +// let resp_oid = &resp.0.variable_bindings[0].name; +// let n = resp_oid.len() - 1; +// if resp_oid[0..n] != oid_tab[0..n] { +// break; +// } +// message = create_next_request(request_id, &resp_oid); +// } +// retval.concat(build_response(decoded, &oid, true).0); +// request_id += 1; +// } +// retval +//} + /// /// Bulk get /// This function is similar to the get function but it uses the GetBulkRequest PDU @@ -285,71 +216,71 @@ pub fn r_snmp_walk(target: &str, oid: &str) -> SnmpResult { /// # Example /// ``` /// use snmp_rust::r_snmp_bulk_get; -/// let result = r_snmp_bulk_get("127.0.0.1:161", "2c", "public", "1.3.6.1.2.1.25.3.3.1.2"); +/// let result = snmp_bulk_get("127.0.0.1:161", "2c", "public", "1.3.6.1.2.1.25.3.3.1.2"); /// ``` -pub fn r_snmp_bulk_get( - target: &str, - _version: &str, - community: &str, - non_repeaters: u32, - max_repetitions: u32, - oid: &Vec<&str>, -) -> SnmpResult { - let mut oids_tab = oid - .iter() - .map(|x| { - x.split('.') - .map(|x| x.parse::().unwrap()) - .collect::>() - }) - .collect::>>(); - - let mut retval = SnmpResult::new(); - let mut request_id: i32 = 1; - - let socket = UdpSocket::bind("0.0.0.0:0").unwrap(); - socket.connect(target).expect("connect function failed"); - let duration = std::time::Duration::from_millis(1000); - socket.set_read_timeout(Some(duration)).unwrap(); - - let variable_bindings = oids_tab - .iter() - .map(|x| VarBind { - name: ObjectIdentifier::new_unchecked(x.to_vec().into()), - value: VarBindValue::Unspecified, - }) - .collect::>(); - - let pdu = BulkPdu { - request_id, - non_repeaters, - max_repetitions, - variable_bindings, - }; - - let get_request: GetBulkRequest = GetBulkRequest(pdu); - - let message: Message = Message { - version: 1.into(), - community: community.to_string().into(), - data: get_request.into(), - }; - - // Send the message through an UDP socket - let encoded: Vec = rasn::der::encode(&message).unwrap(); - let res: usize = socket.send(&encoded).unwrap(); - assert!(res == encoded.len()); - - let mut buf: [u8; 1024] = [0; 1024]; - let resp: (usize, std::net::SocketAddr) = socket.recv_from(buf.as_mut_slice()).unwrap(); - - trace!("Received {} bytes", resp.0); - assert!(resp.0 > 0); - let decoded: Message = rasn::ber::decode(&buf[0..resp.0]).unwrap(); - let (result, _completed) = build_response(decoded, "", false); - retval.concat(result); - retval -} +//pub fn snmp_bulk_get( +// target: &str, +// _version: &str, +// community: &str, +// non_repeaters: u32, +// max_repetitions: u32, +// oid: &Vec<&str>, +//) -> SnmpResult { +// let mut oids_tab = oid +// .iter() +// .map(|x| { +// x.split('.') +// .map(|x| x.parse::().unwrap()) +// .collect::>() +// }) +// .collect::>>(); +// +// let mut retval = SnmpResult::new(); +// let mut request_id: i32 = 1; +// +// let socket = UdpSocket::bind("0.0.0.0:0").unwrap(); +// socket.connect(target).expect("connect function failed"); +// let duration = std::time::Duration::from_millis(1000); +// socket.set_read_timeout(Some(duration)).unwrap(); +// +// let variable_bindings = oids_tab +// .iter() +// .map(|x| VarBind { +// name: ObjectIdentifier::new_unchecked(x.to_vec().into()), +// value: VarBindValue::Unspecified, +// }) +// .collect::>(); +// +// let pdu = BulkPdu { +// request_id, +// non_repeaters, +// max_repetitions, +// variable_bindings, +// }; +// +// let get_request: GetBulkRequest = GetBulkRequest(pdu); +// +// let message: Message = Message { +// version: 1.into(), +// community: community.to_string().into(), +// data: get_request.into(), +// }; +// +// // Send the message through an UDP socket +// let encoded: Vec = rasn::der::encode(&message).unwrap(); +// let res: usize = socket.send(&encoded).unwrap(); +// assert!(res == encoded.len()); +// +// let mut buf: [u8; 1024] = [0; 1024]; +// let resp: (usize, std::net::SocketAddr) = socket.recv_from(buf.as_mut_slice()).unwrap(); +// +// trace!("Received {} bytes", resp.0); +// assert!(resp.0 > 0); +// let decoded: Message = rasn::ber::decode(&buf[0..resp.0]).unwrap(); +// let (result, _completed) = build_response(decoded, "", false); +// retval.concat(result); +// retval +//} /// /// Bulk walk @@ -364,17 +295,92 @@ pub fn r_snmp_bulk_get( /// /// # Example /// ``` -/// use snmp_rust::r_snmp_bulk_walk; -/// let result = r_snmp_bulk_walk("127.0.0.1:161", "2c", "public", "1.3.6.1.2.1.25.3.3.1.2"); +/// use snmp_rust::snmp_bulk_walk; +/// let result = snmp_bulk_walk("127.0.0.1:161", "2c", "public", "1.3.6.1.2.1.25.3.3.1.2"); /// ``` -pub fn r_snmp_bulk_walk(target: &str, _version: &str, community: &str, oid: &str) -> SnmpResult { +//pub fn snmp_bulk_walk(target: &str, _version: &str, community: &str, oid: &str) -> SnmpResult { +// let mut oid_tab = oid +// .split('.') +// .map(|x| x.parse::().unwrap()) +// .collect::>(); +// +// let mut retval = SnmpResult::new_simple(); +// let mut request_id: i32 = 1; +// +// let socket = UdpSocket::bind("0.0.0.0:0").unwrap(); +// socket.connect(target).expect("connect function failed"); +// let duration = std::time::Duration::from_millis(1000); +// socket.set_read_timeout(Some(duration)).unwrap(); +// +// loop { +// let variable_bindings = vec![VarBind { +// name: ObjectIdentifier::new_unchecked(oid_tab.to_vec().into()), +// value: VarBindValue::Unspecified, +// }]; +// +// let pdu = BulkPdu { +// request_id, +// non_repeaters: 0, +// max_repetitions: 10, +// variable_bindings, +// }; +// +// let get_request: GetBulkRequest = GetBulkRequest(pdu); +// +// let message: Message = Message { +// version: 1.into(), +// community: community.to_string().into(), +// data: get_request.into(), +// }; +// +// // Send the message through an UDP socket +// let encoded: Vec = rasn::der::encode(&message).unwrap(); +// let res: usize = socket.send(&encoded).unwrap(); +// assert!(res == encoded.len()); +// +// let mut buf: [u8; 1024] = [0; 1024]; +// let resp: (usize, std::net::SocketAddr) = socket.recv_from(buf.as_mut_slice()).unwrap(); +// +// trace!("Received {} bytes", resp.0); +// assert!(resp.0 > 0); +// let decoded: Message = rasn::ber::decode(&buf[0..resp.0]).unwrap(); +// if let Pdus::Response(resp) = &decoded.data { +// let resp_oid = &resp.0.variable_bindings[0].name; +// let n = resp_oid.len() - 1; +// } +// let (result, completed) = build_response(decoded, &oid, true); +// retval.concat(result); +// if completed { +// break; +// } +// if !retval.variables.is_empty() { +// oid_tab = retval +// .variables +// .last() +// .unwrap() +// .name +// .split('.') +// .map(|x| x.parse::().unwrap()) +// .collect::>(); +// } +// } +// retval +//} + +pub fn snmp_bulk_walk_with_labels<'a>( + target: &str, + _version: &str, + community: &str, + oid: &str, + labels: &'a BTreeMap, +) -> SnmpResult<'a> { let mut oid_tab = oid .split('.') .map(|x| x.parse::().unwrap()) .collect::>(); - let mut retval = SnmpResult::new(); - let mut request_id: i32 = 1; + let mut retval = SnmpResult::new(&labels); + let request_id: i32 = 1; let socket = UdpSocket::bind("0.0.0.0:0").unwrap(); socket.connect(target).expect("connect function failed"); @@ -416,27 +422,28 @@ pub fn r_snmp_bulk_walk(target: &str, _version: &str, community: &str, oid: &str if let Pdus::Response(resp) = &decoded.data { let resp_oid = &resp.0.variable_bindings[0].name; let n = resp_oid.len() - 1; + oid_tab = resp.0.variable_bindings[n - 1].name.to_string().split('.') + .map(|x| x.parse::().unwrap()) + .collect::>(); } - let (result, completed) = build_response(decoded, &oid, true); + let (result, completed) = build_response_with_labels(decoded, &oid, labels, true); retval.concat(result); if completed { break; } - oid_tab = retval - .variables - .last() - .unwrap() - .name - .split('.') - .map(|x| x.parse::().unwrap()) - .collect::>(); } retval } -fn build_response(decoded: Message, oid: &str, walk: bool) -> (SnmpResult, bool) { - let mut retval = SnmpResult::new(); +fn build_response_with_labels<'a>( + decoded: Message, + oid: &str, + labels: &'a BTreeMap, + walk: bool, +) -> (SnmpResult<'a>, bool) { + let mut retval = SnmpResult::new(labels); let mut completed = false; + let mut last_oid: &str = ""; if let Pdus::Response(resp) = &decoded.data { let vars = &resp.0.variable_bindings; @@ -445,9 +452,20 @@ fn build_response(decoded: Message, oid: &str, walk: bool) -> (SnmpResult, if walk { if !name.starts_with(oid) { completed = true; + last_oid = ""; break; } } + let mut idx: i32 = -1; + retval.labels.iter().enumerate().for_each(|label| { + if name.ends_with(label.1.label) { + idx = label.0 as i32; + return; + } + }); + if idx == -1 { + continue; + } match &var.value { VarBindValue::Unspecified => { warn!("Unspecified"); @@ -469,20 +487,30 @@ fn build_response(decoded: Message, oid: &str, walk: bool) -> (SnmpResult, match value { rasn_smi::v2::SimpleSyntax::Integer(value) => { let v = value.try_into().unwrap(); - retval.add_variable(name, SnmpValue::Integer(v)); + retval.add_variable(idx as usize, name, SnmpValue::Integer(v)); + last_oid = retval.get_last_oid(idx as usize); } rasn_smi::v2::SimpleSyntax::String(value) => { // We transform the value into a rust String retval.add_variable( + idx as usize, name, SnmpValue::String( String::from_utf8(value.to_vec()).unwrap(), ), ); + last_oid = retval.get_last_oid(idx as usize); + } + rasn_smi::v2::SimpleSyntax::ObjectId(value) => { + let oid: String = + value.iter().map(|&id| id.to_string() + ".").collect(); + retval.add_variable(idx as usize, name, SnmpValue::String(oid)); + last_oid = retval.get_last_oid(idx as usize); } _ => { retval - .add_variable(name, SnmpValue::String("Other".to_string())); + .add_variable(idx as usize, name, SnmpValue::String("Other".to_string())); + last_oid = retval.get_last_oid(idx as usize); } }; } @@ -497,6 +525,93 @@ fn build_response(decoded: Message, oid: &str, walk: bool) -> (SnmpResult, (retval, completed) } +fn build_response<'a>( + decoded: Message, + oid: &str, + walk: bool, +) -> (SnmpResult<'a>, bool) { + let mut retval = SnmpResult::new_simple(); + let mut completed = false; + let mut last_oid: &str = ""; + + if let Pdus::Response(resp) = &decoded.data { + let vars = &resp.0.variable_bindings; + for var in vars { + let name = var.name.to_string(); + if walk { + if !name.starts_with(oid) { + completed = true; + last_oid = ""; + break; + } + } + let mut idx: i32 = -1; + retval.labels.iter().enumerate().for_each(|label| { + if name.ends_with(label.1.label) { + idx = label.0 as i32; + return; + } + }); + if idx == -1 { + continue; + } + match &var.value { + VarBindValue::Unspecified => { + warn!("Unspecified"); + } + VarBindValue::NoSuchObject => { + warn!("NoSuchObject"); + } + VarBindValue::NoSuchInstance => { + warn!("NoSuchInstance"); + } + VarBindValue::EndOfMibView => { + warn!("EndOfMibView"); + } + VarBindValue::Value(value) => { + warn!("Value {:?}", &value); + match value { + rasn_smi::v2::ObjectSyntax::Simple(value) => { + info!("Simple {:?}", value); + match value { + rasn_smi::v2::SimpleSyntax::Integer(value) => { + let v = value.try_into().unwrap(); + retval.add_variable(idx as usize, name, SnmpValue::Integer(v)); + last_oid = retval.get_last_oid(idx as usize); + } + rasn_smi::v2::SimpleSyntax::String(value) => { + // We transform the value into a rust String + retval.add_variable(idx as usize, + name, + SnmpValue::String( + String::from_utf8(value.to_vec()).unwrap(), + ), + ); + last_oid = retval.get_last_oid(idx as usize); + } + rasn_smi::v2::SimpleSyntax::ObjectId(value) => { + let oid: String = + value.iter().map(|&id| id.to_string() + ".").collect(); + retval.add_variable(idx as usize, name, SnmpValue::String(oid)); + last_oid = retval.get_last_oid(idx as usize); + } + _ => { + retval + .add_variable(idx as usize, name, SnmpValue::String("Other".to_string())); + last_oid = retval.get_last_oid(idx as usize); + } + }; + } + rasn_smi::v2::ObjectSyntax::ApplicationWide(value) => { + info!("Application {:?}", value); + } + }; + } + }; + } + } + (retval, completed) +} //mod tests { // use super::*; //