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 Some((len, 1 + num_octets))
195}
196
197pub fn decode_length(
203 data: &[u8],
204 base_offset: usize,
205 target: Option<SocketAddr>,
206) -> Result<(usize, usize)> {
207 let target = target.unwrap_or(UNKNOWN_TARGET);
208
209 if data.is_empty() {
210 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %base_offset, kind = %DecodeErrorKind::TruncatedData }, "truncated data: unexpected end of input in length");
211 return Err(Error::MalformedResponse { target }.boxed());
212 }
213
214 let first = data[0];
215
216 if first == 0x80 {
217 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %base_offset, kind = %DecodeErrorKind::IndefiniteLength }, "indefinite length encoding not supported");
219 return Err(Error::MalformedResponse { target }.boxed());
220 }
221
222 if first & 0x80 == 0 {
223 Ok((first as usize, 1))
225 } else {
226 let num_octets = (first & 0x7F) as usize;
228
229 if num_octets == 0 {
230 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %base_offset, kind = %DecodeErrorKind::InvalidLength }, "invalid length encoding: zero octets in long form");
231 return Err(Error::MalformedResponse { target }.boxed());
232 }
233
234 if num_octets > 8 {
235 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %base_offset, kind = %DecodeErrorKind::LengthTooLong { octets: num_octets } }, "length encoding too long");
237 return Err(Error::MalformedResponse { target }.boxed());
238 }
239
240 if data.len() < 1 + num_octets {
241 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");
242 return Err(Error::MalformedResponse { target }.boxed());
243 }
244
245 let mut len: usize = 0;
246 for i in 0..num_octets {
247 len = (len << 8) | (data[1 + i] as usize);
248 }
249
250 if len > MAX_LENGTH {
251 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %base_offset, kind = %DecodeErrorKind::LengthExceedsMax { length: len, max: MAX_LENGTH } }, "length exceeds maximum");
252 return Err(Error::MalformedResponse { target }.boxed());
253 }
254
255 Ok((len, 1 + num_octets))
256 }
257}
258
259#[cfg(test)]
260mod tests {
261 use super::*;
262
263 #[test]
264 fn test_short_form() {
265 assert_eq!(decode_length(&[0], 0, None).unwrap(), (0, 1));
266 assert_eq!(decode_length(&[127], 0, None).unwrap(), (127, 1));
267 assert_eq!(decode_length(&[1], 0, None).unwrap(), (1, 1));
268 }
269
270 #[test]
271 fn test_long_form_1_byte() {
272 assert_eq!(decode_length(&[0x81, 128], 0, None).unwrap(), (128, 2));
273 assert_eq!(decode_length(&[0x81, 255], 0, None).unwrap(), (255, 2));
274 }
275
276 #[test]
277 fn test_long_form_2_bytes() {
278 assert_eq!(
279 decode_length(&[0x82, 0x01, 0x00], 0, None).unwrap(),
280 (256, 3)
281 );
282 assert_eq!(
283 decode_length(&[0x82, 0xFF, 0xFF], 0, None).unwrap(),
284 (65535, 3)
285 );
286 }
287
288 #[test]
289 fn test_indefinite_rejected() {
290 assert!(decode_length(&[0x80], 0, None).is_err());
291 }
292
293 #[test]
294 fn test_encode_short() {
295 let (buf, len) = encode_length(0);
296 assert_eq!(&buf[..len], &[0]);
297
298 let (buf, len) = encode_length(127);
299 assert_eq!(&buf[..len], &[127]);
300 }
301
302 #[test]
303 fn test_encode_long() {
304 let (buf, len) = encode_length(128);
305 assert_eq!(&buf[..len], &[128, 0x81]);
306
307 let (buf, len) = encode_length(256);
308 assert_eq!(&buf[..len], &[0, 1, 0x82]);
309 }
310
311 #[test]
312 fn test_accept_oversized_length_encoding() {
313 let result = decode_length(&[0x82, 0x00, 0x05], 0, None);
316 assert_eq!(result.unwrap(), (5, 3));
317
318 let result = decode_length(&[0x81, 0x01], 0, None);
320 assert_eq!(result.unwrap(), (1, 2));
321
322 let result = decode_length(&[0x82, 0x00, 0x7F], 0, None);
324 assert_eq!(result.unwrap(), (127, 3));
325
326 let result = decode_length(&[0x83, 0x00, 0x00, 0x80], 0, None);
328 assert_eq!(result.unwrap(), (128, 4));
329 }
330
331 #[test]
332 fn test_length_encoded_len() {
333 assert_eq!(length_encoded_len(0), 1);
334 assert_eq!(length_encoded_len(127), 1);
335 assert_eq!(length_encoded_len(128), 2);
336 assert_eq!(length_encoded_len(255), 2);
337 assert_eq!(length_encoded_len(256), 3);
338 assert_eq!(length_encoded_len(65535), 3);
339 assert_eq!(length_encoded_len(65536), 4);
340 }
341
342 #[test]
343 fn test_base128_len() {
344 assert_eq!(base128_len(0), 1);
345 assert_eq!(base128_len(127), 1);
346 assert_eq!(base128_len(128), 2);
347 assert_eq!(base128_len(16_383), 2);
348 assert_eq!(base128_len(16_384), 3);
349 assert_eq!(base128_len(2_097_151), 3);
350 assert_eq!(base128_len(2_097_152), 4);
351 assert_eq!(base128_len(268_435_455), 4);
352 assert_eq!(base128_len(268_435_456), 5);
353 assert_eq!(base128_len(u32::MAX), 5);
354 }
355
356 #[test]
357 fn test_integer_content_len() {
358 assert_eq!(integer_content_len(0), 1);
360 assert_eq!(integer_content_len(1), 1);
362 assert_eq!(integer_content_len(127), 1);
363 assert_eq!(integer_content_len(128), 2);
365 assert_eq!(integer_content_len(255), 2);
366 assert_eq!(integer_content_len(256), 2);
368 assert_eq!(integer_content_len(32767), 2);
369 assert_eq!(integer_content_len(32768), 3);
370 assert_eq!(integer_content_len(-1), 1);
372 assert_eq!(integer_content_len(-128), 1);
373 assert_eq!(integer_content_len(-129), 2);
374 assert_eq!(integer_content_len(i32::MAX), 4);
376 assert_eq!(integer_content_len(i32::MIN), 4);
377 }
378
379 #[test]
380 fn test_unsigned32_content_len() {
381 assert_eq!(unsigned32_content_len(0), 1);
382 assert_eq!(unsigned32_content_len(127), 1);
383 assert_eq!(unsigned32_content_len(128), 2); assert_eq!(unsigned32_content_len(255), 2); assert_eq!(unsigned32_content_len(256), 2);
386 assert_eq!(unsigned32_content_len(u32::MAX), 5); }
388
389 #[test]
390 fn test_unsigned64_content_len() {
391 assert_eq!(unsigned64_content_len(0), 1);
392 assert_eq!(unsigned64_content_len(127), 1);
393 assert_eq!(unsigned64_content_len(128), 2); assert_eq!(unsigned64_content_len(u64::MAX), 9); }
396
397 #[test]
398 fn test_long_form_5_to_8_byte_length_accepted() {
399 let result = decode_length(&[0x85, 0x00, 0x00, 0x00, 0x00, 0x05], 0, None);
402 assert_eq!(result.unwrap(), (5, 6));
403
404 let result = decode_length(
406 &[0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01],
407 0,
408 None,
409 );
410 assert_eq!(result.unwrap(), (1, 9));
411
412 let result = decode_length(
414 &[0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01],
415 0,
416 None,
417 );
418 assert!(result.is_err());
419 }
420
421 #[test]
422 fn test_max_length_enforced() {
423 let max = MAX_LENGTH;
425 let max_bytes = [
426 0x83,
427 ((max >> 16) & 0xFF) as u8,
428 ((max >> 8) & 0xFF) as u8,
429 (max & 0xFF) as u8,
430 ];
431 let result = decode_length(&max_bytes, 0, None);
432 assert_eq!(result.unwrap(), (MAX_LENGTH, 4));
433
434 let over = MAX_LENGTH + 1;
436 let over_bytes = [
437 0x84, ((over >> 24) & 0xFF) as u8,
439 ((over >> 16) & 0xFF) as u8,
440 ((over >> 8) & 0xFF) as u8,
441 (over & 0xFF) as u8,
442 ];
443 let result = decode_length(&over_bytes, 0, None);
444 assert!(result.is_err());
445 let err = result.unwrap_err();
446 assert!(
447 matches!(*err, Error::MalformedResponse { .. }),
448 "Expected MalformedResponse error, got {err:?}"
449 );
450 }
451
452 mod proptests {
453 use super::*;
454 use crate::ber::EncodeBuf;
455 use proptest::prelude::*;
456
457 proptest! {
458 #[test]
459 fn integer_content_len_matches_encoder(value: i32) {
460 let mut buf = EncodeBuf::new();
462 buf.push_integer(value);
463 let encoded_len = buf.len();
464 let actual_content_len = encoded_len - 2;
467 prop_assert_eq!(
468 integer_content_len(value),
469 actual_content_len,
470 "Mismatch for value {}: computed={}, actual={}",
471 value,
472 integer_content_len(value),
473 actual_content_len
474 );
475 }
476
477 #[test]
478 fn unsigned32_content_len_matches_encoder(value: u32) {
479 let mut buf = EncodeBuf::new();
480 buf.push_unsigned32(crate::ber::tag::application::COUNTER32, value);
481 let encoded_len = buf.len();
482 let actual_content_len = encoded_len - 2;
484 prop_assert_eq!(
485 unsigned32_content_len(value),
486 actual_content_len,
487 "Mismatch for value {}", value
488 );
489 }
490
491 #[test]
492 fn unsigned64_content_len_matches_encoder(value: u64) {
493 let mut buf = EncodeBuf::new();
494 buf.push_integer64(value);
495 let encoded_len = buf.len();
496 let actual_content_len = encoded_len - 2;
498 prop_assert_eq!(
499 unsigned64_content_len(value),
500 actual_content_len,
501 "Mismatch for value {}", value
502 );
503 }
504 }
505 }
506}