snmp_parser/
generic.rs

1use crate::error::SnmpError;
2use crate::snmp::*;
3use crate::snmpv3::*;
4use asn1_rs::{Any, FromBer, Tag};
5use nom::combinator::map_res;
6use nom::{Err, IResult};
7
8/// An SNMP messsage parser, accepting v1, v2c or v3 messages
9///
10/// # Examples
11///
12/// ```rust
13/// use snmp_parser::{ScopedPduData, SecurityModel, SnmpGenericMessage};
14/// use snmp_parser::asn1_rs::FromBer;
15///
16/// static SNMPV3_REQ: &[u8] = include_bytes!("../assets/snmpv3_req.bin");
17///
18/// match SnmpGenericMessage::from_ber(&SNMPV3_REQ) {
19///   Ok((_, msg)) => {
20///     match msg {
21///       SnmpGenericMessage::V1(_) => todo!(),
22///       SnmpGenericMessage::V2(_) => todo!(),
23///       SnmpGenericMessage::V3(msgv3) => {
24///         assert!(msgv3.version == 3);
25///         assert!(msgv3.header_data.msg_security_model == SecurityModel::USM);
26///         match msgv3.data {
27///           ScopedPduData::Plaintext(_pdu) => { },
28///           ScopedPduData::Encrypted(_) => (),
29///         }
30///       }
31///     }
32///   },
33///   Err(e) => panic!("{}", e),
34/// }
35/// ```
36#[derive(Debug, PartialEq)]
37pub enum SnmpGenericMessage<'a> {
38    /// SNMP Version 1 (SNMPv1) message
39    V1(SnmpMessage<'a>),
40    /// SNMP Version 2c (SNMPv2c) message
41    V2(SnmpMessage<'a>),
42    /// SNMP Version 3 (SNMPv3) message
43    V3(SnmpV3Message<'a>),
44}
45
46impl<'a> FromBer<'a, SnmpError> for SnmpGenericMessage<'a> {
47    fn from_ber(bytes: &'a [u8]) -> asn1_rs::ParseResult<'a, Self, SnmpError> {
48        let (rem, any) = Any::from_ber(bytes).or(Err(Err::Error(SnmpError::InvalidMessage)))?;
49        if any.tag() != Tag::Sequence {
50            return Err(Err::Error(SnmpError::InvalidMessage));
51        }
52        let (r, version) = u32::from_ber(any.data).map_err(Err::convert)?;
53        let (_, msg) = match version {
54            0 => {
55                let (rem, msg) = parse_snmp_v1_pdu_content(r)?;
56                (rem, SnmpGenericMessage::V1(msg))
57            }
58            1 => {
59                let (rem, msg) = parse_snmp_v2c_pdu_content(r)?;
60                (rem, SnmpGenericMessage::V2(msg))
61            }
62            3 => {
63                let (rem, msg) = parse_snmp_v3_pdu_content(r)?;
64                (rem, SnmpGenericMessage::V3(msg))
65            }
66            _ => return Err(Err::Error(SnmpError::InvalidVersion)),
67        };
68        Ok((rem, msg))
69    }
70}
71
72fn parse_snmp_v1_pdu_content(i: &[u8]) -> IResult<&[u8], SnmpMessage, SnmpError> {
73    let (i, community) = parse_ber_octetstring_as_str(i).map_err(Err::convert)?;
74    let (i, pdu) = parse_snmp_v1_pdu(i)?;
75    let msg = SnmpMessage {
76        version: 0,
77        community: community.to_string(),
78        pdu,
79    };
80    Ok((i, msg))
81}
82
83fn parse_snmp_v2c_pdu_content(i: &[u8]) -> IResult<&[u8], SnmpMessage, SnmpError> {
84    let (i, community) = parse_ber_octetstring_as_str(i).map_err(Err::convert)?;
85    let (i, pdu) = parse_snmp_v2c_pdu(i)?;
86    let msg = SnmpMessage {
87        version: 1,
88        community: community.to_string(),
89        pdu,
90    };
91    Ok((i, msg))
92}
93
94fn parse_snmp_v3_pdu_content(i: &[u8]) -> IResult<&[u8], SnmpV3Message, SnmpError> {
95    let (i, hdr) = parse_snmp_v3_headerdata(i)?;
96    let (i, secp) = map_res(<&[u8]>::from_ber, |x| parse_secp(x, &hdr))(i).map_err(Err::convert)?;
97    let (i, data) = parse_snmp_v3_data(i, &hdr)?;
98    let msg = SnmpV3Message {
99        version: 3,
100        header_data: hdr,
101        security_params: secp,
102        data,
103    };
104    Ok((i, msg))
105}
106
107/// Parse an SNMP messsage, accepting v1, v2c or v3 messages
108///
109/// This function is equivalent to `SnmpGenericMessage::from_ber`
110pub fn parse_snmp_generic_message(i: &[u8]) -> IResult<&[u8], SnmpGenericMessage, SnmpError> {
111    SnmpGenericMessage::from_ber(i)
112}