1use std::net::SocketAddr;
9
10use crate::error::internal::DecodeErrorKind;
11use crate::error::{Error, Result, UNKNOWN_TARGET};
12
13pub const MAX_LENGTH: usize = 0x200000; #[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 <= 0xFFFFFF {
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 < 0x200000 {
53 3
54 } else if value < 0x10000000 {
55 4
56 } else {
57 5
58 }
59}
60
61#[inline]
63pub(crate) const fn integer_content_len(value: i32) -> usize {
64 let bytes = value.to_be_bytes();
65
66 if value >= 0 {
67 if bytes[0] != 0 {
69 4
70 } else if bytes[1] != 0 || bytes[2] & 0x80 != 0 {
71 if bytes[1] & 0x80 != 0 { 4 } else { 3 }
72 } else if bytes[2] != 0 || bytes[3] & 0x80 != 0 {
73 if bytes[2] & 0x80 != 0 { 3 } else { 2 }
74 } else {
75 1
76 }
77 } else {
78 if bytes[0] != 0xFF {
80 4
81 } else if bytes[1] != 0xFF || bytes[2] & 0x80 == 0 {
82 if bytes[1] & 0x80 == 0 { 4 } else { 3 }
83 } else if bytes[2] != 0xFF || bytes[3] & 0x80 == 0 {
84 if bytes[2] & 0x80 == 0 { 3 } else { 2 }
85 } else {
86 1
87 }
88 }
89}
90
91#[inline]
93pub(crate) const fn unsigned32_content_len(value: u32) -> usize {
94 if value == 0 {
95 return 1;
96 }
97
98 let bytes = value.to_be_bytes();
99
100 if bytes[0] != 0 {
102 if bytes[0] & 0x80 != 0 { 5 } else { 4 }
103 } else if bytes[1] != 0 {
104 if bytes[1] & 0x80 != 0 { 4 } else { 3 }
105 } else if bytes[2] != 0 {
106 if bytes[2] & 0x80 != 0 { 3 } else { 2 }
107 } else if bytes[3] & 0x80 != 0 {
108 2
109 } else {
110 1
111 }
112}
113
114#[inline]
116pub(crate) const fn unsigned64_content_len(value: u64) -> usize {
117 if value == 0 {
118 return 1;
119 }
120
121 let bytes = value.to_be_bytes();
122
123 if bytes[0] != 0 {
125 if bytes[0] & 0x80 != 0 { 9 } else { 8 }
126 } else if bytes[1] != 0 {
127 if bytes[1] & 0x80 != 0 { 8 } else { 7 }
128 } else if bytes[2] != 0 {
129 if bytes[2] & 0x80 != 0 { 7 } else { 6 }
130 } else if bytes[3] != 0 {
131 if bytes[3] & 0x80 != 0 { 6 } else { 5 }
132 } else if bytes[4] != 0 {
133 if bytes[4] & 0x80 != 0 { 5 } else { 4 }
134 } else if bytes[5] != 0 {
135 if bytes[5] & 0x80 != 0 { 4 } else { 3 }
136 } else if bytes[6] != 0 {
137 if bytes[6] & 0x80 != 0 { 3 } else { 2 }
138 } else if bytes[7] & 0x80 != 0 {
139 2
140 } else {
141 1
142 }
143}
144
145pub fn encode_length(len: usize) -> ([u8; 5], usize) {
149 let mut buf = [0u8; 5];
150
151 if len <= 127 {
152 buf[0] = len as u8;
154 (buf, 1)
155 } else if len <= 0xFF {
156 buf[0] = len as u8;
158 buf[1] = 0x81;
159 (buf, 2)
160 } else if len <= 0xFFFF {
161 buf[0] = len as u8;
163 buf[1] = (len >> 8) as u8;
164 buf[2] = 0x82;
165 (buf, 3)
166 } else if len <= 0xFFFFFF {
167 buf[0] = len as u8;
169 buf[1] = (len >> 8) as u8;
170 buf[2] = (len >> 16) as u8;
171 buf[3] = 0x83;
172 (buf, 4)
173 } else {
174 buf[0] = len as u8;
176 buf[1] = (len >> 8) as u8;
177 buf[2] = (len >> 16) as u8;
178 buf[3] = (len >> 24) as u8;
179 buf[4] = 0x84;
180 (buf, 5)
181 }
182}
183
184pub fn decode_length(
190 data: &[u8],
191 base_offset: usize,
192 target: Option<SocketAddr>,
193) -> Result<(usize, usize)> {
194 let target = target.unwrap_or(UNKNOWN_TARGET);
195
196 if data.is_empty() {
197 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %base_offset, kind = %DecodeErrorKind::TruncatedData }, "truncated data: unexpected end of input in length");
198 return Err(Error::MalformedResponse { target }.boxed());
199 }
200
201 let first = data[0];
202
203 if first == 0x80 {
204 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %base_offset, kind = %DecodeErrorKind::IndefiniteLength }, "indefinite length encoding not supported");
206 return Err(Error::MalformedResponse { target }.boxed());
207 }
208
209 if first & 0x80 == 0 {
210 Ok((first as usize, 1))
212 } else {
213 let num_octets = (first & 0x7F) as usize;
215
216 if num_octets == 0 {
217 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %base_offset, kind = %DecodeErrorKind::InvalidLength }, "invalid length encoding: zero octets in long form");
218 return Err(Error::MalformedResponse { target }.boxed());
219 }
220
221 if num_octets > 4 {
222 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %base_offset, kind = %DecodeErrorKind::LengthTooLong { octets: num_octets } }, "length encoding too long");
223 return Err(Error::MalformedResponse { target }.boxed());
224 }
225
226 if data.len() < 1 + num_octets {
227 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");
228 return Err(Error::MalformedResponse { target }.boxed());
229 }
230
231 let mut len: usize = 0;
232 for i in 0..num_octets {
233 len = (len << 8) | (data[1 + i] as usize);
234 }
235
236 if len > MAX_LENGTH {
237 tracing::debug!(target: "async_snmp::ber", { snmp.offset = %base_offset, kind = %DecodeErrorKind::LengthExceedsMax { length: len, max: MAX_LENGTH } }, "length exceeds maximum");
238 return Err(Error::MalformedResponse { target }.boxed());
239 }
240
241 Ok((len, 1 + num_octets))
242 }
243}
244
245#[cfg(test)]
246mod tests {
247 use super::*;
248
249 #[test]
250 fn test_short_form() {
251 assert_eq!(decode_length(&[0], 0, None).unwrap(), (0, 1));
252 assert_eq!(decode_length(&[127], 0, None).unwrap(), (127, 1));
253 assert_eq!(decode_length(&[1], 0, None).unwrap(), (1, 1));
254 }
255
256 #[test]
257 fn test_long_form_1_byte() {
258 assert_eq!(decode_length(&[0x81, 128], 0, None).unwrap(), (128, 2));
259 assert_eq!(decode_length(&[0x81, 255], 0, None).unwrap(), (255, 2));
260 }
261
262 #[test]
263 fn test_long_form_2_bytes() {
264 assert_eq!(
265 decode_length(&[0x82, 0x01, 0x00], 0, None).unwrap(),
266 (256, 3)
267 );
268 assert_eq!(
269 decode_length(&[0x82, 0xFF, 0xFF], 0, None).unwrap(),
270 (65535, 3)
271 );
272 }
273
274 #[test]
275 fn test_indefinite_rejected() {
276 assert!(decode_length(&[0x80], 0, None).is_err());
277 }
278
279 #[test]
280 fn test_encode_short() {
281 let (buf, len) = encode_length(0);
282 assert_eq!(&buf[..len], &[0]);
283
284 let (buf, len) = encode_length(127);
285 assert_eq!(&buf[..len], &[127]);
286 }
287
288 #[test]
289 fn test_encode_long() {
290 let (buf, len) = encode_length(128);
291 assert_eq!(&buf[..len], &[128, 0x81]);
292
293 let (buf, len) = encode_length(256);
294 assert_eq!(&buf[..len], &[0, 1, 0x82]);
295 }
296
297 #[test]
298 fn test_accept_oversized_length_encoding() {
299 let result = decode_length(&[0x82, 0x00, 0x05], 0, None);
302 assert_eq!(result.unwrap(), (5, 3));
303
304 let result = decode_length(&[0x81, 0x01], 0, None);
306 assert_eq!(result.unwrap(), (1, 2));
307
308 let result = decode_length(&[0x82, 0x00, 0x7F], 0, None);
310 assert_eq!(result.unwrap(), (127, 3));
311
312 let result = decode_length(&[0x83, 0x00, 0x00, 0x80], 0, None);
314 assert_eq!(result.unwrap(), (128, 4));
315 }
316
317 #[test]
318 fn test_length_encoded_len() {
319 assert_eq!(length_encoded_len(0), 1);
320 assert_eq!(length_encoded_len(127), 1);
321 assert_eq!(length_encoded_len(128), 2);
322 assert_eq!(length_encoded_len(255), 2);
323 assert_eq!(length_encoded_len(256), 3);
324 assert_eq!(length_encoded_len(65535), 3);
325 assert_eq!(length_encoded_len(65536), 4);
326 }
327
328 #[test]
329 fn test_base128_len() {
330 assert_eq!(base128_len(0), 1);
331 assert_eq!(base128_len(127), 1);
332 assert_eq!(base128_len(128), 2);
333 assert_eq!(base128_len(16383), 2);
334 assert_eq!(base128_len(16384), 3);
335 assert_eq!(base128_len(2097151), 3);
336 assert_eq!(base128_len(2097152), 4);
337 assert_eq!(base128_len(268435455), 4);
338 assert_eq!(base128_len(268435456), 5);
339 assert_eq!(base128_len(u32::MAX), 5);
340 }
341
342 #[test]
343 fn test_integer_content_len() {
344 assert_eq!(integer_content_len(0), 1);
346 assert_eq!(integer_content_len(1), 1);
348 assert_eq!(integer_content_len(127), 1);
349 assert_eq!(integer_content_len(128), 2);
351 assert_eq!(integer_content_len(255), 2);
352 assert_eq!(integer_content_len(256), 2);
354 assert_eq!(integer_content_len(32767), 2);
355 assert_eq!(integer_content_len(32768), 3);
356 assert_eq!(integer_content_len(-1), 1);
358 assert_eq!(integer_content_len(-128), 1);
359 assert_eq!(integer_content_len(-129), 2);
360 assert_eq!(integer_content_len(i32::MAX), 4);
362 assert_eq!(integer_content_len(i32::MIN), 4);
363 }
364
365 #[test]
366 fn test_unsigned32_content_len() {
367 assert_eq!(unsigned32_content_len(0), 1);
368 assert_eq!(unsigned32_content_len(127), 1);
369 assert_eq!(unsigned32_content_len(128), 2); assert_eq!(unsigned32_content_len(255), 2); assert_eq!(unsigned32_content_len(256), 2);
372 assert_eq!(unsigned32_content_len(u32::MAX), 5); }
374
375 #[test]
376 fn test_unsigned64_content_len() {
377 assert_eq!(unsigned64_content_len(0), 1);
378 assert_eq!(unsigned64_content_len(127), 1);
379 assert_eq!(unsigned64_content_len(128), 2); assert_eq!(unsigned64_content_len(u64::MAX), 9); }
382
383 #[test]
384 fn test_max_length_enforced() {
385 let max = MAX_LENGTH;
387 let max_bytes = [
388 0x83,
389 ((max >> 16) & 0xFF) as u8,
390 ((max >> 8) & 0xFF) as u8,
391 (max & 0xFF) as u8,
392 ];
393 let result = decode_length(&max_bytes, 0, None);
394 assert_eq!(result.unwrap(), (MAX_LENGTH, 4));
395
396 let over = MAX_LENGTH + 1;
398 let over_bytes = [
399 0x84, ((over >> 24) & 0xFF) as u8,
401 ((over >> 16) & 0xFF) as u8,
402 ((over >> 8) & 0xFF) as u8,
403 (over & 0xFF) as u8,
404 ];
405 let result = decode_length(&over_bytes, 0, None);
406 assert!(result.is_err());
407 let err = result.unwrap_err();
408 assert!(
409 matches!(*err, Error::MalformedResponse { .. }),
410 "Expected MalformedResponse error, got {:?}",
411 err
412 );
413 }
414
415 mod proptests {
416 use super::*;
417 use crate::ber::EncodeBuf;
418 use proptest::prelude::*;
419
420 proptest! {
421 #[test]
422 fn integer_content_len_matches_encoder(value: i32) {
423 let mut buf = EncodeBuf::new();
425 buf.push_integer(value);
426 let encoded_len = buf.len();
427 let actual_content_len = encoded_len - 2;
430 prop_assert_eq!(
431 integer_content_len(value),
432 actual_content_len,
433 "Mismatch for value {}: computed={}, actual={}",
434 value,
435 integer_content_len(value),
436 actual_content_len
437 );
438 }
439
440 #[test]
441 fn unsigned32_content_len_matches_encoder(value: u32) {
442 let mut buf = EncodeBuf::new();
443 buf.push_unsigned32(crate::ber::tag::application::COUNTER32, value);
444 let encoded_len = buf.len();
445 let actual_content_len = encoded_len - 2;
447 prop_assert_eq!(
448 unsigned32_content_len(value),
449 actual_content_len,
450 "Mismatch for value {}", value
451 );
452 }
453
454 #[test]
455 fn unsigned64_content_len_matches_encoder(value: u64) {
456 let mut buf = EncodeBuf::new();
457 buf.push_integer64(value);
458 let encoded_len = buf.len();
459 let actual_content_len = encoded_len - 2;
461 prop_assert_eq!(
462 unsigned64_content_len(value),
463 actual_content_len,
464 "Mismatch for value {}", value
465 );
466 }
467 }
468 }
469}