1use std::net::SocketAddr;
9
10use crate::error::internal::DecodeErrorKind;
11use crate::error::{Error, Result, UNKNOWN_TARGET};
12
13pub const MAX_LENGTH: usize = 0x20_0000; #[inline]
24pub(crate) const fn length_encoded_len(len: usize) -> usize {
25 if len <= 127 {
26 1
27 } else if len <= 0xFF {
28 2
29 } else if len <= 0xFFFF {
30 3
31 } else if len <= 0xFF_FFFF {
32 4
33 } else {
34 5
35 }
36}
37
38#[inline]
42pub(crate) const fn base128_len(value: u32) -> usize {
43 if value == 0 {
44 return 1;
45 }
46 if value < 0x80 {
49 1
50 } else if value < 0x4000 {
51 2
52 } else if value < 0x20_0000 {
53 3
54 } else if value < 0x1000_0000 {
55 4
56 } else {
57 5
58 }
59}
60
61#[inline]
63pub(crate) fn integer_content_len(value: i32) -> usize {
64 super::encode::encode_integer_stack(value).1
65}
66
67#[inline]
69pub(crate) const fn unsigned32_content_len(value: u32) -> usize {
70 if value == 0 {
71 return 1;
72 }
73
74 let bytes = value.to_be_bytes();
75
76 if bytes[0] != 0 {
78 if bytes[0] & 0x80 != 0 { 5 } else { 4 }
79 } else if bytes[1] != 0 {
80 if bytes[1] & 0x80 != 0 { 4 } else { 3 }
81 } else if bytes[2] != 0 {
82 if bytes[2] & 0x80 != 0 { 3 } else { 2 }
83 } else if bytes[3] & 0x80 != 0 {
84 2
85 } else {
86 1
87 }
88}
89
90#[inline]
92pub(crate) const fn unsigned64_content_len(value: u64) -> usize {
93 if value == 0 {
94 return 1;
95 }
96
97 let bytes = value.to_be_bytes();
98
99 if bytes[0] != 0 {
101 if bytes[0] & 0x80 != 0 { 9 } else { 8 }
102 } else if bytes[1] != 0 {
103 if bytes[1] & 0x80 != 0 { 8 } else { 7 }
104 } else if bytes[2] != 0 {
105 if bytes[2] & 0x80 != 0 { 7 } else { 6 }
106 } else if bytes[3] != 0 {
107 if bytes[3] & 0x80 != 0 { 6 } else { 5 }
108 } else if bytes[4] != 0 {
109 if bytes[4] & 0x80 != 0 { 5 } else { 4 }
110 } else if bytes[5] != 0 {
111 if bytes[5] & 0x80 != 0 { 4 } else { 3 }
112 } else if bytes[6] != 0 {
113 if bytes[6] & 0x80 != 0 { 3 } else { 2 }
114 } else if bytes[7] & 0x80 != 0 {
115 2
116 } else {
117 1
118 }
119}
120
121#[must_use]
125pub fn encode_length(len: usize) -> ([u8; 5], usize) {
126 let mut buf = [0u8; 5];
127
128 if len <= 127 {
129 buf[0] = len as u8;
131 (buf, 1)
132 } else if len <= 0xFF {
133 buf[0] = len as u8;
135 buf[1] = 0x81;
136 (buf, 2)
137 } else if len <= 0xFFFF {
138 buf[0] = len as u8;
140 buf[1] = (len >> 8) as u8;
141 buf[2] = 0x82;
142 (buf, 3)
143 } else if len <= 0xFF_FFFF {
144 buf[0] = len as u8;
146 buf[1] = (len >> 8) as u8;
147 buf[2] = (len >> 16) as u8;
148 buf[3] = 0x83;
149 (buf, 4)
150 } else {
151 buf[0] = len as u8;
153 buf[1] = (len >> 8) as u8;
154 buf[2] = (len >> 16) as u8;
155 buf[3] = (len >> 24) as u8;
156 buf[4] = 0x84;
157 (buf, 5)
158 }
159}
160
161pub(crate) fn parse_ber_length(data: &[u8]) -> Option<(usize, usize)> {
167 if data.is_empty() {
168 return None;
169 }
170
171 let first = data[0];
172
173 if first < 0x80 {
174 return Some((first as usize, 1));
176 }
177
178 if first == 0x80 {
179 return None;
181 }
182
183 let num_octets = (first & 0x7F) as usize;
185 if num_octets == 0 || num_octets > 8 || data.len() < 1 + num_octets {
186 return None;
187 }
188
189 let mut len: usize = 0;
190 for i in 0..num_octets {
191 len = (len << 8) | (data[1 + i] as usize);
192 }
193
194 if len > MAX_LENGTH || len > data.len() - (1 + num_octets) {
199 return None;
200 }
201
202 Some((len, 1 + num_octets))
203}
204
205pub fn decode_length(
211 data: &[u8],
212 base_offset: usize,
213 target: Option<SocketAddr>,
214) -> Result<(usize, usize)> {
215 let target = target.unwrap_or(UNKNOWN_TARGET);
216
217 if data.is_empty() {
218 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %base_offset, kind = %DecodeErrorKind::TruncatedData }, "truncated data: unexpected end of input in length");
219 return Err(Error::MalformedResponse { target }.boxed());
220 }
221
222 let first = data[0];
223
224 if first == 0x80 {
225 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %base_offset, kind = %DecodeErrorKind::IndefiniteLength }, "indefinite length encoding not supported");
227 return Err(Error::MalformedResponse { target }.boxed());
228 }
229
230 if first & 0x80 == 0 {
231 Ok((first as usize, 1))
233 } else {
234 let num_octets = (first & 0x7F) as usize;
236
237 if num_octets == 0 {
238 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %base_offset, kind = %DecodeErrorKind::InvalidLength }, "invalid length encoding: zero octets in long form");
239 return Err(Error::MalformedResponse { target }.boxed());
240 }
241
242 if num_octets > 8 {
243 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %base_offset, kind = %DecodeErrorKind::LengthTooLong { octets: num_octets } }, "length encoding too long");
245 return Err(Error::MalformedResponse { target }.boxed());
246 }
247
248 if data.len() < 1 + num_octets {
249 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %base_offset, kind = %DecodeErrorKind::InsufficientData { needed: 1 + num_octets, available: data.len() } }, "truncated data in length field");
250 return Err(Error::MalformedResponse { target }.boxed());
251 }
252
253 let mut len: usize = 0;
254 for i in 0..num_octets {
255 len = (len << 8) | (data[1 + i] as usize);
256 }
257
258 if len > MAX_LENGTH {
259 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %base_offset, kind = %DecodeErrorKind::LengthExceedsMax { length: len, max: MAX_LENGTH } }, "length exceeds maximum");
260 return Err(Error::MalformedResponse { target }.boxed());
261 }
262
263 Ok((len, 1 + num_octets))
264 }
265}
266
267#[cfg(test)]
268mod tests {
269 use super::*;
270
271 #[test]
272 fn test_short_form() {
273 assert_eq!(decode_length(&[0], 0, None).unwrap(), (0, 1));
274 assert_eq!(decode_length(&[127], 0, None).unwrap(), (127, 1));
275 assert_eq!(decode_length(&[1], 0, None).unwrap(), (1, 1));
276 }
277
278 #[test]
279 fn test_long_form_1_byte() {
280 assert_eq!(decode_length(&[0x81, 128], 0, None).unwrap(), (128, 2));
281 assert_eq!(decode_length(&[0x81, 255], 0, None).unwrap(), (255, 2));
282 }
283
284 #[test]
285 fn test_long_form_2_bytes() {
286 assert_eq!(
287 decode_length(&[0x82, 0x01, 0x00], 0, None).unwrap(),
288 (256, 3)
289 );
290 assert_eq!(
291 decode_length(&[0x82, 0xFF, 0xFF], 0, None).unwrap(),
292 (65535, 3)
293 );
294 }
295
296 #[test]
297 fn test_indefinite_rejected() {
298 assert!(decode_length(&[0x80], 0, None).is_err());
299 }
300
301 #[test]
302 fn test_encode_short() {
303 let (buf, len) = encode_length(0);
304 assert_eq!(&buf[..len], &[0]);
305
306 let (buf, len) = encode_length(127);
307 assert_eq!(&buf[..len], &[127]);
308 }
309
310 #[test]
311 fn test_encode_long() {
312 let (buf, len) = encode_length(128);
313 assert_eq!(&buf[..len], &[128, 0x81]);
314
315 let (buf, len) = encode_length(256);
316 assert_eq!(&buf[..len], &[0, 1, 0x82]);
317 }
318
319 #[test]
320 fn test_accept_oversized_length_encoding() {
321 let result = decode_length(&[0x82, 0x00, 0x05], 0, None);
324 assert_eq!(result.unwrap(), (5, 3));
325
326 let result = decode_length(&[0x81, 0x01], 0, None);
328 assert_eq!(result.unwrap(), (1, 2));
329
330 let result = decode_length(&[0x82, 0x00, 0x7F], 0, None);
332 assert_eq!(result.unwrap(), (127, 3));
333
334 let result = decode_length(&[0x83, 0x00, 0x00, 0x80], 0, None);
336 assert_eq!(result.unwrap(), (128, 4));
337 }
338
339 #[test]
340 fn test_length_encoded_len() {
341 assert_eq!(length_encoded_len(0), 1);
342 assert_eq!(length_encoded_len(127), 1);
343 assert_eq!(length_encoded_len(128), 2);
344 assert_eq!(length_encoded_len(255), 2);
345 assert_eq!(length_encoded_len(256), 3);
346 assert_eq!(length_encoded_len(65535), 3);
347 assert_eq!(length_encoded_len(65536), 4);
348 }
349
350 #[test]
351 fn test_base128_len() {
352 assert_eq!(base128_len(0), 1);
353 assert_eq!(base128_len(127), 1);
354 assert_eq!(base128_len(128), 2);
355 assert_eq!(base128_len(16_383), 2);
356 assert_eq!(base128_len(16_384), 3);
357 assert_eq!(base128_len(2_097_151), 3);
358 assert_eq!(base128_len(2_097_152), 4);
359 assert_eq!(base128_len(268_435_455), 4);
360 assert_eq!(base128_len(268_435_456), 5);
361 assert_eq!(base128_len(u32::MAX), 5);
362 }
363
364 #[test]
365 fn test_integer_content_len() {
366 assert_eq!(integer_content_len(0), 1);
368 assert_eq!(integer_content_len(1), 1);
370 assert_eq!(integer_content_len(127), 1);
371 assert_eq!(integer_content_len(128), 2);
373 assert_eq!(integer_content_len(255), 2);
374 assert_eq!(integer_content_len(256), 2);
376 assert_eq!(integer_content_len(32767), 2);
377 assert_eq!(integer_content_len(32768), 3);
378 assert_eq!(integer_content_len(-1), 1);
380 assert_eq!(integer_content_len(-128), 1);
381 assert_eq!(integer_content_len(-129), 2);
382 assert_eq!(integer_content_len(i32::MAX), 4);
384 assert_eq!(integer_content_len(i32::MIN), 4);
385 }
386
387 #[test]
388 fn test_unsigned32_content_len() {
389 assert_eq!(unsigned32_content_len(0), 1);
390 assert_eq!(unsigned32_content_len(127), 1);
391 assert_eq!(unsigned32_content_len(128), 2); assert_eq!(unsigned32_content_len(255), 2); assert_eq!(unsigned32_content_len(256), 2);
394 assert_eq!(unsigned32_content_len(u32::MAX), 5); }
396
397 #[test]
398 fn test_unsigned64_content_len() {
399 assert_eq!(unsigned64_content_len(0), 1);
400 assert_eq!(unsigned64_content_len(127), 1);
401 assert_eq!(unsigned64_content_len(128), 2); assert_eq!(unsigned64_content_len(u64::MAX), 9); }
404
405 #[test]
406 fn test_long_form_5_to_8_byte_length_accepted() {
407 let result = decode_length(&[0x85, 0x00, 0x00, 0x00, 0x00, 0x05], 0, None);
410 assert_eq!(result.unwrap(), (5, 6));
411
412 let result = decode_length(
414 &[0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01],
415 0,
416 None,
417 );
418 assert_eq!(result.unwrap(), (1, 9));
419
420 let result = decode_length(
422 &[0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01],
423 0,
424 None,
425 );
426 assert!(result.is_err());
427 }
428
429 #[test]
430 fn test_parse_ber_length_rejects_oversized() {
431 let huge = [0x88, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
435 assert_eq!(parse_ber_length(&huge), None);
436
437 let over = MAX_LENGTH + 1;
440 let over_bytes = [
441 0x84,
442 ((over >> 24) & 0xFF) as u8,
443 ((over >> 16) & 0xFF) as u8,
444 ((over >> 8) & 0xFF) as u8,
445 (over & 0xFF) as u8,
446 ];
447 assert_eq!(parse_ber_length(&over_bytes), None);
448
449 assert_eq!(parse_ber_length(&[0x81, 0x05, 0x00, 0x00]), None);
452
453 let mut ok = vec![0x81, 0x80];
456 ok.extend(std::iter::repeat_n(0u8, 128));
457 assert_eq!(parse_ber_length(&ok), Some((128, 2)));
458 }
459
460 #[test]
461 fn test_max_length_enforced() {
462 let max = MAX_LENGTH;
464 let max_bytes = [
465 0x83,
466 ((max >> 16) & 0xFF) as u8,
467 ((max >> 8) & 0xFF) as u8,
468 (max & 0xFF) as u8,
469 ];
470 let result = decode_length(&max_bytes, 0, None);
471 assert_eq!(result.unwrap(), (MAX_LENGTH, 4));
472
473 let over = MAX_LENGTH + 1;
475 let over_bytes = [
476 0x84, ((over >> 24) & 0xFF) as u8,
478 ((over >> 16) & 0xFF) as u8,
479 ((over >> 8) & 0xFF) as u8,
480 (over & 0xFF) as u8,
481 ];
482 let result = decode_length(&over_bytes, 0, None);
483 assert!(result.is_err());
484 let err = result.unwrap_err();
485 assert!(
486 matches!(*err, Error::MalformedResponse { .. }),
487 "Expected MalformedResponse error, got {err:?}"
488 );
489 }
490
491 mod proptests {
492 use super::*;
493 use crate::ber::EncodeBuf;
494 use proptest::prelude::*;
495
496 proptest! {
497 #[test]
498 fn integer_content_len_matches_encoder(value: i32) {
499 let mut buf = EncodeBuf::new();
501 buf.push_integer(value);
502 let encoded_len = buf.len();
503 let actual_content_len = encoded_len - 2;
506 prop_assert_eq!(
507 integer_content_len(value),
508 actual_content_len,
509 "Mismatch for value {}: computed={}, actual={}",
510 value,
511 integer_content_len(value),
512 actual_content_len
513 );
514 }
515
516 #[test]
517 fn unsigned32_content_len_matches_encoder(value: u32) {
518 let mut buf = EncodeBuf::new();
519 buf.push_unsigned32(crate::ber::tag::application::COUNTER32, value);
520 let encoded_len = buf.len();
521 let actual_content_len = encoded_len - 2;
523 prop_assert_eq!(
524 unsigned32_content_len(value),
525 actual_content_len,
526 "Mismatch for value {}", value
527 );
528 }
529
530 #[test]
531 fn unsigned64_content_len_matches_encoder(value: u64) {
532 let mut buf = EncodeBuf::new();
533 buf.push_integer64(value);
534 let encoded_len = buf.len();
535 let actual_content_len = encoded_len - 2;
537 prop_assert_eq!(
538 unsigned64_content_len(value),
539 actual_content_len,
540 "Mismatch for value {}", value
541 );
542 }
543 }
544 }
545}