netlink/
messaging.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! A module for managing message passing between Netlink and its clients.
6
7use futures::Stream;
8use netlink_packet_core::{
9    NetlinkBuffer, NetlinkDeserializable, NetlinkHeader, NetlinkMessage, NetlinkPayload,
10    NetlinkSerializable,
11};
12use netlink_packet_route::RouteNetlinkMessageParseError;
13use netlink_packet_utils::nla::NlaError;
14use netlink_packet_utils::{DecodeError, Parseable};
15use std::fmt::Debug;
16
17use crate::multicast_groups::ModernGroup;
18use crate::netlink_packet;
19use crate::netlink_packet::errno::Errno;
20
21/// A type capable of sending messages, `M`, from Netlink to a client.
22pub trait Sender<M>: Clone + Send + Sync {
23    /// Sends the given message to the client.
24    ///
25    /// If the message is a multicast, `group` will hold a `Some`; `None` for
26    /// unicast messages.
27    ///
28    /// Implementors must ensure this call does not block.
29    fn send(&mut self, message: NetlinkMessage<M>, group: Option<ModernGroup>);
30}
31
32/// A type capable of receiving messages, `M`, from a client to Netlink.
33///
34/// [`Stream`] already provides a sufficient interface for this purpose.
35pub trait Receiver<M, C>:
36    Stream<Item: UnvalidatedNetlinkMessage<Message = M, Credentials = C>> + Send
37where
38    M: Send + MessageWithPermission,
39    C: Send,
40{
41}
42
43/// Blanket implementation allows any [`Stream`] to be used as a [`Receiver`].
44impl<M, C, S> Receiver<M, C> for S
45where
46    M: Send + MessageWithPermission,
47    C: Send,
48    S: Stream<Item: UnvalidatedNetlinkMessage<Message = M, Credentials = C>> + Send,
49{
50}
51
52/// A permission that is required from the sender when processing a netlink
53/// request.
54pub enum Permission {
55    /// GET messages in NETLINK_ROUTE.
56    NetlinkRouteRead,
57
58    /// SET/NEW/DELETE messages in NETLINK_ROUTE.
59    NetlinkRouteWrite,
60}
61
62/// An object responsible to validating permissions for netlink clients.
63pub trait AccessControl<C>: Clone {
64    /// Returns true if a client with the specified credentials has the
65    /// specified permission.
66    fn grant_assess(&self, creds: &C, permission: Permission) -> Result<(), Errno>;
67}
68
69/// A message that may require special permissions from the sender to be
70/// processed.
71pub trait MessageWithPermission {
72    /// Returns the permission that's required in order to process this message.
73    fn permission(&self) -> Permission;
74}
75
76/// An error observed when parsing a netlink message.
77#[derive(Debug)]
78pub struct ParseError {
79    /// The error encountered during parsing.
80    pub error: DecodeError,
81    /// The header on the original message.
82    ///
83    /// If a header was not able to be extracted from the original message,
84    /// `None` is set.
85    pub header: Option<NetlinkHeader>,
86}
87
88/// A trait abstracting netlink messages that may already be parsed or still
89/// need to go through parsing.
90pub trait MaybeParsedNetlinkMessage {
91    /// The inner message type potentially contained by this message.
92    type Message: MessageWithPermission;
93
94    /// Parses the message, returning an owned [`NetlinkMessage`] on success.
95    fn try_into_parsed(self) -> Result<NetlinkMessage<Self::Message>, ParseError>;
96}
97
98impl<M: MessageWithPermission> MaybeParsedNetlinkMessage for NetlinkMessage<M> {
99    type Message = M;
100    fn try_into_parsed(self) -> Result<NetlinkMessage<M>, ParseError> {
101        Ok(self)
102    }
103}
104
105/// An unparsed netlink message backed by the bytes in `B`.
106pub struct UnparsedNetlinkMessage<B, M> {
107    data: B,
108    _marker: std::marker::PhantomData<M>,
109}
110
111impl<B, M> UnparsedNetlinkMessage<B, M> {
112    /// Creates a new `UnparsedNetlinkMessage`.
113    pub fn new(data: B) -> Self {
114        Self { data, _marker: std::marker::PhantomData }
115    }
116}
117
118impl<M, B> MaybeParsedNetlinkMessage for UnparsedNetlinkMessage<B, M>
119where
120    B: AsRef<[u8]>,
121    M: NetlinkDeserializable + MessageWithPermission,
122    M::Error: Into<DecodeError>,
123{
124    type Message = M;
125
126    fn try_into_parsed(self) -> Result<NetlinkMessage<M>, ParseError> {
127        let Self { data, _marker } = self;
128        let data = data.as_ref();
129        let netlink_buffer =
130            NetlinkBuffer::new(&data).map_err(|error| ParseError { error, header: None })?;
131        NetlinkMessage::<M>::parse(&netlink_buffer).map_err(|error| ParseError {
132            error,
133            // Silently drop the parsing error here, the error from parsing the
134            // NetlinkMessage itself should be enough.
135            header: NetlinkHeader::parse(&netlink_buffer).ok(),
136        })
137    }
138}
139
140/// The outcome of validating a netlink message.
141#[derive(Debug)]
142#[allow(missing_docs)]
143pub enum ValidationError {
144    /// The message failed to parse.
145    Parse(ParseError),
146    /// The provided credentials are insufficient for the requested operation.
147    Permission { header: NetlinkHeader, error: Errno },
148}
149
150// TODO(https://fxbug.dev/450959280): Move this close to the netlink crates, so
151// we have more control of the error types more locally,
152fn nla_error_to_errno(error: &NlaError) -> Errno {
153    match error {
154        NlaError::BufferTooSmall { .. }
155        | NlaError::LengthMismatch { .. }
156        | NlaError::InvalidLength { .. } => Errno::EINVAL,
157    }
158}
159
160// TODO(https://fxbug.dev/450959280): Move this close to the netlink crates, so
161// we have more control of the error types more locally,
162fn route_netlink_error_to_errno(error: &RouteNetlinkMessageParseError) -> Errno {
163    match error {
164        RouteNetlinkMessageParseError::ParseBuffer(decode_error)
165        | RouteNetlinkMessageParseError::InvalidLinkMessage(decode_error) => {
166            decode_error_to_errno(decode_error)
167        }
168        RouteNetlinkMessageParseError::InvalidRouteMessage(_)
169        | RouteNetlinkMessageParseError::InvalidAddrMessage(_)
170        | RouteNetlinkMessageParseError::InvalidPrefixMessage(_)
171        | RouteNetlinkMessageParseError::InvalidFibRuleMessage(_)
172        | RouteNetlinkMessageParseError::InvalidTcMessage(_)
173        | RouteNetlinkMessageParseError::InvalidNsidMessage(_)
174        | RouteNetlinkMessageParseError::InvalidNeighbourMessage(_)
175        | RouteNetlinkMessageParseError::InvalidNeighbourTableMessage(_)
176        | RouteNetlinkMessageParseError::InvalidNeighbourDiscoveryUserOptionMessage(_) => {
177            Errno::EINVAL
178        }
179        RouteNetlinkMessageParseError::UnknownMessageType(_) => Errno::ENOTSUP,
180    }
181}
182
183// TODO(https://fxbug.dev/450959280): Move this close to the netlink crates, so
184// we have more control of the error types more locally,
185fn decode_error_to_errno(error: &DecodeError) -> Errno {
186    match error {
187        DecodeError::InvalidMACAddress
188        | DecodeError::InvalidIPAddress
189        | DecodeError::Utf8Error(_)
190        | DecodeError::InvalidU8
191        | DecodeError::InvalidU16
192        | DecodeError::InvalidU32
193        | DecodeError::InvalidU64
194        | DecodeError::InvalidU128
195        | DecodeError::InvalidI32
196        | DecodeError::InvalidBufferLength { .. } => Errno::EINVAL,
197        DecodeError::Nla(nla_error) => nla_error_to_errno(nla_error),
198        DecodeError::Other(error) => {
199            if let Some(error) = error.downcast_ref::<RouteNetlinkMessageParseError>() {
200                return route_netlink_error_to_errno(error);
201            }
202            Errno::EINVAL
203        }
204        DecodeError::FailedToParseNlMsgError(error)
205        | DecodeError::FailedToParseNlMsgDone(error)
206        | DecodeError::FailedToParseMessageWithType { message_type: _, source: error }
207        | DecodeError::FailedToParseNetlinkHeader(error) => decode_error_to_errno(error),
208    }
209}
210
211impl ValidationError {
212    /// Creates an error message response from this error, if one can be
213    /// created.
214    pub fn into_error_message<M: NetlinkSerializable>(self) -> Option<NetlinkMessage<M>> {
215        match self {
216            ValidationError::Parse(ParseError { error, header }) => {
217                // If we couldn't parse at least a header, we can't respond.
218                let header = header?;
219                // NB: Decode error from netlink_core doesn't quite have enough
220                // granularity here for us to be able to tell not supported from
221                // supported, but malformed.
222                Some(netlink_packet::new_error(Err(decode_error_to_errno(&error)), header))
223            }
224            ValidationError::Permission { header, error } => {
225                Some(netlink_packet::new_error(Err(error), header))
226            }
227        }
228    }
229}
230
231/// Encapsulates `NetlinkMessage` with the credentials of the sender.
232#[derive(Clone, Debug)]
233pub struct NetlinkMessageWithCreds<M, C> {
234    message: M,
235    creds: C,
236}
237
238impl<M, C> NetlinkMessageWithCreds<M, C> {
239    /// Creates a new instance.
240    pub fn new(message: M, creds: C) -> Self {
241        Self { message, creds }
242    }
243}
244
245/// A trait abstracting a yet unvalidated netlink message.
246///
247/// This trait provides storage-abstraction for [`NetlinkMessageWithCreds`].
248pub trait UnvalidatedNetlinkMessage {
249    /// The message type in this unvalidated message.
250    type Message;
251    /// The credentials type required for validation.
252    type Credentials;
253
254    /// Validates permission using the specified `AccessControl` and returns
255    /// the parsed message. If the permission is not granted then return an
256    /// error that should be sent back to the client.
257    fn validate_creds_and_get_message<PS: AccessControl<Self::Credentials>>(
258        self,
259        access_control: &PS,
260    ) -> Result<NetlinkMessage<Self::Message>, ValidationError>;
261}
262
263impl<M, C> UnvalidatedNetlinkMessage for NetlinkMessageWithCreds<M, C>
264where
265    M: MaybeParsedNetlinkMessage,
266    M::Message: MessageWithPermission,
267{
268    type Message = M::Message;
269    type Credentials = C;
270
271    fn validate_creds_and_get_message<PS: AccessControl<C>>(
272        self,
273        access_control: &PS,
274    ) -> Result<NetlinkMessage<M::Message>, ValidationError> {
275        let Self { message, creds } = self;
276        let message = message.try_into_parsed().map_err(ValidationError::Parse)?;
277        let permission = match &message.payload {
278            NetlinkPayload::InnerMessage(msg) => msg.permission(),
279            NetlinkPayload::Done(_)
280            | NetlinkPayload::Error(_)
281            | NetlinkPayload::Noop
282            | NetlinkPayload::Overrun(_) => return Ok(message),
283        };
284
285        access_control
286            .grant_assess(&creds, permission)
287            .map_err(|error| ValidationError::Permission { header: message.header, error })?;
288        Ok(message)
289    }
290}
291
292/// A type capable of providing a concrete types used in Netlink.
293pub trait NetlinkContext {
294    /// The type used to represent process credentials.
295    type Creds: Clone + Send + Debug;
296
297    /// The type of [`Sender`] provided.
298    type Sender<M: Clone + NetlinkSerializable + Send>: Sender<M>;
299
300    /// The type of [`Receiver`] provided.
301    type Receiver<M: Send + MessageWithPermission + NetlinkDeserializable<Error: Into<DecodeError>>>: Receiver<M, Self::Creds>;
302
303    /// The type of an object that validates access to netlink operations.
304    type AccessControl<'a>: AccessControl<Self::Creds>;
305}
306
307#[cfg(test)]
308pub(crate) mod testutil {
309    use super::*;
310    use crate::mpsc;
311    use futures::{FutureExt as _, StreamExt as _};
312    use netlink_packet_core::NetlinkSerializable;
313
314    #[derive(Clone, Debug, PartialEq, Eq)]
315    pub(crate) struct SentMessage<M> {
316        pub message: NetlinkMessage<M>,
317        pub group: Option<ModernGroup>,
318    }
319
320    impl<M> SentMessage<M> {
321        pub(crate) fn unicast(message: NetlinkMessage<M>) -> Self {
322            Self { message, group: None }
323        }
324
325        pub(crate) fn multicast(message: NetlinkMessage<M>, group: ModernGroup) -> Self {
326            Self { message, group: Some(group) }
327        }
328    }
329
330    #[derive(Clone, Debug)]
331    pub(crate) struct FakeSender<M> {
332        sender: futures::channel::mpsc::UnboundedSender<SentMessage<M>>,
333    }
334
335    impl<M: Clone + Send + NetlinkSerializable> Sender<M> for FakeSender<M> {
336        fn send(&mut self, message: NetlinkMessage<M>, group: Option<ModernGroup>) {
337            self.sender
338                .unbounded_send(SentMessage { message, group })
339                .expect("unable to send message");
340        }
341    }
342
343    pub(crate) struct FakeSenderSink<M> {
344        receiver: futures::channel::mpsc::UnboundedReceiver<SentMessage<M>>,
345    }
346
347    impl<M> FakeSenderSink<M> {
348        pub(crate) fn take_messages(&mut self) -> Vec<SentMessage<M>> {
349            let mut messages = Vec::new();
350            while let Some(msg_opt) = self.receiver.next().now_or_never() {
351                match msg_opt {
352                    Some(msg) => messages.push(msg),
353                    None => return messages, // Stream closed.
354                };
355            }
356            // All receiver messages that were ready were added.
357            messages
358        }
359
360        pub(crate) async fn next_message(&mut self) -> SentMessage<M> {
361            self.receiver.next().await.expect("receiver unexpectedly closed")
362        }
363    }
364
365    pub(crate) fn fake_sender_with_sink<M>() -> (FakeSender<M>, FakeSenderSink<M>) {
366        let (sender, receiver) = futures::channel::mpsc::unbounded();
367        (FakeSender { sender }, FakeSenderSink { receiver })
368    }
369
370    #[derive(Default, Debug, Clone)]
371    pub(crate) struct FakeCreds {
372        error: Option<Errno>,
373    }
374
375    impl FakeCreds {
376        pub fn with_error(error: Errno) -> Self {
377            FakeCreds { error: Some(error) }
378        }
379    }
380
381    #[derive(Default, Clone)]
382    pub(crate) struct FakeAccessControl {}
383
384    impl AccessControl<FakeCreds> for FakeAccessControl {
385        fn grant_assess(&self, creds: &FakeCreds, _perm: Permission) -> Result<(), Errno> {
386            if let Some(ref error) = creds.error { Err(*error) } else { Ok(()) }
387        }
388    }
389
390    pub(crate) struct TestNetlinkContext;
391
392    impl NetlinkContext for TestNetlinkContext {
393        type Creds = FakeCreds;
394        type Sender<M: Clone + NetlinkSerializable + Send> = FakeSender<M>;
395        type Receiver<
396            M: Send + MessageWithPermission + NetlinkDeserializable<Error: Into<DecodeError>>,
397        > = mpsc::Receiver<NetlinkMessageWithCreds<NetlinkMessage<M>, Self::Creds>>;
398        type AccessControl<'a> = FakeAccessControl;
399    }
400}