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 pub fn from_slice(data: &[u8]) -> Self {
42 Self::new(Bytes::copy_from_slice(data))
43 }
44
45 fn target(&self) -> SocketAddr {
47 self.target.unwrap_or(UNKNOWN_TARGET)
48 }
49
50 fn malformed(&self) -> Box<crate::error::Error> {
52 Error::MalformedResponse {
53 target: self.target(),
54 }
55 .boxed()
56 }
57
58 pub fn offset(&self) -> usize {
60 self.offset
61 }
62
63 pub fn remaining(&self) -> usize {
65 self.data.len() - self.offset
66 }
67
68 pub fn is_empty(&self) -> bool {
70 self.offset >= self.data.len()
71 }
72
73 pub fn peek_byte(&self) -> Option<u8> {
75 if self.offset < self.data.len() {
76 Some(self.data[self.offset])
77 } else {
78 None
79 }
80 }
81
82 pub fn peek_tag(&self) -> Option<u8> {
88 let byte = self.peek_byte()?;
89 if byte & 0x1F == 0x1F {
90 return None;
91 }
92 Some(byte)
93 }
94
95 pub fn read_byte(&mut self) -> Result<u8> {
97 if self.offset >= self.data.len() {
98 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::TruncatedData }, "truncated data: unexpected end of input");
99 return Err(self.malformed());
100 }
101 let byte = self.data[self.offset];
102 self.offset += 1;
103 Ok(byte)
104 }
105
106 pub fn read_tag(&mut self) -> Result<u8> {
112 let tag = self.read_byte()?;
113 if tag & 0x1F == 0x1F {
114 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset - 1, kind = %DecodeErrorKind::UnexpectedTag { expected: 0, actual: tag } }, "multi-byte tag not supported");
115 return Err(self.malformed());
116 }
117 Ok(tag)
118 }
119
120 pub fn read_length(&mut self) -> Result<usize> {
122 let (len, consumed) = decode_length(&self.data[self.offset..], self.offset, self.target)?;
123 self.offset += consumed;
124 Ok(len)
125 }
126
127 pub fn read_bytes(&mut self, len: usize) -> Result<Bytes> {
129 if self.offset.saturating_add(len) > self.data.len() {
131 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::InsufficientData { needed: len, available: self.remaining() } }, "insufficient data");
132 return Err(self.malformed());
133 }
134 let bytes = self.data.slice(self.offset..self.offset + len);
135 self.offset += len;
136 Ok(bytes)
137 }
138
139 pub fn expect_tag(&mut self, expected: u8) -> Result<usize> {
141 let tag = self.read_tag()?;
142 if tag != expected {
143 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset - 1, kind = %DecodeErrorKind::UnexpectedTag { expected, actual: tag } }, "unexpected tag");
144 return Err(self.malformed());
145 }
146 self.read_length()
147 }
148
149 pub fn read_integer(&mut self) -> Result<i32> {
151 let len = self.expect_tag(tag::universal::INTEGER)?;
152 self.read_integer_value(len)
153 }
154
155 pub fn read_integer_value(&mut self, len: usize) -> Result<i32> {
157 if len == 0 {
158 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::ZeroLengthInteger }, "zero-length integer");
159 return Err(self.malformed());
160 }
161 if len > 8 {
162 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::IntegerTooLong { length: len } }, "integer encoding too long");
164 return Err(self.malformed());
165 }
166
167 let bytes = self.read_bytes(len)?;
168
169 let is_negative = bytes[0] & 0x80 != 0;
172 let mut value: i64 = if is_negative { -1 } else { 0 };
173
174 for &byte in bytes.iter() {
175 value = (value << 8) | (byte as i64);
176 }
177
178 Ok(value as i32)
179 }
180
181 pub fn read_integer64(&mut self, expected_tag: u8) -> Result<u64> {
183 let len = self.expect_tag(expected_tag)?;
184 self.read_integer64_value(len)
185 }
186
187 pub fn read_integer64_value(&mut self, len: usize) -> Result<u64> {
189 if len == 0 {
190 tracing::warn!(target: "async_snmp::ber", { snmp.offset = %self.offset }, "zero-length Counter64; interpreting as 0");
192 return Ok(0);
193 }
194 if len > 9 {
195 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::Integer64TooLong { length: len } }, "integer64 too long");
197 return Err(self.malformed());
198 }
199
200 let bytes = self.read_bytes(len)?;
201
202 if len == 9 && bytes[0] != 0x00 {
203 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::Integer64MissingLeadingZero }, "9-octet integer64 missing leading zero");
204 return Err(self.malformed());
205 }
206
207 let mut value: u64 = 0;
208
209 for &byte in bytes.iter() {
210 value = (value << 8) | (byte as u64);
211 }
212
213 Ok(value)
214 }
215
216 pub fn read_unsigned32(&mut self, expected_tag: u8) -> Result<u32> {
218 let len = self.expect_tag(expected_tag)?;
219 self.read_unsigned32_value(len)
220 }
221
222 pub fn read_unsigned32_value(&mut self, len: usize) -> Result<u32> {
224 if len == 0 {
225 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::ZeroLengthInteger }, "zero-length integer");
226 return Err(self.malformed());
227 }
228 if len > 9 {
229 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::Unsigned32TooLong { length: len } }, "unsigned32 encoding too long");
231 return Err(self.malformed());
232 }
233
234 let bytes = self.read_bytes(len)?;
235
236 if len == 9 && bytes[0] != 0x00 {
237 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::Unsigned32MissingLeadingZero }, "9-octet unsigned32 missing leading zero");
238 return Err(self.malformed());
239 }
240
241 let mut value: u64 = 0;
244
245 for &byte in bytes.iter() {
246 value = (value << 8) | (byte as u64);
247 }
248
249 Ok(value as u32)
250 }
251
252 pub fn read_octet_string(&mut self) -> Result<Bytes> {
254 let len = self.expect_tag(tag::universal::OCTET_STRING)?;
255 self.read_bytes(len)
256 }
257
258 pub fn read_null(&mut self) -> Result<()> {
260 let len = self.expect_tag(tag::universal::NULL)?;
261 if len != 0 {
262 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::InvalidNull }, "NULL with non-zero length");
263 return Err(self.malformed());
264 }
265 Ok(())
266 }
267
268 pub fn read_oid(&mut self) -> Result<Oid> {
270 let len = self.expect_tag(tag::universal::OBJECT_IDENTIFIER)?;
271 let bytes = self.read_bytes(len)?;
272 Oid::from_ber(&bytes)
273 }
274
275 pub fn read_oid_value(&mut self, len: usize) -> Result<Oid> {
277 let bytes = self.read_bytes(len)?;
278 Oid::from_ber(&bytes)
279 }
280
281 pub fn read_sequence(&mut self) -> Result<Decoder> {
283 self.read_constructed(tag::universal::SEQUENCE)
284 }
285
286 pub fn read_constructed(&mut self, expected_tag: u8) -> Result<Decoder> {
288 let len = self.expect_tag(expected_tag)?;
289 let content = self.read_bytes(len)?;
290 Ok(Decoder {
291 data: content,
292 offset: 0,
293 target: self.target,
294 })
295 }
296
297 pub fn read_ip_address(&mut self) -> Result<[u8; 4]> {
299 let len = self.expect_tag(tag::application::IP_ADDRESS)?;
300 if len != 4 {
301 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::InvalidIpAddressLength { length: len } }, "IP address must be 4 bytes");
302 return Err(self.malformed());
303 }
304 let bytes = self.read_bytes(4)?;
305 Ok([bytes[0], bytes[1], bytes[2], bytes[3]])
306 }
307
308 pub fn skip_tlv(&mut self) -> Result<()> {
310 let _tag = self.read_tag()?;
311 let len = self.read_length()?;
312 let new_offset = self.offset.saturating_add(len);
314 if new_offset > self.data.len() {
315 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %self.offset, kind = %DecodeErrorKind::TlvOverflow }, "TLV extends past end of data");
316 return Err(self.malformed());
317 }
318 self.offset = new_offset;
319 Ok(())
320 }
321
322 pub fn sub_decoder(&mut self, len: usize) -> Result<Decoder> {
324 let content = self.read_bytes(len)?;
325 Ok(Decoder {
326 data: content,
327 offset: 0,
328 target: self.target,
329 })
330 }
331
332 pub fn as_bytes(&self) -> &Bytes {
334 &self.data
335 }
336
337 pub fn remaining_slice(&self) -> &[u8] {
339 &self.data[self.offset..]
340 }
341}
342
343#[cfg(test)]
344mod tests {
345 use super::*;
346
347 #[test]
348 fn test_decode_integer() {
349 let mut dec = Decoder::from_slice(&[0x02, 0x01, 0x00]);
350 assert_eq!(dec.read_integer().unwrap(), 0);
351
352 let mut dec = Decoder::from_slice(&[0x02, 0x01, 0x7F]);
353 assert_eq!(dec.read_integer().unwrap(), 127);
354
355 let mut dec = Decoder::from_slice(&[0x02, 0x02, 0x00, 0x80]);
356 assert_eq!(dec.read_integer().unwrap(), 128);
357
358 let mut dec = Decoder::from_slice(&[0x02, 0x01, 0xFF]);
359 assert_eq!(dec.read_integer().unwrap(), -1);
360
361 let mut dec = Decoder::from_slice(&[0x02, 0x01, 0x80]);
362 assert_eq!(dec.read_integer().unwrap(), -128);
363 }
364
365 #[test]
366 fn test_decode_null() {
367 let mut dec = Decoder::from_slice(&[0x05, 0x00]);
368 dec.read_null().unwrap();
369 }
370
371 #[test]
372 fn test_decode_octet_string() {
373 let mut dec = Decoder::from_slice(&[0x04, 0x05, b'h', b'e', b'l', b'l', b'o']);
374 let s = dec.read_octet_string().unwrap();
375 assert_eq!(&s[..], b"hello");
376 }
377
378 #[test]
379 fn test_decode_oid() {
380 let mut dec = Decoder::from_slice(&[0x06, 0x03, 0x2B, 0x06, 0x01]);
382 let oid = dec.read_oid().unwrap();
383 assert_eq!(oid.arcs(), &[1, 3, 6, 1]);
384 }
385
386 #[test]
387 fn test_decode_sequence() {
388 let mut dec = Decoder::from_slice(&[0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02]);
390 let mut seq = dec.read_sequence().unwrap();
391 assert_eq!(seq.read_integer().unwrap(), 1);
392 assert_eq!(seq.read_integer().unwrap(), 2);
393 }
394
395 #[test]
396 fn test_accept_non_minimal_integer() {
397 let mut dec = Decoder::from_slice(&[0x02, 0x02, 0x00, 0x01]);
399 assert_eq!(dec.read_integer().unwrap(), 1);
400
401 let mut dec = Decoder::from_slice(&[0x02, 0x02, 0x00, 0x7F]);
403 assert_eq!(dec.read_integer().unwrap(), 127);
404
405 let mut dec = Decoder::from_slice(&[0x02, 0x03, 0x00, 0x00, 0x80]);
407 assert_eq!(dec.read_integer().unwrap(), 128);
408
409 let mut dec = Decoder::from_slice(&[0x02, 0x02, 0xFF, 0xFF]);
411 assert_eq!(dec.read_integer().unwrap(), -1);
412 }
413
414 #[test]
415 fn test_integer_too_long_truncates() {
416 let mut dec = Decoder::from_slice(&[0x02, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05]);
419 assert_eq!(dec.read_integer().unwrap(), 0x02030405_i32);
420
421 let mut dec =
423 Decoder::from_slice(&[0x02, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]);
424 assert_eq!(dec.read_integer().unwrap(), 0x05060708_i32);
425
426 let mut dec = Decoder::from_slice(&[
428 0x02, 0x09, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
429 ]);
430 assert!(
431 dec.read_integer().is_err(),
432 "9-byte integer must be rejected"
433 );
434 }
435
436 #[test]
437 fn test_unsigned32_too_long_truncates() {
438 let mut dec = Decoder::from_slice(&[0x42, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
441 assert_eq!(dec.read_unsigned32(0x42).unwrap(), 0x03040506_u32);
442
443 let mut dec = Decoder::from_slice(&[
445 0x42, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
446 ]);
447 assert_eq!(dec.read_unsigned32(0x42).unwrap(), u32::MAX);
448
449 let mut dec = Decoder::from_slice(&[
451 0x42, 0x0A, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
452 ]);
453 assert!(
454 dec.read_unsigned32(0x42).is_err(),
455 "10-byte unsigned32 must be rejected"
456 );
457 }
458
459 #[test]
460 fn test_zero_length_counter64_accepted() {
461 let mut dec = Decoder::from_slice(&[0x46, 0x00]);
463 let result = dec.read_integer64(0x46);
464 assert!(result.is_ok(), "zero-length Counter64 should be accepted");
465 assert_eq!(result.unwrap(), 0);
466 }
467
468 #[test]
469 fn test_counter64_nine_bytes_requires_leading_zero() {
470 let mut dec = Decoder::from_slice(&[
473 0x46, 0x09, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
474 ]);
475 let result = dec.read_integer64(0x46);
476 assert!(
477 result.is_err(),
478 "expected error for 9-byte Counter64 without leading zero"
479 );
480
481 let mut dec = Decoder::from_slice(&[
483 0x46, 0x09, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
484 ]);
485 let result = dec.read_integer64(0x46);
486 assert!(
487 result.is_ok(),
488 "expected success for 9-byte Counter64 with leading zero"
489 );
490 assert_eq!(result.unwrap(), u64::MAX);
491 }
492
493 #[test]
494 fn test_unsigned32_nine_bytes_requires_leading_zero() {
495 let mut dec = Decoder::from_slice(&[
497 0x42, 0x09, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
498 ]);
499 assert!(
500 dec.read_unsigned32(0x42).is_err(),
501 "9-byte unsigned32 without leading zero must be rejected"
502 );
503
504 let mut dec = Decoder::from_slice(&[
506 0x42, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
507 ]);
508 assert_eq!(dec.read_unsigned32(0x42).unwrap(), u32::MAX);
509
510 let mut dec = Decoder::from_slice(&[0x42, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00]);
512 assert_eq!(dec.read_unsigned32(0x42).unwrap(), 0u32);
513 }
514
515 #[test]
516 fn test_read_bytes_rejects_oversized_length() {
517 let mut dec = Decoder::from_slice(&[0x01, 0x02, 0x03]);
519 let result = dec.read_bytes(100);
521 assert!(result.is_err());
522 let err = result.unwrap_err();
523 assert!(
524 matches!(*err, crate::error::Error::MalformedResponse { .. }),
525 "expected MalformedResponse error, got {:?}",
526 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 {:?}",
541 err
542 );
543 }
544
545 #[test]
546 fn test_read_tag_rejects_multi_byte_tag() {
547 let mut dec = Decoder::from_slice(&[0x1F, 0x02, 0x00]);
550 let result = dec.read_tag();
551 assert!(result.is_err());
552 let err = result.unwrap_err();
553 assert!(
554 matches!(*err, crate::error::Error::MalformedResponse { .. }),
555 "expected MalformedResponse error for multi-byte tag, got {:?}",
556 err
557 );
558
559 let mut dec = Decoder::from_slice(&[0x3F, 0x02, 0x00]);
561 let result = dec.read_tag();
562 assert!(result.is_err());
563
564 let mut dec = Decoder::from_slice(&[0x9F, 0x02, 0x00]);
566 let result = dec.read_tag();
567 assert!(result.is_err());
568
569 let mut dec = Decoder::from_slice(&[0x02, 0x01, 0x00]);
571 let result = dec.read_tag();
572 assert!(result.is_ok());
573 assert_eq!(result.unwrap(), 0x02);
574 }
575
576 #[test]
577 fn test_peek_tag_rejects_multi_byte_tag() {
578 let dec = Decoder::from_slice(&[0x1F, 0x02, 0x00]);
580 let result = dec.peek_tag();
581 assert!(
582 result.is_none(),
583 "peek_tag should return None for multi-byte tag"
584 );
585
586 let dec = Decoder::from_slice(&[0x30, 0x00]);
588 let result = dec.peek_tag();
589 assert_eq!(result, Some(0x30));
590 }
591}