tacacs_plus_protocol/packet/
header.rs

1use byteorder::{ByteOrder, NetworkEndian};
2use getset::{CopyGetters, MutGetters};
3
4use super::{PacketFlags, PacketType};
5use crate::{DeserializeError, SerializeError, Version};
6
7/// Information included in a TACACS+ packet header.
8#[derive(PartialEq, Eq, Debug, Clone, Copy, Hash, CopyGetters, MutGetters)]
9pub struct HeaderInfo {
10    #[getset(get_copy = "pub", get_mut = "pub(super)")]
11    /// The protocol major and minor version.
12    version: Version,
13
14    #[getset(get_copy = "pub")]
15    /// The sequence number of the packet. This should be odd for client packets, and even for server packets.
16    sequence_number: u8,
17
18    #[getset(get_copy = "pub", get_mut = "pub(super)")]
19    /// Session/packet flags.
20    flags: PacketFlags,
21
22    #[getset(get_copy = "pub")]
23    /// ID of the current session.
24    session_id: u32,
25}
26
27impl HeaderInfo {
28    /// Size of a full TACACS+ packet header.
29    pub const HEADER_SIZE_BYTES: usize = 12;
30
31    /// Bundles some information to be put in the header of a TACACS+ packet.
32    pub fn new(version: Version, sequence_number: u8, flags: PacketFlags, session_id: u32) -> Self {
33        Self {
34            version,
35            sequence_number,
36            flags,
37            session_id,
38        }
39    }
40
41    /// Serializes the information stored in a `HeaderInfo` struct, along with the supplemented information to form a complete header.
42    pub(super) fn serialize(
43        &self,
44        buffer: &mut [u8],
45        packet_type: PacketType,
46        body_length: u32,
47    ) -> Result<usize, SerializeError> {
48        // ensure buffer is large enough to store header
49        if buffer.len() >= Self::HEADER_SIZE_BYTES {
50            buffer[0] = self.version.into();
51            buffer[1] = packet_type as u8;
52            buffer[2] = self.sequence_number;
53            buffer[3] = self.flags.bits();
54
55            // session id is middle 4 bytes of header
56            NetworkEndian::write_u32(&mut buffer[4..8], self.session_id);
57
58            // body length goes at the end of the header (last 4 bytes)
59            NetworkEndian::write_u32(&mut buffer[8..12], body_length);
60
61            Ok(Self::HEADER_SIZE_BYTES)
62        } else {
63            Err(SerializeError::NotEnoughSpace)
64        }
65    }
66}
67
68impl TryFrom<&[u8]> for HeaderInfo {
69    type Error = DeserializeError;
70
71    fn try_from(buffer: &[u8]) -> Result<Self, Self::Error> {
72        let header = Self {
73            version: buffer[0].try_into()?,
74            sequence_number: buffer[2],
75            flags: PacketFlags::from_bits(buffer[3])
76                .ok_or(DeserializeError::InvalidHeaderFlags(buffer[3]))?,
77            session_id: NetworkEndian::read_u32(&buffer[4..8]),
78        };
79
80        Ok(header)
81    }
82}