|
5 | 5 |
|
6 | 6 | use std::{ |
7 | 7 | collections::HashMap, |
8 | | - fmt::{self, Debug, Formatter}, |
| 8 | + fmt, |
9 | 9 | io::{self, BufRead, BufReader, Read}, |
10 | 10 | net::SocketAddr, |
11 | 11 | str::FromStr, |
12 | 12 | time::{Duration, SystemTime}, |
13 | 13 | }; |
14 | 14 |
|
15 | 15 | #[cfg(target_os = "linux")] |
16 | | -use netlink_packet_wireguard::{ |
17 | | - constants::{WGDEVICE_F_REPLACE_PEERS, WGPEER_F_REPLACE_ALLOWEDIPS}, |
18 | | - nlas::{WgAllowedIpAttrs, WgDeviceAttrs, WgPeer, WgPeerAttrs}, |
19 | | -}; |
| 16 | +use netlink_packet_wireguard::{constants::WGDEVICE_F_REPLACE_PEERS, nlas::WgDeviceAttrs}; |
20 | 17 | #[cfg(feature = "serde")] |
21 | 18 | use serde::{Deserialize, Serialize}; |
22 | 19 |
|
23 | | -use crate::{error::WireguardInterfaceError, key::Key, net::IpAddrMask, utils::resolve}; |
24 | | - |
25 | | -/// WireGuard peer representation. |
26 | | -#[derive(Clone, Default, PartialEq)] |
27 | | -#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] |
28 | | -pub struct Peer { |
29 | | - pub public_key: Key, |
30 | | - pub preshared_key: Option<Key>, |
31 | | - pub protocol_version: Option<u32>, |
32 | | - pub endpoint: Option<SocketAddr>, |
33 | | - pub last_handshake: Option<SystemTime>, |
34 | | - pub tx_bytes: u64, |
35 | | - pub rx_bytes: u64, |
36 | | - pub persistent_keepalive_interval: Option<u16>, |
37 | | - pub allowed_ips: Vec<IpAddrMask>, |
38 | | -} |
39 | | - |
40 | | -// implement manually to avoid exposing preshared keys |
41 | | -impl fmt::Debug for Peer { |
42 | | - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
43 | | - f.debug_struct("Peer") |
44 | | - .field("public_key", &self.public_key) |
45 | | - .field("protocol_version", &self.protocol_version) |
46 | | - .field("endpoint", &self.endpoint) |
47 | | - .field("last_handshake", &self.last_handshake) |
48 | | - .field("tx_bytes", &self.tx_bytes) |
49 | | - .field("rx_bytes", &self.rx_bytes) |
50 | | - .field( |
51 | | - "persistent_keepalive_interval", |
52 | | - &self.persistent_keepalive_interval, |
53 | | - ) |
54 | | - .field("allowed_ips", &self.allowed_ips) |
55 | | - .finish_non_exhaustive() |
56 | | - } |
57 | | -} |
58 | | - |
59 | | -impl Peer { |
60 | | - /// Create new `Peer` with a given `public_key`. |
61 | | - #[must_use] |
62 | | - pub fn new(public_key: Key) -> Self { |
63 | | - Self { |
64 | | - public_key, |
65 | | - preshared_key: None, |
66 | | - protocol_version: None, |
67 | | - endpoint: None, |
68 | | - last_handshake: None, |
69 | | - tx_bytes: 0, |
70 | | - rx_bytes: 0, |
71 | | - persistent_keepalive_interval: None, |
72 | | - allowed_ips: Vec::new(), |
73 | | - } |
74 | | - } |
75 | | - |
76 | | - pub fn set_allowed_ips(&mut self, allowed_ips: Vec<IpAddrMask>) { |
77 | | - self.allowed_ips = allowed_ips; |
78 | | - } |
79 | | - |
80 | | - /// Resolves endpoint address to [`SocketAddr`] and sets the field |
81 | | - pub fn set_endpoint(&mut self, endpoint: &str) -> Result<(), WireguardInterfaceError> { |
82 | | - self.endpoint = Some(resolve(endpoint)?); |
83 | | - Ok(()) |
84 | | - } |
85 | | - |
86 | | - #[must_use] |
87 | | - pub fn as_uapi_update(&self) -> String { |
88 | | - let mut output = format!("public_key={}\n", self.public_key.to_lower_hex()); |
89 | | - if let Some(key) = &self.preshared_key { |
90 | | - output.push_str("preshared_key="); |
91 | | - output.push_str(&key.to_lower_hex()); |
92 | | - output.push('\n'); |
93 | | - } |
94 | | - if let Some(endpoint) = &self.endpoint { |
95 | | - output.push_str("endpoint="); |
96 | | - output.push_str(&endpoint.to_string()); |
97 | | - output.push('\n'); |
98 | | - } |
99 | | - if let Some(interval) = &self.persistent_keepalive_interval { |
100 | | - output.push_str("persistent_keepalive_interval="); |
101 | | - output.push_str(&interval.to_string()); |
102 | | - output.push('\n'); |
103 | | - } |
104 | | - output.push_str("replace_allowed_ips=true\n"); |
105 | | - for allowed_ip in &self.allowed_ips { |
106 | | - output.push_str("allowed_ip="); |
107 | | - output.push_str(&allowed_ip.to_string()); |
108 | | - output.push('\n'); |
109 | | - } |
110 | | - |
111 | | - output |
112 | | - } |
113 | | - |
114 | | - #[must_use] |
115 | | - pub fn as_uapi_remove(&self) -> String { |
116 | | - format!( |
117 | | - "public_key={}\nremove=true\n", |
118 | | - self.public_key.to_lower_hex() |
119 | | - ) |
120 | | - } |
121 | | -} |
122 | | - |
123 | | -#[cfg(target_os = "linux")] |
124 | | -impl Peer { |
125 | | - #[must_use] |
126 | | - pub(crate) fn from_nlas(nlas: &[WgPeerAttrs]) -> Self { |
127 | | - let mut peer = Self::default(); |
128 | | - |
129 | | - for nla in nlas { |
130 | | - match nla { |
131 | | - WgPeerAttrs::PublicKey(value) => peer.public_key = Key::new(*value), |
132 | | - WgPeerAttrs::PresharedKey(value) => peer.preshared_key = Some(Key::new(*value)), |
133 | | - WgPeerAttrs::Endpoint(value) => peer.endpoint = Some(*value), |
134 | | - WgPeerAttrs::PersistentKeepalive(value) => { |
135 | | - peer.persistent_keepalive_interval = Some(*value); |
136 | | - } |
137 | | - WgPeerAttrs::LastHandshake(value) => peer.last_handshake = Some(*value), |
138 | | - WgPeerAttrs::RxBytes(value) => peer.rx_bytes = *value, |
139 | | - WgPeerAttrs::TxBytes(value) => peer.tx_bytes = *value, |
140 | | - WgPeerAttrs::AllowedIps(nlas) => { |
141 | | - for nla in nlas { |
142 | | - let ip = nla.iter().find_map(|nla| match nla { |
143 | | - WgAllowedIpAttrs::IpAddr(ip) => Some(*ip), |
144 | | - _ => None, |
145 | | - }); |
146 | | - let cidr = nla.iter().find_map(|nla| match nla { |
147 | | - WgAllowedIpAttrs::Cidr(cidr) => Some(*cidr), |
148 | | - _ => None, |
149 | | - }); |
150 | | - if let (Some(ip), Some(cidr)) = (ip, cidr) { |
151 | | - peer.allowed_ips.push(IpAddrMask::new(ip, cidr)); |
152 | | - } |
153 | | - } |
154 | | - } |
155 | | - _ => (), |
156 | | - } |
157 | | - } |
158 | | - |
159 | | - peer |
160 | | - } |
161 | | - |
162 | | - #[must_use] |
163 | | - pub(crate) fn as_nlas(&self, ifname: &str) -> Vec<WgDeviceAttrs> { |
164 | | - vec![ |
165 | | - WgDeviceAttrs::IfName(ifname.into()), |
166 | | - WgDeviceAttrs::Peers(vec![self.as_nlas_peer()]), |
167 | | - ] |
168 | | - } |
169 | | - |
170 | | - #[must_use] |
171 | | - pub(crate) fn as_nlas_peer(&self) -> WgPeer { |
172 | | - let mut attrs = vec![WgPeerAttrs::PublicKey(self.public_key.as_array())]; |
173 | | - if let Some(keepalive) = self.persistent_keepalive_interval { |
174 | | - attrs.push(WgPeerAttrs::PersistentKeepalive(keepalive)); |
175 | | - } |
176 | | - |
177 | | - if let Some(endpoint) = self.endpoint { |
178 | | - attrs.push(WgPeerAttrs::Endpoint(endpoint)); |
179 | | - } |
180 | | - |
181 | | - if let Some(preshared_key) = &self.preshared_key { |
182 | | - attrs.push(WgPeerAttrs::PresharedKey(preshared_key.as_array())); |
183 | | - } |
184 | | - |
185 | | - attrs.push(WgPeerAttrs::Flags(WGPEER_F_REPLACE_ALLOWEDIPS)); |
186 | | - let allowed_ips = self |
187 | | - .allowed_ips |
188 | | - .iter() |
189 | | - .map(IpAddrMask::to_nlas_allowed_ip) |
190 | | - .collect(); |
191 | | - attrs.push(WgPeerAttrs::AllowedIps(allowed_ips)); |
192 | | - |
193 | | - WgPeer(attrs) |
194 | | - } |
195 | | -} |
| 20 | +use super::{key::Key, peer::Peer}; |
196 | 21 |
|
197 | 22 | /// WireGuard host representation. |
198 | 23 | #[derive(Clone, Default)] |
199 | 24 | #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] |
200 | 25 | pub struct Host { |
201 | 26 | pub listen_port: u16, |
202 | 27 | pub private_key: Option<Key>, |
| 28 | + // FwMark with value of 0, removes the setting from WireGuard interface. |
203 | 29 | pub(super) fwmark: Option<u32>, |
204 | 30 | pub peers: HashMap<Key, Peer>, |
205 | 31 | } |
206 | 32 |
|
207 | | -// implement manually to avoid exposing private keys |
208 | | -impl Debug for Host { |
209 | | - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { |
| 33 | +// Implement `Debug` manually to avoid exposing private keys. |
| 34 | +impl fmt::Debug for Host { |
| 35 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
210 | 36 | f.debug_struct("Host") |
211 | 37 | .field("listen_port", &self.listen_port) |
212 | 38 | .field("fwmark", &self.fwmark) |
|
0 commit comments