netlink_packet/netlink/
header.rs

1use super::{NetlinkBuffer, NetlinkFlags, NETLINK_HEADER_LEN};
2use crate::{DecodeError, Emitable, Parseable};
3
4/// A Netlink header representation.
5///
6/// A netlink header has the following structure:
7///
8/// ```no_rust
9/// 0                8                16              24               32
10/// +----------------+----------------+----------------+----------------+
11/// |                 packet length (including header)                  |
12/// +----------------+----------------+----------------+----------------+
13/// |          message type           |              flags              |
14/// +----------------+----------------+----------------+----------------+
15/// |                           sequence number                         |
16/// +----------------+----------------+----------------+----------------+
17/// |                   port number (formerly known as PID)             |
18/// +----------------+----------------+----------------+----------------+
19/// ```
20///
21/// # Example: parsing a netlink header
22///
23/// ```rust
24/// extern crate netlink_packet;
25/// use netlink_packet::{NetlinkBuffer, NetlinkHeader, Parseable};
26/// use netlink_packet::constants::{RTM_GETLINK, NLM_F_ROOT, NLM_F_REQUEST, NLM_F_MATCH};
27///
28/// // a packet captured with tcpdump that was sent when running `ip link show`
29/// static PKT: [u8; 40] = [
30///     0x28, 0x00, 0x00, 0x00, // length = 40
31///     0x12, 0x00, // message type = 18 (RTM_GETLINK)
32///     0x01, 0x03, // flags = Request + Specify Tree Root + Return All Matching
33///     0x34, 0x0e, 0xf9, 0x5a, // sequence number = 1526271540
34///     0x00, 0x00, 0x00, 0x00, // port id = 0
35///     // payload
36///     0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
37///     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
38///     0x08, 0x00, 0x1d, 0x00, 0x01, 0x00, 0x00, 0x00];
39///
40/// fn main() {
41///     let pkt: NetlinkHeader = NetlinkBuffer::new_checked(&PKT[..]).unwrap().parse().unwrap();
42///     assert_eq!(pkt.length(), 40);
43///     assert_eq!(pkt.message_type(), RTM_GETLINK);
44///     assert_eq!(pkt.sequence_number(), 1_526_271_540);
45///     assert_eq!(pkt.port_number(), 0);
46///     assert_eq!(u16::from(pkt.flags()), NLM_F_ROOT | NLM_F_REQUEST | NLM_F_MATCH);
47/// }
48/// ```
49///
50/// # Example: emitting a netlink header
51///
52/// ```
53/// extern crate netlink_packet;
54/// use netlink_packet::{NetlinkBuffer, NetlinkHeader, NetlinkFlags, Emitable};
55/// use netlink_packet::constants::{RTM_GETLINK, NLM_F_ROOT, NLM_F_REQUEST, NLM_F_MATCH};
56///
57/// // a packet captured with tcpdump that was sent when running `ip link show`
58/// static PKT: [u8; 40] = [
59///     0x28, 0x00, 0x00, 0x00, // length = 40
60///     0x12, 0x00, // message type = 18 (RTM_GETLINK)
61///     0x01, 0x03, // flags = Request + Specify Tree Root + Return All Matching
62///     0x34, 0x0e, 0xf9, 0x5a, // sequence number = 1526271540
63///     0x00, 0x00, 0x00, 0x00, // port id = 0
64///     // payload
65///     0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
66///     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67///     0x08, 0x00, 0x1d, 0x00, 0x01, 0x00, 0x00, 0x00];
68///
69/// fn main() {
70///     let flags = NetlinkFlags::from(NLM_F_ROOT | NLM_F_REQUEST | NLM_F_MATCH);
71///     let pkt = NetlinkHeader::new(40, RTM_GETLINK, flags, 0x5af9_0e34, 0);
72///     assert_eq!(pkt.buffer_len(), 16);
73///     let mut buf = vec![0; 16];
74///     pkt.emit(&mut buf[..]);
75///     assert_eq!(&buf[..], &PKT[..16]);
76/// }
77/// ```
78#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Default)]
79pub struct NetlinkHeader {
80    /// Length of the netlink packet, including the header and the payload
81    length: u32,
82
83    /// NetlinkMessage type. The meaning of this field depends on the netlink protocol family in use.
84    message_type: u16,
85
86    /// Flags
87    flags: NetlinkFlags,
88
89    /// Sequence number of the packet
90    sequence_number: u32,
91
92    /// Port number (usually set to the the process ID)
93    port_number: u32,
94}
95
96impl NetlinkHeader {
97    /// Create a new header, initialized with the given values
98    pub fn new(
99        length: u32,
100        message_type: u16,
101        flags: NetlinkFlags,
102        sequence_number: u32,
103        port_number: u32,
104    ) -> Self {
105        NetlinkHeader {
106            length,
107            message_type,
108            flags,
109            sequence_number,
110            port_number,
111        }
112    }
113
114    /// Get the length field
115    pub fn length(&self) -> u32 {
116        self.length
117    }
118
119    /// Get a mutable reference to the length field
120    pub fn length_mut(&mut self) -> &mut u32 {
121        &mut self.length
122    }
123
124    /// Setter for the length field
125    pub fn set_length(&mut self, value: u32) -> &mut Self {
126        self.length = value;
127        self
128    }
129
130    /// Get the message type field
131    pub fn message_type(&self) -> u16 {
132        self.message_type
133    }
134
135    /// Get a mutable reference to the message type field
136    pub fn message_type_mut(&mut self) -> &mut u16 {
137        &mut self.message_type
138    }
139
140    /// Setter for the message_type field
141    pub fn set_message_type(&mut self, value: u16) -> &mut Self {
142        self.message_type = value;
143        self
144    }
145
146    /// Get the flags field
147    pub fn flags(&self) -> NetlinkFlags {
148        self.flags
149    }
150
151    /// Get a mutable reference to the flags field
152    pub fn flags_mut(&mut self) -> &mut NetlinkFlags {
153        &mut self.flags
154    }
155
156    /// Setter for the flags field
157    pub fn set_flags(&mut self, value: NetlinkFlags) -> &mut Self {
158        self.flags = value;
159        self
160    }
161
162    /// Get the sequence number field
163    pub fn sequence_number(&self) -> u32 {
164        self.sequence_number
165    }
166
167    /// Get a mutable reference to the sequence number field
168    pub fn sequence_number_mut(&mut self) -> &mut u32 {
169        &mut self.sequence_number
170    }
171
172    /// Setter for the sequence number field
173    pub fn set_sequence_number(&mut self, value: u32) -> &mut Self {
174        self.sequence_number = value;
175        self
176    }
177
178    /// Get the port number field
179    pub fn port_number(&self) -> u32 {
180        self.port_number
181    }
182
183    /// Get a mutable reference to the port number field
184    pub fn port_number_mut(&mut self) -> &mut u32 {
185        &mut self.port_number
186    }
187
188    /// Setter for the port number field
189    pub fn set_port_number(&mut self, value: u32) -> &mut Self {
190        self.port_number = value;
191        self
192    }
193}
194
195impl Emitable for NetlinkHeader {
196    fn buffer_len(&self) -> usize {
197        NETLINK_HEADER_LEN
198    }
199
200    fn emit(&self, buffer: &mut [u8]) {
201        let mut buffer = NetlinkBuffer::new(buffer);
202        buffer.set_message_type(self.message_type);
203        buffer.set_length(self.length);
204        buffer.set_flags(self.flags);
205        buffer.set_sequence_number(self.sequence_number);
206        buffer.set_port_number(self.port_number);
207    }
208}
209
210impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NetlinkHeader> for NetlinkBuffer<&'a T> {
211    fn parse(&self) -> Result<NetlinkHeader, DecodeError> {
212        Ok(NetlinkHeader {
213            length: self.length(),
214            message_type: self.message_type(),
215            flags: self.flags(),
216            sequence_number: self.sequence_number(),
217            port_number: self.port_number(),
218        })
219    }
220}
221
222#[cfg(all(test, feature = "rtnetlink"))]
223mod tests {
224    use super::*;
225    use crate::constants::*;
226    use crate::flags::*;
227
228    // a packet captured with tcpdump that was sent when running `ip link show`
229    #[rustfmt::skip]
230    static IP_LINK_SHOW_PKT: [u8; 40] = [
231        0x28, 0x00, 0x00, 0x00, // length = 40
232        0x12, 0x00, // message type = 18 (RTM_GETLINK)
233        0x01, 0x03, // flags = Request + Specify Tree Root + Return All Matching
234        0x34, 0x0e, 0xf9, 0x5a, // sequence number = 1526271540
235        0x00, 0x00, 0x00, 0x00, // port id = 0
236        // payload
237        0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
238        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
239        0x08, 0x00, 0x1d, 0x00, 0x01, 0x00, 0x00, 0x00];
240
241    #[test]
242    fn repr_parse() {
243        let repr: NetlinkHeader = NetlinkBuffer::new_checked(&IP_LINK_SHOW_PKT[..])
244            .unwrap()
245            .parse()
246            .unwrap();
247        assert_eq!(repr.length, 40);
248        assert_eq!(repr.message_type, RTM_GETLINK);
249        assert_eq!(repr.sequence_number, 1_526_271_540);
250        assert_eq!(repr.port_number, 0);
251        assert_eq!(
252            Into::<u16>::into(repr.flags),
253            NLM_F_ROOT | NLM_F_REQUEST | NLM_F_MATCH
254        );
255    }
256
257    #[test]
258    fn repr_emit() {
259        let repr = NetlinkHeader {
260            length: 40,
261            message_type: RTM_GETLINK,
262            sequence_number: 1_526_271_540,
263            flags: NetlinkFlags::from(NLM_F_ROOT | NLM_F_REQUEST | NLM_F_MATCH),
264            port_number: 0,
265        };
266        assert_eq!(repr.buffer_len(), 16);
267        let mut buf = vec![0; 16];
268        repr.emit(&mut buf[..]);
269        assert_eq!(&buf[..], &IP_LINK_SHOW_PKT[..16]);
270    }
271}