use async_snmp::{Auth, Client, Error, ErrorStatus, Retry, Value, oid};
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::from_default_env()
.add_directive("async_snmp=info".parse()?),
)
.init();
let target = ("127.0.0.1", 11161);
let client = Client::builder(target, Auth::v2c("public"))
.request_timeout(Duration::from_secs(5))
.retry(Retry::fixed(3, Duration::ZERO).expect("valid retry count"))
.connect()
.await?;
println!("UDP client configured for {}", client.peer_addr());
println!("\n--- GET sysDescr.0 ---");
let sys_descr = oid!(1, 3, 6, 1, 2, 1, 1, 1, 0);
match client.get(&sys_descr).await {
Ok(response) => {
for anomaly in &response.anomalies {
eprintln!("Response shape anomaly: {anomaly:?}");
}
for varbind in &response.varbinds {
print_varbind(varbind);
}
if let Some(varbind) = response.single()
&& let Some(s) = varbind.value.as_str()
{
println!("As string: {s}");
}
}
Err(e) => {
handle_error("GET", &e);
}
}
println!("\n--- GET_MANY (system MIB) ---");
let oids = [
oid!(1, 3, 6, 1, 2, 1, 1, 1, 0), oid!(1, 3, 6, 1, 2, 1, 1, 3, 0), oid!(1, 3, 6, 1, 2, 1, 1, 5, 0), oid!(1, 3, 6, 1, 2, 1, 1, 6, 0), ];
match client.get_many(&oids).await {
Ok(response) => {
for anomaly in &response.anomalies {
eprintln!("Response shape anomaly: {anomaly:?}");
}
for vb in response.varbinds {
print_varbind(&vb);
}
}
Err(e) => {
handle_error("GET_MANY", &e);
}
}
println!("\n--- GETNEXT from system ---");
let system_oid = oid!(1, 3, 6, 1, 2, 1, 1);
match client.get_next(&system_oid).await {
Ok(response) => {
for anomaly in &response.anomalies {
eprintln!("Response shape anomaly: {anomaly:?}");
}
for varbind in response.varbinds {
println!("Next OID after {}: {}", system_oid, varbind.oid);
print_varbind(&varbind);
}
}
Err(e) => {
handle_error("GETNEXT", &e);
}
}
println!("\n--- SET sysContact.0 ---");
let write_client = Client::builder(target, Auth::v2c("private"))
.request_timeout(Duration::from_secs(5))
.connect()
.await?;
let sys_contact = oid!(1, 3, 6, 1, 2, 1, 1, 4, 0);
let new_value = Value::from("admin@example.com");
match write_client.set(&sys_contact, new_value).await {
Ok(response) => {
for anomaly in &response.anomalies {
eprintln!("Response shape anomaly: {anomaly:?}");
}
for varbind in response.varbinds {
print_varbind(&varbind);
}
}
Err(e) => {
handle_error("SET", &e);
}
}
println!("\n--- Verify SET ---");
match client.get(&sys_contact).await {
Ok(response) => {
for anomaly in &response.anomalies {
eprintln!("Response shape anomaly: {anomaly:?}");
}
for varbind in response.varbinds {
print_varbind(&varbind);
}
}
Err(e) => {
handle_error("GET (verify)", &e);
}
}
println!("\nExample complete!");
Ok(())
}
fn print_varbind(varbind: &async_snmp::VarBind) {
match &varbind.value {
Value::NoSuchObject => {
println!(" {}: object identity is not available", varbind.oid);
}
Value::NoSuchInstance => {
println!(" {}: object instance does not exist", varbind.oid);
}
Value::EndOfMibView => {
println!(" {}: end of MIB view", varbind.oid);
}
value => println!(" {}: {value:?}", varbind.oid),
}
}
fn handle_error(operation: &str, error: &Error) {
match error {
Error::Snmp {
status, index, oid, ..
} => {
println!("{operation} failed: SNMP error {status:?} at index {index}");
if let Some(oid) = oid {
println!(" Problematic OID: {oid}");
}
match status {
ErrorStatus::NoSuchName => {
println!(" -> OID does not exist on this SNMPv1 agent");
}
ErrorStatus::NotWritable => {
println!(" -> OID is read-only");
}
ErrorStatus::AuthorizationError => {
println!(" -> Access denied (check community string)");
}
_ => {}
}
}
Error::Timeout {
target,
elapsed,
retries,
..
} => {
println!("{operation} failed: Timeout after {elapsed:?} ({retries} retries)");
println!(" -> Check if agent at {target} is reachable");
}
Error::Network { target, source, .. } => {
println!("{operation} failed: Network error - {source}");
println!(" -> Target: {target}");
}
_ => {
println!("{operation} failed: {error}");
}
}
}