wireguard_conf/models/
peer.rs

1use either::Either;
2use ipnet::Ipv4Net;
3
4use std::fmt;
5
6use crate::prelude::*;
7
8/// Struct, that represents `[Peer]` section in configuration.
9///
10/// [Wireguard docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#peer)
11#[must_use]
12#[derive(Clone, Debug)]
13pub struct Peer {
14    /// Peer's endpoint.
15    ///
16    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#endpoint)
17    pub endpoint: Option<String>,
18
19    /// Peer's allowed IPs.
20    ///
21    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#allowedips)
22    pub allowed_ips: Vec<Ipv4Net>,
23
24    /// Peer's persistent keepalive.
25    ///
26    /// Represents in seconds how often to send an authenticated empty packet to the peer, for the
27    /// purpose of keeping a stateful firewall or NAT mapping valid persistently.
28    ///
29    /// Setting this value to `0` omits it in config.
30    ///
31    /// [Wireguard docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#persistentkeepalive)
32    pub persistent_keepalive: u16,
33
34    /// Peer's key.
35    ///
36    /// If [`PrivateKey`] is provided, then peer can be exported to interface & full config.
37    /// Otherwise only to peer section of config.
38    pub key: Either<PrivateKey, PublicKey>,
39
40    /// AmneziaWG settings.
41    ///
42    /// Used for packet obfuscation.
43    #[cfg(feature = "amneziawg")]
44    #[cfg_attr(docsrs, doc(cfg(feature = "amneziawg")))]
45    pub amnezia_settings: Option<AmneziaSettings>,
46}
47
48impl Peer {
49    /// Get Peer's [`Interface`].
50    ///
51    /// Pass server's interface to `interface` argument.
52    ///
53    /// # Errors
54    ///
55    /// - [`WireguardError::NoPrivateKeyProvided`] -- peer don't have private key.
56    ///   You need to provide [`PrivateKey`] for creating interfaces from peers.
57    /// - [`WireguardError::NoAssignedIP`] -- no assigned ip found.
58    ///   This means that your peer doesn't have allowed ip, that is in interface's addresses
59    ///   network.
60    pub fn to_interface(&self, interface: &Interface) -> WireguardResult<Interface> {
61        let Either::Left(private_key) = self.key.clone() else {
62            return Err(WireguardError::NoPrivateKeyProvided);
63        };
64
65        let assigned_ip = *self
66            .allowed_ips
67            .iter()
68            .find(|&net| interface.address.contains(net))
69            .ok_or(WireguardError::NoAssignedIP)?;
70
71        Ok(Interface {
72            endpoint: None,
73
74            address: assigned_ip,
75            listen_port: None,
76            private_key,
77            dns: interface.dns.clone(),
78
79            table: None,
80            mtu: None,
81
82            #[cfg(feature = "amneziawg")]
83            amnezia_settings: self.amnezia_settings.clone(),
84
85            pre_up: vec![],
86            pre_down: vec![],
87            post_up: vec![],
88            post_down: vec![],
89
90            peers: vec![interface.to_peer()],
91        })
92    }
93}
94
95/// Implements [`fmt::Display`] for exporting peer.
96///
97/// # Note
98///
99/// It exports only `[Peer] ...` part. To export full interface, use [`Peer::to_interface()`]
100/// and then `.to_string()`
101impl fmt::Display for Peer {
102    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103        writeln!(f, "[Peer]")?;
104        if let Some(endpoint) = self.endpoint.clone() {
105            writeln!(f, "Endpoint = {endpoint}")?;
106        }
107        writeln!(
108            f,
109            "AllowedIPs = {}",
110            self.allowed_ips
111                .iter()
112                .map(std::string::ToString::to_string)
113                .collect::<Vec<String>>()
114                .join(",")
115        )?;
116        writeln!(
117            f,
118            "PublicKey = {}",
119            self.key.clone().right_or_else(|key| PublicKey::from(&key))
120        )?;
121        if self.persistent_keepalive != 0 {
122            writeln!(f, "PersistentKeepalive = {}", self.persistent_keepalive)?;
123        }
124
125        Ok(())
126    }
127}