snmp/
lib.rs

1// Copyright 2016 Hroi Sigurdsson
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! # RUST-SNMP
10//! Dependency-free basic SNMPv2 client in Rust.
11//!
12//! Suppports:
13//!
14//! - GET
15//! - GETNEXT
16//! - GETBULK
17//! - SET
18//! - Basic SNMPv2 types
19//! - Synchronous requests
20//! - UDP transport
21//!
22//! Currently does not support:
23//!
24//! - SNMPv1
25//! - SNMPv3
26//! - MIBs
27//! - Async requests
28//! - Transports other than UDP
29//!
30//! ## TODO
31//! - Async requests
32//! - Walking function
33//! - Additional `ObjectIdentifier` utility methods
34//! - Decouple PDU building/parsing from socket handling
35//! - SNMPv3 (would require an external dependency)
36//!
37
38//! # Examples
39//!
40//! ## GET NEXT
41//! ```no_run
42//! use std::time::Duration;
43//! use snmp::{SyncSession, Value};
44//!
45//! let sys_descr_oid = &[1,3,6,1,2,1,1,1,];
46//! let agent_addr    = "198.51.100.123:161";
47//! let community     = b"f00b4r";
48//! let timeout       = Duration::from_secs(2);
49//!
50//! let mut sess = SyncSession::new(agent_addr, community, Some(timeout), 0).unwrap();
51//! let mut response = sess.getnext(sys_descr_oid).unwrap();
52//! if let Some((_oid, Value::OctetString(sys_descr))) = response.varbinds.next() {
53//!     println!("myrouter sysDescr: {}", String::from_utf8_lossy(sys_descr));
54//! }
55//! ```
56//! ## GET BULK
57//! ```no_run
58//! use std::time::Duration;
59//! use snmp::SyncSession;
60//!
61//! let system_oid      = &[1,3,6,1,2,1,1,];
62//! let agent_addr      = "[2001:db8:f00:b413::abc]:161";
63//! let community       = b"f00b4r";
64//! let timeout         = Duration::from_secs(2);
65//! let non_repeaters   = 0;
66//! let max_repetitions = 7; // number of items in "system" OID
67//!
68//! let mut sess = SyncSession::new(agent_addr, community, Some(timeout), 0).unwrap();
69//! let response = sess.getbulk(&[system_oid], non_repeaters, max_repetitions).unwrap();
70//!
71//! for (name, val) in response.varbinds {
72//!     println!("{} => {:?}", name, val);
73//! }
74//! ```
75//! ## SET
76//! ```no_run
77//! use std::time::Duration;
78//! use snmp::{SyncSession, Value};
79//!
80//! let syscontact_oid  = &[1,3,6,1,2,1,1,4,0];
81//! let contact         = Value::OctetString(b"Thomas A. Anderson");
82//! let agent_addr      = "[2001:db8:f00:b413::abc]:161";
83//! let community       = b"f00b4r";
84//! let timeout         = Duration::from_secs(2);
85//!
86//! let mut sess = SyncSession::new(agent_addr, community, Some(timeout), 0).unwrap();
87//! let response = sess.set(&[(syscontact_oid, contact)]).unwrap();
88//!
89//! assert_eq!(response.error_status, snmp::snmp::ERRSTATUS_NOERROR);
90//! for (name, val) in response.varbinds {
91//!     println!("{} => {:?}", name, val);
92//! }
93//! ```
94
95#![cfg_attr(feature = "private-tests", feature(test))]
96#![allow(unknown_lints, doc_markdown)]
97
98use std::fmt;
99use std::io;
100use std::mem;
101use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs, UdpSocket};
102use std::num::Wrapping;
103use std::ptr;
104use std::time::Duration;
105
106#[cfg(target_pointer_width="32")]
107const USIZE_LEN: usize = 4;
108#[cfg(target_pointer_width="64")]
109const USIZE_LEN: usize = 8;
110
111#[cfg(test)]
112mod tests;
113
114#[derive(Debug, PartialEq)]
115pub enum SnmpError {
116    AsnParseError,
117    AsnInvalidLen,
118    AsnWrongType,
119    AsnUnsupportedType,
120    AsnEof,
121    AsnIntOverflow,
122
123    UnsupportedVersion,
124    RequestIdMismatch,
125    CommunityMismatch,
126    ValueOutOfRange,
127
128    SendError,
129    ReceiveError,
130}
131
132type SnmpResult<T> = Result<T, SnmpError>;
133
134const BUFFER_SIZE: usize = 4096;
135
136pub mod asn1 {
137    #![allow(dead_code, identity_op, eq_op)]
138
139    pub const PRIMITIVE:             u8 = 0b00000000;
140    pub const CONSTRUCTED:           u8 = 0b00100000;
141
142    pub const CLASS_UNIVERSAL:       u8 = 0b00000000;
143    pub const CLASS_APPLICATION:     u8 = 0b01000000;
144    pub const CLASS_CONTEXTSPECIFIC: u8 = 0b10000000;
145    pub const CLASS_PRIVATE:         u8 = 0b11000000;
146
147    pub const TYPE_BOOLEAN:          u8 = CLASS_UNIVERSAL | PRIMITIVE   |  1;
148    pub const TYPE_INTEGER:          u8 = CLASS_UNIVERSAL | PRIMITIVE   |  2;
149    pub const TYPE_OCTETSTRING:      u8 = CLASS_UNIVERSAL | PRIMITIVE   |  4;
150    pub const TYPE_NULL:             u8 = CLASS_UNIVERSAL | PRIMITIVE   |  5;
151    pub const TYPE_OBJECTIDENTIFIER: u8 = CLASS_UNIVERSAL | PRIMITIVE   |  6;
152    pub const TYPE_SEQUENCE:         u8 = CLASS_UNIVERSAL | CONSTRUCTED | 16;
153    pub const TYPE_SET:              u8 = CLASS_UNIVERSAL | CONSTRUCTED | 17;
154}
155
156pub mod snmp {
157    #![allow(dead_code, identity_op, eq_op)]
158
159    use super::asn1;
160
161    pub const VERSION_2:    i64 = 1;
162
163    pub const MSG_GET:      u8 = asn1::CLASS_CONTEXTSPECIFIC | asn1::CONSTRUCTED | 0;
164    pub const MSG_GET_NEXT: u8 = asn1::CLASS_CONTEXTSPECIFIC | asn1::CONSTRUCTED | 1;
165    pub const MSG_RESPONSE: u8 = asn1::CLASS_CONTEXTSPECIFIC | asn1::CONSTRUCTED | 2;
166    pub const MSG_SET:      u8 = asn1::CLASS_CONTEXTSPECIFIC | asn1::CONSTRUCTED | 3;
167    pub const MSG_GET_BULK: u8 = asn1::CLASS_CONTEXTSPECIFIC | asn1::CONSTRUCTED | 5;
168    pub const MSG_INFORM:   u8 = asn1::CLASS_CONTEXTSPECIFIC | asn1::CONSTRUCTED | 6;
169    pub const MSG_TRAP:     u8 = asn1::CLASS_CONTEXTSPECIFIC | asn1::CONSTRUCTED | 7;
170    pub const MSG_REPORT:   u8 = asn1::CLASS_CONTEXTSPECIFIC | asn1::CONSTRUCTED | 8;
171
172    pub const TYPE_IPADDRESS:  u8 = asn1::CLASS_APPLICATION | 0;
173    pub const TYPE_COUNTER32:  u8 = asn1::CLASS_APPLICATION | 1;
174    pub const TYPE_UNSIGNED32: u8 = asn1::CLASS_APPLICATION | 2;
175    pub const TYPE_GAUGE32:    u8 = TYPE_UNSIGNED32;
176    pub const TYPE_TIMETICKS:  u8 = asn1::CLASS_APPLICATION | 3;
177    pub const TYPE_OPAQUE:     u8 = asn1::CLASS_APPLICATION | 4;
178    pub const TYPE_COUNTER64:  u8 = asn1::CLASS_APPLICATION | 6;
179
180    pub const ERRSTATUS_NOERROR:             u32 =  0;
181    pub const ERRSTATUS_TOOBIG:              u32 =  1;
182    pub const ERRSTATUS_NOSUCHNAME:          u32 =  2;
183    pub const ERRSTATUS_BADVALUE:            u32 =  3;
184    pub const ERRSTATUS_READONLY:            u32 =  4;
185    pub const ERRSTATUS_GENERR:              u32 =  5;
186    pub const ERRSTATUS_NOACCESS:            u32 =  6;
187    pub const ERRSTATUS_WRONGTYPE:           u32 =  7;
188    pub const ERRSTATUS_WRONGLENGTH:         u32 =  8;
189    pub const ERRSTATUS_WRONGENCODING:       u32 =  9;
190    pub const ERRSTATUS_WRONGVALUE:          u32 = 10;
191    pub const ERRSTATUS_NOCREATION:          u32 = 11;
192    pub const ERRSTATUS_INCONSISTENTVALUE:   u32 = 12;
193    pub const ERRSTATUS_RESOURCEUNAVAILABLE: u32 = 13;
194    pub const ERRSTATUS_COMMITFAILED:        u32 = 14;
195    pub const ERRSTATUS_UNDOFAILED:          u32 = 15;
196    pub const ERRSTATUS_AUTHORIZATIONERROR:  u32 = 16;
197    pub const ERRSTATUS_NOTWRITABLE:         u32 = 17;
198    pub const ERRSTATUS_INCONSISTENTNAME:    u32 = 18;
199}
200
201pub mod pdu {
202    use super::{BUFFER_SIZE, USIZE_LEN, asn1, snmp, Value};
203    use std::{fmt, mem, ops, ptr};
204
205    pub struct Buf {
206        len: usize,
207        buf: [u8; BUFFER_SIZE],
208    }
209
210    impl fmt::Debug for Buf {
211        fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
212            fmt.debug_list()
213                .entries(&self[..])
214                .finish()
215        }
216    }
217
218    impl Default for Buf {
219        fn default() -> Buf {
220            Buf {
221                len: 0,
222                buf: unsafe { mem::uninitialized() },
223            }
224        }
225    }
226
227    impl ops::Deref for Buf {
228        type Target = [u8];
229        fn deref(&self) -> &[u8] {
230            &self.buf[BUFFER_SIZE - self.len..]
231        }
232    }
233
234    impl Buf {
235
236        fn available(&mut self) -> &mut [u8] {
237            &mut self.buf[..(BUFFER_SIZE - self.len)]
238        }
239
240        fn push_chunk(&mut self, chunk: &[u8]) {
241            let offset = BUFFER_SIZE - self.len;
242            self.buf[(offset - chunk.len())..offset].copy_from_slice(chunk);
243            self.len += chunk.len();
244        }
245
246        fn push_byte(&mut self, byte: u8) {
247            self.buf[BUFFER_SIZE - self.len - 1] = byte;
248            self.len += 1;
249        }
250
251        fn reset(&mut self) {
252            self.len = 0;
253        }
254
255        fn scribble_bytes<F>(&mut self, mut f: F)
256            where F: FnMut(&mut [u8]) -> usize
257        {
258            let scribbled = f(self.available());
259            self.len += scribbled;
260        }
261
262        fn push_constructed<F>(&mut self, ident: u8, mut f: F)
263            where F: FnMut(&mut Self)
264        {
265            let before_len = self.len;
266            f(self);
267            let written = self.len - before_len;
268            self.push_length(written);
269            self.push_byte(ident);
270        }
271
272        fn push_sequence<F>(&mut self, f: F)
273            where F: FnMut(&mut Self)
274        {
275            self.push_constructed(asn1::TYPE_SEQUENCE, f)
276        }
277
278        // fn push_set<F>(&mut self, f: F)
279        //     where F: FnMut(&mut Self)
280        // {
281        //     self.push_constructed(asn1::TYPE_SET, f)
282        // }
283
284        fn push_length(&mut self, len: usize) {
285            if len < 128 {
286                // short form
287                self.push_byte(len as u8);
288            } else {
289                // long form
290                let num_leading_nulls = (len.leading_zeros() / 8) as usize;
291                let length_len = mem::size_of::<usize>() - num_leading_nulls;
292                let leading_byte = length_len as u8 | 0b1000_0000;
293                self.scribble_bytes(|o| {
294                    assert!(o.len() >= length_len + 1);
295                    let bytes = unsafe { mem::transmute::<usize, [u8; USIZE_LEN]>(len.to_be()) };
296                    let write_offset = o.len() - length_len - 1;
297                    o[write_offset] = leading_byte;
298                    o[write_offset + 1..].copy_from_slice(&bytes[num_leading_nulls..]);
299                    length_len + 1
300                });
301            }
302        }
303
304        fn push_integer(&mut self, n: i64) {
305            let len = self.push_i64(n);
306            self.push_length(len);
307            self.push_byte(asn1::TYPE_INTEGER);
308        }
309
310        fn push_counter32(&mut self, n: u32) {
311            let len = self.push_i64(n as i64);
312            self.push_length(len);
313            self.push_byte(snmp::TYPE_COUNTER32);
314        }
315
316        fn push_unsigned32(&mut self, n: u32) {
317            let len = self.push_i64(n as i64);
318            self.push_length(len);
319            self.push_byte(snmp::TYPE_UNSIGNED32);
320        }
321
322        fn push_timeticks(&mut self, n: u32) {
323            let len = self.push_i64(n as i64);
324            self.push_length(len);
325            self.push_byte(snmp::TYPE_TIMETICKS);
326        }
327
328        fn push_opaque(&mut self, bytes: &[u8]) {
329            self.push_chunk(bytes);
330            self.push_length(bytes.len());
331            self.push_byte(snmp::TYPE_OPAQUE);
332        }
333
334        fn push_counter64(&mut self, n: u64) {
335            let len = self.push_i64(n as i64);
336            self.push_length(len);
337            self.push_byte(snmp::TYPE_COUNTER64);
338        }
339
340        fn push_i64(&mut self, mut n: i64) -> usize {
341            let (null, num_null_bytes) = if !n.is_negative() {
342                (0x00u8, (n.leading_zeros() / 8) as usize)
343            } else {
344                (0xffu8, ((!n).leading_zeros() / 8) as usize)
345            };
346            n = n.to_be();
347            let count = unsafe {
348                let mut wbuf = self.available();
349                let mut src_ptr = &n as *const i64 as *const u8;
350                let mut dst_ptr = wbuf.as_mut_ptr()
351                    .offset((wbuf.len() - mem::size_of::<i64>()) as isize);
352                let mut count = mem::size_of::<i64>() - num_null_bytes;
353                if count == 0 {
354                    count = 1;
355                }
356                // preserve sign
357                if (*(src_ptr.offset((mem::size_of::<i64>() - count) as isize)) ^ null) > 127u8 {
358                    count += 1;
359                }
360                assert!(wbuf.len() >= count);
361                let offset = (mem::size_of::<i64>() - count) as isize;
362                src_ptr = src_ptr.offset(offset);
363                dst_ptr = dst_ptr.offset(offset);
364                ptr::copy_nonoverlapping(src_ptr, dst_ptr, count);
365                count
366            };
367            self.len += count;
368            count
369        }
370
371        fn push_boolean(&mut self, boolean: bool) {
372            if boolean == true {
373                self.push_byte(0x1);
374            }  else {
375                self.push_byte(0x0);
376            }
377            self.push_length(1);
378            self.push_byte(asn1::TYPE_BOOLEAN);
379        }
380
381        fn push_ipaddress(&mut self, ip: &[u8; 4]) {
382            self.push_chunk(ip);
383            self.push_length(ip.len());
384            self.push_byte(snmp::TYPE_IPADDRESS);
385        }
386
387        fn push_null(&mut self) {
388            self.push_chunk(&[asn1::TYPE_NULL, 0]);
389        }
390
391        fn push_object_identifier_raw(&mut self, input: &[u8]) {
392            self.push_chunk(input);
393            self.push_length(input.len());
394            self.push_byte(asn1::TYPE_OBJECTIDENTIFIER);
395        }
396
397        fn push_object_identifier(&mut self, input: &[u32]) {
398            assert!(input.len() >= 2);
399            let length_before = self.len;
400
401            self.scribble_bytes(|output| {
402                let mut pos = output.len() - 1;
403                let (head, tail) = input.split_at(2);
404                assert!(head[0] < 3 && head[1] < 40);
405
406                // encode the subids in reverse order
407                for subid in tail.iter().rev() {
408                    let mut subid = *subid;
409                    let mut last_byte = true;
410                    loop {
411                        assert!(pos != 0);
412                        if last_byte {
413                            // continue bit is cleared
414                            output[pos] = (subid & 0b01111111) as u8;
415                            last_byte = false;
416                        } else {
417                            // continue bit is set
418                            output[pos] = (subid | 0b10000000) as u8;
419                        }
420                        pos -= 1;
421                        subid >>= 7;
422
423                        if subid == 0 {
424                            break;
425                        }
426                    }
427                }
428
429                // encode the head last
430                output[pos] = (head[0] * 40 + head[1]) as u8;
431                output.len() - pos
432            });
433            let length_after = self.len;
434            self.push_length(length_after - length_before);
435            self.push_byte(asn1::TYPE_OBJECTIDENTIFIER);
436        }
437
438        fn push_octet_string(&mut self, bytes: &[u8]) {
439            self.push_chunk(bytes);
440            self.push_length(bytes.len());
441            self.push_byte(asn1::TYPE_OCTETSTRING);
442        }
443    }
444
445    pub fn build_get(community: &[u8], req_id: i32, name: &[u32], buf: &mut Buf) {
446        buf.reset();
447        buf.push_sequence(|buf| {
448            buf.push_constructed(snmp::MSG_GET, |buf| {
449                buf.push_sequence(|buf| {
450                    buf.push_sequence(|buf| {
451                        buf.push_null(); // value
452                        buf.push_object_identifier(name); // name
453                    })
454                });
455                buf.push_integer(0); // error index
456                buf.push_integer(0); // error status
457                buf.push_integer(req_id as i64);
458            });
459            buf.push_octet_string(community);
460            buf.push_integer(snmp::VERSION_2 as i64);
461        });
462    }
463
464    pub fn build_getnext(community: &[u8], req_id: i32, name: &[u32], buf: &mut Buf) {
465        buf.reset();
466        buf.push_sequence(|buf| {
467            buf.push_constructed(snmp::MSG_GET_NEXT, |buf| {
468                buf.push_sequence(|buf| {
469                    buf.push_sequence(|buf| {
470                        buf.push_null(); // value
471                        buf.push_object_identifier(name); // name
472                    })
473                });
474                buf.push_integer(0); // error index
475                buf.push_integer(0); // error status
476                buf.push_integer(req_id as i64);
477            });
478            buf.push_octet_string(community);
479            buf.push_integer(snmp::VERSION_2 as i64);
480        });
481    }
482
483    pub fn build_getbulk(community: &[u8], req_id: i32, names: &[&[u32]],
484                         non_repeaters: u32, max_repetitions: u32, buf: &mut Buf) {
485        buf.reset();
486        buf.push_sequence(|buf| {
487            buf.push_constructed(snmp::MSG_GET_BULK, |buf| {
488                buf.push_sequence(|buf| {
489                    for name in names.iter().rev() {
490                        buf.push_sequence(|buf| {
491                            buf.push_null(); // value
492                            buf.push_object_identifier(name); // name
493                        });
494                    }
495                });
496                buf.push_integer(max_repetitions as i64);
497                buf.push_integer(non_repeaters as i64);
498                buf.push_integer(req_id as i64);
499            });
500            buf.push_octet_string(community);
501            buf.push_integer(snmp::VERSION_2 as i64);
502        });
503    }
504
505    pub fn build_set(community: &[u8], req_id: i32, values: &[(&[u32], Value)], buf: &mut Buf) {
506        buf.reset();
507        buf.push_sequence(|buf| {
508            buf.push_constructed(snmp::MSG_SET, |buf| {
509                buf.push_sequence(|buf| {
510                    for &(ref name, ref val) in values.iter().rev() {
511                        buf.push_sequence(|buf| {
512                            use Value::*;
513                            match *val {
514                                Boolean(b)                  => buf.push_boolean(b),
515                                Null                        => buf.push_null(),
516                                Integer(i)                  => buf.push_integer(i),
517                                OctetString(ostr)           => buf.push_octet_string(ostr),
518                                ObjectIdentifier(ref objid) => buf.push_object_identifier_raw(objid.raw()),
519                                IpAddress(ref ip)           => buf.push_ipaddress(ip),
520                                Counter32(i)                => buf.push_counter32(i),
521                                Unsigned32(i)               => buf.push_unsigned32(i),
522                                Timeticks(tt)               => buf.push_timeticks(tt),
523                                Opaque(bytes)               => buf.push_opaque(bytes),
524                                Counter64(i)                => buf.push_counter64(i),
525                                _ => unimplemented!(),
526                            }
527                            buf.push_object_identifier(name); // name
528                        });
529                    }
530                });
531                buf.push_integer(0);
532                buf.push_integer(0);
533                buf.push_integer(req_id as i64);
534            });
535            buf.push_octet_string(community);
536            buf.push_integer(snmp::VERSION_2 as i64);
537        });
538    }
539}
540
541fn decode_i64(i: &[u8]) -> SnmpResult<i64> {
542    if i.len() > mem::size_of::<i64>() {
543        return Err(SnmpError::AsnIntOverflow);
544    }
545    let mut bytes = [0u8; 8];
546    bytes[(mem::size_of::<i64>() - i.len())..].copy_from_slice(i);
547
548    let mut ret = unsafe { mem::transmute::<[u8; 8], i64>(bytes).to_be()};
549    {
550        //sign extend
551        let shift_amount = (mem::size_of::<i64>() - i.len()) * 8;
552        ret = (ret << shift_amount) >> shift_amount;
553    }
554    Ok(ret)
555}
556
557/// Wrapper around raw bytes representing an ASN.1 OBJECT IDENTIFIER.
558#[derive(PartialEq)]
559pub struct ObjectIdentifier<'a> {
560    inner: &'a [u8],
561}
562
563impl<'a> fmt::Debug for ObjectIdentifier<'a> {
564    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
565        f.debug_list().entries(self.inner).finish()
566    }
567}
568
569pub type ObjIdBuf = [u32; 128];
570
571impl<'a> fmt::Display for ObjectIdentifier<'a> {
572    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
573        let mut buf: ObjIdBuf = unsafe { mem::uninitialized() };
574        let mut first = true;
575        match self.read_name(&mut buf) {
576            Ok(name) => {
577                for subid in name {
578                    if first {
579                        first = false;
580                        f.write_fmt(format_args!("{}", subid))?;
581                    } else {
582                        f.write_fmt(format_args!(".{}", subid))?;
583                    }
584                }
585                Ok(())
586            }
587            Err(err) => f.write_fmt(format_args!("Invalid OID: {:?}", err))
588        }
589    }
590}
591
592impl<'a> PartialEq<[u32]> for ObjectIdentifier<'a> {
593    fn eq(&self, other: &[u32]) -> bool {
594        let mut buf: ObjIdBuf = unsafe { mem::uninitialized() };
595        if let Ok(name) = self.read_name(&mut buf) {
596            name == other
597        } else {
598            false
599        }
600    }
601}
602
603impl<'a, 'b> PartialEq<&'b [u32]> for ObjectIdentifier<'a> {
604    fn eq(&self, other: &&[u32]) -> bool {
605        self == *other
606    }
607}
608
609impl<'a> ObjectIdentifier<'a> {
610    fn from_bytes(bytes: &[u8]) -> ObjectIdentifier {
611        ObjectIdentifier {
612            inner: bytes,
613        }
614    }
615
616    /// Reads out the OBJECT IDENTIFIER sub-IDs as a slice of u32s.
617    /// Caller must provide storage for 128 sub-IDs.
618    pub fn read_name<'b>(&self, out: &'b mut ObjIdBuf) -> SnmpResult<&'b [u32]> {
619        let input = self.inner;
620        let output = &mut out[..];
621        if input.len() < 2 {
622            return Err(SnmpError::AsnInvalidLen);
623        }
624        let subid1 = (input[0] / 40) as u32;
625        let subid2 = (input[0] % 40) as u32;
626        output[0] = subid1;
627        output[1] = subid2;
628        let mut pos = 2;
629        let mut cur_oid: u32 = 0;
630        let mut is_done = false;
631        for b in &input[1..] {
632            if pos == output.len() {
633                return Err(SnmpError::AsnEof);
634            }
635            is_done = b & 0b10000000 == 0;
636            let val = b & 0b01111111;
637            cur_oid = cur_oid.checked_shl(7).ok_or(SnmpError::AsnIntOverflow)?;
638            cur_oid |= val as u32;
639            if is_done {
640                output[pos] = cur_oid;
641                pos += 1;
642                cur_oid = 0;
643            }
644        }
645        if !is_done {
646            Err(SnmpError::AsnParseError)
647        } else {
648            Ok(&output[..pos])
649        }
650    }
651
652    pub fn raw(&self) -> &'a [u8] {
653        self.inner
654    }
655}
656
657/// ASN.1/DER decoder iterator.
658///
659/// Supports:
660///
661/// - types required by SNMP.
662///
663/// Does not support:
664///
665/// - extended tag IDs.
666/// - indefinite lengths (disallowed by DER).
667/// - INTEGER values not representable by i64.
668pub struct AsnReader<'a> {
669    inner: &'a [u8],
670}
671
672impl<'a> Clone for AsnReader<'a> {
673    fn clone(&self) -> AsnReader<'a> {
674        AsnReader {
675            inner: self.inner,
676        }
677    }
678}
679
680impl<'a> fmt::Debug for AsnReader<'a> {
681    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
682        f.debug_list().entries(self.clone()).finish()
683    }
684}
685
686impl<'a> AsnReader<'a> {
687
688    pub fn from_bytes(bytes: &[u8]) -> AsnReader {
689        AsnReader {inner: bytes}
690    }
691
692    pub fn peek_byte(&mut self) -> SnmpResult<u8> {
693        if self.inner.is_empty() {
694            Err(SnmpError::AsnEof)
695        } else {
696            Ok(self.inner[0])
697        }
698    }
699
700    pub fn read_byte(&mut self) -> SnmpResult<u8> {
701        match self.inner.split_first() {
702            Some((head, tail)) => {
703                self.inner = tail;
704                Ok(*head)
705            }
706            _ => Err(SnmpError::AsnEof)
707        }
708    }
709
710    pub fn read_length(&mut self) -> SnmpResult<usize> {
711        if let Some((head, tail)) = self.inner.split_first() {
712            let o: usize;
713            if head < &128 {
714                // short form
715                o = *head as usize;
716                self.inner = tail;
717                Ok(o)
718            } else if head == &0xff {
719                Err(SnmpError::AsnInvalidLen) // reserved for future use
720            } else {
721                // long form
722                let length_len = (*head & 0b01111111) as usize;
723                if length_len == 0 {
724                    // Indefinite length. Not allowed in DER.
725                    return Err(SnmpError::AsnInvalidLen);
726                }
727
728                let mut bytes = [0u8; USIZE_LEN];
729                bytes[(USIZE_LEN - length_len)..]
730                    .copy_from_slice(&tail[..length_len]);
731
732                o = unsafe { mem::transmute::<[u8; USIZE_LEN], usize>(bytes).to_be()};
733                self.inner = &tail[length_len as usize..];
734                Ok(o)
735            }
736        } else {
737            Err(SnmpError::AsnEof)
738        }
739    }
740
741    pub fn read_i64_type(&mut self, expected_ident: u8) -> SnmpResult<i64> {
742        let ident = self.read_byte()?;
743        if ident != expected_ident {
744            return Err(SnmpError::AsnWrongType);
745        }
746        let val_len = self.read_length()?;
747        if val_len > self.inner.len() {
748            return Err(SnmpError::AsnInvalidLen);
749        }
750        let (val, remaining) = self.inner.split_at(val_len);
751        self.inner = remaining;
752        decode_i64(val)
753    }
754
755    pub fn read_raw(&mut self, expected_ident: u8) -> SnmpResult<&'a [u8]> {
756        let ident = self.read_byte()?;
757        if ident != expected_ident {
758            return Err(SnmpError::AsnWrongType);
759        }
760        let val_len = self.read_length()?;
761        if val_len > self.inner.len() {
762            return Err(SnmpError::AsnInvalidLen);
763        }
764        let (val, remaining) = self.inner.split_at(val_len);
765        self.inner = remaining;
766        Ok(val)
767    }
768
769    pub fn read_constructed<F>(&mut self, expected_ident: u8, f: F) -> SnmpResult<()>
770        where F: Fn(&mut AsnReader) -> SnmpResult<()>
771    {
772        let ident = self.read_byte()?;
773        if ident != expected_ident {
774            return Err(SnmpError::AsnWrongType);
775        }
776        let seq_len = self.read_length()?;
777        if seq_len > self.inner.len() {
778            return Err(SnmpError::AsnInvalidLen);
779        }
780        let (seq_bytes, remaining) = self.inner.split_at(seq_len);
781        let mut reader = AsnReader::from_bytes(seq_bytes);
782        self.inner = remaining;
783        f(&mut reader)
784    }
785
786    //
787    // ASN
788    //
789
790    pub fn read_asn_boolean(&mut self) -> SnmpResult<bool> {
791        let ident = self.read_byte()?;
792        if ident != asn1::TYPE_NULL {
793            return Err(SnmpError::AsnWrongType);
794        }
795        let val_len = self.read_length()?;
796        if val_len != 1 {
797            return Err(SnmpError::AsnInvalidLen);
798        }
799        match self.read_byte()? {
800            0 => Ok(false),
801            1 => Ok(true),
802            _ => Err(SnmpError::AsnParseError), // DER mandates 1/0 for booleans
803        }
804    }
805
806    pub fn read_asn_integer(&mut self) -> SnmpResult<i64> {
807        self.read_i64_type(asn1::TYPE_INTEGER)
808    }
809
810    pub fn read_asn_octetstring(&mut self) -> SnmpResult<&'a [u8]> {
811        self.read_raw(asn1::TYPE_OCTETSTRING)
812    }
813
814    pub fn read_asn_null(&mut self) -> SnmpResult<()> {
815        let ident = self.read_byte()?;
816        if ident != asn1::TYPE_NULL {
817            return Err(SnmpError::AsnWrongType);
818        }
819        let null_len = self.read_length()?;
820        if null_len != 0 {
821            Err(SnmpError::AsnInvalidLen)
822        } else {
823            Ok(())
824        }
825    }
826
827    pub fn read_asn_objectidentifier(&mut self) -> SnmpResult<ObjectIdentifier<'a>> {
828        let ident = self.read_byte()?;
829        if ident != asn1::TYPE_OBJECTIDENTIFIER {
830            return Err(SnmpError::AsnWrongType);
831        }
832        let val_len = self.read_length()?;
833        if val_len > self.inner.len() {
834            return Err(SnmpError::AsnInvalidLen);
835        }
836        let (input, remaining) = self.inner.split_at(val_len);
837        self.inner = remaining;
838
839        Ok(ObjectIdentifier::from_bytes(input))
840    }
841
842    pub fn read_asn_sequence<F>(&mut self, f: F) -> SnmpResult<()>
843        where F: Fn(&mut AsnReader) -> SnmpResult<()>
844    {
845        self.read_constructed(asn1::TYPE_SEQUENCE, f)
846    }
847
848    // fn read_asn_set<F>(&mut self, f: F) -> SnmpResult<()>
849    //     where F: Fn(&mut AsnReader) -> SnmpResult<()>
850    // {
851    //     self.read_constructed(asn1::TYPE_SET, f)
852    // }
853
854    //
855    // SNMP
856    //
857
858    pub fn read_snmp_counter32(&mut self) -> SnmpResult<u32> {
859        self.read_i64_type(snmp::TYPE_COUNTER32).map(|v| v as u32)
860    }
861
862    pub fn read_snmp_unsigned32(&mut self) -> SnmpResult<u32> {
863        self.read_i64_type(snmp::TYPE_UNSIGNED32).map(|v| v as u32)
864    }
865
866    pub fn read_snmp_timeticks(&mut self) -> SnmpResult<u32> {
867        self.read_i64_type(snmp::TYPE_TIMETICKS).map(|v| v as u32)
868    }
869
870    pub fn read_snmp_counter64(&mut self) -> SnmpResult<u64> {
871        self.read_i64_type(snmp::TYPE_COUNTER64).map(|v| v as u64)
872    }
873
874    pub fn read_snmp_opaque(&mut self) -> SnmpResult<&'a [u8]> {
875        self.read_raw(snmp::TYPE_OPAQUE)
876    }
877
878    pub fn read_snmp_ipaddress(&mut self) -> SnmpResult<[u8; 4]> {
879        //let mut ip = [0u8; 4];
880        let val = self.read_raw(snmp::TYPE_IPADDRESS)?;
881        if val.len() != 4 {
882            return Err(SnmpError::AsnInvalidLen);
883        }
884        //&mut ip[..].copy_from_slice(val);
885        //Ok(ip)
886        unsafe { Ok(ptr::read(val.as_ptr() as *const _)) }
887    }
888
889    // fn read_snmp_get<F>(&mut self, f: F) -> SnmpResult<()>
890    //     where F: Fn(&mut AsnReader) -> SnmpResult<()>
891    // {
892    //     self.read_constructed(snmp::MSG_GET, f)
893    // }
894
895    // fn read_snmp_getnext<F>(&mut self, f: F) -> SnmpResult<()>
896    //     where F: Fn(&mut AsnReader) -> SnmpResult<()>
897    // {
898    //     self.read_constructed(snmp::MSG_GET_NEXT, f)
899    // }
900
901    // fn read_snmp_getbulk<F>(&mut self, f: F) -> SnmpResult<()>
902    //     where F: Fn(&mut AsnReader) -> SnmpResult<()>
903    // {
904    //     self.read_constructed(snmp::MSG_GET_BULK, f)
905    // }
906
907    // fn read_snmp_response<F>(&mut self, f: F) -> SnmpResult<()>
908    //     where F: Fn(&mut AsnReader) -> SnmpResult<()>
909    // {
910    //     self.read_constructed(snmp::MSG_RESPONSE, f)
911    // }
912
913    // fn read_snmp_inform<F>(&mut self, f: F) -> SnmpResult<()>
914    //     where F: Fn(&mut AsnReader) -> SnmpResult<()>
915    // {
916    //     self.read_constructed(snmp::MSG_INFORM, f)
917    // }
918
919    // fn read_snmp_report<F>(&mut self, f: F) -> SnmpResult<()>
920    //     where F: Fn(&mut AsnReader) -> SnmpResult<()>
921    // {
922    //     self.read_constructed(snmp::MSG_REPORT, f)
923    // }
924
925    // fn read_snmp_set<F>(&mut self, f: F) -> SnmpResult<()>
926    //     where F: Fn(&mut AsnReader) -> SnmpResult<()>
927    // {
928    //     self.read_constructed(snmp::MSG_SET, f)
929    // }
930
931    // fn read_snmp_trap<F>(&mut self, f: F) -> SnmpResult<()>
932    //     where F: Fn(&mut AsnReader) -> SnmpResult<()>
933    // {
934    //     self.read_constructed(snmp::MSG_TRAP, f)
935    // }
936
937}
938
939
940pub enum Value<'a> {
941    Boolean(bool),
942    Null,
943    Integer(i64),
944    OctetString(&'a [u8]),
945    ObjectIdentifier(ObjectIdentifier<'a>),
946    Sequence(AsnReader<'a>),
947    Set(AsnReader<'a>),
948    Constructed(u8, AsnReader<'a>),
949
950    IpAddress([u8;4]),
951    Counter32(u32),
952    Unsigned32(u32),
953    Timeticks(u32),
954    Opaque(&'a [u8]),
955    Counter64(u64),
956
957    SnmpGetRequest(AsnReader<'a>),
958    SnmpGetNextRequest(AsnReader<'a>),
959    SnmpGetBulkRequest(AsnReader<'a>),
960    SnmpResponse(AsnReader<'a>),
961    SnmpSetRequest(AsnReader<'a>),
962    SnmpInformRequest(AsnReader<'a>),
963    SnmpTrap(AsnReader<'a>),
964    SnmpReport(AsnReader<'a>),
965}
966
967impl<'a> fmt::Debug for Value<'a> {
968    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
969        use Value::*;
970        match *self {
971            Boolean(v)                   => write!(f, "BOOLEAN: {}", v),
972            Integer(n)                   => write!(f, "INTEGER: {}", n),
973            OctetString(slice)           => write!(f, "OCTET STRING: {}", String::from_utf8_lossy(slice)),
974            ObjectIdentifier(ref obj_id) => write!(f, "OBJECT IDENTIFIER: {}", obj_id),
975            Null                         => write!(f, "NULL"),
976            Sequence(ref val)            => write!(f, "SEQUENCE: {:#?}", val),
977            Set(ref val)                 => write!(f, "SET: {:?}", val),
978            Constructed(ident, ref val)  => write!(f, "CONSTRUCTED-{}: {:#?}", ident, val),
979
980            IpAddress(val)               => write!(f, "IP ADDRESS: {}.{}.{}.{}", val[0], val[1], val[2], val[3]),
981            Counter32(val)               => write!(f, "COUNTER32: {}", val),
982            Unsigned32(val)              => write!(f, "UNSIGNED32: {}", val),
983            Timeticks(val)               => write!(f, "TIMETICKS: {}", val),
984            Opaque(val)                  => write!(f, "OPAQUE: {:?}", val),
985            Counter64(val)               => write!(f, "COUNTER64: {}", val),
986
987            SnmpGetRequest(ref val)      => write!(f, "SNMP GET REQUEST: {:#?}", val),
988            SnmpGetNextRequest(ref val)  => write!(f, "SNMP GET NEXT REQUEST: {:#?}", val),
989            SnmpGetBulkRequest(ref val)  => write!(f, "SNMP GET BULK REQUEST: {:#?}", val),
990            SnmpResponse(ref val)        => write!(f, "SNMP RESPONSE: {:#?}", val),
991            SnmpSetRequest(ref val)      => write!(f, "SNMP SET REQUEST: {:#?}", val),
992            SnmpInformRequest(ref val)   => write!(f, "SNMP INFORM REQUEST: {:#?}", val),
993            SnmpTrap(ref val)            => write!(f, "SNMP TRAP: {:#?}", val),
994            SnmpReport(ref val)          => write!(f, "SNMP REPORT: {:#?}", val),
995        }
996    }
997}
998
999impl<'a> Iterator for AsnReader<'a> {
1000    type Item = Value<'a>;
1001
1002    fn next(&mut self) -> Option<Value<'a>> {
1003        use Value::*;
1004        if let Ok(ident) = self.peek_byte() {
1005            let ret: SnmpResult<Value> = match ident {
1006                asn1::TYPE_BOOLEAN          => self.read_asn_boolean().map(Boolean),
1007                asn1::TYPE_NULL             => self.read_asn_null().map(|_| Null),
1008                asn1::TYPE_INTEGER          => self.read_asn_integer().map(Integer),
1009                asn1::TYPE_OCTETSTRING      => self.read_asn_octetstring().map(OctetString),
1010                asn1::TYPE_OBJECTIDENTIFIER => self.read_asn_objectidentifier().map(ObjectIdentifier),
1011                asn1::TYPE_SEQUENCE         => self.read_raw(ident).map(|v| Sequence(AsnReader::from_bytes(v))),
1012                asn1::TYPE_SET              => self.read_raw(ident).map(|v| Set(AsnReader::from_bytes(v))),
1013                snmp::TYPE_IPADDRESS        => self.read_snmp_ipaddress().map(IpAddress),
1014                snmp::TYPE_COUNTER32        => self.read_snmp_counter32().map(Counter32),
1015                snmp::TYPE_UNSIGNED32       => self.read_snmp_unsigned32().map(Unsigned32),
1016                snmp::TYPE_TIMETICKS        => self.read_snmp_timeticks().map(Timeticks),
1017                snmp::TYPE_OPAQUE           => self.read_snmp_opaque().map(Opaque),
1018                snmp::TYPE_COUNTER64        => self.read_snmp_counter64().map(Counter64),
1019                snmp::MSG_GET               => self.read_raw(ident).map(|v| SnmpGetRequest(AsnReader::from_bytes(v))),
1020                snmp::MSG_GET_NEXT          => self.read_raw(ident).map(|v| SnmpGetNextRequest(AsnReader::from_bytes(v))),
1021                snmp::MSG_GET_BULK          => self.read_raw(ident).map(|v| SnmpGetBulkRequest(AsnReader::from_bytes(v))),
1022                snmp::MSG_RESPONSE          => self.read_raw(ident).map(|v| SnmpResponse(AsnReader::from_bytes(v))),
1023                snmp::MSG_SET               => self.read_raw(ident).map(|v| SnmpSetRequest(AsnReader::from_bytes(v))),
1024                snmp::MSG_INFORM            => self.read_raw(ident).map(|v| SnmpInformRequest(AsnReader::from_bytes(v))),
1025                snmp::MSG_TRAP              => self.read_raw(ident).map(|v| SnmpTrap(AsnReader::from_bytes(v))),
1026                snmp::MSG_REPORT            => self.read_raw(ident).map(|v| SnmpReport(AsnReader::from_bytes(v))),
1027                ident if ident & asn1::CONSTRUCTED == asn1::CONSTRUCTED =>
1028                                              self.read_raw(ident).map(|v| Constructed(ident, AsnReader::from_bytes(v))),
1029                _ =>                          Err(SnmpError::AsnUnsupportedType),
1030            };
1031            ret.ok()
1032        } else {
1033            None
1034        }
1035    }
1036}
1037
1038/// Synchronous SNMPv2 client.
1039pub struct SyncSession {
1040    socket: UdpSocket,
1041    community: Vec<u8>,
1042    req_id: Wrapping<i32>,
1043    send_pdu: pdu::Buf,
1044    recv_buf: [u8; BUFFER_SIZE],
1045}
1046
1047impl SyncSession {
1048    pub fn new<SA>(destination: SA, community: &[u8], timeout: Option<Duration>, starting_req_id: i32) -> io::Result<Self>
1049        where SA: ToSocketAddrs
1050    {
1051        let socket = match destination.to_socket_addrs()?.next() {
1052            Some(SocketAddr::V4(_)) => UdpSocket::bind((Ipv4Addr::new(0,0,0,0), 0))?,
1053            Some(SocketAddr::V6(_)) => UdpSocket::bind((Ipv6Addr::new(0,0,0,0,0,0,0,0), 0))?,
1054            None => panic!("empty list of socket addrs"),
1055        };
1056        socket.set_read_timeout(timeout)?;
1057        socket.connect(destination)?;
1058        Ok(SyncSession {
1059            socket: socket,
1060            community: community.to_vec(),
1061            req_id: Wrapping(starting_req_id),
1062            send_pdu: pdu::Buf::default(),
1063            recv_buf: [0; 4096],
1064        })
1065    }
1066
1067    fn send_and_recv(socket: &UdpSocket, pdu: &pdu::Buf, out: &mut [u8]) -> SnmpResult<usize> {
1068        if let Ok(_pdu_len) = socket.send(&pdu[..]) {
1069            match socket.recv(out) {
1070                Ok(len) => Ok(len),
1071                Err(_) => Err(SnmpError::ReceiveError)
1072            }
1073        } else {
1074            Err(SnmpError::SendError)
1075        }
1076    }
1077
1078    pub fn get(&mut self, name: &[u32]) -> SnmpResult<SnmpPdu> {
1079        let req_id = self.req_id.0;
1080        pdu::build_get(self.community.as_slice(), req_id, name, &mut self.send_pdu);
1081        let recv_len = Self::send_and_recv(&self.socket, &self.send_pdu, &mut self.recv_buf[..])?;
1082        self.req_id += Wrapping(1);
1083        let pdu_bytes = &self.recv_buf[..recv_len];
1084        let resp = SnmpPdu::from_bytes(pdu_bytes)?;
1085        if resp.message_type != SnmpMessageType::Response {
1086            return Err(SnmpError::AsnWrongType);
1087        }
1088        if resp.req_id != req_id {
1089            return Err(SnmpError::RequestIdMismatch);
1090        }
1091        if resp.community != &self.community[..] {
1092            return Err(SnmpError::CommunityMismatch);
1093        }
1094        Ok(resp)
1095    }
1096
1097    pub fn getnext(&mut self, name: &[u32]) -> SnmpResult<SnmpPdu> {
1098        let req_id = self.req_id.0;
1099        pdu::build_getnext(self.community.as_slice(), req_id, name, &mut self.send_pdu);
1100        let recv_len = Self::send_and_recv(&self.socket, &self.send_pdu, &mut self.recv_buf[..])?;
1101        self.req_id += Wrapping(1);
1102        let pdu_bytes = &self.recv_buf[..recv_len];
1103        let resp = SnmpPdu::from_bytes(pdu_bytes)?;
1104        if resp.message_type != SnmpMessageType::Response {
1105            return Err(SnmpError::AsnWrongType);
1106        }
1107        if resp.req_id != req_id {
1108            return Err(SnmpError::RequestIdMismatch);
1109        }
1110        if resp.community != &self.community[..] {
1111            return Err(SnmpError::CommunityMismatch);
1112        }
1113        Ok(resp)
1114    }
1115
1116    pub fn getbulk(&mut self, names: &[&[u32]], non_repeaters: u32, max_repetitions: u32) -> SnmpResult<SnmpPdu> {
1117        let req_id = self.req_id.0;
1118        pdu::build_getbulk(self.community.as_slice(), req_id, names, non_repeaters, max_repetitions, &mut self.send_pdu);
1119        let recv_len = Self::send_and_recv(&self.socket, &self.send_pdu, &mut self.recv_buf[..])?;
1120        self.req_id += Wrapping(1);
1121        let pdu_bytes = &self.recv_buf[..recv_len];
1122        let resp = SnmpPdu::from_bytes(pdu_bytes)?;
1123        if resp.message_type != SnmpMessageType::Response {
1124            return Err(SnmpError::AsnWrongType);
1125        }
1126        if resp.req_id != req_id {
1127            return Err(SnmpError::RequestIdMismatch);
1128        }
1129        if resp.community != &self.community[..] {
1130            return Err(SnmpError::CommunityMismatch);
1131        }
1132        Ok(resp)
1133    }
1134
1135    /// # Panics if any of the values are not one of these supported types:
1136    ///   - `Boolean`
1137    ///   - `Null`
1138    ///   - `Integer`
1139    ///   - `OctetString`
1140    ///   - `ObjectIdentifier`
1141    ///   - `IpAddress`
1142    ///   - `Counter32`
1143    ///   - `Unsigned32`
1144    ///   - `Timeticks`
1145    ///   - `Opaque`
1146    ///   - `Counter64`
1147    pub fn set(&mut self, values: &[(&[u32], Value)]) -> SnmpResult<SnmpPdu> {
1148        let req_id = self.req_id.0;
1149        pdu::build_set(self.community.as_slice(), req_id, values, &mut self.send_pdu);
1150        let recv_len = Self::send_and_recv(&self.socket, &self.send_pdu, &mut self.recv_buf[..])?;
1151        self.req_id += Wrapping(1);
1152        let pdu_bytes = &self.recv_buf[..recv_len];
1153        let resp = SnmpPdu::from_bytes(pdu_bytes)?;
1154        if resp.message_type != SnmpMessageType::Response {
1155            return Err(SnmpError::AsnWrongType);
1156        }
1157        if resp.req_id != req_id {
1158            return Err(SnmpError::RequestIdMismatch);
1159        }
1160        if resp.community != &self.community[..] {
1161            return Err(SnmpError::CommunityMismatch);
1162        }
1163        Ok(resp)
1164    }
1165}
1166
1167#[derive(Debug)]
1168pub struct SnmpPdu<'a> {
1169    version: i64,
1170    community: &'a [u8],
1171    pub message_type: SnmpMessageType,
1172    pub req_id: i32,
1173    pub error_status: u32,
1174    pub error_index: u32,
1175    pub varbinds: Varbinds<'a>,
1176}
1177
1178impl<'a> SnmpPdu<'a> {
1179    pub fn from_bytes(bytes: &'a [u8]) -> SnmpResult<SnmpPdu<'a>> {
1180        let seq = AsnReader::from_bytes(bytes).read_raw(asn1::TYPE_SEQUENCE)?;
1181        let mut rdr = AsnReader::from_bytes(seq);
1182        let version = rdr.read_asn_integer()?;
1183        if version != snmp::VERSION_2 {
1184            return Err(SnmpError::UnsupportedVersion);
1185        }
1186        let community = rdr.read_asn_octetstring()?;
1187        let ident = rdr.peek_byte()?;
1188        let message_type = SnmpMessageType::from_ident(ident)?;
1189
1190        let mut response_pdu = AsnReader::from_bytes(rdr.read_raw(ident)?);
1191
1192        let req_id = response_pdu.read_asn_integer()?;
1193        if req_id < i32::min_value() as i64 || req_id > i32::max_value() as i64 {
1194            return Err(SnmpError::ValueOutOfRange);
1195        }
1196
1197        let error_status = response_pdu.read_asn_integer()?;
1198        if error_status < 0 || error_status > i32::max_value() as i64 {
1199            return Err(SnmpError::ValueOutOfRange);
1200        }
1201
1202        let error_index = response_pdu.read_asn_integer()?;
1203        if error_index < 0 || error_index > i32::max_value() as i64 {
1204            return Err(SnmpError::ValueOutOfRange);
1205        }
1206
1207        let varbind_bytes = response_pdu.read_raw(asn1::TYPE_SEQUENCE)?;
1208        let varbinds = Varbinds::from_bytes(varbind_bytes);
1209
1210        Ok(
1211            SnmpPdu {
1212                version: version,
1213                community: community,
1214                message_type: message_type,
1215                req_id: req_id as i32,
1216                error_status: error_status as u32,
1217                error_index: error_index as u32,
1218                varbinds: varbinds,
1219            }
1220        )
1221    }
1222}
1223
1224#[derive(Debug, PartialEq)]
1225pub enum SnmpMessageType {
1226    GetRequest,
1227    GetNextRequest,
1228    GetBulkRequest,
1229    Response,
1230    SetRequest,
1231    InformRequest,
1232    Trap,
1233    Report,
1234}
1235
1236impl SnmpMessageType {
1237    pub fn from_ident(ident: u8) -> SnmpResult<SnmpMessageType> {
1238        use SnmpMessageType::*;
1239        Ok(
1240            match ident {
1241                snmp::MSG_GET      => GetRequest,
1242                snmp::MSG_GET_NEXT => GetNextRequest,
1243                snmp::MSG_GET_BULK => GetBulkRequest,
1244                snmp::MSG_RESPONSE => Response,
1245                snmp::MSG_SET      => SetRequest,
1246                snmp::MSG_INFORM   => InformRequest,
1247                snmp::MSG_TRAP     => Trap,
1248                snmp::MSG_REPORT   => Report,
1249                _ => return Err(SnmpError::AsnWrongType),
1250            }
1251        )
1252    }
1253}
1254
1255#[derive(Clone)]
1256pub struct Varbinds<'a> {
1257    inner:  AsnReader<'a>,
1258}
1259
1260impl<'a> fmt::Debug for Varbinds<'a> {
1261    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1262        // f.debug_list().entries(self.clone()).finish()
1263        let mut ds = f.debug_struct("Varbinds");
1264        for (name, val) in self.clone() {
1265            ds.field(&format!("{}", name), &format!("{:?}", val));
1266        }
1267        ds.finish()
1268    }
1269}
1270
1271impl<'a> Varbinds<'a> {
1272    fn from_bytes(bytes: &'a [u8]) -> Varbinds<'a> {
1273        Varbinds {
1274            inner: AsnReader::from_bytes(bytes)
1275        }
1276    }
1277}
1278
1279impl<'a> Iterator for Varbinds<'a> {
1280    type Item = (ObjectIdentifier<'a>, Value<'a>);
1281    fn next(&mut self) -> Option<Self::Item> {
1282        if let Ok(seq) = self.inner.read_raw(asn1::TYPE_SEQUENCE) {
1283            let mut pair = AsnReader::from_bytes(seq);
1284            if let (Ok(name), Some(value)) = (pair.read_asn_objectidentifier(), pair.next()) {
1285                return Some((name, value));
1286            }
1287        }
1288        None
1289    }
1290}