1use std::net::SocketAddr;
6
7use super::length::decode_length;
8use super::tag;
9use crate::error::internal::DecodeErrorKind;
10use crate::error::{Error, Result, UNKNOWN_TARGET};
11use crate::oid::Oid;
12use bytes::Bytes;
13
14pub struct Decoder {
16 data: Bytes,
17 offset: usize,
18 target: Option<SocketAddr>,
19}
20
21impl Decoder {
22 pub fn new(data: Bytes) -> Self {
24 Self {
25 data,
26 offset: 0,
27 target: None,
28 }
29 }
30
31 pub fn with_target(data: Bytes, target: SocketAddr) -> Self {
33 Self {
34 data,
35 offset: 0,
36 target: Some(target),
37 }
38 }
39
40 #[must_use]
42 pub fn from_slice(data: &[u8]) -> Self {
43 Self::new(Bytes::copy_from_slice(data))
44 }
45
46 fn target(&self) -> SocketAddr {
48 self.target.unwrap_or(UNKNOWN_TARGET)
49 }
50
51 fn malformed(&self) -> Box<crate::error::Error> {
53 Error::MalformedResponse {
54 target: self.target(),
55 }
56 .boxed()
57 }
58
59 pub fn offset(&self) -> usize {
61 self.offset
62 }
63
64 pub fn remaining(&self) -> usize {
66 self.data.len() - self.offset
67 }
68
69 pub fn is_empty(&self) -> bool {
71 self.offset >= self.data.len()
72 }
73
74 pub fn peek_byte(&self) -> Option<u8> {
76 if self.offset < self.data.len() {
77 Some(self.data[self.offset])
78 } else {
79 None
80 }
81 }
82
83 pub fn peek_tag(&self) -> Option<u8> {
89 let byte = self.peek_byte()?;
90 if byte & 0x1F == 0x1F {
91 return None;
92 }
93 Some(byte)
94 }
95
96 pub fn read_byte(&mut self) -> Result<u8> {
98 if self.offset >= self.data.len() {
99 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::TruncatedData }, "truncated data: unexpected end of input");
100 return Err(self.malformed());
101 }
102 let byte = self.data[self.offset];
103 self.offset += 1;
104 Ok(byte)
105 }
106
107 pub fn read_tag(&mut self) -> Result<u8> {
113 let tag = self.read_byte()?;
114 if tag & 0x1F == 0x1F {
115 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset - 1, kind = %DecodeErrorKind::UnexpectedTag { expected: 0, actual: tag } }, "multi-byte tag not supported");
116 return Err(self.malformed());
117 }
118 Ok(tag)
119 }
120
121 pub fn read_length(&mut self) -> Result<usize> {
123 let (len, consumed) = decode_length(&self.data[self.offset..], self.offset, self.target)?;
124 self.offset += consumed;
125 Ok(len)
126 }
127
128 pub fn read_bytes(&mut self, len: usize) -> Result<Bytes> {
130 if self.offset.saturating_add(len) > self.data.len() {
132 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::InsufficientData { needed: len, available: self.remaining() } }, "insufficient data");
133 return Err(self.malformed());
134 }
135 let bytes = self.data.slice(self.offset..self.offset + len);
136 self.offset += len;
137 Ok(bytes)
138 }
139
140 pub fn expect_tag(&mut self, expected: u8) -> Result<usize> {
142 let tag = self.read_tag()?;
143 if tag != expected {
144 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset - 1, kind = %DecodeErrorKind::UnexpectedTag { expected, actual: tag } }, "unexpected tag");
145 return Err(self.malformed());
146 }
147 self.read_length()
148 }
149
150 pub fn read_integer(&mut self) -> Result<i32> {
152 let len = self.expect_tag(tag::universal::INTEGER)?;
153 self.read_integer_value(len)
154 }
155
156 pub(crate) fn read_bounded_integer(&mut self, minimum: i32, maximum: i32) -> Result<i32> {
162 debug_assert!(minimum <= maximum);
163
164 let len = self.expect_tag(tag::universal::INTEGER)?;
165 let value = self.read_signed_integer_value(len)?;
166 if value < i64::from(minimum) || value > i64::from(maximum) {
167 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::IntegerOutOfRange { value, minimum, maximum } }, "integer outside constrained range");
168 return Err(self.malformed());
169 }
170
171 Ok(value as i32)
172 }
173
174 pub fn read_integer_value(&mut self, len: usize) -> Result<i32> {
176 Ok(self.read_signed_integer_value(len)? as i32)
180 }
181
182 fn read_signed_integer_value(&mut self, len: usize) -> Result<i64> {
185 if len == 0 {
186 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::ZeroLengthInteger }, "zero-length integer");
187 return Err(self.malformed());
188 }
189 if len > 8 {
190 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::IntegerTooLong { length: len } }, "integer encoding too long");
192 return Err(self.malformed());
193 }
194
195 let bytes = self.read_bytes(len)?;
196
197 let is_negative = bytes[0] & 0x80 != 0;
200 let mut value: i64 = if is_negative { -1 } else { 0 };
201
202 for &byte in &bytes {
203 value = (value << 8) | i64::from(byte);
204 }
205
206 Ok(value)
207 }
208
209 pub fn read_integer64(&mut self, expected_tag: u8) -> Result<u64> {
211 let len = self.expect_tag(expected_tag)?;
212 self.read_integer64_value(len)
213 }
214
215 pub fn read_integer64_value(&mut self, len: usize) -> Result<u64> {
217 if len == 0 {
218 tracing::warn!(target: "async_snmp::ber", { snmp.offset = %self.offset }, "zero-length Counter64; interpreting as 0");
220 return Ok(0);
221 }
222 if len > 9 {
223 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::Integer64TooLong { length: len } }, "integer64 too long");
225 return Err(self.malformed());
226 }
227
228 let bytes = self.read_bytes(len)?;
229
230 if len == 9 && bytes[0] != 0x00 {
231 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::Integer64MissingLeadingZero }, "9-octet integer64 missing leading zero");
232 return Err(self.malformed());
233 }
234
235 let mut value: u64 = 0;
236
237 for &byte in &bytes {
238 value = (value << 8) | u64::from(byte);
239 }
240
241 Ok(value)
242 }
243
244 pub fn read_unsigned32(&mut self, expected_tag: u8) -> Result<u32> {
246 let len = self.expect_tag(expected_tag)?;
247 self.read_unsigned32_value(len)
248 }
249
250 pub fn read_unsigned32_value(&mut self, len: usize) -> Result<u32> {
252 if len == 0 {
253 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::ZeroLengthInteger }, "zero-length integer");
254 return Err(self.malformed());
255 }
256 if len > 9 {
257 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::Unsigned32TooLong { length: len } }, "unsigned32 encoding too long");
259 return Err(self.malformed());
260 }
261
262 let bytes = self.read_bytes(len)?;
263
264 if len == 9 && bytes[0] != 0x00 {
265 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::Unsigned32MissingLeadingZero }, "9-octet unsigned32 missing leading zero");
266 return Err(self.malformed());
267 }
268
269 let mut value: u64 = 0;
272
273 for &byte in &bytes {
274 value = (value << 8) | u64::from(byte);
275 }
276
277 Ok(value as u32)
278 }
279
280 pub fn read_octet_string(&mut self) -> Result<Bytes> {
282 let len = self.expect_tag(tag::universal::OCTET_STRING)?;
283 self.read_bytes(len)
284 }
285
286 pub fn read_null(&mut self) -> Result<()> {
288 let len = self.expect_tag(tag::universal::NULL)?;
289 if len != 0 {
290 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::InvalidNull }, "NULL with non-zero length");
291 return Err(self.malformed());
292 }
293 Ok(())
294 }
295
296 pub fn read_oid(&mut self) -> Result<Oid> {
298 let len = self.expect_tag(tag::universal::OBJECT_IDENTIFIER)?;
299 let bytes = self.read_bytes(len)?;
300 Oid::from_ber(&bytes)
301 }
302
303 pub fn read_oid_value(&mut self, len: usize) -> Result<Oid> {
305 let bytes = self.read_bytes(len)?;
306 Oid::from_ber(&bytes)
307 }
308
309 pub fn read_sequence(&mut self) -> Result<Decoder> {
311 self.read_constructed(tag::universal::SEQUENCE)
312 }
313
314 pub fn read_constructed(&mut self, expected_tag: u8) -> Result<Decoder> {
316 let len = self.expect_tag(expected_tag)?;
317 let content = self.read_bytes(len)?;
318 Ok(Decoder {
319 data: content,
320 offset: 0,
321 target: self.target,
322 })
323 }
324
325 pub fn read_ip_address(&mut self) -> Result<[u8; 4]> {
327 let len = self.expect_tag(tag::application::IP_ADDRESS)?;
328 if len != 4 {
329 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::InvalidIpAddressLength { length: len } }, "IP address must be 4 bytes");
330 return Err(self.malformed());
331 }
332 let bytes = self.read_bytes(4)?;
333 Ok([bytes[0], bytes[1], bytes[2], bytes[3]])
334 }
335
336 pub fn skip_tlv(&mut self) -> Result<()> {
338 let _tag = self.read_tag()?;
339 let len = self.read_length()?;
340 let new_offset = self.offset.saturating_add(len);
342 if new_offset > self.data.len() {
343 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::TlvOverflow }, "TLV extends past end of data");
344 return Err(self.malformed());
345 }
346 self.offset = new_offset;
347 Ok(())
348 }
349
350 pub fn sub_decoder(&mut self, len: usize) -> Result<Decoder> {
352 let content = self.read_bytes(len)?;
353 Ok(Decoder {
354 data: content,
355 offset: 0,
356 target: self.target,
357 })
358 }
359
360 pub fn as_bytes(&self) -> &Bytes {
362 &self.data
363 }
364
365 pub fn remaining_slice(&self) -> &[u8] {
367 &self.data[self.offset..]
368 }
369}
370
371#[cfg(test)]
372mod tests {
373 use super::*;
374
375 #[test]
376 fn test_decode_integer() {
377 let mut dec = Decoder::from_slice(&[0x02, 0x01, 0x00]);
378 assert_eq!(dec.read_integer().unwrap(), 0);
379
380 let mut dec = Decoder::from_slice(&[0x02, 0x01, 0x7F]);
381 assert_eq!(dec.read_integer().unwrap(), 127);
382
383 let mut dec = Decoder::from_slice(&[0x02, 0x02, 0x00, 0x80]);
384 assert_eq!(dec.read_integer().unwrap(), 128);
385
386 let mut dec = Decoder::from_slice(&[0x02, 0x01, 0xFF]);
387 assert_eq!(dec.read_integer().unwrap(), -1);
388
389 let mut dec = Decoder::from_slice(&[0x02, 0x01, 0x80]);
390 assert_eq!(dec.read_integer().unwrap(), -128);
391 }
392
393 #[test]
394 fn test_decode_null() {
395 let mut dec = Decoder::from_slice(&[0x05, 0x00]);
396 dec.read_null().unwrap();
397 }
398
399 #[test]
400 fn test_decode_octet_string() {
401 let mut dec = Decoder::from_slice(&[0x04, 0x05, b'h', b'e', b'l', b'l', b'o']);
402 let s = dec.read_octet_string().unwrap();
403 assert_eq!(&s[..], b"hello");
404 }
405
406 #[test]
407 fn test_decode_oid() {
408 let mut dec = Decoder::from_slice(&[0x06, 0x03, 0x2B, 0x06, 0x01]);
410 let oid = dec.read_oid().unwrap();
411 assert_eq!(oid.arcs(), &[1, 3, 6, 1]);
412 }
413
414 #[test]
415 fn test_decode_sequence() {
416 let mut dec = Decoder::from_slice(&[0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02]);
418 let mut seq = dec.read_sequence().unwrap();
419 assert_eq!(seq.read_integer().unwrap(), 1);
420 assert_eq!(seq.read_integer().unwrap(), 2);
421 }
422
423 #[test]
424 fn test_accept_non_minimal_integer() {
425 let mut dec = Decoder::from_slice(&[0x02, 0x02, 0x00, 0x01]);
427 assert_eq!(dec.read_integer().unwrap(), 1);
428
429 let mut dec = Decoder::from_slice(&[0x02, 0x02, 0x00, 0x7F]);
431 assert_eq!(dec.read_integer().unwrap(), 127);
432
433 let mut dec = Decoder::from_slice(&[0x02, 0x03, 0x00, 0x00, 0x80]);
435 assert_eq!(dec.read_integer().unwrap(), 128);
436
437 let mut dec = Decoder::from_slice(&[0x02, 0x02, 0xFF, 0xFF]);
439 assert_eq!(dec.read_integer().unwrap(), -1);
440 }
441
442 #[test]
443 fn test_integer_too_long_truncates() {
444 let mut dec = Decoder::from_slice(&[0x02, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05]);
447 assert_eq!(dec.read_integer().unwrap(), 0x02_03_04_05_i32);
448
449 let mut dec =
451 Decoder::from_slice(&[0x02, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]);
452 assert_eq!(dec.read_integer().unwrap(), 0x05_06_07_08_i32);
453
454 let mut dec = Decoder::from_slice(&[
456 0x02, 0x09, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
457 ]);
458 assert!(
459 dec.read_integer().is_err(),
460 "9-byte integer must be rejected"
461 );
462 }
463
464 #[test]
465 fn bounded_integer_rejects_values_that_generic_decode_truncates() {
466 const TWO_TO_32: &[u8] = &[0x02, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00];
467 const NEGATIVE_TWO_TO_32: &[u8] = &[0x02, 0x05, 0xFF, 0x00, 0x00, 0x00, 0x00];
468
469 let mut generic = Decoder::from_slice(TWO_TO_32);
470 assert_eq!(generic.read_integer().unwrap(), 0);
471 let mut bounded = Decoder::from_slice(TWO_TO_32);
472 assert!(bounded.read_bounded_integer(0, i32::MAX).is_err());
473
474 let mut generic = Decoder::from_slice(NEGATIVE_TWO_TO_32);
475 assert_eq!(generic.read_integer().unwrap(), 0);
476 let mut bounded = Decoder::from_slice(NEGATIVE_TWO_TO_32);
477 assert!(bounded.read_bounded_integer(0, i32::MAX).is_err());
478
479 let mut lower_bound = Decoder::from_slice(&[0x02, 0x01, 0x00]);
480 assert_eq!(lower_bound.read_bounded_integer(0, i32::MAX).unwrap(), 0);
481 let mut upper_bound = Decoder::from_slice(&[0x02, 0x04, 0x7F, 0xFF, 0xFF, 0xFF]);
482 assert_eq!(
483 upper_bound.read_bounded_integer(0, i32::MAX).unwrap(),
484 i32::MAX
485 );
486 }
487
488 #[test]
489 fn test_unsigned32_too_long_truncates() {
490 let mut dec = Decoder::from_slice(&[0x42, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
493 assert_eq!(dec.read_unsigned32(0x42).unwrap(), 0x03_04_05_06_u32);
494
495 let mut dec = Decoder::from_slice(&[
497 0x42, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
498 ]);
499 assert_eq!(dec.read_unsigned32(0x42).unwrap(), u32::MAX);
500
501 let mut dec = Decoder::from_slice(&[
503 0x42, 0x0A, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
504 ]);
505 assert!(
506 dec.read_unsigned32(0x42).is_err(),
507 "10-byte unsigned32 must be rejected"
508 );
509 }
510
511 #[test]
512 fn test_zero_length_counter64_accepted() {
513 let mut dec = Decoder::from_slice(&[0x46, 0x00]);
515 let result = dec.read_integer64(0x46);
516 assert!(result.is_ok(), "zero-length Counter64 should be accepted");
517 assert_eq!(result.unwrap(), 0);
518 }
519
520 #[test]
521 fn test_counter64_nine_bytes_requires_leading_zero() {
522 let mut dec = Decoder::from_slice(&[
525 0x46, 0x09, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
526 ]);
527 let result = dec.read_integer64(0x46);
528 assert!(
529 result.is_err(),
530 "expected error for 9-byte Counter64 without leading zero"
531 );
532
533 let mut dec = Decoder::from_slice(&[
535 0x46, 0x09, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
536 ]);
537 let result = dec.read_integer64(0x46);
538 assert!(
539 result.is_ok(),
540 "expected success for 9-byte Counter64 with leading zero"
541 );
542 assert_eq!(result.unwrap(), u64::MAX);
543 }
544
545 #[test]
546 fn test_unsigned32_nine_bytes_requires_leading_zero() {
547 let mut dec = Decoder::from_slice(&[
549 0x42, 0x09, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
550 ]);
551 assert!(
552 dec.read_unsigned32(0x42).is_err(),
553 "9-byte unsigned32 without leading zero must be rejected"
554 );
555
556 let mut dec = Decoder::from_slice(&[
558 0x42, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
559 ]);
560 assert_eq!(dec.read_unsigned32(0x42).unwrap(), u32::MAX);
561
562 let mut dec = Decoder::from_slice(&[0x42, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00]);
564 assert_eq!(dec.read_unsigned32(0x42).unwrap(), 0u32);
565 }
566
567 #[test]
568 fn test_read_bytes_rejects_oversized_length() {
569 let mut dec = Decoder::from_slice(&[0x01, 0x02, 0x03]);
571 let result = dec.read_bytes(100);
573 assert!(result.is_err());
574 let err = result.unwrap_err();
575 assert!(
576 matches!(*err, crate::error::Error::MalformedResponse { .. }),
577 "expected MalformedResponse error, got {err:?}"
578 );
579 }
580
581 #[test]
582 fn test_skip_tlv_rejects_oversized_length() {
583 let mut dec = Decoder::from_slice(&[0x04, 0x82, 0x01, 0x00, 0xAA, 0xBB, 0xCC]);
586 let result = dec.skip_tlv();
587 assert!(result.is_err());
588 let err = result.unwrap_err();
589 assert!(
590 matches!(*err, crate::error::Error::MalformedResponse { .. }),
591 "expected MalformedResponse error, got {err:?}"
592 );
593 }
594
595 #[test]
596 fn test_read_tag_rejects_multi_byte_tag() {
597 let mut dec = Decoder::from_slice(&[0x1F, 0x02, 0x00]);
600 let result = dec.read_tag();
601 assert!(result.is_err());
602 let err = result.unwrap_err();
603 assert!(
604 matches!(*err, crate::error::Error::MalformedResponse { .. }),
605 "expected MalformedResponse error for multi-byte tag, got {err:?}"
606 );
607
608 let mut dec = Decoder::from_slice(&[0x3F, 0x02, 0x00]);
610 let result = dec.read_tag();
611 assert!(result.is_err());
612
613 let mut dec = Decoder::from_slice(&[0x9F, 0x02, 0x00]);
615 let result = dec.read_tag();
616 assert!(result.is_err());
617
618 let mut dec = Decoder::from_slice(&[0x02, 0x01, 0x00]);
620 let result = dec.read_tag();
621 assert!(result.is_ok());
622 assert_eq!(result.unwrap(), 0x02);
623 }
624
625 #[test]
626 fn test_peek_tag_rejects_multi_byte_tag() {
627 let dec = Decoder::from_slice(&[0x1F, 0x02, 0x00]);
629 let result = dec.peek_tag();
630 assert!(
631 result.is_none(),
632 "peek_tag should return None for multi-byte tag"
633 );
634
635 let dec = Decoder::from_slice(&[0x30, 0x00]);
637 let result = dec.peek_tag();
638 assert_eq!(result, Some(0x30));
639 }
640}