netlink_packet_core/
header.rs

1// SPDX-License-Identifier: MIT
2
3use crate::{buffer::NETLINK_HEADER_LEN, DecodeError, Emitable, NetlinkBuffer, Parseable};
4
5/// A Netlink header representation. A netlink header has the following structure:
6///
7/// ```no_rust
8/// 0                8                16              24               32
9/// +----------------+----------------+----------------+----------------+
10/// |                 packet length (including header)                  |
11/// +----------------+----------------+----------------+----------------+
12/// |          message type           |              flags              |
13/// +----------------+----------------+----------------+----------------+
14/// |                           sequence number                         |
15/// +----------------+----------------+----------------+----------------+
16/// |                   port number (formerly known as PID)             |
17/// +----------------+----------------+----------------+----------------+
18/// ```
19#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Default)]
20pub struct NetlinkHeader {
21    /// Length of the netlink packet, including the header and the payload
22    pub length: u32,
23
24    /// NetlinkMessage type. The meaning of this field depends on the netlink protocol family in use.
25    pub message_type: u16,
26
27    /// Flags. It should be set to one of the `NLM_F_*` constants.
28    pub flags: u16,
29
30    /// Sequence number of the packet
31    pub sequence_number: u32,
32
33    /// Port number (usually set to the the process ID)
34    pub port_number: u32,
35}
36
37impl Emitable for NetlinkHeader {
38    fn buffer_len(&self) -> usize {
39        NETLINK_HEADER_LEN
40    }
41
42    fn emit(&self, buffer: &mut [u8]) {
43        let mut buffer = NetlinkBuffer::new(buffer);
44        buffer.set_message_type(self.message_type);
45        buffer.set_length(self.length);
46        buffer.set_flags(self.flags);
47        buffer.set_sequence_number(self.sequence_number);
48        buffer.set_port_number(self.port_number);
49    }
50}
51
52impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NetlinkBuffer<&'a T>> for NetlinkHeader {
53    fn parse(buf: &NetlinkBuffer<&'a T>) -> Result<NetlinkHeader, DecodeError> {
54        Ok(NetlinkHeader {
55            length: buf.length(),
56            message_type: buf.message_type(),
57            flags: buf.flags(),
58            sequence_number: buf.sequence_number(),
59            port_number: buf.port_number(),
60        })
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67    use crate::constants::*;
68
69    // a packet captured with tcpdump that was sent when running `ip link show`
70    #[rustfmt::skip]
71    static IP_LINK_SHOW_PKT: [u8; 40] = [
72        0x28, 0x00, 0x00, 0x00, // length = 40
73        0x12, 0x00, // message type = 18 (RTM_GETLINK)
74        0x01, 0x03, // flags = Request + Specify Tree Root + Return All Matching
75        0x34, 0x0e, 0xf9, 0x5a, // sequence number = 1526271540
76        0x00, 0x00, 0x00, 0x00, // port id = 0
77        // payload
78        0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80        0x08, 0x00, 0x1d, 0x00, 0x01, 0x00, 0x00, 0x00];
81
82    const RTM_GETLINK: u16 = 18;
83
84    #[test]
85    fn repr_parse() {
86        let repr =
87            NetlinkHeader::parse(&NetlinkBuffer::new_checked(&IP_LINK_SHOW_PKT[..]).unwrap())
88                .unwrap();
89        assert_eq!(repr.length, 40);
90        assert_eq!(repr.message_type, RTM_GETLINK);
91        assert_eq!(repr.sequence_number, 1_526_271_540);
92        assert_eq!(repr.port_number, 0);
93        assert_eq!(repr.flags, NLM_F_ROOT | NLM_F_REQUEST | NLM_F_MATCH);
94    }
95
96    #[test]
97    fn repr_emit() {
98        let repr = NetlinkHeader {
99            length: 40,
100            message_type: RTM_GETLINK,
101            sequence_number: 1_526_271_540,
102            flags: NLM_F_ROOT | NLM_F_REQUEST | NLM_F_MATCH,
103            port_number: 0,
104        };
105        assert_eq!(repr.buffer_len(), 16);
106        let mut buf = vec![0; 16];
107        repr.emit(&mut buf[..]);
108        assert_eq!(&buf[..], &IP_LINK_SHOW_PKT[..16]);
109    }
110}