async_snmp/cli/
hints.rs

1//! Well-known OID name hints.
2//!
3//! This module provides a small hardcoded table of common OID names for display purposes.
4//! This is NOT MIB support - just friendly names for common system OIDs.
5
6use crate::Oid;
7
8/// Well-known OID entries.
9static WELL_KNOWN_OIDS: &[(&[u32], &str)] = &[
10    // SNMPv2-MIB::system
11    (&[1, 3, 6, 1, 2, 1, 1, 1, 0], "sysDescr.0"),
12    (&[1, 3, 6, 1, 2, 1, 1, 2, 0], "sysObjectID.0"),
13    (&[1, 3, 6, 1, 2, 1, 1, 3, 0], "sysUpTime.0"),
14    (&[1, 3, 6, 1, 2, 1, 1, 4, 0], "sysContact.0"),
15    (&[1, 3, 6, 1, 2, 1, 1, 5, 0], "sysName.0"),
16    (&[1, 3, 6, 1, 2, 1, 1, 6, 0], "sysLocation.0"),
17    (&[1, 3, 6, 1, 2, 1, 1, 7, 0], "sysServices.0"),
18    // IF-MIB::interfaces
19    (&[1, 3, 6, 1, 2, 1, 2, 1, 0], "ifNumber.0"),
20    // Common table roots (without instance)
21    (&[1, 3, 6, 1, 2, 1, 1], "system"),
22    (&[1, 3, 6, 1, 2, 1, 2], "interfaces"),
23    (&[1, 3, 6, 1, 2, 1, 2, 2], "ifTable"),
24    (&[1, 3, 6, 1, 2, 1, 2, 2, 1], "ifEntry"),
25];
26
27/// Look up a friendly name for an OID.
28///
29/// Returns `None` if the OID is not in the well-known table.
30pub fn lookup(oid: &Oid) -> Option<&'static str> {
31    let arcs = oid.arcs();
32    WELL_KNOWN_OIDS
33        .iter()
34        .find(|(pattern, _)| *pattern == arcs)
35        .map(|(_, name)| *name)
36}
37
38/// Parse an OID from string, supporting both dotted notation and well-known names.
39///
40/// Accepts:
41/// - Dotted notation: "1.3.6.1.2.1.1.1.0"
42/// - Well-known names: "sysDescr.0", "system", "ifTable"
43pub fn parse_oid(s: &str) -> Result<Oid, String> {
44    // First try as dotted notation
45    if s.chars()
46        .next()
47        .map(|c| c.is_ascii_digit())
48        .unwrap_or(false)
49    {
50        return Oid::parse(s).map_err(|e| format!("invalid OID '{}': {}", s, e));
51    }
52
53    // Try well-known names (case-insensitive)
54    let lower = s.to_ascii_lowercase();
55    for (arcs, name) in WELL_KNOWN_OIDS {
56        if name.to_ascii_lowercase() == lower {
57            return Ok(Oid::from_slice(arcs));
58        }
59    }
60
61    Err(format!(
62        "unknown OID name '{}'; use dotted notation (e.g., 1.3.6.1.2.1.1.1.0)",
63        s
64    ))
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70
71    #[test]
72    fn test_lookup_found() {
73        let oid = Oid::from_slice(&[1, 3, 6, 1, 2, 1, 1, 1, 0]);
74        assert_eq!(lookup(&oid), Some("sysDescr.0"));
75    }
76
77    #[test]
78    fn test_lookup_not_found() {
79        let oid = Oid::from_slice(&[1, 3, 6, 1, 99, 99, 99]);
80        assert_eq!(lookup(&oid), None);
81    }
82
83    #[test]
84    fn test_parse_dotted() {
85        let oid = parse_oid("1.3.6.1.2.1.1.1.0").unwrap();
86        assert_eq!(oid.arcs(), &[1, 3, 6, 1, 2, 1, 1, 1, 0]);
87    }
88
89    #[test]
90    fn test_parse_well_known() {
91        let oid = parse_oid("sysDescr.0").unwrap();
92        assert_eq!(oid.arcs(), &[1, 3, 6, 1, 2, 1, 1, 1, 0]);
93
94        let oid = parse_oid("system").unwrap();
95        assert_eq!(oid.arcs(), &[1, 3, 6, 1, 2, 1, 1]);
96    }
97
98    #[test]
99    fn test_parse_case_insensitive() {
100        let oid = parse_oid("SYSDESCR.0").unwrap();
101        assert_eq!(oid.arcs(), &[1, 3, 6, 1, 2, 1, 1, 1, 0]);
102    }
103
104    #[test]
105    fn test_parse_unknown_name() {
106        assert!(parse_oid("unknownOid").is_err());
107    }
108}