src/vrrpv2.rs
author Sunil Nimmagadda <sunil@nimmagadda.net>
Thu, 28 Dec 2023 23:17:24 +0530
changeset 16 8c8be538d0e6
parent 13 61c484b134c8
child 17 90d097c9ea62
permissions -rw-r--r--
Refactor parser. Simplify error handling and provide better error Enum to report parsing errors accurately.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
16
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
     1
//! Parser recognising a VRRP v2 packet.
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
     2
use nom::error::Error;
8
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
     3
use nom::multi::count;
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
     4
use nom::number::complete::{be_u16, be_u32, u8};
16
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
     5
use nom::{bits::complete::take, IResult};
7
e3058ceb81cc Module to parse(unimplemented) VRRPv2 packet.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
     6
use std::net::Ipv4Addr;
e3058ceb81cc Module to parse(unimplemented) VRRPv2 packet.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
     7
16
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
     8
type BitInput<'a> = (&'a [u8], usize);
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
     9
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    10
/// A VRRP version 2 packet.
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    11
///
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    12
/// Packet format
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    13
///
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    14
///  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    15
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    16
/// |Version| Type  | Virtual Rtr ID|   Priority    | Count IP Addrs|
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    17
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    18
/// |   Auth Type   |   Adver Int   |          Checksum             |
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    19
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    20
/// |                         IP Address (1)                        |
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    21
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    22
/// |                            .                                  |
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    23
/// |                            .                                  |
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    24
/// |                            .                                  |
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    25
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    26
/// |                         IP Address (n)                        |
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    27
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    28
/// |                     Authentication Data (1)                   |
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    29
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    30
/// |                     Authentication Data (2)                   |
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    31
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    32
#[derive(Debug, PartialEq)]
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    33
pub struct VRRPv2 {
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    34
    pub virtual_router_id: u8,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    35
    pub priority: u8,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    36
    pub count_ip_addrs: u8,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    37
    pub auth_type: VRRPv2AuthType,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    38
    pub advertisement_interval: u8,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    39
    pub checksum: u16,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    40
    pub ip_addrs: Vec<Ipv4Addr>,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    41
}
7
e3058ceb81cc Module to parse(unimplemented) VRRPv2 packet.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    42
8
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
    43
#[derive(Debug, Clone, PartialEq)]
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
    44
pub enum VRRPv2Error {
16
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    45
    InvalidAuthType,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    46
    InvalidChecksum,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    47
    InvalidType,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    48
    InvalidVersion,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    49
    ParseError,
7
e3058ceb81cc Module to parse(unimplemented) VRRPv2 packet.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    50
}
e3058ceb81cc Module to parse(unimplemented) VRRPv2 packet.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    51
8
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
    52
#[derive(Debug, PartialEq)]
7
e3058ceb81cc Module to parse(unimplemented) VRRPv2 packet.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    53
pub enum VRRPv2AuthType {
e3058ceb81cc Module to parse(unimplemented) VRRPv2 packet.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    54
    VRRPv2AuthNoAuth = 0x00,
e3058ceb81cc Module to parse(unimplemented) VRRPv2 packet.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    55
    VRRPv2AuthReserved1 = 0x01,
e3058ceb81cc Module to parse(unimplemented) VRRPv2 packet.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    56
    VRRPv2AuthReserved2 = 0x02,
e3058ceb81cc Module to parse(unimplemented) VRRPv2 packet.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    57
}
e3058ceb81cc Module to parse(unimplemented) VRRPv2 packet.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    58
16
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    59
/// Helper function to let compiler infer generic parameters.
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    60
fn take_nibble(input: BitInput) -> IResult<BitInput, u8> {
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    61
    take(4usize)(input)
8
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
    62
}
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
    63
16
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    64
fn parse(input: &[u8]) -> Result<VRRPv2, VRRPv2Error> {
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    65
    let Ok(((input, _), version)) = take_nibble((input, 0)) else {
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    66
        return Err(VRRPv2Error::ParseError);
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    67
    };
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    68
    if version != 2 {
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    69
        return Err(VRRPv2Error::InvalidVersion);
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    70
    }
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    71
    let Ok(((input, _), type_)) = take_nibble((input, 4)) else {
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    72
        return Err(VRRPv2Error::ParseError);
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    73
    };
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    74
    //Advertisement
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    75
    if type_ != 1 {
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    76
        return Err(VRRPv2Error::InvalidType);
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    77
    }
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    78
    let Ok((input, virtual_router_id)) = u8::<&[u8], Error<&[u8]>>(input) else {
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    79
        return Err(VRRPv2Error::ParseError);
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    80
    };
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    81
    let Ok((input, priority)) = u8::<&[u8], Error<&[u8]>>(input) else {
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    82
        return Err(VRRPv2Error::ParseError);
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    83
    };
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    84
    let Ok((input, count_ip_addrs)) = u8::<&[u8], Error<&[u8]>>(input) else {
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    85
        return Err(VRRPv2Error::ParseError);
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    86
    };
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    87
    let Ok((input, auth_type)) = u8::<&[u8], Error<&[u8]>>(input) else {
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    88
        return Err(VRRPv2Error::ParseError);
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    89
    };
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    90
    let auth_type = match auth_type {
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    91
        0 => VRRPv2AuthType::VRRPv2AuthNoAuth,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    92
        1 => VRRPv2AuthType::VRRPv2AuthReserved1,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    93
        2 => VRRPv2AuthType::VRRPv2AuthReserved2,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    94
        _ => return Err(VRRPv2Error::InvalidAuthType),
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    95
    };
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    96
    let Ok((input, advertisement_interval)) = u8::<&[u8], Error<&[u8]>>(input) else {
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    97
        return Err(VRRPv2Error::ParseError);
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    98
    };
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
    99
    let Ok((input, checksum)) = be_u16::<&[u8], Error<&[u8]>>(input) else {
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   100
        return Err(VRRPv2Error::ParseError);
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   101
    };
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   102
    let Ok((_, xs)) = count(be_u32::<&[u8], Error<&[u8]>>, usize::from(count_ip_addrs))(input)
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   103
    else {
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   104
        return Err(VRRPv2Error::ParseError);
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   105
    };
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   106
    let ip_addrs: Vec<Ipv4Addr> = xs.into_iter().map(Ipv4Addr::from).collect();
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   107
    Ok(VRRPv2 {
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   108
        virtual_router_id,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   109
        priority,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   110
        count_ip_addrs,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   111
        auth_type,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   112
        advertisement_interval,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   113
        checksum,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   114
        ip_addrs,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   115
    })
7
e3058ceb81cc Module to parse(unimplemented) VRRPv2 packet.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   116
}
8
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   117
13
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   118
// Nightly has a nicer array_chunks API to express it more succinctly.
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   119
// let mut chunks = bytes.array_chunks(2);
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   120
// let mut sum = chunks.map(u16::from_ne_bytes).map(|b| b as u32).sum::<u32>();
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   121
// // handle the remainder
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   122
// if let Some([b]) = chunks.remainder() {
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   123
//     sum += *b as u32
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   124
// }
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   125
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   126
// Shadowing can be used to avoid `mut`...
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   127
// let sum =...;
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   128
// let sum = (sum & 0xffff) + (sum >> 16);
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   129
// let sum = (sum & 0xffff) + (sum >> 16);
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   130
// manually un-rolling while loop since it's needed atmost twice for an u32.
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   131
fn validate_checksum(bytes: &[u8]) -> bool {
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   132
    let mut sum: u32 = bytes.chunks(2).fold(0, |acc: u32, x| {
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   133
        acc + u32::from(u16::from_ne_bytes(x.try_into().unwrap()))
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   134
    });
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   135
    while (sum >> 16) > 0 {
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   136
        sum = (sum & 0xffff) + (sum >> 16);
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   137
    }
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   138
    let checksum = !(sum as u16);
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   139
    checksum == 0
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   140
}
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   141
16
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   142
/// Parse and validate a byte array to construct a VRRPv2 struct.
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   143
///
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   144
/// # Examples
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   145
///
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   146
/// ```
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   147
/// use vrrpd::vrrpv2::VRRPv2;
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   148
/// use vrrpd::vrrpv2::VRRPv2AuthType;
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   149
/// use vrrpd::vrrpv2::from_bytes;
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   150
/// use std::net::Ipv4Addr;
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   151
///
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   152
/// let bytes = [
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   153
///    0x21, 0x01, 0x64, 0x01, 0x00, 0x01, 0xba, 0x52, 0xc0, 0xa8, 0x00, 0x01, 0x00, 0x00, 0x00,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   154
///    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   155
/// ];
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   156
/// let expected = VRRPv2 {
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   157
///     virtual_router_id: 1,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   158
///     priority: 100,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   159
///     count_ip_addrs: 1,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   160
///     auth_type: VRRPv2AuthType::VRRPv2AuthNoAuth,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   161
///     checksum: 47698,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   162
///     advertisement_interval: 1,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   163
///     ip_addrs: vec![Ipv4Addr::from([192, 168, 0, 1])],
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   164
/// };
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   165
/// assert_eq!(from_bytes(&bytes), Ok(expected));
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   166
/// ```
8
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   167
pub fn from_bytes(bytes: &[u8]) -> Result<VRRPv2, VRRPv2Error> {
16
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   168
    let vrrpv2 = parse(bytes)?;
13
61c484b134c8 Shuffle code for clarity.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 12
diff changeset
   169
    if !validate_checksum(bytes) {
16
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   170
        return Err(VRRPv2Error::InvalidChecksum);
8
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   171
    }
16
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   172
    Ok(vrrpv2)
8
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   173
}
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   174
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   175
#[test]
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   176
fn test_incomplete_bytes() {
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   177
    let bytes = [0x21, 0x01];
16
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   178
    assert_eq!(from_bytes(&bytes), Err(VRRPv2Error::ParseError));
8
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   179
}
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   180
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   181
#[test]
16
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   182
fn test_invalid_version() {
8
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   183
    let bytes = [
16
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   184
        0x31, 0x2a, 0x64, 0x1, 0x0, 0x1, 0xaa, 0x29, 0xc0, 0xa8, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   185
        0x0, 0x0, 0x0,
8
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   186
    ];
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   187
    let got = from_bytes(&bytes);
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   188
    assert_eq!(got.is_err(), true);
16
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   189
    assert_eq!(got.err(), Some(VRRPv2Error::InvalidVersion));
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   190
}
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   191
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   192
#[test]
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   193
fn test_invalid_type() {
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   194
    let bytes = [
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   195
        0x20, 0x1, 0x2a, 0x0, 0x0, 0x1, 0xb5, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   196
        0x0, 0x0, 0x0,
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   197
    ];
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   198
    let got = from_bytes(&bytes);
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   199
    assert_eq!(got.is_err(), true);
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   200
    assert_eq!(got.err(), Some(VRRPv2Error::InvalidType));
8
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   201
}
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   202
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   203
#[test]
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   204
fn test_invalid_auth_type() {
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   205
    let bytes = [
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   206
        0x21, 0x01, 0x64, 0x01, 0x03, 0x01, 0xba, 0x52, 0xc0, 0xa8, 0x00, 0x01, 0x00, 0x00, 0x00,
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   207
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   208
    ];
16
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   209
    assert_eq!(from_bytes(&bytes), Err(VRRPv2Error::InvalidAuthType));
8
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   210
}
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   211
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   212
#[test]
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   213
fn test_invalid_checksum() {
10
aef7eb135a0c Validate checksum.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 8
diff changeset
   214
    let bytes = [
aef7eb135a0c Validate checksum.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 8
diff changeset
   215
        0x21, 0x01, 0x64, 0x01, 0x00, 0x01, 0xbb, 0x52, 0xc0, 0xa8, 0x00, 0x01, 0x00, 0x00, 0x00,
aef7eb135a0c Validate checksum.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 8
diff changeset
   216
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
aef7eb135a0c Validate checksum.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 8
diff changeset
   217
    ];
16
8c8be538d0e6 Refactor parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 13
diff changeset
   218
    assert_eq!(from_bytes(&bytes), Err(VRRPv2Error::InvalidChecksum));
8
e4cad4eba60b Implement a VRRPv2 packet parser.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents: 7
diff changeset
   219
}