1use sawp::error::{NomError, Result};
5use sawp::parser::{Direction, Parse};
6use sawp::probe::Probe;
7use sawp::protocol::Protocol;
8use sawp_flags::{BitFlags, Flag, Flags};
9
10use nom::bytes::streaming::tag;
11use nom::bytes::streaming::take;
12use nom::combinator;
13use nom::error::ErrorKind;
14use nom::multi::many0;
15use nom::number::streaming::{be_u24, be_u32, be_u64, be_u8};
16use nom::IResult;
17
18use num_enum::TryFromPrimitive;
19use std::convert::TryFrom;
20use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
21
22#[derive(Debug)]
23pub struct Diameter {}
24
25#[derive(Debug, PartialEq, Eq)]
26pub struct Header {
27 version: u8,
28 length: u32, flags: u8,
30 code: u32, app_id: u32,
32 hop_id: u32,
33 end_id: u32,
34}
35
36#[derive(Debug, PartialEq, Eq, TryFromPrimitive)]
38#[repr(u32)]
39pub enum AttributeCode {
40 Unknown = 0,
41 AcctInterimInterval = 85,
42 AccountingRealtimeRequired = 483,
43 AcctMultiSessionId = 50,
44 AccountingRecordNumber = 485,
45 AccountingRecordType = 480,
46 AcctSessionId = 44,
47 AccountingSubSessionId = 287,
48 AcctApplicationId = 259,
49 AuthApplicationId = 258,
50 AuthRequestType = 274,
51 AuthorizationLifetime = 291,
52 AuthGracePeriod = 276,
53 AuthSessionState = 277,
54 ReAuthRequestType = 285,
55 Class = 25,
56 DestinationHost = 293,
57 DestinationRealm = 235,
58 DisconnectCause = 273,
59 ErrorMessage = 281,
60 ErrorReportingHost = 294,
61 EventTimestamp = 55,
62 ExperimentalResult = 297,
63 ExperimentalResultCode = 298,
64 FailedAVP = 279,
65 FirmwareRevision = 267,
66 HostIPAddress = 257,
67 InbandSecurityId = 299,
68 MultiRoundTimeOut = 272,
69 OriginHost = 264,
70 OriginRealm = 296,
71 OriginStateId = 278,
72 ProductName = 269,
73 ProxyHost = 280,
74 ProxyInfo = 284,
75 ProxyState = 33,
76 RedirectHost = 292,
77 RedirectHostUsage = 261,
78 RedirectMaxCacheTime = 262,
79 ResultCode = 268,
80 RouteRecord = 282,
81 SessionId = 263,
82 SessionTimeout = 27,
83 SessionBinding = 270,
84 SessionServerFailover = 271,
85 SupportedVendorId = 265,
86 TerminationCause = 295,
87 UserName = 1,
88 VendorId = 266,
89 VendorSpecificApplicationId = 260,
90}
91
92#[derive(Debug, PartialEq, Eq)]
93pub struct Attribute {
94 raw: u32,
96 code: AttributeCode,
98}
99
100impl Attribute {
101 pub fn new(val: u32) -> Self {
102 Attribute {
103 raw: val,
104 code: AttributeCode::try_from(val).unwrap_or(AttributeCode::Unknown),
105 }
106 }
107}
108
109#[derive(Debug, PartialEq)]
111pub enum Value {
112 Unhandled(Vec<u8>),
113 OctetString(Vec<u8>),
114 Integer32(i32),
115 Integer64(i64),
116 Unsigned32(u32),
117 Unsigned64(u64),
118 Float32(f32),
119 Float64(f64),
120 Grouped(Vec<AVP>),
121 Enumerated(u32),
122 UTF8String(String),
123 DiameterIdentity(String),
124 DiameterURI(String),
125 Address(std::net::IpAddr),
126 Time(u32),
127}
128
129impl Value {
130 pub fn new<'a>(
131 code: &AttributeCode,
132 data: &'a [u8],
133 ) -> IResult<&'a [u8], (Self, Flags<ErrorFlags>)> {
134 match code {
135 AttributeCode::AcctSessionId | AttributeCode::ProxyState => {
136 Ok((&[], (Value::OctetString(data.into()), ErrorFlags::none())))
137 }
138 AttributeCode::AcctInterimInterval
139 | AttributeCode::AccountingRecordNumber
140 | AttributeCode::AcctApplicationId
141 | AttributeCode::AuthApplicationId
142 | AttributeCode::AuthorizationLifetime
143 | AttributeCode::AuthGracePeriod
144 | AttributeCode::ExperimentalResultCode
145 | AttributeCode::FirmwareRevision
146 | AttributeCode::InbandSecurityId
147 | AttributeCode::MultiRoundTimeOut
148 | AttributeCode::OriginStateId
149 | AttributeCode::RedirectMaxCacheTime
150 | AttributeCode::ResultCode
151 | AttributeCode::SessionTimeout
152 | AttributeCode::SessionBinding
153 | AttributeCode::SupportedVendorId
154 | AttributeCode::VendorId => {
155 let (input, val) = be_u32(data)?;
156 Ok((input, (Value::Unsigned32(val), ErrorFlags::none())))
157 }
158 AttributeCode::AccountingSubSessionId => {
159 let (input, val) = be_u64(data)?;
160 Ok((input, (Value::Unsigned64(val), ErrorFlags::none())))
161 }
162 AttributeCode::AccountingRealtimeRequired
163 | AttributeCode::AccountingRecordType
164 | AttributeCode::AuthRequestType
165 | AttributeCode::AuthSessionState
166 | AttributeCode::ReAuthRequestType
167 | AttributeCode::DisconnectCause
168 | AttributeCode::RedirectHostUsage
169 | AttributeCode::SessionServerFailover
170 | AttributeCode::TerminationCause => {
171 let (input, val) = be_u32(data)?;
172 Ok((input, (Value::Enumerated(val), ErrorFlags::none())))
173 }
174 AttributeCode::ExperimentalResult
175 | AttributeCode::FailedAVP
176 | AttributeCode::ProxyInfo
177 | AttributeCode::VendorSpecificApplicationId => {
178 let (input, (avps, error_flags)) = parse_avps(data)?;
179 Ok((input, (Value::Grouped(avps), error_flags)))
180 }
181 AttributeCode::AcctMultiSessionId
182 | AttributeCode::Class
183 | AttributeCode::ErrorMessage
184 | AttributeCode::ProductName
185 | AttributeCode::SessionId
186 | AttributeCode::UserName => match String::from_utf8(data.to_vec()) {
187 Ok(string) => Ok((&[], (Value::UTF8String(string), ErrorFlags::none()))),
188 Err(_) => Ok((
189 &[],
190 (Value::Unhandled(data.into()), ErrorFlags::DataValue.into()),
191 )),
192 },
193 AttributeCode::DestinationHost
194 | AttributeCode::DestinationRealm
195 | AttributeCode::ErrorReportingHost
196 | AttributeCode::OriginHost
197 | AttributeCode::OriginRealm
198 | AttributeCode::ProxyHost
199 | AttributeCode::RouteRecord => match String::from_utf8(data.to_vec()) {
200 Ok(string) => Ok((&[], (Value::DiameterIdentity(string), ErrorFlags::none()))),
201 Err(_) => Ok((
202 &[],
203 (Value::Unhandled(data.into()), ErrorFlags::DataValue.into()),
204 )),
205 },
206 AttributeCode::RedirectHost => match String::from_utf8(data.to_vec()) {
207 Ok(string) => Ok((&[], (Value::DiameterURI(string), ErrorFlags::none()))),
208 Err(_) => Ok((
209 &[],
210 (Value::Unhandled(data.into()), ErrorFlags::DataValue.into()),
211 )),
212 },
213 AttributeCode::HostIPAddress => match data.len() {
214 4 => Ok((
215 &[],
216 (
217 Value::Address(IpAddr::V4(Ipv4Addr::from(
219 <[u8; 4]>::try_from(data).unwrap(),
220 ))),
221 ErrorFlags::none(),
222 ),
223 )),
224 16 => Ok((
225 &[],
226 (
227 Value::Address(IpAddr::V6(Ipv6Addr::from(
229 <[u8; 16]>::try_from(data).unwrap(),
230 ))),
231 ErrorFlags::none(),
232 ),
233 )),
234 _ => Ok((
235 &[],
236 (Value::Unhandled(data.into()), ErrorFlags::DataLength.into()),
237 )),
238 },
239 AttributeCode::EventTimestamp => {
240 let (input, seconds) = be_u32(data)?;
241 Ok((input, (Value::Time(seconds), ErrorFlags::none())))
242 }
243 _ => Ok((&[], (Value::Unhandled(data.into()), ErrorFlags::none()))),
244 }
245 }
246}
247
248#[derive(Debug, PartialEq)]
249pub struct AVP {
250 attribute: Attribute,
251 flags: u8,
252 length: u32, vendor_id: Option<u32>,
254 value: Value,
255 padding: Vec<u8>,
256}
257
258#[repr(u8)]
263#[derive(Clone, Copy, Debug, PartialEq, Eq, BitFlags)]
264pub enum ErrorFlags {
265 DataValue = 0b0000_0001,
266 DataLength = 0b0000_0010,
267 NonZeroReserved = 0b0000_0100,
268 NonZeroPadding = 0b0000_1000,
269}
270
271#[derive(Debug, PartialEq)]
272pub struct Message {
273 pub header: Header,
274 pub avps: Vec<AVP>,
275 pub error_flags: Flags<ErrorFlags>,
276}
277
278fn length(read: usize) -> impl Fn(&[u8]) -> IResult<&[u8], u32> {
283 move |input: &[u8]| {
284 let (input, length) = be_u24(input)?;
285 let len = length as usize;
286 if len < read {
287 Err(nom::Err::Error(NomError::new(
288 input,
289 ErrorKind::LengthValue,
290 )))
291 } else if len > (input.len() + read) {
292 Err(nom::Err::Incomplete(nom::Needed::new(
293 len - (input.len() + read),
294 )))
295 } else {
296 Ok((input, length))
297 }
298 }
299}
300
301impl Header {
302 const SIZE: usize = 20;
303 const PRE_LENGTH_SIZE: usize = 4;
306
307 pub const REQUEST_FLAG: u8 = 0b1000_0000;
309 pub const PROXIABLE_FLAG: u8 = 0b0100_0000;
310 pub const ERROR_FLAG: u8 = 0b0010_0000;
311 pub const POTENTIALLY_RETRANSMITTED_FLAG: u8 = 0b0001_0000;
312 pub const RESERVED_MASK: u8 = 0b0000_1111;
313
314 fn reserved_set(flags: u8) -> bool {
315 flags & Self::RESERVED_MASK != 0
316 }
317
318 pub fn is_request(&self) -> bool {
321 self.flags & Self::REQUEST_FLAG != 0
322 }
323
324 pub fn is_proxiable(&self) -> bool {
327 self.flags & Self::PROXIABLE_FLAG != 0
328 }
329
330 pub fn is_error(&self) -> bool {
335 self.flags & Self::ERROR_FLAG != 0
336 }
337
338 pub fn is_potentially_retransmitted(&self) -> bool {
343 self.flags & Self::POTENTIALLY_RETRANSMITTED_FLAG != 0
344 }
345
346 pub fn get_reserved(&self) -> u8 {
349 self.flags & Self::RESERVED_MASK
350 }
351
352 pub fn length(&self) -> usize {
354 (self.length as usize) - Self::SIZE
355 }
356
357 pub fn parse(input: &[u8]) -> IResult<&[u8], (Self, Flags<ErrorFlags>)> {
358 let mut error_flags = ErrorFlags::none();
359 let (input, version) = tag(&[1u8])(input)?;
360 let (input, length) = length(Self::PRE_LENGTH_SIZE)(input)?;
361 if (length as usize) < Self::SIZE {
362 return Err(nom::Err::Error(NomError::new(
363 input,
364 ErrorKind::LengthValue,
365 )));
366 }
367 let (input, flags) = be_u8(input)?;
368 if Self::reserved_set(flags) {
369 error_flags |= ErrorFlags::NonZeroReserved;
370 }
371 let (input, code) = be_u24(input)?;
372 let (input, app_id) = be_u32(input)?;
373 let (input, hop_id) = be_u32(input)?;
374 let (input, end_id) = be_u32(input)?;
375
376 Ok((
377 input,
378 (
379 Self {
380 version: version[0],
381 length,
382 flags,
383 code,
384 app_id,
385 hop_id,
386 end_id,
387 },
388 error_flags,
389 ),
390 ))
391 }
392}
393
394impl AVP {
395 const PRE_LENGTH_SIZE: usize = 8;
398
399 pub const VENDOR_SPECIFIC_FLAG: u8 = 0b1000_0000;
401 pub const MANDATORY_FLAG: u8 = 0b0100_0000;
402 pub const PROTECTED_FLAG: u8 = 0b0010_0000;
403 pub const RESERVED_MASK: u8 = 0b0001_1111;
404
405 fn vendor_specific_flag(flags: u8) -> bool {
406 flags & Self::VENDOR_SPECIFIC_FLAG != 0
407 }
408
409 fn reserved_set(flags: u8) -> bool {
410 flags & Self::RESERVED_MASK != 0
411 }
412
413 fn padding(length: usize) -> usize {
414 match length % 4 {
415 0 => 0,
416 n => 4 - n,
417 }
418 }
419
420 pub fn is_vendor_specific(&self) -> bool {
425 Self::vendor_specific_flag(self.flags)
426 }
427
428 pub fn is_mandatory(&self) -> bool {
432 self.flags & Self::MANDATORY_FLAG != 0
433 }
434
435 pub fn is_protected(&self) -> bool {
438 self.flags & Self::PROTECTED_FLAG != 0
439 }
440
441 pub fn get_reserved(&self) -> u8 {
444 self.flags & Self::RESERVED_MASK
445 }
446
447 pub fn parse(input: &[u8]) -> IResult<&[u8], (Self, Flags<ErrorFlags>)> {
448 let mut error_flags = ErrorFlags::none();
449 let (input, raw_code) = be_u32(input)?;
450 let (input, flags) = be_u8(input)?;
451 if Self::reserved_set(flags) {
452 error_flags |= ErrorFlags::NonZeroReserved;
453 }
454 let (input, length) = length(Self::PRE_LENGTH_SIZE)(input)?;
455 let header_size = if Self::vendor_specific_flag(flags) {
456 Self::PRE_LENGTH_SIZE + 4
457 } else {
458 Self::PRE_LENGTH_SIZE
459 };
460 if (length as usize) < header_size {
461 return Err(nom::Err::Error(NomError::new(
462 input,
463 ErrorKind::LengthValue,
464 )));
465 }
466 let data_length = (length as usize) - header_size;
467 let (input, vendor_id) = if Self::vendor_specific_flag(flags) {
468 let (input, v) = be_u32(input)?;
469 (input, Some(v))
470 } else {
471 (input, None)
472 };
473
474 let (input, data) = take(data_length)(input)?;
475 let (input, padding) = take(Self::padding(data_length))(input)?;
476 if !padding.iter().all(|&item| item == 0) {
477 error_flags |= ErrorFlags::NonZeroPadding;
478 }
479 let attribute = Attribute::new(raw_code);
480 let value = match Value::new(&attribute.code, data) {
481 Ok((rest, (value, flags))) => {
482 if !rest.is_empty() {
483 error_flags |= ErrorFlags::DataLength;
484 }
485 error_flags |= flags;
486 value
487 }
488 Err(nom::Err::Error(NomError {
489 input: _,
490 code: ErrorKind::LengthValue,
491 }))
492 | Err(nom::Err::Incomplete(_)) => {
493 error_flags |= ErrorFlags::DataLength;
494 Value::Unhandled(data.into())
495 }
496 Err(_) => {
497 error_flags |= ErrorFlags::DataValue;
498 Value::Unhandled(data.into())
499 }
500 };
501
502 Ok((
503 input,
504 (
505 Self {
506 attribute,
507 flags,
508 length,
509 vendor_id,
510 value,
511 padding: padding.into(),
512 },
513 error_flags,
514 ),
515 ))
516 }
517}
518
519impl Protocol<'_> for Diameter {
520 type Message = Message;
521
522 fn name() -> &'static str {
523 "diameter"
524 }
525}
526
527fn parse_avps(input: &[u8]) -> IResult<&[u8], (Vec<AVP>, Flags<ErrorFlags>)> {
528 let (rest, avps_flags) = many0(combinator::complete(AVP::parse))(input)?;
529 if !rest.is_empty() {
530 Err(nom::Err::Error(NomError::new(input, ErrorKind::Many0)))
532 } else {
533 let mut error_flags = ErrorFlags::none();
534 let mut avps = Vec::new();
535 for (avp, flag) in avps_flags {
536 error_flags |= flag;
537 avps.push(avp)
538 }
539
540 Ok((rest, (avps, error_flags)))
541 }
542}
543
544impl<'a> Parse<'a> for Diameter {
545 fn parse(
546 &self,
547 input: &'a [u8],
548 _direction: Direction,
549 ) -> Result<(&'a [u8], Option<Self::Message>)> {
550 let mut error_flags = ErrorFlags::none();
551 let (input, (header, flags)) = Header::parse(input)?;
552 error_flags |= flags;
553
554 let (input, avps_input) = combinator::complete(take(header.length()))(input)?;
557 let (_, (avps, flags)) = parse_avps(avps_input)?;
558 error_flags |= flags;
559 Ok((
560 input,
561 Some(Message {
562 header,
563 avps,
564 error_flags,
565 }),
566 ))
567 }
568}
569
570impl<'a> Probe<'a> for Diameter {}
571
572#[cfg(test)]
573mod tests {
574 use super::*;
575 use rstest::rstest;
576 use sawp::error;
577 use sawp::probe::Status;
578
579 #[test]
580 fn test_name() {
581 assert_eq!(Diameter::name(), "diameter");
582 }
583
584 #[rstest(
585 input,
586 expected,
587 case::empty(b"", Err(nom::Err::Incomplete(nom::Needed::new(1)))),
588 case::hello_world(b"hello world", Err(nom::Err::Error(NomError::new(b"hello world" as &[u8], ErrorKind::Tag)))),
589 case::invalid_length(
590 &[
591 0x01,
593 0x00, 0x00, 0x0c,
595 0x80,
597 0x00, 0x01, 0x01,
599 0x00, 0x00, 0x00, 0x00,
601 0x53, 0xca, 0xfe, 0x6a,
603 0x7d, 0xc0, 0xa1, 0x1b,
605 ],
606 Err(nom::Err::Error(NomError::new(
607 &[
608 0x80_u8,
610 0x00, 0x01, 0x01,
612 0x00, 0x00, 0x00, 0x00,
614 0x53, 0xca, 0xfe, 0x6a,
616 0x7d, 0xc0, 0xa1, 0x1b,
618 ] as &[u8],
619 ErrorKind::LengthValue))
620 )
621 ),
622 case::diagnostic(
623 &[
624 0x01,
626 0x00, 0x00, 0x14,
628 0x80,
630 0x00, 0x01, 0x01,
632 0x00, 0x00, 0x00, 0x00,
634 0x53, 0xca, 0xfe, 0x6a,
636 0x7d, 0xc0, 0xa1, 0x1b,
638 ],
639 Ok((&[] as &[u8],
640 (
641 Header {
642 version: 1,
643 length: 20,
644 flags: 128,
645 code: 257,
646 app_id: 0,
647 hop_id: 0x53ca_fe6a,
648 end_id: 0x7dc0_a11b,
649 },
650 ErrorFlags::none(),
651 )))
652 ),
653 case::reserved_set(
654 &[
655 0x01,
657 0x00, 0x00, 0x14,
659 0x0f,
661 0x00, 0x01, 0x01,
663 0x00, 0x00, 0x00, 0x00,
665 0x53, 0xca, 0xfe, 0x6a,
667 0x7d, 0xc0, 0xa1, 0x1b,
669 ],
670 Ok((&[] as &[u8],
671 (
672 Header {
673 version: 1,
674 length: 20,
675 flags: 15,
676 code: 257,
677 app_id: 0,
678 hop_id: 0x53ca_fe6a,
679 end_id: 0x7dc0_a11b,
680 },
681 ErrorFlags::NonZeroReserved.into(),
682 )))
683 ),
684 case::diagnostic(
685 &[
686 0x01,
688 0x00, 0x00, 0x18,
690 0x80,
692 0x00, 0x01, 0x01,
694 0x00, 0x00, 0x00, 0x00,
696 0x53, 0xca, 0xfe, 0x6a,
698 0x7d, 0xc0, 0xa1, 0x1b,
700 ],
701 Err(nom::Err::Incomplete(nom::Needed::new(4)))
702 ),
703 )]
704 fn test_header(input: &[u8], expected: IResult<&[u8], (Header, Flags<ErrorFlags>)>) {
705 assert_eq!(Header::parse(input), expected);
706 }
707
708 #[rstest(
709 input,
710 expected,
711 case::empty(b"", Err(nom::Err::Incomplete(nom::Needed::new(4)))),
712 case::diagnostic(
713 &[
714 0x00, 0x00, 0x01, 0x08,
716 0x40,
718 0x00, 0x00, 0x1f,
720 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2e,
722 0x65, 0x61, 0x70, 0x2e, 0x74, 0x65, 0x73, 0x74,
723 0x62, 0x65, 0x64, 0x2e, 0x61, 0x61, 0x61,
724 0x00,
726 ],
727 Ok((&[] as &[u8],
728 (
729 AVP {
730 attribute: Attribute {
731 raw: 264,
732 code: AttributeCode::OriginHost,
733 },
734 flags: 0x40,
735 length: 31,
736 vendor_id: None,
737 value: Value::DiameterIdentity("backend.eap.testbed.aaa".into()),
738 padding: vec![0x00],
739 },
740 ErrorFlags::none(),
741 )))
742 ),
743 case::diagnostic_vendor_id(
744 &[
745 0x00, 0x00, 0x01, 0x08,
747 0x80,
749 0x00, 0x00, 0x0c,
751 0x49, 0x96, 0x02, 0xd2,
753 ],
756 Ok((&[] as &[u8],
757 (
758 AVP {
759 attribute: Attribute {
760 raw: 264,
761 code: AttributeCode::OriginHost,
762 },
763 flags: 0x80,
764 length: 12,
765 vendor_id: Some(1_234_567_890u32),
766 value: Value::DiameterIdentity("".into()),
767 padding: Vec::new(),
768 },
769 ErrorFlags::none(),
770 )))
771 ),
772 case::unsigned_32_format(
773 &[
774 0x00, 0x00, 0x01, 0x0a,
776 0x00,
778 0x00, 0x00, 0x0d,
780 0x00, 0x00, 0x00, 0x7b,
783 0x01,
784 0x00, 0x00, 0x00,
786 ],
787 Ok((&[] as &[u8],
788 (
789 AVP {
790 attribute: Attribute {
791 raw: 266,
792 code: AttributeCode::VendorId,
793 },
794 flags: 0x00,
795 length: 13,
796 vendor_id: None,
797 value: Value::Unsigned32(123),
798
799 padding: vec![0x00, 0x00, 0x00],
800 },
801 ErrorFlags::DataLength.into(),
802 )))
803 ),
804 case::unsigned_64_format(
805 &[
806 0x00, 0x00, 0x01, 0x1f,
808 0x00,
810 0x00, 0x00, 0x10,
812 0x00, 0x00, 0x00, 0x7B,
815 0x01, 0x02, 0x02, 0x03,
816 ],
817 Ok((&[] as &[u8],
818 (
819 AVP {
820 attribute: Attribute {
821 raw: 287,
822 code: AttributeCode::AccountingSubSessionId,
823 },
824 flags: 0x00,
825 length: 16,
826 vendor_id: None,
827 value: Value::Unsigned64(528_297_886_211),
828 padding: Vec::new(),
829 },
830 ErrorFlags::none(),
831 )))
832 ),
833 case::enumerated_format(
834 &[
835 0x00, 0x00, 0x01, 0xe3,
837 0x00,
839 0x00, 0x00, 0x0c,
841 0x00, 0x00, 0x00, 0x02,
844 ],
845 Ok((&[] as &[u8],
846 (
847 AVP {
848 attribute: Attribute {
849 raw: 483,
850 code: AttributeCode::AccountingRealtimeRequired,
851 },
852 flags: 0x00,
853 length: 12,
854 vendor_id: None,
855 value: Value::Enumerated(2),
856 padding: Vec::new(),
857 },
858 ErrorFlags::none(),
859 )))
860 ),
861 case::octet_string_format(
862 &[
863 0x00, 0x00, 0x00, 0x2c,
865 0x00,
867 0x00, 0x00, 0x0f,
869 0x01, 0x02, 0x03, 0x04,
872 0x05, 0x06, 0x07,
873 0xef,
875 ],
876 Ok((&[] as &[u8],
877 (
878 AVP {
879 attribute: Attribute {
880 raw: 44,
881 code: AttributeCode::AcctSessionId,
882 },
883 flags: 0x00,
884 length: 15,
885 vendor_id: None,
886 value: Value::OctetString(vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]),
887 padding: vec![0xef],
888 },
889 ErrorFlags::NonZeroPadding.into(),
890 )))
891 ),
892 case::utf8_string_format(
893 &[
894 0x00, 0x00, 0x00, 0x01,
896 0x00,
898 0x00, 0x00, 0x14,
900 0x48, 0x65, 0x6c, 0x6c,
903 0x6f, 0x20, 0x57, 0x6f,
904 0x72, 0x6c, 0x64, 0x21,
905 ],
906 Ok((&[] as &[u8],
907 (
908 AVP {
909 attribute: Attribute {
910 raw: 1,
911 code: AttributeCode::UserName,
912 },
913 flags: 0x00,
914 length: 20,
915 vendor_id: None,
916 value: Value::UTF8String("Hello World!".into()),
917 padding: Vec::new(),
918 },
919 ErrorFlags::none(),
920 )))
921 ),
922 case::diameter_uri_format(
923 &[
924 0x00, 0x00, 0x01, 0x24,
926 0x00,
928 0x00, 0x00, 0x13,
930 0x65, 0x78, 0x61, 0x6d,
933 0x70, 0x6c, 0x65, 0x2e,
934 0x63, 0x6f, 0x6d,
935 0x00,
937 ],
938 Ok((&[] as &[u8],
939 (
940 AVP {
941 attribute: Attribute {
942 raw: 292,
943 code: AttributeCode::RedirectHost,
944 },
945 flags: 0x00,
946 length: 19,
947 vendor_id: None,
948 value: Value::DiameterURI("example.com".into()),
949 padding: vec![0x00],
950 },
951 ErrorFlags::none(),
952 )))
953 ),
954 case::address_v4_format(
955 &[
956 0x00, 0x00, 0x01, 0x01,
958 0x0f,
960 0x00, 0x00, 0x0c,
962 0x0a, 0x0a, 0x00, 0x01,
965 ],
966 Ok((&[] as &[u8],
967 (
968 AVP {
969 attribute: Attribute {
970 raw: 257,
971 code: AttributeCode::HostIPAddress,
972 },
973 flags: 0x0f,
974 length: 12,
975 vendor_id: None,
976 value: Value::Address(IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1))),
977 padding: Vec::new(),
978 },
979 ErrorFlags::NonZeroReserved.into(),
980 )))
981 ),
982 case::address_v6_format(
983 &[
984 0x00, 0x00, 0x01, 0x01,
986 0x00,
988 0x00, 0x00, 0x18,
990 0x20, 0x01, 0x0d, 0xb8,
993 0x85, 0xa3, 0x00, 0x00,
994 0x00, 0x00, 0x8a, 0x2e,
995 0x03, 0x70, 0x73, 0x34,
996 ],
997 Ok((&[] as &[u8],
998 (
999 AVP {
1000 attribute: Attribute {
1001 raw: 257,
1002 code: AttributeCode::HostIPAddress,
1003 },
1004 flags: 0x00,
1005 length: 24,
1006 vendor_id: None,
1007 value: Value::Address(IpAddr::V6(Ipv6Addr::new(
1008 0x2001, 0x0db8, 0x85a3, 0x0000,
1009 0x0000, 0x8a2e, 0x0370, 0x7334))),
1010 padding: Vec::new(),
1011 },
1012 ErrorFlags::none(),
1013 )))
1014 ),
1015 case::time_format(
1016 &[
1017 0x00, 0x00, 0x00, 0x37,
1019 0x00,
1021 0x00, 0x00, 0x0c,
1023 0xe2, 0x2d, 0x06, 0x80
1026 ],
1027 Ok((&[] as &[u8],
1028 (
1029 AVP {
1030 attribute: Attribute {
1031 raw: 55,
1032 code: AttributeCode::EventTimestamp,
1033 },
1034 flags: 0x00,
1035 length: 12,
1036 vendor_id: None,
1037 value: Value::Time(3_794_601_600),
1038 padding: Vec::new(),
1039 },
1040 ErrorFlags::none(),
1041 )))
1042 ),
1043 case::grouped_format(
1044 &[
1045 0x00, 0x00, 0x01, 0x29,
1047 0x00,
1049 0x00, 0x00, 0x2c,
1051 0x00, 0x00, 0x01, 0x08,
1057 0x00,
1059 0x00, 0x00, 0x13,
1061 0x65, 0x78, 0x61, 0x6d,
1064 0x70, 0x6c, 0x65, 0x2e,
1065 0x63, 0x6f, 0x6d,
1066 0x01,
1068
1069 0x00, 0x00, 0x00, 0x2c,
1072 0x0f,
1074 0x00, 0x00, 0x0f,
1076 0x01, 0x02, 0x03, 0x04,
1079 0x05, 0x06, 0x07,
1080 0x00,
1082 ],
1083 Ok((&[] as &[u8],
1084 (
1085 AVP {
1086 attribute: Attribute {
1087 raw: 297,
1088 code: AttributeCode::ExperimentalResult,
1089 },
1090 flags: 0x00,
1091 length: 44,
1092 vendor_id: None,
1093 value: Value::Grouped(vec![
1094 AVP {
1095 attribute: Attribute {
1096 raw: 264,
1097 code: AttributeCode::OriginHost,
1098 },
1099 flags: 0x00,
1100 length: 19,
1101 vendor_id: None,
1102 value: Value::DiameterIdentity("example.com".into()),
1103 padding: vec![0x01],
1104 },
1105 AVP {
1106 attribute: Attribute {
1107 raw: 44,
1108 code: AttributeCode::AcctSessionId,
1109 },
1110 flags: 0x0f,
1111 length: 15,
1112 vendor_id: None,
1113 value: Value::OctetString(vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]),
1114 padding: vec![0x00],
1115 }]),
1116 padding: Vec::new(),
1117 },
1118 ErrorFlags::NonZeroPadding | ErrorFlags::NonZeroReserved
1119 )))
1120 ),
1121 case::invalid_utf8(
1122 &[
1123 0x00, 0x00, 0x00, 0x01,
1125 0x00,
1127 0x00, 0x00, 0x0c,
1129 0xfe, 0xfe, 0xff, 0xff,
1132 ],
1133 Ok((&[] as &[u8],
1134 (
1135 AVP {
1136 attribute: Attribute {
1137 raw: 1,
1138 code: AttributeCode::UserName,
1139 },
1140 flags: 0x00,
1141 length: 12,
1142 vendor_id: None,
1143 value: Value::Unhandled(vec![0xfe, 0xfe, 0xff, 0xff]),
1144 padding: Vec::new(),
1145 },
1146 ErrorFlags::DataValue.into(),
1147 )))
1148 ),
1149 case::invalid_address(
1150 &[
1151 0x00, 0x00, 0x01, 0x01,
1153 0x00,
1155 0x00, 0x00, 0x0d,
1157 0x0a, 0x0a, 0x00, 0x01, 0x01,
1160 0x00, 0x00, 0x00,
1162 ],
1163 Ok((&[] as &[u8],
1164 (
1165 AVP {
1166 attribute: Attribute {
1167 raw: 257,
1168 code: AttributeCode::HostIPAddress,
1169 },
1170 flags: 0x00,
1171 length: 13,
1172 vendor_id: None,
1173 value: Value::Unhandled(vec![0x0a, 0x0a, 0x00, 0x01, 0x01]),
1174 padding: vec![0x00, 0x00, 0x00],
1175 },
1176 ErrorFlags::DataLength.into(),
1177 )))
1178 ),
1179 case::unhandled(
1180 &[
1181 0x00, 0x00, 0x00, 0x02,
1183 0x00,
1185 0x00, 0x00, 0x0d,
1187 0x0a, 0x0a, 0x00, 0x01, 0x01,
1190 0x00, 0x00, 0x00,
1192 ],
1193 Ok((&[] as &[u8],
1194 (
1195 AVP {
1196 attribute: Attribute {
1197 raw: 2,
1198 code: AttributeCode::Unknown,
1199 },
1200 flags: 0x00,
1201 length: 13,
1202 vendor_id: None,
1203 value: Value::Unhandled(vec![0x0a, 0x0a, 0x00, 0x01, 0x01]),
1204 padding: vec![0x00, 0x00, 0x00],
1205 },
1206 ErrorFlags::none(),
1207 )))
1208 )
1209 )]
1210 fn test_avp(input: &[u8], expected: IResult<&[u8], (AVP, Flags<ErrorFlags>)>) {
1211 assert_eq!(AVP::parse(input), expected);
1212 }
1213
1214 #[rstest(
1215 input,
1216 expected,
1217 case::empty(b"", Err(error::Error::incomplete_needed(1))),
1218 case::header(
1219 &[
1220 0x01,
1222 0x00, 0x00, 0x14,
1224 0x80,
1226 0x00, 0x01, 0x01,
1228 0x00, 0x00, 0x00, 0x00,
1230 0x53, 0xca, 0xfe, 0x6a,
1232 0x7d, 0xc0, 0xa1, 0x1b,
1234 ],
1235 Ok((&[] as &[u8],
1236 Some(Message {
1237 header: Header {
1238 version: 1,
1239 length: 20,
1240 flags: 128,
1241 code: 257,
1242 app_id: 0,
1243 hop_id: 0x53ca_fe6a,
1244 end_id: 0x7dc0_a11b,
1245 },
1246 avps: Vec::new(),
1247 error_flags: ErrorFlags::none(),
1248 })
1249 ))
1250 ),
1251 case::full_message(
1252 &[
1253 0x01,
1256 0x00, 0x00, 0x40,
1258 0x8f,
1260 0x00, 0x01, 0x01,
1262 0x00, 0x00, 0x00, 0x00,
1264 0x53, 0xca, 0xfe, 0x6a,
1266 0x7d, 0xc0, 0xa1, 0x1b,
1268
1269 0x00, 0x00, 0x01, 0x08,
1272 0x40,
1274 0x00, 0x00, 0x1f,
1276 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2e,
1278 0x65, 0x61, 0x70, 0x2e, 0x74, 0x65, 0x73, 0x74,
1279 0x62, 0x65, 0x64, 0x2e, 0x61, 0x61, 0x61,
1280 0x01,
1282
1283 0x00, 0x00, 0x01, 0x08,
1286 0x80,
1288 0x00, 0x00, 0x0c,
1290 0x49, 0x96, 0x02, 0xd2,
1292 ],
1295 Ok((&[] as &[u8],
1296 Some(Message {
1297 header: Header {
1298 version: 1,
1299 length: 64,
1300 flags: 143,
1301 code: 257,
1302 app_id: 0,
1303 hop_id: 0x53ca_fe6a,
1304 end_id: 0x7dc0_a11b,
1305 },
1306 avps: vec![
1307 AVP {
1308 attribute: Attribute {
1309 raw: 264,
1310 code: AttributeCode::OriginHost,
1311 },
1312 flags: 0x40,
1313 length: 31,
1314 vendor_id: None,
1315 value: Value::DiameterIdentity("backend.eap.testbed.aaa".into()),
1316 padding: vec![0x01],
1317 },
1318 AVP {
1319 attribute: Attribute {
1320 raw: 264,
1321 code: AttributeCode::OriginHost,
1322 },
1323 flags: 0x80,
1324 length: 12,
1325 vendor_id: Some(1_234_567_890u32),
1326 value: Value::DiameterIdentity("".into()),
1327 padding: Vec::new(),
1328 },
1329 ],
1330 error_flags : ErrorFlags::NonZeroReserved | ErrorFlags::NonZeroPadding,
1331 })
1332 ))),
1333 case::incomplete(
1334 &[
1335 0x01,
1338 0x00, 0x00, 0x42,
1340 0x80,
1342 0x00, 0x01, 0x01,
1344 0x00, 0x00, 0x00, 0x00,
1346 0x53, 0xca, 0xfe, 0x6a,
1348 0x7d, 0xc0, 0xa1, 0x1b,
1350
1351 0x00, 0x00, 0x01, 0x08,
1354 0x40,
1356 0x00, 0x00, 0x1f,
1358 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2e,
1360 0x65, 0x61, 0x70, 0x2e, 0x74, 0x65, 0x73, 0x74,
1361 0x62, 0x65, 0x64, 0x2e, 0x61, 0x61, 0x61,
1362 0x00,
1364
1365 0x00, 0x00, 0x01, 0x08,
1368 0x80,
1370 0x00, 0x00, 0x0e,
1372 0x49, 0x96, 0x02, 0xd2,
1374 ],
1377 Err(error::Error::incomplete_needed(2))
1378 ),
1379 case::invalid_avp(
1380 &[
1381 0x01,
1384 0x00, 0x00, 0x40,
1386 0x80,
1388 0x00, 0x01, 0x01,
1390 0x00, 0x00, 0x00, 0x00,
1392 0x53, 0xca, 0xfe, 0x6a,
1394 0x7d, 0xc0, 0xa1, 0x1b,
1396
1397 0x00, 0x00, 0x01, 0x08,
1400 0x40,
1402 0x00, 0x00, 0x1f,
1404 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x2e,
1406 0x65, 0x61, 0x70, 0x2e, 0x74, 0x65, 0x73, 0x74,
1407 0x62, 0x65, 0x64, 0x2e, 0x61, 0x61, 0x61,
1408 0x00,
1410
1411 0x00, 0x00, 0x01, 0x08,
1414 0x80,
1416 0x00, 0x00, 0x0e,
1418 0x49, 0x96, 0x02, 0xd2,
1420 ],
1423 Err(error::Error::parse(Some("Many0".to_string()))),
1424 ),
1425 )]
1426 fn test_parse(input: &[u8], expected: Result<(&[u8], Option<Message>)>) {
1427 let diameter = Diameter {};
1428
1429 assert_eq!(diameter.parse(input, Direction::Unknown), expected);
1430 }
1431
1432 #[rstest(
1433 input,
1434 expected,
1435 case::empty(b"", Status::Incomplete),
1436 case::hello_world(b"hello world", Status::Unrecognized),
1437 case::header(
1438 &[
1439 0x01,
1441 0x00, 0x00, 0x14,
1443 0x80,
1445 0x00, 0x01, 0x01,
1447 0x00, 0x00, 0x00, 0x00,
1449 0x53, 0xca, 0xfe, 0x6a,
1451 0x7d, 0xc0, 0xa1, 0x1b,
1453 ],
1454 Status::Recognized
1455 ),
1456 )]
1457 fn test_probe(input: &[u8], expected: Status) {
1458 let diameter = Diameter {};
1459
1460 assert_eq!(diameter.probe(input, Direction::Unknown), expected);
1461 }
1462}