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}