netlink_packet_wireguard/nlas/
device.rs1use 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}