wireguard_conf/models/
peer.rs

1use derive_builder::Builder;
2use either::Either;
3use ipnet::IpNet;
4
5use std::fmt;
6use std::net::{IpAddr, Ipv6Addr};
7use std::{convert::Infallible, net::Ipv4Addr};
8
9#[cfg(feature = "serde")]
10#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
11use serde::{Deserialize, Serialize};
12
13use crate::prelude::*;
14
15/// Options for [`Peer::to_interface()`].
16#[derive(Clone, Copy, Debug, PartialEq, Default)]
17#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
18pub struct ToInterfaceOptions {
19    /// Option, for setting server as default gateway.
20    default_gateway: bool,
21
22    /// Option, for setting persistent keepalive to client's peer.
23    persistent_keepalive: u16,
24}
25
26impl ToInterfaceOptions {
27    /// Create new [`ToInterfaceOptions`].
28    #[must_use]
29    pub fn new() -> Self {
30        Self::default()
31    }
32
33    /// Sets server as default gateway.
34    ///
35    /// When client interface will be generated, it will set `client_interface.peers[0].allowed_ips` to `0.0.0.0/0`
36    #[must_use]
37    pub fn default_gateway(mut self, value: bool) -> Self {
38        self.default_gateway = value;
39        self
40    }
41
42    /// Sets persistent keepalive to client's peer.
43    ///
44    #[must_use]
45    pub fn persistent_keepalive(mut self, value: u16) -> Self {
46        self.persistent_keepalive = value;
47        self
48    }
49}
50
51/// Struct, that represents `[Peer]` section in configuration.
52///
53/// [Wireguard docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#peer)
54#[must_use]
55#[derive(Clone, Debug, PartialEq, Builder)]
56#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
57#[builder(build_fn(private, name = "fallible_build", error = "Infallible"))]
58pub struct Peer {
59    /// Peer's endpoint.
60    ///
61    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#endpoint)
62    #[builder(setter(into, strip_option), default)]
63    pub endpoint: Option<String>,
64
65    /// Peer's allowed IPs.
66    ///
67    /// - */32 and */128 ipnets will be generated as regular ips (f.e. 1.2.3.4/32 -> 1.2.3.4)
68    ///
69    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#allowedips)
70    #[builder(setter(into), default)]
71    pub allowed_ips: Vec<IpNet>,
72
73    /// Peer's persistent keepalive.
74    ///
75    /// Represents in seconds how often to send an authenticated empty packet to the peer, for the
76    /// purpose of keeping a stateful firewall or NAT mapping valid persistently.
77    ///
78    /// Setting this value to `0` omits it in config.
79    ///
80    /// [Wireguard docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#persistentkeepalive)
81    #[builder(default)]
82    pub persistent_keepalive: u16,
83
84    /// Peer's key.
85    ///
86    /// If [`PrivateKey`] is provided, then peer can be exported to interface & full config.
87    /// Otherwise only to peer section of config.
88    #[builder(default = Either::Left(PrivateKey::random()))]
89    pub key: Either<PrivateKey, PublicKey>,
90
91    /// Peer's preshared-key.
92    #[builder(setter(strip_option), default)]
93    pub preshared_key: Option<PresharedKey>,
94}
95
96impl Peer {
97    /// Create new `PeerBuilder`. Alias for `PeerBuilder::new()`.
98    ///
99    /// ```rust
100    /// # use wireguard_conf::prelude::*;
101    /// # use wireguard_conf::as_ipnet;
102    /// #
103    /// let interface = Peer::builder()
104    ///     .allowed_ips([as_ipnet!("0.0.0.0/0")])
105    ///     // <snip>
106    ///     .build();
107    /// ```
108    #[must_use]
109    pub fn builder() -> PeerBuilder {
110        PeerBuilder::default()
111    }
112}
113
114impl PeerBuilder {
115    /// Create new `PeerBuilder`.
116    ///
117    /// ```rust
118    /// # use wireguard_conf::prelude::*;
119    /// # use wireguard_conf::as_ipnet;
120    /// #
121    /// let interface = PeerBuilder::new()
122    ///     .allowed_ips([as_ipnet!("0.0.0.0/0")])
123    ///     // <snip>
124    ///     .build();
125    /// ```
126    #[must_use]
127    pub fn new() -> Self {
128        Self::default()
129    }
130
131    /// Sets private key.
132    ///
133    /// Shorthand for `.key(Either::Left(value))`.
134    pub fn private_key(&mut self, value: PrivateKey) -> &mut Self {
135        self.key = Some(Either::Left(value));
136        self
137    }
138
139    /// Sets public key.
140    ///
141    /// Shorthand for `.key(Either::Right(value))`.
142    pub fn public_key(&mut self, value: PublicKey) -> &mut Self {
143        self.key = Some(Either::Right(value));
144        self
145    }
146
147    /// Builds an `Interface`.
148    pub fn build(&self) -> Peer {
149        self.fallible_build().unwrap_or_else(|_| unreachable!())
150    }
151}
152
153impl Peer {
154    /// Generate [`Interface`] from client's [`Peer`] and server's [`Interface`].
155    ///
156    /// `options`
157    ///
158    /// # Errors
159    ///
160    /// - [`WireguardError::NoPrivateKeyProvided`] -- peer don't have private key.
161    ///   You need to provide [`PrivateKey`] for creating interfaces from peers.
162    /// - [`WireguardError::NoAssignedIP`] -- no assigned ip found.
163    ///   This means that your peer doesn't have allowed ip, that is in interface's addresses
164    ///   network.
165    pub fn to_interface(
166        &self,
167        server_interface: &Interface,
168        options: ToInterfaceOptions,
169    ) -> WireguardResult<Interface> {
170        let Either::Left(private_key) = self.key.clone() else {
171            return Err(WireguardError::NoPrivateKeyProvided);
172        };
173
174        let assigned_ips: Vec<IpNet> = self
175            .allowed_ips
176            .iter()
177            .filter_map(|allowed_ip| {
178                for server_address in &server_interface.address {
179                    if server_address.contains(allowed_ip) {
180                        return IpNet::new(allowed_ip.addr(), server_address.prefix_len()).ok();
181                    }
182                }
183
184                None
185            })
186            .collect();
187
188        if assigned_ips.is_empty() {
189            return Err(WireguardError::NoAssignedIP);
190        }
191
192        let mut client_interface = Interface {
193            endpoint: None,
194
195            address: assigned_ips.clone(),
196            listen_port: None,
197            private_key,
198            dns: server_interface.dns.clone(),
199
200            table: None,
201            mtu: None,
202
203            #[cfg(feature = "amneziawg")]
204            amnezia_settings: server_interface.amnezia_settings.clone(),
205
206            pre_up: vec![],
207            pre_down: vec![],
208            post_up: vec![],
209            post_down: vec![],
210
211            peers: vec![server_interface.to_peer()],
212        };
213
214        if options.default_gateway {
215            client_interface.peers[0].allowed_ips = {
216                let mut allowed_ips = Vec::with_capacity(1);
217
218                if assigned_ips.iter().any(|ip| ip.addr().is_ipv4()) {
219                    allowed_ips.push(IpNet::new_assert(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0));
220                }
221
222                if assigned_ips.iter().any(|ip| ip.addr().is_ipv6()) {
223                    allowed_ips.push(IpNet::new_assert(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0));
224                }
225
226                allowed_ips
227            };
228        }
229
230        if options.persistent_keepalive != 0 {
231            client_interface.peers[0].persistent_keepalive = options.persistent_keepalive;
232        }
233
234        Ok(client_interface)
235    }
236}
237
238/// Implements [`fmt::Display`] for exporting peer.
239///
240/// # Note
241///
242/// It exports only `[Peer] ...` part. To export full interface, use [`Peer::to_interface()`]
243/// and then `.to_string()`
244impl fmt::Display for Peer {
245    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246        writeln!(f, "[Peer]")?;
247        if let Some(endpoint) = self.endpoint.clone() {
248            writeln!(f, "Endpoint = {endpoint}")?;
249        }
250        writeln!(
251            f,
252            "AllowedIPs = {}",
253            self.allowed_ips
254                .iter()
255                .map(std::string::ToString::to_string)
256                .collect::<Vec<String>>()
257                .join(",")
258        )?;
259        writeln!(
260            f,
261            "PublicKey = {}",
262            self.key.clone().right_or_else(|key| PublicKey::from(&key))
263        )?;
264        if let Some(preshared_key) = &self.preshared_key {
265            writeln!(f, "PresharedKey = {preshared_key}")?;
266        }
267        if self.persistent_keepalive != 0 {
268            writeln!(f, "PersistentKeepalive = {}", self.persistent_keepalive)?;
269        }
270
271        Ok(())
272    }
273}