radius_parser/
radius.rs

1//! Radius accounting
2//!
3//! RFC 2865: Remote Authentication Dial In User Service (RADIUS)
4//! RFC 2866: RADIUS Accounting
5
6use crate::radius_attr::*;
7use nom::bytes::streaming::take;
8use nom::combinator::{complete, cond, map, map_parser};
9use nom::multi::many1;
10use nom::number::streaming::{be_u16, be_u8};
11use nom::IResult;
12
13#[derive(Clone, Copy, Debug, PartialEq, Eq)]
14pub struct RadiusCode(pub u8);
15
16#[allow(non_upper_case_globals)]
17impl RadiusCode {
18    pub const AccessRequest: RadiusCode = RadiusCode(1);
19    pub const AccessAccept: RadiusCode = RadiusCode(2);
20    pub const AccessReject: RadiusCode = RadiusCode(3);
21    pub const AccountingRequest: RadiusCode = RadiusCode(4);
22    pub const AccountingResponse: RadiusCode = RadiusCode(5);
23    pub const AccessChallenge: RadiusCode = RadiusCode(11);
24    pub const StatusServer: RadiusCode = RadiusCode(12);
25    pub const StatusClient: RadiusCode = RadiusCode(13);
26    pub const Reserved: RadiusCode = RadiusCode(255);
27}
28
29#[derive(Clone, Debug, PartialEq)]
30pub struct RadiusData<'a> {
31    pub code: RadiusCode,
32    pub identifier: u8,
33    pub length: u16,
34    pub authenticator: &'a [u8], // 16 bytes
35    pub attributes: Option<Vec<RadiusAttribute<'a>>>,
36}
37
38pub fn parse_radius_data(i: &[u8]) -> IResult<&[u8], RadiusData> {
39    let (i, code) = map(be_u8, RadiusCode)(i)?;
40    let (i, identifier) = be_u8(i)?;
41    let (i, length) = be_u16(i)?;
42    let (i, authenticator) = take(16usize)(i)?;
43    // We cannot use cond(length > 20, ... take(length-20) ... here
44    // because `length-20` will be evaluated before cond, resulting in a potential
45    // (though harmless, since not used) integer underflow
46    // So, force lazy evaluation in `take`
47    let (i, attributes) = cond(
48        length > 20,
49        map_parser(
50            |d| take(length - 20)(d),
51            many1(complete(parse_radius_attribute)),
52        ),
53    )(i)?;
54    let data = RadiusData {
55        code,
56        identifier,
57        length,
58        authenticator,
59        attributes,
60    };
61    Ok((i, data))
62}