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