netlink_packet_wireguard/nlas/
device.rs

1// SPDX-License-Identifier: MIT
2
3use crate::{
4    constants::*,
5    nlas::{WgPeer, WgPeerAttrs},
6};
7use netlink_packet_core::{
8    emit_u16, emit_u32, parse_string, parse_u16, parse_u32, DecodeError,
9    Emitable, ErrorContext, Nla, NlaBuffer, NlasIterator, Parseable,
10};
11use std::{convert::TryInto, mem::size_of_val};
12
13#[derive(Clone, Debug, PartialEq, Eq)]
14pub enum WgDeviceAttrs {
15    Unspec(Vec<u8>),
16    IfIndex(u32),
17    IfName(String),
18    PrivateKey([u8; WG_KEY_LEN]),
19    PublicKey([u8; WG_KEY_LEN]),
20    ListenPort(u16),
21    Fwmark(u32),
22    Peers(Vec<WgPeer>),
23    Flags(u32),
24}
25
26impl Nla for WgDeviceAttrs {
27    fn value_len(&self) -> usize {
28        match self {
29            WgDeviceAttrs::Unspec(bytes) => bytes.len(),
30            WgDeviceAttrs::IfIndex(v) => size_of_val(v),
31            WgDeviceAttrs::IfName(v) => v.len() + 1,
32            WgDeviceAttrs::PrivateKey(v) => size_of_val(v),
33            WgDeviceAttrs::PublicKey(v) => size_of_val(v),
34            WgDeviceAttrs::ListenPort(v) => size_of_val(v),
35            WgDeviceAttrs::Fwmark(v) => size_of_val(v),
36            WgDeviceAttrs::Peers(nlas) => {
37                nlas.iter().map(|op| op.buffer_len()).sum()
38            }
39            WgDeviceAttrs::Flags(v) => size_of_val(v),
40        }
41    }
42
43    fn kind(&self) -> u16 {
44        match self {
45            WgDeviceAttrs::Unspec(_) => WGDEVICE_A_UNSPEC,
46            WgDeviceAttrs::IfIndex(_) => WGDEVICE_A_IFINDEX,
47            WgDeviceAttrs::IfName(_) => WGDEVICE_A_IFNAME,
48            WgDeviceAttrs::PrivateKey(_) => WGDEVICE_A_PRIVATE_KEY,
49            WgDeviceAttrs::PublicKey(_) => WGDEVICE_A_PUBLIC_KEY,
50            WgDeviceAttrs::ListenPort(_) => WGDEVICE_A_LISTEN_PORT,
51            WgDeviceAttrs::Fwmark(_) => WGDEVICE_A_FWMARK,
52            WgDeviceAttrs::Peers(_) => WGDEVICE_A_PEERS,
53            WgDeviceAttrs::Flags(_) => WGDEVICE_A_FLAGS,
54        }
55    }
56
57    fn emit_value(&self, buffer: &mut [u8]) {
58        match self {
59            WgDeviceAttrs::Unspec(bytes) => buffer.copy_from_slice(bytes),
60            WgDeviceAttrs::IfIndex(v) => emit_u32(buffer, *v).unwrap(),
61            WgDeviceAttrs::IfName(s) => {
62                buffer[..s.len()].copy_from_slice(s.as_bytes());
63                buffer[s.len()] = 0;
64            }
65            WgDeviceAttrs::PrivateKey(v) => buffer.copy_from_slice(v),
66            WgDeviceAttrs::PublicKey(v) => buffer.copy_from_slice(v),
67            WgDeviceAttrs::ListenPort(v) => emit_u16(buffer, *v).unwrap(),
68            WgDeviceAttrs::Fwmark(v) => emit_u32(buffer, *v).unwrap(),
69            WgDeviceAttrs::Peers(nlas) => {
70                let mut len = 0;
71                for op in nlas {
72                    op.emit(&mut buffer[len..]);
73                    len += op.buffer_len();
74                }
75            }
76            WgDeviceAttrs::Flags(v) => emit_u32(buffer, *v).unwrap(),
77        }
78    }
79
80    fn is_nested(&self) -> bool {
81        matches!(self, WgDeviceAttrs::Peers(_))
82    }
83}
84
85impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
86    for WgDeviceAttrs
87{
88    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
89        let payload = buf.value();
90        Ok(match buf.kind() {
91            WGDEVICE_A_UNSPEC => Self::Unspec(payload.to_vec()),
92            WGDEVICE_A_IFINDEX => Self::IfIndex(
93                parse_u32(payload)
94                    .context("invalid WGDEVICE_A_IFINDEX value")?,
95            ),
96            WGDEVICE_A_IFNAME => Self::IfName(
97                parse_string(payload)
98                    .context("invalid WGDEVICE_A_IFNAME value")?,
99            ),
100            WGDEVICE_A_PRIVATE_KEY => Self::PrivateKey(
101                payload
102                    .try_into()
103                    .map_err(|e: std::array::TryFromSliceError| {
104                        DecodeError::from(e.to_string())
105                    })
106                    .context("invalid WGDEVICE_A_PRIVATE_KEY value")?,
107            ),
108            WGDEVICE_A_PUBLIC_KEY => Self::PublicKey(
109                payload
110                    .try_into()
111                    .map_err(|e: std::array::TryFromSliceError| {
112                        DecodeError::from(e.to_string())
113                    })
114                    .context("invalid WGDEVICE_A_PUBLIC_KEY value")?,
115            ),
116            WGDEVICE_A_LISTEN_PORT => Self::ListenPort(
117                parse_u16(payload)
118                    .context("invalid WGDEVICE_A_LISTEN_PORT value")?,
119            ),
120            WGDEVICE_A_FWMARK => Self::Fwmark(
121                parse_u32(payload)
122                    .context("invalid WGDEVICE_A_FWMARK value")?,
123            ),
124            WGDEVICE_A_PEERS => {
125                let error_msg = "failed to parse WGDEVICE_A_PEERS";
126                let mut peers = Vec::new();
127                for nlas in NlasIterator::new(payload) {
128                    let nlas = &nlas.context(error_msg)?;
129                    let mut group = Vec::new();
130                    for nla in NlasIterator::new(nlas.value()) {
131                        let nla = &nla.context(error_msg)?;
132                        let parsed =
133                            WgPeerAttrs::parse(nla).context(error_msg)?;
134                        group.push(parsed);
135                    }
136                    peers.push(WgPeer(group));
137                }
138                Self::Peers(peers)
139            }
140            WGDEVICE_A_FLAGS => Self::Flags(
141                parse_u32(payload).context("invalid WGDEVICE_A_FLAGS value")?,
142            ),
143            kind => {
144                return Err(DecodeError::from(format!(
145                    "invalid NLA kind: {}",
146                    kind
147                )))
148            }
149        })
150    }
151}