Skip to main content

rasn_snmp/
v2.rs

1//! Version 2 (RFC 3416)
2use rasn::prelude::*;
3
4pub use smi::v2::{IpAddress, ObjectName, ObjectSyntax, TimeTicks};
5
6#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
7#[rasn(choice)]
8pub enum Pdus {
9    GetRequest(GetRequest),
10    GetNextRequest(GetNextRequest),
11    Response(Response),
12    SetRequest(SetRequest),
13    GetBulkRequest(GetBulkRequest),
14    InformRequest(InformRequest),
15    Trap(Trap),
16    Report(Report),
17}
18
19#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
20#[rasn(tag(0))]
21#[rasn(delegate)]
22pub struct GetRequest(pub Pdu);
23
24#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
25#[rasn(tag(1))]
26#[rasn(delegate)]
27pub struct GetNextRequest(pub Pdu);
28
29#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
30#[rasn(tag(2))]
31#[rasn(delegate)]
32pub struct Response(pub Pdu);
33
34#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
35#[rasn(tag(3))]
36#[rasn(delegate)]
37pub struct SetRequest(pub Pdu);
38
39#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
40#[rasn(tag(5))]
41#[rasn(delegate)]
42pub struct GetBulkRequest(pub BulkPdu);
43
44#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
45#[rasn(tag(6))]
46#[rasn(delegate)]
47pub struct InformRequest(pub Pdu);
48
49#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
50#[rasn(tag(7))]
51#[rasn(delegate)]
52pub struct Trap(pub Pdu);
53
54#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
55#[rasn(tag(8))]
56#[rasn(delegate)]
57pub struct Report(pub Pdu);
58
59#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
60pub struct Pdu {
61    pub request_id: i32,
62    pub error_status: u32,
63    pub error_index: u32,
64    pub variable_bindings: VarBindList,
65}
66
67impl Pdu {
68    pub const ERROR_STATUS_NO_ERROR: u32 = 0;
69    pub const ERROR_STATUS_TOO_BIG: u32 = 1;
70    pub const ERROR_STATUS_NO_SUCH_NAME: u32 = 2;
71    pub const ERROR_STATUS_BAD_VALUE: u32 = 3;
72    pub const ERROR_STATUS_READ_ONLY: u32 = 4;
73    pub const ERROR_STATUS_GEN_ERR: u32 = 5;
74    pub const ERROR_STATUS_NO_ACCESS: u32 = 6;
75    pub const ERROR_STATUS_WRONG_TYPE: u32 = 7;
76    pub const ERROR_STATUS_WRONG_LENGTH: u32 = 8;
77    pub const ERROR_STATUS_WRONG_ENCODING: u32 = 9;
78    pub const ERROR_STATUS_WRONG_VALUE: u32 = 10;
79    pub const ERROR_STATUS_NO_CREATION: u32 = 11;
80    pub const ERROR_STATUS_INCONSISTENT_VALUE: u32 = 12;
81    pub const ERROR_STATUS_RESOURCE_UNAVAILABLE: u32 = 13;
82    pub const ERROR_STATUS_COMMIT_FAILED: u32 = 14;
83    pub const ERROR_STATUS_UNDO_FAILED: u32 = 15;
84    pub const ERROR_STATUS_AUTHORIZATION_ERROR: u32 = 16;
85    pub const ERROR_STATUS_NOT_WRITABLE: u32 = 17;
86    pub const ERROR_STATUS_INCONSISTENT_NAME: u32 = 18;
87}
88
89#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
90pub struct BulkPdu {
91    pub request_id: i32,
92    pub non_repeaters: u32,
93    pub max_repetitions: u32,
94    pub variable_bindings: VarBindList,
95}
96
97pub type VarBindList = alloc::vec::Vec<VarBind>;
98
99#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
100pub struct VarBind {
101    pub name: ObjectName,
102    pub value: VarBindValue,
103}
104
105#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)]
106#[rasn(choice)]
107pub enum VarBindValue {
108    Value(ObjectSyntax),
109    Unspecified,
110    #[rasn(tag(0))]
111    NoSuchObject,
112    #[rasn(tag(1))]
113    NoSuchInstance,
114    #[rasn(tag(2))]
115    EndOfMibView,
116}
117
118#[cfg(test)]
119mod tests {
120    use pretty_assertions::assert_eq;
121
122    use super::*;
123    use alloc::vec;
124    use rasn::types::ObjectIdentifier;
125    use smi::v2::SimpleSyntax;
126
127    #[test]
128    fn encode_decode_response() {
129        let request = crate::v2c::Message {
130            version: 1.into(),
131            community: "public".as_bytes().into(),
132            data: Response(Pdu {
133                request_id: 1414684022,
134                error_status: Pdu::ERROR_STATUS_NO_ERROR,
135                error_index: 0,
136                variable_bindings: vec![
137                    VarBind {
138                        name: ObjectIdentifier::new_unchecked(
139                            vec![1, 3, 6, 1, 2, 1, 2, 2, 1, 1, 12].into(),
140                        ),
141                        value: VarBindValue::NoSuchInstance,
142                    },
143                    VarBind {
144                        name: ObjectIdentifier::new_unchecked(
145                            vec![1, 3, 6, 1, 2, 1, 2, 2, 1, 1, 13].into(),
146                        ),
147                        value: VarBindValue::Value(ObjectSyntax::Simple(SimpleSyntax::Integer(
148                            6.into(),
149                        ))),
150                    },
151                ],
152            }),
153        };
154
155        #[rustfmt::skip]
156        let expected_data: &[u8] = &[
157            //    SEQUENCE {
158            //       INTEGER 0x01 (1 decimal)
159            //       OCTETSTRING 7075626C6963
160            //       [2] {
161            //          INTEGER 0x54525D76 (1414684022 decimal)
162            //          INTEGER 0x00 (0 decimal)
163            //          INTEGER 0x00 (0 decimal)
164            //          SEQUENCE {
165            //             SEQUENCE {
166            //                OBJECTIDENTIFIER 1.3.6.1.2.2.1.1.12
167            //                [1]
168            //             }
169            //             SEQUENCE {
170            //                OBJECTIDENTIFIER 1.3.6.1.2.2.1.1.13
171            //                INTEGER 0x06 (6 decimal)
172            //             }
173            //          }
174            //       }
175            //    }
176
177            // SEQUENCE -> Message
178            0x30, 0x3C,
179
180            // INTEGER -> Message::version
181            0x02, 0x01,
182
183            // OCTET STRING -> Message::community
184            0x01, 0x04,
185
186                // "public"
187                0x06, 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63,
188
189            // application constructed tag 2 -> Response
190            0xA2, 0x2F,
191
192                // INTEGER -> request_id
193                0x02, 0x04, 0x54, 0x52, 0x5D, 0x76,
194
195                // INTEGER -> error_status
196                0x02, 0x01, 0x00,
197
198                // INTEGER -> error_index
199                0x02, 0x01, 0x00,
200
201                // SEQUENCE -> VarBindList
202                0x30, 0x21,
203
204                    // VarBind Name
205                    0x30, 0x0E,
206                        // OBJECTIDENTIFIER 1.3.6.1.2.2.1.1.13
207                        0x06, 0x0A, 0x2B, 0x06, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, 0x0C,
208
209                        // VarBind Value NoSuchInstance
210                        0x81, 0x00,
211
212                    // VarBind Name
213                    0x30, 0x0F,
214                        // OBJECTIDENTIFIER 1.3.6.1.2.2.1.1.13
215                        0x06, 0x0A, 0x2B, 0x06, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, 0x0D,
216
217                        // INTEGER 0x06 (6 decimal)
218                        0x02, 0x01, 0x06,
219        ];
220
221        // Encode Response message into BER
222        let encoded_data = rasn::ber::encode(&request).unwrap();
223        assert_eq!(encoded_data, expected_data);
224
225        // Decode object from BER
226        let decoded_request = rasn::ber::decode(&encoded_data);
227
228        assert!(decoded_request.is_ok());
229        assert_eq!(request, decoded_request.unwrap());
230    }
231
232    #[test]
233    fn get_bulk_request() {
234        let request = GetBulkRequest(BulkPdu {
235            request_id: 1414684022,
236            non_repeaters: 1,
237            max_repetitions: 2,
238            variable_bindings: vec![
239                VarBind {
240                    name: ObjectIdentifier::new_unchecked(vec![1, 3, 6, 1, 2, 1, 1, 3].into()),
241                    value: VarBindValue::Unspecified,
242                },
243                VarBind {
244                    name: ObjectIdentifier::new_unchecked(
245                        vec![1, 3, 6, 1, 2, 1, 4, 0x16, 1, 2].into(),
246                    ),
247                    value: VarBindValue::Unspecified,
248                },
249                VarBind {
250                    name: ObjectIdentifier::new_unchecked(
251                        vec![1, 3, 6, 1, 2, 1, 4, 0x16, 1, 4].into(),
252                    ),
253                    value: VarBindValue::Unspecified,
254                },
255            ],
256        });
257
258        let data = rasn::ber::encode(&request).unwrap();
259
260        rasn::ber::decode::<GetBulkRequest>(&data).unwrap();
261        assert_eq!(
262            data,
263            vec![
264                // [5] IMPLICIT SEEQUENCE
265                0xA5, 0x39, // INTEGER
266                0x02, 0x04, 0x54, 0x52, 0x5d, 0x76, // INTEGER
267                0x02, 0x01, 0x01, // INTEGER
268                0x02, 0x01, 0x02, // SEQUENCE
269                0x30, 0x2b, // SEQUENCE
270                0x30, 0x0b, // OBJECT IDENTIFIER
271                0x06, 0x07, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x03, // NULL
272                0x05, 0x00, // SEQUENCE
273                0x30, 0x0d, // OBJECT IDENTIFIER
274                0x06, 0x09, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x04, 0x16, 0x01, 0x02, // NULL
275                0x05, 0x00, // SEQUENCE
276                0x30, 0x0d, // OBJECT IDENTIFIER
277                0x06, 0x09, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x04, 0x16, 0x01, 0x04, // NULL
278                0x05, 0x00,
279            ]
280        );
281    }
282}