Skip to main content

netlink_packet_wireguard/
attribute.rs

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