enh(generic-snmp): snmpbulkget almost works and we have a timeout, 1000ms currently

This commit is contained in:
David Boucher 2025-03-30 17:57:03 +02:00
parent 4a31f1b2e4
commit 0760bc53eb
2 changed files with 76 additions and 56 deletions

View File

@ -2,7 +2,7 @@ extern crate serde;
extern crate serde_json; extern crate serde_json;
use serde::Deserialize; use serde::Deserialize;
use snmp::{r_snmp_bulk_walk, SnmpResult, SnmpValue}; use snmp::{r_snmp_bulk_get, r_snmp_bulk_walk, SnmpResult, SnmpValue};
use std::collections::BTreeMap; use std::collections::BTreeMap;
@ -182,6 +182,9 @@ impl Command {
//ext: &CommandExt, //ext: &CommandExt,
) -> CmdResult { ) -> CmdResult {
let mut res: BTreeMap<String, i64> = BTreeMap::new(); let mut res: BTreeMap<String, i64> = BTreeMap::new();
let mut to_get = Vec::new();
let mut get_name = Vec::new();
for s in self.collect.snmp.iter() { for s in self.collect.snmp.iter() {
match s.query { match s.query {
QueryType::Walk => { QueryType::Walk => {
@ -203,8 +206,16 @@ impl Command {
} }
} }
QueryType::Get => { QueryType::Get => {
// let r = r_snmp_bulk_get(target, version, community, &s.oid); to_get.push(s.oid.as_str());
// res.insert(&s.name, r); get_name.push(&s.name);
}
}
}
if !to_get.is_empty() {
let r = 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);
} }
} }
} }

View File

@ -170,6 +170,9 @@ pub fn r_snmp_get(target: &str, oid: &str, community: &str) -> SnmpResult {
// Send the message through an UDP socket // Send the message through an UDP socket
let socket = UdpSocket::bind("0.0.0.0:0").unwrap(); let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
socket.connect(target).expect("connect function failed"); 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 encoded = rasn::der::encode(&message).unwrap();
let res = socket.send(&encoded).unwrap(); let res = socket.send(&encoded).unwrap();
assert!(res == encoded.len()); assert!(res == encoded.len());
@ -237,11 +240,13 @@ pub fn r_snmp_walk(target: &str, oid: &str) -> SnmpResult {
}; };
let mut message = create_next_request(request_id, &oid_tab); 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 { loop {
// 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 encoded: Vec<u8> = rasn::der::encode(&message).unwrap(); let encoded: Vec<u8> = rasn::der::encode(&message).unwrap();
let res: usize = socket.send(&encoded).unwrap(); let res: usize = socket.send(&encoded).unwrap();
assert!(res == encoded.len()); assert!(res == encoded.len());
@ -282,68 +287,67 @@ pub fn r_snmp_walk(target: &str, oid: &str) -> SnmpResult {
/// use snmp_rust::r_snmp_bulk_get; /// 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 = r_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, oid: &str) -> SnmpResult { pub fn r_snmp_bulk_get(
let mut oid_tab = oid target: &str,
.split('.') _version: &str,
.map(|x| x.parse::<u32>().unwrap()) community: &str,
.collect::<Vec<u32>>(); non_repeaters: u32,
max_repetitions: u32,
oid: &Vec<&str>,
) -> SnmpResult {
let mut oids_tab = oid
.iter()
.map(|x| {
x.split('.')
.map(|x| x.parse::<u32>().unwrap())
.collect::<Vec<u32>>()
})
.collect::<Vec<Vec<u32>>>();
let mut retval = SnmpResult::new(); let mut retval = SnmpResult::new();
let mut request_id: i32 = 1; let mut request_id: i32 = 1;
let socket = UdpSocket::bind("0.0.0.0:0").unwrap(); let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
socket.connect(target).expect("connect function failed"); 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 = oids_tab
let variable_bindings = vec![VarBind { .iter()
name: ObjectIdentifier::new_unchecked(oid_tab.to_vec().into()), .map(|x| VarBind {
name: ObjectIdentifier::new_unchecked(x.to_vec().into()),
value: VarBindValue::Unspecified, value: VarBindValue::Unspecified,
}]; })
.collect::<Vec<VarBind>>();
let pdu = BulkPdu { let pdu = BulkPdu {
request_id, request_id,
non_repeaters: 0, non_repeaters,
max_repetitions: 10, max_repetitions,
variable_bindings, variable_bindings,
}; };
let get_request: GetBulkRequest = GetBulkRequest(pdu); let get_request: GetBulkRequest = GetBulkRequest(pdu);
let message: Message<GetBulkRequest> = Message { let message: Message<GetBulkRequest> = Message {
version: 1.into(), version: 1.into(),
community: community.to_string().into(), community: community.to_string().into(),
data: get_request.into(), data: get_request.into(),
}; };
// Send the message through an UDP socket // Send the message through an UDP socket
let encoded: Vec<u8> = rasn::der::encode(&message).unwrap(); let encoded: Vec<u8> = rasn::der::encode(&message).unwrap();
let res: usize = socket.send(&encoded).unwrap(); let res: usize = socket.send(&encoded).unwrap();
assert!(res == encoded.len()); assert!(res == encoded.len());
let mut buf: [u8; 1024] = [0; 1024]; let mut buf: [u8; 1024] = [0; 1024];
let resp: (usize, std::net::SocketAddr) = socket.recv_from(buf.as_mut_slice()).unwrap(); let resp: (usize, std::net::SocketAddr) = socket.recv_from(buf.as_mut_slice()).unwrap();
trace!("Received {} bytes", resp.0); trace!("Received {} bytes", resp.0);
assert!(resp.0 > 0); assert!(resp.0 > 0);
let decoded: Message<Pdus> = rasn::ber::decode(&buf[0..resp.0]).unwrap(); let decoded: Message<Pdus> = rasn::ber::decode(&buf[0..resp.0]).unwrap();
if let Pdus::Response(resp) = &decoded.data { let (result, _completed) = build_response(decoded, false);
let resp_oid = &resp.0.variable_bindings[0].name; retval.concat(result);
let n = resp_oid.len() - 1;
}
let (result, completed) = build_response(decoded, true);
retval.concat(result);
if completed {
break;
}
oid_tab = retval
.variables
.last()
.unwrap()
.name
.split('.')
.map(|x| x.parse::<u32>().unwrap())
.collect::<Vec<u32>>();
}
retval retval
} }
@ -374,6 +378,8 @@ pub fn r_snmp_bulk_walk(target: &str, _version: &str, community: &str, oid: &str
let socket = UdpSocket::bind("0.0.0.0:0").unwrap(); let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
socket.connect(target).expect("connect function failed"); socket.connect(target).expect("connect function failed");
let duration = std::time::Duration::from_millis(1000);
socket.set_read_timeout(Some(duration)).unwrap();
loop { loop {
let variable_bindings = vec![VarBind { let variable_bindings = vec![VarBind {
@ -474,11 +480,14 @@ fn build_response(decoded: Message<Pdus>, walk: bool) -> (SnmpResult, bool) {
// We transform the value into a rust String // We transform the value into a rust String
retval.add_variable( retval.add_variable(
name, name,
SnmpValue::String(String::from_utf8(value.to_vec()).unwrap()), SnmpValue::String(
String::from_utf8(value.to_vec()).unwrap(),
),
); );
} }
_ => { _ => {
retval.add_variable(name, SnmpValue::String("Other".to_string())); retval
.add_variable(name, SnmpValue::String("Other".to_string()));
} }
}; };
} }