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 fn read_integer_value(&mut self, len: usize) -> Result<i32> {
158 if len == 0 {
159 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::ZeroLengthInteger }, "zero-length integer");
160 return Err(self.malformed());
161 }
162 if len > 8 {
163 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::IntegerTooLong { length: len } }, "integer encoding too long");
165 return Err(self.malformed());
166 }
167
168 let bytes = self.read_bytes(len)?;
169
170 let is_negative = bytes[0] & 0x80 != 0;
173 let mut value: i64 = if is_negative { -1 } else { 0 };
174
175 for &byte in &bytes {
176 value = (value << 8) | i64::from(byte);
177 }
178
179 Ok(value as i32)
180 }
181
182 pub fn read_integer64(&mut self, expected_tag: u8) -> Result<u64> {
184 let len = self.expect_tag(expected_tag)?;
185 self.read_integer64_value(len)
186 }
187
188 pub fn read_integer64_value(&mut self, len: usize) -> Result<u64> {
190 if len == 0 {
191 tracing::warn!(target: "async_snmp::ber", { snmp.offset = %self.offset }, "zero-length Counter64; interpreting as 0");
193 return Ok(0);
194 }
195 if len > 9 {
196 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::Integer64TooLong { length: len } }, "integer64 too long");
198 return Err(self.malformed());
199 }
200
201 let bytes = self.read_bytes(len)?;
202
203 if len == 9 && bytes[0] != 0x00 {
204 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::Integer64MissingLeadingZero }, "9-octet integer64 missing leading zero");
205 return Err(self.malformed());
206 }
207
208 let mut value: u64 = 0;
209
210 for &byte in &bytes {
211 value = (value << 8) | u64::from(byte);
212 }
213
214 Ok(value)
215 }
216
217 pub fn read_unsigned32(&mut self, expected_tag: u8) -> Result<u32> {
219 let len = self.expect_tag(expected_tag)?;
220 self.read_unsigned32_value(len)
221 }
222
223 pub fn read_unsigned32_value(&mut self, len: usize) -> Result<u32> {
225 if len == 0 {
226 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::ZeroLengthInteger }, "zero-length integer");
227 return Err(self.malformed());
228 }
229 if len > 9 {
230 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::Unsigned32TooLong { length: len } }, "unsigned32 encoding too long");
232 return Err(self.malformed());
233 }
234
235 let bytes = self.read_bytes(len)?;
236
237 if len == 9 && bytes[0] != 0x00 {
238 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::Unsigned32MissingLeadingZero }, "9-octet unsigned32 missing leading zero");
239 return Err(self.malformed());
240 }
241
242 let mut value: u64 = 0;
245
246 for &byte in &bytes {
247 value = (value << 8) | u64::from(byte);
248 }
249
250 Ok(value as u32)
251 }
252
253 pub fn read_octet_string(&mut self) -> Result<Bytes> {
255 let len = self.expect_tag(tag::universal::OCTET_STRING)?;
256 self.read_bytes(len)
257 }
258
259 pub fn read_null(&mut self) -> Result<()> {
261 let len = self.expect_tag(tag::universal::NULL)?;
262 if len != 0 {
263 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::InvalidNull }, "NULL with non-zero length");
264 return Err(self.malformed());
265 }
266 Ok(())
267 }
268
269 pub fn read_oid(&mut self) -> Result<Oid> {
271 let len = self.expect_tag(tag::universal::OBJECT_IDENTIFIER)?;
272 let bytes = self.read_bytes(len)?;
273 Oid::from_ber(&bytes)
274 }
275
276 pub fn read_oid_value(&mut self, len: usize) -> Result<Oid> {
278 let bytes = self.read_bytes(len)?;
279 Oid::from_ber(&bytes)
280 }
281
282 pub fn read_sequence(&mut self) -> Result<Decoder> {
284 self.read_constructed(tag::universal::SEQUENCE)
285 }
286
287 pub fn read_constructed(&mut self, expected_tag: u8) -> Result<Decoder> {
289 let len = self.expect_tag(expected_tag)?;
290 let content = self.read_bytes(len)?;
291 Ok(Decoder {
292 data: content,
293 offset: 0,
294 target: self.target,
295 })
296 }
297
298 pub fn read_ip_address(&mut self) -> Result<[u8; 4]> {
300 let len = self.expect_tag(tag::application::IP_ADDRESS)?;
301 if len != 4 {
302 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::InvalidIpAddressLength { length: len } }, "IP address must be 4 bytes");
303 return Err(self.malformed());
304 }
305 let bytes = self.read_bytes(4)?;
306 Ok([bytes[0], bytes[1], bytes[2], bytes[3]])
307 }
308
309 pub fn skip_tlv(&mut self) -> Result<()> {
311 let _tag = self.read_tag()?;
312 let len = self.read_length()?;
313 let new_offset = self.offset.saturating_add(len);
315 if new_offset > self.data.len() {
316 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::TlvOverflow }, "TLV extends past end of data");
317 return Err(self.malformed());
318 }
319 self.offset = new_offset;
320 Ok(())
321 }
322
323 pub fn sub_decoder(&mut self, len: usize) -> Result<Decoder> {
325 let content = self.read_bytes(len)?;
326 Ok(Decoder {
327 data: content,
328 offset: 0,
329 target: self.target,
330 })
331 }
332
333 pub fn as_bytes(&self) -> &Bytes {
335 &self.data
336 }
337
338 pub fn remaining_slice(&self) -> &[u8] {
340 &self.data[self.offset..]
341 }
342}
343
344#[cfg(test)]
345mod tests {
346 use super::*;
347
348 #[test]
349 fn test_decode_integer() {
350 let mut dec = Decoder::from_slice(&[0x02, 0x01, 0x00]);
351 assert_eq!(dec.read_integer().unwrap(), 0);
352
353 let mut dec = Decoder::from_slice(&[0x02, 0x01, 0x7F]);
354 assert_eq!(dec.read_integer().unwrap(), 127);
355
356 let mut dec = Decoder::from_slice(&[0x02, 0x02, 0x00, 0x80]);
357 assert_eq!(dec.read_integer().unwrap(), 128);
358
359 let mut dec = Decoder::from_slice(&[0x02, 0x01, 0xFF]);
360 assert_eq!(dec.read_integer().unwrap(), -1);
361
362 let mut dec = Decoder::from_slice(&[0x02, 0x01, 0x80]);
363 assert_eq!(dec.read_integer().unwrap(), -128);
364 }
365
366 #[test]
367 fn test_decode_null() {
368 let mut dec = Decoder::from_slice(&[0x05, 0x00]);
369 dec.read_null().unwrap();
370 }
371
372 #[test]
373 fn test_decode_octet_string() {
374 let mut dec = Decoder::from_slice(&[0x04, 0x05, b'h', b'e', b'l', b'l', b'o']);
375 let s = dec.read_octet_string().unwrap();
376 assert_eq!(&s[..], b"hello");
377 }
378
379 #[test]
380 fn test_decode_oid() {
381 let mut dec = Decoder::from_slice(&[0x06, 0x03, 0x2B, 0x06, 0x01]);
383 let oid = dec.read_oid().unwrap();
384 assert_eq!(oid.arcs(), &[1, 3, 6, 1]);
385 }
386
387 #[test]
388 fn test_decode_sequence() {
389 let mut dec = Decoder::from_slice(&[0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02]);
391 let mut seq = dec.read_sequence().unwrap();
392 assert_eq!(seq.read_integer().unwrap(), 1);
393 assert_eq!(seq.read_integer().unwrap(), 2);
394 }
395
396 #[test]
397 fn test_accept_non_minimal_integer() {
398 let mut dec = Decoder::from_slice(&[0x02, 0x02, 0x00, 0x01]);
400 assert_eq!(dec.read_integer().unwrap(), 1);
401
402 let mut dec = Decoder::from_slice(&[0x02, 0x02, 0x00, 0x7F]);
404 assert_eq!(dec.read_integer().unwrap(), 127);
405
406 let mut dec = Decoder::from_slice(&[0x02, 0x03, 0x00, 0x00, 0x80]);
408 assert_eq!(dec.read_integer().unwrap(), 128);
409
410 let mut dec = Decoder::from_slice(&[0x02, 0x02, 0xFF, 0xFF]);
412 assert_eq!(dec.read_integer().unwrap(), -1);
413 }
414
415 #[test]
416 fn test_integer_too_long_truncates() {
417 let mut dec = Decoder::from_slice(&[0x02, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05]);
420 assert_eq!(dec.read_integer().unwrap(), 0x02_03_04_05_i32);
421
422 let mut dec =
424 Decoder::from_slice(&[0x02, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]);
425 assert_eq!(dec.read_integer().unwrap(), 0x05_06_07_08_i32);
426
427 let mut dec = Decoder::from_slice(&[
429 0x02, 0x09, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
430 ]);
431 assert!(
432 dec.read_integer().is_err(),
433 "9-byte integer must be rejected"
434 );
435 }
436
437 #[test]
438 fn test_unsigned32_too_long_truncates() {
439 let mut dec = Decoder::from_slice(&[0x42, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
442 assert_eq!(dec.read_unsigned32(0x42).unwrap(), 0x03_04_05_06_u32);
443
444 let mut dec = Decoder::from_slice(&[
446 0x42, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
447 ]);
448 assert_eq!(dec.read_unsigned32(0x42).unwrap(), u32::MAX);
449
450 let mut dec = Decoder::from_slice(&[
452 0x42, 0x0A, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
453 ]);
454 assert!(
455 dec.read_unsigned32(0x42).is_err(),
456 "10-byte unsigned32 must be rejected"
457 );
458 }
459
460 #[test]
461 fn test_zero_length_counter64_accepted() {
462 let mut dec = Decoder::from_slice(&[0x46, 0x00]);
464 let result = dec.read_integer64(0x46);
465 assert!(result.is_ok(), "zero-length Counter64 should be accepted");
466 assert_eq!(result.unwrap(), 0);
467 }
468
469 #[test]
470 fn test_counter64_nine_bytes_requires_leading_zero() {
471 let mut dec = Decoder::from_slice(&[
474 0x46, 0x09, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
475 ]);
476 let result = dec.read_integer64(0x46);
477 assert!(
478 result.is_err(),
479 "expected error for 9-byte Counter64 without leading zero"
480 );
481
482 let mut dec = Decoder::from_slice(&[
484 0x46, 0x09, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
485 ]);
486 let result = dec.read_integer64(0x46);
487 assert!(
488 result.is_ok(),
489 "expected success for 9-byte Counter64 with leading zero"
490 );
491 assert_eq!(result.unwrap(), u64::MAX);
492 }
493
494 #[test]
495 fn test_unsigned32_nine_bytes_requires_leading_zero() {
496 let mut dec = Decoder::from_slice(&[
498 0x42, 0x09, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
499 ]);
500 assert!(
501 dec.read_unsigned32(0x42).is_err(),
502 "9-byte unsigned32 without leading zero must be rejected"
503 );
504
505 let mut dec = Decoder::from_slice(&[
507 0x42, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
508 ]);
509 assert_eq!(dec.read_unsigned32(0x42).unwrap(), u32::MAX);
510
511 let mut dec = Decoder::from_slice(&[0x42, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00]);
513 assert_eq!(dec.read_unsigned32(0x42).unwrap(), 0u32);
514 }
515
516 #[test]
517 fn test_read_bytes_rejects_oversized_length() {
518 let mut dec = Decoder::from_slice(&[0x01, 0x02, 0x03]);
520 let result = dec.read_bytes(100);
522 assert!(result.is_err());
523 let err = result.unwrap_err();
524 assert!(
525 matches!(*err, crate::error::Error::MalformedResponse { .. }),
526 "expected MalformedResponse error, got {err:?}"
527 );
528 }
529
530 #[test]
531 fn test_skip_tlv_rejects_oversized_length() {
532 let mut dec = Decoder::from_slice(&[0x04, 0x82, 0x01, 0x00, 0xAA, 0xBB, 0xCC]);
535 let result = dec.skip_tlv();
536 assert!(result.is_err());
537 let err = result.unwrap_err();
538 assert!(
539 matches!(*err, crate::error::Error::MalformedResponse { .. }),
540 "expected MalformedResponse error, got {err:?}"
541 );
542 }
543
544 #[test]
545 fn test_read_tag_rejects_multi_byte_tag() {
546 let mut dec = Decoder::from_slice(&[0x1F, 0x02, 0x00]);
549 let result = dec.read_tag();
550 assert!(result.is_err());
551 let err = result.unwrap_err();
552 assert!(
553 matches!(*err, crate::error::Error::MalformedResponse { .. }),
554 "expected MalformedResponse error for multi-byte tag, got {err:?}"
555 );
556
557 let mut dec = Decoder::from_slice(&[0x3F, 0x02, 0x00]);
559 let result = dec.read_tag();
560 assert!(result.is_err());
561
562 let mut dec = Decoder::from_slice(&[0x9F, 0x02, 0x00]);
564 let result = dec.read_tag();
565 assert!(result.is_err());
566
567 let mut dec = Decoder::from_slice(&[0x02, 0x01, 0x00]);
569 let result = dec.read_tag();
570 assert!(result.is_ok());
571 assert_eq!(result.unwrap(), 0x02);
572 }
573
574 #[test]
575 fn test_peek_tag_rejects_multi_byte_tag() {
576 let dec = Decoder::from_slice(&[0x1F, 0x02, 0x00]);
578 let result = dec.peek_tag();
579 assert!(
580 result.is_none(),
581 "peek_tag should return None for multi-byte tag"
582 );
583
584 let dec = Decoder::from_slice(&[0x30, 0x00]);
586 let result = dec.peek_tag();
587 assert_eq!(result, Some(0x30));
588 }
589}