1use std::convert::TryInto;
2use std::fmt::Debug;
3
4use rand::Rng;
5use thiserror::Error;
6
7use crate::core::attributes::Attributes;
8use crate::core::avp::{AVPType, AVP};
9use crate::core::code::Code;
10
11#[cfg(feature = "md5")]
12use md5::compute;
13
14#[cfg(feature = "openssl")]
15use openssl::hash::{hash, MessageDigest};
16
17const MAX_PACKET_LENGTH: usize = 4096;
18const RADIUS_PACKET_HEADER_LENGTH: usize = 20; #[derive(Error, Debug, PartialEq)]
21pub enum PacketError {
22 #[error("RADIUS packet doesn't have enough length of bytes; it has to be at least {0} bytes, but actual length was {1}")]
24 InsufficientPacketPayloadLengthError(usize, usize),
25
26 #[error("RADIUS packet header indicates the length as {0} bytes, but this is insufficient; this must have {1} bytes at least")]
28 InsufficientHeaderDefinedPacketLengthError(usize, usize),
29
30 #[error("RADIUS packet header indicates the length as {0} bytes, but this exceeds the maximum length {1} bytes")]
32 HeaderDefinedPacketLengthExceedsMaximumLimitError(usize, usize),
33
34 #[error("failed to decode the packet: {0}")]
36 DecodingError(String),
37
38 #[error("failed to encode the packet: {0}")]
40 EncodingError(String),
41
42 #[error("Unknown RADIUS packet type code: {0}")]
44 UnknownCodeError(String),
45
46 #[error("computation of hash failed: {0}")]
48 HashComputationFailed(String),
49}
50
51#[derive(Clone, PartialEq)]
53pub struct Packet {
54 code: Code,
55 identifier: u8,
56 authenticator: Vec<u8>,
57 secret: Vec<u8>,
58 attributes: Attributes,
59}
60
61impl Packet {
62 pub fn new(code: Code, secret: &[u8]) -> Self {
67 Self::_new(code, secret, None)
68 }
69
70 pub fn new_with_identifier(code: Code, secret: &[u8], identifier: u8) -> Self {
74 Self::_new(code, secret, Some(identifier))
75 }
76
77 fn _new(code: Code, secret: &[u8], maybe_identifier: Option<u8>) -> Self {
78 let mut rng = rand::thread_rng();
79 let authenticator = (0..16).map(|_| rng.gen()).collect::<Vec<u8>>();
80 Packet {
81 code: code.to_owned(),
82 identifier: match maybe_identifier {
83 Some(ident) => ident,
84 None => rng.gen(),
85 },
86 authenticator,
87 secret: secret.to_owned(),
88 attributes: Attributes(vec![]),
89 }
90 }
91
92 pub fn get_code(&self) -> Code {
93 self.code
94 }
95
96 pub fn get_identifier(&self) -> u8 {
97 self.identifier
98 }
99
100 pub fn get_secret(&self) -> &Vec<u8> {
101 &self.secret
102 }
103
104 pub fn get_authenticator(&self) -> &Vec<u8> {
105 &self.authenticator
106 }
107
108 pub fn set_identifier(&mut self, identifier: u8) {
110 self.identifier = identifier;
111 }
112
113 pub fn decode(bs: &[u8], secret: &[u8]) -> Result<Self, PacketError> {
115 if bs.len() < RADIUS_PACKET_HEADER_LENGTH {
116 return Err(PacketError::InsufficientPacketPayloadLengthError(
117 RADIUS_PACKET_HEADER_LENGTH,
118 bs.len(),
119 ));
120 }
121
122 let len = match bs[2..4].try_into() {
123 Ok(v) => u16::from_be_bytes(v),
124 Err(e) => return Err(PacketError::DecodingError(e.to_string())),
125 } as usize;
126 if len < RADIUS_PACKET_HEADER_LENGTH {
127 return Err(PacketError::InsufficientHeaderDefinedPacketLengthError(
128 len,
129 RADIUS_PACKET_HEADER_LENGTH,
130 ));
131 }
132 if len > MAX_PACKET_LENGTH {
133 return Err(
134 PacketError::HeaderDefinedPacketLengthExceedsMaximumLimitError(
135 len,
136 MAX_PACKET_LENGTH,
137 ),
138 );
139 }
140 if bs.len() < len {
141 return Err(PacketError::InsufficientPacketPayloadLengthError(
142 len,
143 bs.len(),
144 ));
145 }
146
147 let attributes = match Attributes::decode(&bs[RADIUS_PACKET_HEADER_LENGTH..len]) {
148 Ok(attributes) => attributes,
149 Err(e) => return Err(PacketError::DecodingError(e)),
150 };
151
152 Ok(Packet {
153 code: Code::from(bs[0]),
154 identifier: bs[1],
155 authenticator: bs[4..RADIUS_PACKET_HEADER_LENGTH].to_owned(),
156 secret: secret.to_owned(),
157 attributes,
158 })
159 }
160
161 pub fn make_response_packet(&self, code: Code) -> Self {
163 Packet {
164 code,
165 identifier: self.identifier,
166 authenticator: self.authenticator.clone(),
167 secret: self.secret.clone(),
168 attributes: Attributes(vec![]),
169 }
170 }
171
172 #[cfg(feature = "md5")]
173 pub fn encode(&self) -> Result<Vec<u8>, PacketError> {
175 let mut bs = match self.marshal_binary() {
176 Ok(bs) => bs,
177 Err(e) => return Err(PacketError::EncodingError(e)),
178 };
179
180 match self.code {
181 Code::AccessRequest | Code::StatusServer => Ok(bs),
182 Code::AccessAccept
183 | Code::AccessReject
184 | Code::AccountingRequest
185 | Code::AccountingResponse
186 | Code::AccessChallenge
187 | Code::DisconnectRequest
188 | Code::DisconnectACK
189 | Code::DisconnectNAK
190 | Code::CoARequest
191 | Code::CoAACK
192 | Code::CoANAK => {
193 let mut buf: Vec<u8> = bs[..4].to_vec();
194 match self.code {
195 Code::AccountingRequest | Code::DisconnectRequest | Code::CoARequest => {
199 buf.extend(vec![
200 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
201 0x00, 0x00, 0x00, 0x00,
202 ]);
203 }
204 _ => {
205 buf.extend(self.authenticator.clone()); }
207 }
208 buf.extend(bs[RADIUS_PACKET_HEADER_LENGTH..].to_vec());
209 buf.extend(&self.secret);
210 bs.splice(4..20, compute(&buf).to_vec());
211
212 Ok(bs)
213 }
214 _ => Err(PacketError::UnknownCodeError(format!("{:?}", self.code))),
215 }
216 }
217
218 #[cfg(feature = "openssl")]
219 pub fn encode(&self) -> Result<Vec<u8>, PacketError> {
221 let mut bs = match self.marshal_binary() {
222 Ok(bs) => bs,
223 Err(e) => return Err(PacketError::EncodingError(e)),
224 };
225
226 match self.code {
227 Code::AccessRequest | Code::StatusServer => Ok(bs),
228 Code::AccessAccept
229 | Code::AccessReject
230 | Code::AccountingRequest
231 | Code::AccountingResponse
232 | Code::AccessChallenge
233 | Code::DisconnectRequest
234 | Code::DisconnectACK
235 | Code::DisconnectNAK
236 | Code::CoARequest
237 | Code::CoAACK
238 | Code::CoANAK => {
239 let mut buf: Vec<u8> = bs[..4].to_vec();
240 match self.code {
241 Code::AccountingRequest | Code::DisconnectRequest | Code::CoARequest => {
245 buf.extend(vec![
246 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
247 0x00, 0x00, 0x00, 0x00,
248 ]);
249 }
250 _ => {
251 buf.extend(self.authenticator.clone()); }
253 }
254 buf.extend(bs[RADIUS_PACKET_HEADER_LENGTH..].to_vec());
255 buf.extend(&self.secret);
256 let hash_val = hash(MessageDigest::md5(), &buf);
257 let enc = if let Err(_err) = hash_val {
258 return Err(PacketError::HashComputationFailed(_err.to_string()));
259 } else {
260 hash_val.unwrap()
261 };
262 bs.splice(4..20, enc.to_vec());
263
264 Ok(bs)
265 }
266 _ => Err(PacketError::UnknownCodeError(format!("{:?}", self.code))),
267 }
268 }
269
270 fn marshal_binary(&self) -> Result<Vec<u8>, String> {
286 let encoded_avp = match self.attributes.encode() {
287 Ok(encoded) => encoded,
288 Err(e) => return Err(e),
289 };
290
291 let size = RADIUS_PACKET_HEADER_LENGTH as u16 + encoded_avp.len() as u16;
292 if size as usize > MAX_PACKET_LENGTH {
293 return Err("packet is too large".to_owned());
294 }
295
296 let mut bs: Vec<u8> = Vec::new();
297 bs.push(self.code as u8);
298 bs.push(self.identifier);
299 bs.extend(u16::to_be_bytes(size).to_vec());
300 bs.extend(self.authenticator.to_vec());
301 bs.extend(match self.attributes.encode() {
302 Ok(encoded) => encoded,
303 Err(e) => return Err(e),
304 });
305 Ok(bs)
306 }
307
308 #[cfg(feature = "md5")]
309 pub fn is_authentic_response(response: &[u8], request: &[u8], secret: &[u8]) -> bool {
311 if response.len() < RADIUS_PACKET_HEADER_LENGTH
312 || request.len() < RADIUS_PACKET_HEADER_LENGTH
313 || secret.is_empty()
314 {
315 return false;
316 }
317
318 compute(
319 [
320 &response[..4],
321 &request[4..RADIUS_PACKET_HEADER_LENGTH],
322 &response[RADIUS_PACKET_HEADER_LENGTH..],
323 secret,
324 ]
325 .concat(),
326 )
327 .to_vec()
328 .eq(&response[4..RADIUS_PACKET_HEADER_LENGTH].to_vec())
329 }
330
331 #[cfg(feature = "openssl")]
332 pub fn is_authentic_response(response: &[u8], request: &[u8], secret: &[u8]) -> bool {
334 if response.len() < RADIUS_PACKET_HEADER_LENGTH
335 || request.len() < RADIUS_PACKET_HEADER_LENGTH
336 || secret.is_empty()
337 {
338 return false;
339 }
340
341 let hash_val = hash(
342 MessageDigest::md5(),
343 &[
344 &response[..4],
345 &request[4..RADIUS_PACKET_HEADER_LENGTH],
346 &response[RADIUS_PACKET_HEADER_LENGTH..],
347 secret,
348 ]
349 .concat(),
350 );
351 let enc = hash_val.expect("Hash computation failed using openssl md5 digest algorithm");
352 enc.to_vec()
353 .eq(&response[4..RADIUS_PACKET_HEADER_LENGTH].to_vec())
354 }
355
356 #[cfg(feature = "md5")]
357 pub fn is_authentic_request(request: &[u8], secret: &[u8]) -> bool {
359 if request.len() < RADIUS_PACKET_HEADER_LENGTH || secret.is_empty() {
360 return false;
361 }
362
363 match Code::from(request[0]) {
364 Code::AccessRequest | Code::StatusServer => true,
365 Code::AccountingRequest | Code::DisconnectRequest | Code::CoARequest => compute(
366 [
367 &request[..4],
368 &[
369 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
370 0x00, 0x00, 0x00, 0x00,
371 ],
372 &request[RADIUS_PACKET_HEADER_LENGTH..],
373 secret,
374 ]
375 .concat(),
376 )
377 .to_vec()
378 .eq(&request[4..RADIUS_PACKET_HEADER_LENGTH].to_vec()),
379 _ => false,
380 }
381 }
382
383 #[cfg(feature = "openssl")]
384 pub fn is_authentic_request(request: &[u8], secret: &[u8]) -> bool {
386 if request.len() < RADIUS_PACKET_HEADER_LENGTH || secret.is_empty() {
387 return false;
388 }
389
390 match Code::from(request[0]) {
391 Code::AccessRequest | Code::StatusServer => true,
392 Code::AccountingRequest | Code::DisconnectRequest | Code::CoARequest => {
393 let hash_val = hash(
394 MessageDigest::md5(),
395 &[
396 &request[..4],
397 &[
398 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
399 0x00, 0x00, 0x00, 0x00,
400 ],
401 &request[RADIUS_PACKET_HEADER_LENGTH..],
402 secret,
403 ]
404 .concat(),
405 );
406 let enc =
407 hash_val.expect("Hash computation failed using openssl md5 digest algorithm");
408
409 enc.to_vec()
410 .eq(&request[4..RADIUS_PACKET_HEADER_LENGTH].to_vec())
411 }
412 _ => false,
413 }
414 }
415
416 pub fn add(&mut self, avp: AVP) {
418 self.attributes.add(avp);
419 }
420
421 pub fn extend(&mut self, avps: Vec<AVP>) {
423 self.attributes.extend(avps)
424 }
425
426 pub fn delete(&mut self, typ: AVPType) {
428 self.attributes.del(typ);
429 }
430
431 pub fn lookup(&self, typ: AVPType) -> Option<&AVP> {
433 self.attributes.lookup(typ)
434 }
435
436 pub fn lookup_all(&self, typ: AVPType) -> Vec<&AVP> {
438 self.attributes.lookup_all(typ)
439 }
440}
441
442impl Debug for Packet {
443 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
444 f.debug_struct("Packet")
445 .field("code", &self.code)
446 .field("identifier", &self.identifier)
447 .field("authenticator", &self.authenticator)
448 .field("secret", &"*redacted*")
449 .field("attributes", &self.attributes)
450 .finish()
451 }
452}
453
454#[cfg(test)]
455mod tests {
456 use std::net::Ipv4Addr;
457
458 use crate::core::avp::AVP;
459 use crate::core::code::Code;
460 use crate::core::packet::{
461 Packet, PacketError, MAX_PACKET_LENGTH, RADIUS_PACKET_HEADER_LENGTH,
462 };
463 use crate::core::rfc2865;
464
465 #[test]
466 fn test_for_rfc2865_7_1() -> Result<(), PacketError> {
467 let secret: Vec<u8> = "xyzzy5461".as_bytes().to_vec();
470 let request: Vec<u8> = vec![
471 0x01, 0x00, 0x00, 0x38, 0x0f, 0x40, 0x3f, 0x94, 0x73, 0x97, 0x80, 0x57, 0xbd, 0x83,
472 0xd5, 0xcb, 0x98, 0xf4, 0x22, 0x7a, 0x01, 0x06, 0x6e, 0x65, 0x6d, 0x6f, 0x02, 0x12,
473 0x0d, 0xbe, 0x70, 0x8d, 0x93, 0xd4, 0x13, 0xce, 0x31, 0x96, 0xe4, 0x3f, 0x78, 0x2a,
474 0x0a, 0xee, 0x04, 0x06, 0xc0, 0xa8, 0x01, 0x10, 0x05, 0x06, 0x00, 0x00, 0x00, 0x03,
475 ];
476
477 let request_packet = Packet::decode(&request, &secret)?;
478 assert_eq!(request_packet.code, Code::AccessRequest);
479 assert_eq!(request_packet.identifier, 0);
480 assert_eq!(
481 rfc2865::lookup_user_name(&request_packet).unwrap().unwrap(),
482 "nemo"
483 );
484 assert_eq!(
485 rfc2865::lookup_all_user_name(&request_packet).unwrap(),
486 vec!["nemo"],
487 );
488 assert_eq!(
489 rfc2865::lookup_user_password(&request_packet)
490 .unwrap()
491 .unwrap(),
492 b"arctangent"
493 );
494 assert_eq!(
495 rfc2865::lookup_nas_ip_address(&request_packet)
496 .unwrap()
497 .unwrap(),
498 Ipv4Addr::from([192, 168, 1, 16]),
499 );
500 assert_eq!(
501 rfc2865::lookup_nas_port(&request_packet).unwrap().unwrap(),
502 3
503 );
504 assert_eq!(request_packet.encode().unwrap(), request);
505 assert!(Packet::is_authentic_request(&request, &secret));
506
507 let response: Vec<u8> = vec![
508 0x02, 0x00, 0x00, 0x26, 0x86, 0xfe, 0x22, 0x0e, 0x76, 0x24, 0xba, 0x2a, 0x10, 0x05,
509 0xf6, 0xbf, 0x9b, 0x55, 0xe0, 0xb2, 0x06, 0x06, 0x00, 0x00, 0x00, 0x01, 0x0f, 0x06,
510 0x00, 0x00, 0x00, 0x00, 0x0e, 0x06, 0xc0, 0xa8, 0x01, 0x03,
511 ];
512 let mut response_packet = request_packet.make_response_packet(Code::AccessAccept);
513 rfc2865::add_service_type(&mut response_packet, rfc2865::SERVICE_TYPE_LOGIN_USER);
514 rfc2865::add_login_service(&mut response_packet, rfc2865::LOGIN_SERVICE_TELNET);
515 rfc2865::add_login_ip_host(&mut response_packet, &Ipv4Addr::from([192, 168, 1, 3]));
516 assert_eq!(response_packet.encode().unwrap(), response);
517 assert!(Packet::is_authentic_response(&response, &request, &secret));
518
519 assert!(rfc2865::lookup_service_type(&response_packet).is_some());
521 rfc2865::delete_service_type(&mut response_packet);
522 assert!(rfc2865::lookup_service_type(&response_packet).is_none());
523
524 Ok(())
525 }
526
527 #[test]
528 fn test_for_rfc2865_7_2() -> Result<(), PacketError> {
529 let secret: Vec<u8> = "xyzzy5461".as_bytes().to_vec();
530 let request: Vec<u8> = vec![
531 0x01, 0x01, 0x00, 0x47, 0x2a, 0xee, 0x86, 0xf0, 0x8d, 0x0d, 0x55, 0x96, 0x9c, 0xa5,
532 0x97, 0x8e, 0x0d, 0x33, 0x67, 0xa2, 0x01, 0x08, 0x66, 0x6c, 0x6f, 0x70, 0x73, 0x79,
533 0x03, 0x13, 0x16, 0xe9, 0x75, 0x57, 0xc3, 0x16, 0x18, 0x58, 0x95, 0xf2, 0x93, 0xff,
534 0x63, 0x44, 0x07, 0x72, 0x75, 0x04, 0x06, 0xc0, 0xa8, 0x01, 0x10, 0x05, 0x06, 0x00,
535 0x00, 0x00, 0x14, 0x06, 0x06, 0x00, 0x00, 0x00, 0x02, 0x07, 0x06, 0x00, 0x00, 0x00,
536 0x01,
537 ];
538
539 let request_packet = Packet::decode(&request, &secret)?;
540 assert_eq!(request_packet.get_code(), Code::AccessRequest);
541 assert_eq!(request_packet.identifier, 1);
542 assert_eq!(
543 rfc2865::lookup_user_name(&request_packet).unwrap().unwrap(),
544 "flopsy"
545 );
546 assert_eq!(
547 rfc2865::lookup_nas_ip_address(&request_packet)
548 .unwrap()
549 .unwrap(),
550 Ipv4Addr::from([192, 168, 1, 16]),
551 );
552 assert_eq!(
553 rfc2865::lookup_nas_port(&request_packet).unwrap().unwrap(),
554 20
555 );
556 assert_eq!(
557 rfc2865::lookup_service_type(&request_packet)
558 .unwrap()
559 .unwrap(),
560 rfc2865::SERVICE_TYPE_FRAMED_USER,
561 );
562 assert_eq!(
563 rfc2865::lookup_framed_protocol(&request_packet)
564 .unwrap()
565 .unwrap(),
566 rfc2865::FRAMED_PROTOCOL_PPP,
567 );
568
569 let response: Vec<u8> = vec![
570 0x02, 0x01, 0x00, 0x38, 0x15, 0xef, 0xbc, 0x7d, 0xab, 0x26, 0xcf, 0xa3, 0xdc, 0x34,
571 0xd9, 0xc0, 0x3c, 0x86, 0x01, 0xa4, 0x06, 0x06, 0x00, 0x00, 0x00, 0x02, 0x07, 0x06,
572 0x00, 0x00, 0x00, 0x01, 0x08, 0x06, 0xff, 0xff, 0xff, 0xfe, 0x0a, 0x06, 0x00, 0x00,
573 0x00, 0x00, 0x0d, 0x06, 0x00, 0x00, 0x00, 0x01, 0x0c, 0x06, 0x00, 0x00, 0x05,
574 0xdc,
576 ];
577 let response_packet = Packet::decode(&response, &secret).unwrap();
578
579 assert_eq!(response_packet.get_code(), Code::AccessAccept);
580 assert_eq!(response_packet.get_identifier(), 1);
581 assert_eq!(
582 rfc2865::lookup_service_type(&response_packet)
583 .unwrap()
584 .unwrap(),
585 rfc2865::SERVICE_TYPE_FRAMED_USER
586 );
587 assert_eq!(
588 rfc2865::lookup_framed_protocol(&response_packet)
589 .unwrap()
590 .unwrap(),
591 rfc2865::FRAMED_PROTOCOL_PPP,
592 );
593 assert_eq!(
594 rfc2865::lookup_framed_ip_address(&response_packet)
595 .unwrap()
596 .unwrap(),
597 Ipv4Addr::from([255, 255, 255, 254]),
598 );
599 assert_eq!(
600 rfc2865::lookup_framed_routing(&response_packet)
601 .unwrap()
602 .unwrap(),
603 rfc2865::FRAMED_ROUTING_NONE,
604 );
605 assert_eq!(
606 rfc2865::lookup_framed_compression(&response_packet)
607 .unwrap()
608 .unwrap(),
609 rfc2865::FRAMED_COMPRESSION_VAN_JACOBSON_TCP_IP,
610 );
611 assert_eq!(
612 rfc2865::lookup_framed_mtu(&response_packet)
613 .unwrap()
614 .unwrap(),
615 1500,
616 );
617
618 Ok(())
619 }
620
621 #[test]
622 fn test_passwords() {
623 let passwords = vec![
624 b"".to_vec(),
625 b"qwerty".to_vec(),
626 b"helloworld1231231231231233489hegufudhsgdsfygdf8g".to_vec(),
627 ];
628
629 let secret = b"xyzzy5461";
630
631 for password in passwords {
632 let mut request_packet = Packet::new(Code::AccessRequest, secret);
633 rfc2865::add_user_password(&mut request_packet, &password).unwrap();
634
635 let encoded = request_packet.encode().unwrap();
636
637 let decoded = Packet::decode(&encoded, secret).unwrap();
638 assert_eq!(
639 rfc2865::lookup_user_password(&decoded).unwrap().unwrap(),
640 password
641 );
642 }
643 }
644
645 #[test]
646 fn test_parse_invalid() {
647 struct TestCase<'a> {
648 plain_text: &'a str,
649 expected_error: PacketError,
650 }
651
652 let test_cases = &[
653 TestCase {
654 plain_text: "\x01",
655 expected_error: PacketError::InsufficientPacketPayloadLengthError(RADIUS_PACKET_HEADER_LENGTH, 1),
656 },
657 TestCase {
658 plain_text: "\x01\x7f\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01",
659 expected_error: PacketError::InsufficientHeaderDefinedPacketLengthError(0, RADIUS_PACKET_HEADER_LENGTH),
660 },
661 TestCase {
662 plain_text: "\x01\x7f\x7f\x7f\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01",
663 expected_error: PacketError::HeaderDefinedPacketLengthExceedsMaximumLimitError(32639, MAX_PACKET_LENGTH),
664 },
665 TestCase {
666 plain_text: "\x00\x7f\x00\x16\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00",
667 expected_error: PacketError::InsufficientPacketPayloadLengthError(22, 21),
668 },
669 TestCase {
670 plain_text: "\x01\x01\x00\x16\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00",
671 expected_error: PacketError::DecodingError("invalid attribute length".to_owned()),
672 }
673 ];
674
675 let secret = b"12345";
676 for test_case in test_cases {
677 let result = Packet::decode(test_case.plain_text.as_bytes(), secret);
678 assert!(result.is_err());
679 assert_eq!(result.err().unwrap(), test_case.expected_error);
680 }
681 }
682
683 #[test]
684 fn test_packet_attribute_length_boundary() {
685 let mut packet = Packet::new(Code::AccessRequest, b"12345");
686 packet.add(AVP {
687 typ: 1,
688 value: vec![1; 253],
689 });
690 let encoded = packet.encode();
691 assert!(encoded.is_ok());
692
693 let mut packet = Packet::new(Code::AccessRequest, b"12345");
694 packet.add(AVP {
695 typ: 1,
696 value: vec![1; 254],
697 });
698 let encoded = packet.encode();
699 assert!(encoded.is_err());
700 assert_eq!(
701 encoded.err().unwrap(),
702 PacketError::EncodingError("attribute is too large".to_owned()),
703 );
704 }
705
706 #[test]
707 fn test_with_arbitrary_identifier() {
708 let mut packet = Packet::new(Code::AccessRequest, b"12345");
709 let random_ident = packet.get_identifier();
710 let expected_ident = random_ident + 1;
711 packet.set_identifier(expected_ident);
712 assert_eq!(packet.get_identifier(), expected_ident);
713
714 packet = Packet::new_with_identifier(Code::AccessRequest, b"12345", expected_ident);
715 assert_eq!(packet.get_identifier(), expected_ident);
716 }
717}