netlink_packet_core/lib.rs
1// SPDX-License-Identifier: MIT
2
3//! `netlink-packet-core` provides a generic netlink message
4//! `NetlinkMessage<T>` that is independant of the sub-protocol. Such
5//! messages are not very useful by themselves, since they are just
6//! used to carry protocol-dependant messages. That is what the `T`
7//! represent: `T` is the `NetlinkMessage`'s protocol-dependant
8//! message. This can be any type that implements
9//! `NetlinkSerializable` and `NetlinkDeserializable`.
10//!
11//! For instance, the `netlink-packet-route` crate provides rtnetlink
12//! messages via `netlink_packet_route::RtnlMessage`, and
13//! `netlink-packet-audit` provides audit messages via
14//! `netlink_packet_audit::AuditMessage`.
15//!
16//! By itself, the `netlink-packet-core` crate is not very
17//! useful. However, it is used in `netlink-proto` to provide an
18//! asynchronous implementation of the netlink protocol for any
19//! sub-protocol. Thus, a crate that defines messages for a given
20//! netlink sub-protocol could integrate with `netlink-packet-core`
21//! and would get an asynchronous implementation for free. See the
22//! second example below for such an integration, via the
23//! `NetlinkSerializable` and `NetlinkDeserializable` traits.
24//!
25//! # Example: usage with `netlink-packet-route`
26//!
27//! This example shows how to serialize and deserialize netlink packet
28//! for the rtnetlink sub-protocol. It requires
29//! `netlink-packet-route`.
30//!
31//! ```rust
32//! use netlink_packet_core::{NetlinkHeader, NetlinkMessage, NLM_F_DUMP, NLM_F_REQUEST};
33//! use netlink_packet_route::{LinkMessage, RtnlMessage};
34//!
35//! // Create the netlink message, that contains the rtnetlink
36//! // message
37//! let mut packet = NetlinkMessage {
38//! header: NetlinkHeader {
39//! sequence_number: 1,
40//! flags: NLM_F_DUMP | NLM_F_REQUEST,
41//! ..Default::default()
42//! },
43//! payload: RtnlMessage::GetLink(LinkMessage::default()).into(),
44//! };
45//!
46//! // Before serializing the packet, it is important to call
47//! // finalize() to ensure the header of the message is consistent
48//! // with its payload. Otherwise, a panic may occur when calling
49//! // serialize()
50//! packet.finalize();
51//!
52//! // Prepare a buffer to serialize the packet. Note that we never
53//! // set explicitely `packet.header.length` above. This was done
54//! // automatically when we called `finalize()`
55//! let mut buf = vec![0; packet.header.length as usize];
56//! // Serialize the packet
57//! packet.serialize(&mut buf[..]);
58//!
59//! // Deserialize the packet
60//! let deserialized_packet =
61//! NetlinkMessage::<RtnlMessage>::deserialize(&buf).expect("Failed to deserialize message");
62//!
63//! // Normally, the deserialized packet should be exactly the same
64//! // than the serialized one.
65//! assert_eq!(deserialized_packet, packet);
66//!
67//! println!("{:?}", packet);
68//! ```
69//!
70//! # Example: adding messages for new netlink sub-protocol
71//!
72//! Let's assume we have a netlink protocol called "ping pong" that
73//! defines two types of messages: "ping" messages, which payload can
74//! be any sequence of bytes, and "pong" message, which payload is
75//! also a sequence of bytes. The protocol works as follow: when an
76//! enpoint receives a "ping" message, it answers with a "pong", with
77//! the payload of the "ping" it's answering to.
78//!
79//! "ping" messages have type 18 and "pong" have type "20". Here is
80//! what a "ping" message that would look like if its payload is `[0,
81//! 1, 2, 3]`:
82//!
83//! ```no_rust
84//! 0 8 16 24 32
85//! +----------------+----------------+----------------+----------------+
86//! | packet length (including header) = 16 + 4 = 20 |
87//! +----------------+----------------+----------------+----------------+
88//! | message type = 18 (ping) | flags |
89//! +----------------+----------------+----------------+----------------+
90//! | sequence number |
91//! +----------------+----------------+----------------+----------------+
92//! | port number |
93//! +----------------+----------------+----------------+----------------+
94//! | 0 | 1 | 2 | 3 |
95//! +----------------+----------------+----------------+----------------+
96//! ```
97//!
98//! And the "pong" response would be:
99//!
100//! ```no_rust
101//! 0 8 16 24 32
102//! +----------------+----------------+----------------+----------------+
103//! | packet length (including header) = 16 + 4 = 20 |
104//! +----------------+----------------+----------------+----------------+
105//! | message type = 20 (pong) | flags |
106//! +----------------+----------------+----------------+----------------+
107//! | sequence number |
108//! +----------------+----------------+----------------+----------------+
109//! | port number |
110//! +----------------+----------------+----------------+----------------+
111//! | 0 | 1 | 2 | 3 |
112//! +----------------+----------------+----------------+----------------+
113//! ```
114//!
115//! Here is how we could implement the messages for such a protocol
116//! and integrate this implementation with `netlink-packet-core`:
117//!
118//! ```rust
119//! use netlink_packet_core::{
120//! NetlinkDeserializable, NetlinkHeader, NetlinkMessage, NetlinkPayload, NetlinkSerializable,
121//! };
122//! use std::error::Error;
123//! use std::fmt;
124//!
125//! // PingPongMessage represent the messages for the "ping-pong" netlink
126//! // protocol. There are only two types of messages.
127//! #[derive(Debug, Clone, Eq, PartialEq)]
128//! pub enum PingPongMessage {
129//! Ping(Vec<u8>),
130//! Pong(Vec<u8>),
131//! }
132//!
133//! // The netlink header contains a "message type" field that identifies
134//! // the message it carries. Some values are reserved, and we
135//! // arbitrarily decided that "ping" type is 18 and "pong" type is 20.
136//! pub const PING_MESSAGE: u16 = 18;
137//! pub const PONG_MESSAGE: u16 = 20;
138//!
139//! // A custom error type for when deserialization fails. This is
140//! // required because `NetlinkDeserializable::Error` must implement
141//! // `std::error::Error`, so a simple `String` won't cut it.
142//! #[derive(Debug, Clone, Eq, PartialEq)]
143//! pub struct DeserializeError(&'static str);
144//!
145//! impl Error for DeserializeError {
146//! fn description(&self) -> &str {
147//! self.0
148//! }
149//! fn source(&self) -> Option<&(dyn Error + 'static)> {
150//! None
151//! }
152//! }
153//!
154//! impl fmt::Display for DeserializeError {
155//! fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156//! write!(f, "{}", self.0)
157//! }
158//! }
159//!
160//! // NetlinkDeserializable implementation
161//! impl NetlinkDeserializable for PingPongMessage {
162//! type Error = DeserializeError;
163//!
164//! fn deserialize(header: &NetlinkHeader, payload: &[u8]) -> Result<Self, Self::Error> {
165//! match header.message_type {
166//! PING_MESSAGE => Ok(PingPongMessage::Ping(payload.to_vec())),
167//! PONG_MESSAGE => Ok(PingPongMessage::Pong(payload.to_vec())),
168//! _ => Err(DeserializeError(
169//! "invalid ping-pong message: invalid message type",
170//! )),
171//! }
172//! }
173//! }
174//!
175//! // NetlinkSerializable implementation
176//! impl NetlinkSerializable for PingPongMessage {
177//! fn message_type(&self) -> u16 {
178//! match self {
179//! PingPongMessage::Ping(_) => PING_MESSAGE,
180//! PingPongMessage::Pong(_) => PONG_MESSAGE,
181//! }
182//! }
183//!
184//! fn buffer_len(&self) -> usize {
185//! match self {
186//! PingPongMessage::Ping(vec) | PingPongMessage::Pong(vec) => vec.len(),
187//! }
188//! }
189//!
190//! fn serialize(&self, buffer: &mut [u8]) {
191//! match self {
192//! PingPongMessage::Ping(vec) | PingPongMessage::Pong(vec) => {
193//! buffer.copy_from_slice(&vec[..])
194//! }
195//! }
196//! }
197//! }
198//!
199//! // It can be convenient to be able to create a NetlinkMessage directly
200//! // from a PingPongMessage. Since NetlinkMessage<T> already implements
201//! // From<NetlinkPayload<T>>, we just need to implement
202//! // From<NetlinkPayload<PingPongMessage>> for this to work.
203//! impl From<PingPongMessage> for NetlinkPayload<PingPongMessage> {
204//! fn from(message: PingPongMessage) -> Self {
205//! NetlinkPayload::InnerMessage(message)
206//! }
207//! }
208//!
209//! fn main() {
210//! let ping_pong_message = PingPongMessage::Ping(vec![0, 1, 2, 3]);
211//! let mut packet = NetlinkMessage::from(ping_pong_message);
212//!
213//! // Before serializing the packet, it is very important to call
214//! // finalize() to ensure the header of the message is consistent
215//! // with its payload. Otherwise, a panic may occur when calling
216//! // `serialize()`
217//! packet.finalize();
218//!
219//! // Prepare a buffer to serialize the packet. Note that we never
220//! // set explicitely `packet.header.length` above. This was done
221//! // automatically when we called `finalize()`
222//! let mut buf = vec![0; packet.header.length as usize];
223//! // Serialize the packet
224//! packet.serialize(&mut buf[..]);
225//!
226//! // Deserialize the packet
227//! let deserialized_packet = NetlinkMessage::<PingPongMessage>::deserialize(&buf)
228//! .expect("Failed to deserialize message");
229//!
230//! // Normally, the deserialized packet should be exactly the same
231//! // than the serialized one.
232//! assert_eq!(deserialized_packet, packet);
233//!
234//! // This should print:
235//! // NetlinkMessage { header: NetlinkHeader { length: 20, message_type: 18, flags: 0, sequence_number: 0, port_number: 0 }, payload: InnerMessage(Ping([0, 1, 2, 3])) }
236//! println!("{:?}", packet);
237//! }
238//! ```
239
240use core::ops::{Range, RangeFrom};
241/// Represent a multi-bytes field with a fixed size in a packet
242pub(crate) type Field = Range<usize>;
243/// Represent a field that starts at a given index in a packet
244pub(crate) type Rest = RangeFrom<usize>;
245
246pub mod error;
247pub use self::error::*;
248
249pub mod buffer;
250pub use self::buffer::*;
251
252pub mod header;
253pub use self::header::*;
254
255mod traits;
256pub use self::traits::*;
257
258mod payload;
259pub use self::payload::*;
260
261mod message;
262pub use self::message::*;
263
264pub mod constants;
265pub use self::constants::*;
266
267pub use self::utils::errors::*;
268pub(crate) use self::utils::traits::*;
269pub(crate) use netlink_packet_utils as utils;