1#![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_length(&mut self, len: usize) {
285 if len < 128 {
286 self.push_byte(len as u8);
288 } else {
289 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 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 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 output[pos] = (subid & 0b01111111) as u8;
415 last_byte = false;
416 } else {
417 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 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(); buf.push_object_identifier(name); })
454 });
455 buf.push_integer(0); buf.push_integer(0); 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(); buf.push_object_identifier(name); })
473 });
474 buf.push_integer(0); buf.push_integer(0); 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(); buf.push_object_identifier(name); });
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); });
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 let shift_amount = (mem::size_of::<i64>() - i.len()) * 8;
552 ret = (ret << shift_amount) >> shift_amount;
553 }
554 Ok(ret)
555}
556
557#[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 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
657pub 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 o = *head as usize;
716 self.inner = tail;
717 Ok(o)
718 } else if head == &0xff {
719 Err(SnmpError::AsnInvalidLen) } else {
721 let length_len = (*head & 0b01111111) as usize;
723 if length_len == 0 {
724 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 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), }
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 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 val = self.read_raw(snmp::TYPE_IPADDRESS)?;
881 if val.len() != 4 {
882 return Err(SnmpError::AsnInvalidLen);
883 }
884 unsafe { Ok(ptr::read(val.as_ptr() as *const _)) }
887 }
888
889 }
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
1038pub 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 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 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}