wireguard_conf/models/
builders.rs

1use either::Either;
2use ipnet::Ipv4Net;
3
4use crate::prelude::*;
5
6/// Builder, that used for creating [`Interface`]s.
7///
8/// # Examples
9///
10/// ```
11/// use wireguard_conf::prelude::*;
12///
13/// let server_private_key = PrivateKey::random();
14///
15/// let interface = InterfaceBuilder::new()
16///     .address("10.0.0.1/24".parse().unwrap())
17///     .listen_port(6969)
18///     .private_key(server_private_key.clone())
19///     .set_dns(vec!["8.8.8.8".to_string(), "8.8.4.4".to_string()])
20///     .endpoint("vpn.example.com".to_string())
21///     // .add_peer(some_peer)
22///     .build();
23///
24/// assert_eq!(interface.address, "10.0.0.1/24".parse().unwrap());
25/// assert_eq!(interface.listen_port, Some(6969));
26/// assert_eq!(interface.private_key, server_private_key);
27/// assert_eq!(interface.dns, vec!["8.8.8.8", "8.8.4.4"]);
28/// assert_eq!(interface.endpoint, Some("vpn.example.com".to_string()));
29/// ```
30#[must_use]
31#[derive(Default)]
32pub struct InterfaceBuilder {
33    address: Ipv4Net,
34    listen_port: Option<u16>,
35    private_key: Option<PrivateKey>,
36    dns: Vec<String>,
37    endpoint: Option<String>,
38    peers: Vec<Peer>,
39
40    #[cfg(feature = "amneziawg")]
41    #[cfg_attr(docsrs, doc(cfg(feature = "amneziawg")))]
42    amnezia_settings: Option<AmneziaSettings>,
43}
44
45impl InterfaceBuilder {
46    pub fn new() -> InterfaceBuilder {
47        InterfaceBuilder::default()
48    }
49
50    /// Set the address.
51    ///
52    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#address)
53    pub fn address(mut self, address: Ipv4Net) -> Self {
54        self.address = address;
55        self
56    }
57
58    /// Set the listen port.
59    ///
60    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#listenport)
61    pub fn listen_port(mut self, listen_port: u16) -> Self {
62        self.listen_port = Some(listen_port);
63        self
64    }
65
66    /// Set the private key.
67    ///
68    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#privatekey)
69    pub fn private_key(mut self, private_key: PrivateKey) -> Self {
70        self.private_key = Some(private_key);
71        self
72    }
73
74    /// Set the DNS servers array.
75    ///
76    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#dns-2)
77    pub fn set_dns(mut self, dns: Vec<String>) -> Self {
78        self.dns = dns;
79        self
80    }
81
82    /// Add DNS server.
83    ///
84    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#dns-2)
85    pub fn add_dns(mut self, dns: String) -> Self {
86        self.dns.push(dns);
87        self
88    }
89
90    /// Set the endpoint.
91    ///
92    /// # Note
93    ///
94    /// - In interface's config this set `# Name = ...`
95    /// - If you export interface via [`Interface::as_peer()`], exported peer will have this
96    ///   `Peer.endpoint`
97    ///
98    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#listenport)
99    pub fn endpoint(mut self, endpoint: String) -> Self {
100        self.endpoint = Some(endpoint);
101        self
102    }
103
104    /// Set the Peers array.
105    ///
106    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#peer)
107    pub fn set_peers(mut self, peers: Vec<Peer>) -> Self {
108        self.peers = peers;
109        self
110    }
111
112    /// Add peer.
113    ///
114    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#peer)
115    pub fn add_peer(mut self, peer: Peer) -> Self {
116        self.peers.push(peer);
117        self
118    }
119
120    /// Sets AmneziaWG obfuscation values.
121    ///
122    /// [AmneziaWG Docs](https://github.com/amnezia-vpn/amneziawg-linux-kernel-module?tab=readme-ov-file#configuration)
123    #[cfg(feature = "amneziawg")]
124    #[cfg_attr(docsrs, doc(cfg(feature = "amneziawg")))]
125    pub fn amnezia_settings(mut self, amnezia_settings: AmneziaSettings) -> Self {
126        self.amnezia_settings = Some(amnezia_settings);
127        self
128    }
129
130    /// Creates [`Interface`].
131    pub fn build(self) -> Interface {
132        Interface {
133            address: self.address,
134            listen_port: self.listen_port,
135            private_key: self.private_key.unwrap_or_else(PrivateKey::random),
136            dns: self.dns,
137
138            #[cfg(feature = "amneziawg")]
139            amnezia_settings: None,
140
141            endpoint: self.endpoint,
142            peers: self.peers,
143        }
144    }
145}
146
147/// Builder, that used for creating [`Peer`]s.
148///
149/// # Examples
150///
151/// ```
152/// use wireguard_conf::prelude::*;
153/// use either::Either;
154///
155/// let client_private_key = PrivateKey::random();
156///
157/// let peer = PeerBuilder::new()
158///     .endpoint("public.client.example.com".to_string())
159///     .add_allowed_ip("10.0.0.2/32".parse().unwrap())
160///     .private_key(client_private_key.clone())
161///     // if you don't want to generate interface from peer, you can provide public key
162///     // instead of private_key:
163///     //  .public_key(client_public_key)
164///     .build();
165///
166/// assert_eq!(peer.endpoint, Some("public.client.example.com".to_string()));
167/// assert_eq!(peer.allowed_ips, vec!["10.0.0.2/32".parse().unwrap()]);
168/// assert_eq!(peer.key, Either::Left(client_private_key));
169/// ```
170#[must_use]
171#[derive(Default)]
172pub struct PeerBuilder {
173    endpoint: Option<String>,
174    allowed_ips: Vec<Ipv4Net>,
175    key: Option<Either<PrivateKey, PublicKey>>,
176
177    #[cfg(feature = "amneziawg")]
178    #[cfg_attr(docsrs, doc(cfg(feature = "amneziawg")))]
179    amnezia_settings: Option<AmneziaSettings>,
180}
181
182impl PeerBuilder {
183    pub fn new() -> PeerBuilder {
184        PeerBuilder::default()
185    }
186
187    /// Sets endpoint.
188    ///
189    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#endpoint)
190    pub fn endpoint(mut self, endpoint: String) -> PeerBuilder {
191        self.endpoint = Some(endpoint);
192        self
193    }
194
195    /// Sets Allowed IPs array.
196    ///
197    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#allowedips)
198    pub fn set_allowed_ips(mut self, ip: Vec<Ipv4Net>) -> PeerBuilder {
199        self.allowed_ips = ip;
200        self
201    }
202
203    /// Adds allowed IP.
204    ///
205    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#allowedips)
206    pub fn add_allowed_ip(mut self, ip: Ipv4Net) -> PeerBuilder {
207        self.allowed_ips.push(ip);
208        self
209    }
210
211    /// Sets private key.
212    ///
213    /// # Note
214    ///
215    /// If you set private key (instead of public key), you can generate [`Interface`] from [`Peer`] (see [`Peer::as_interface()`]).
216    ///
217    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#publickey)
218    pub fn private_key(mut self, private_key: PrivateKey) -> PeerBuilder {
219        self.key = Some(Either::Left(private_key));
220        self
221    }
222
223    /// Sets public key.
224    ///
225    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#publickey)
226    pub fn public_key(mut self, public_key: PublicKey) -> PeerBuilder {
227        self.key = Some(Either::Right(public_key));
228        self
229    }
230
231    /// Sets AmneziaWG obfuscation values.
232    ///
233    /// [AmneziaWG Docs](https://github.com/amnezia-vpn/amneziawg-linux-kernel-module?tab=readme-ov-file#configuration)
234    #[cfg(feature = "amneziawg")]
235    #[cfg_attr(docsrs, doc(cfg(feature = "amneziawg")))]
236    pub fn amnezia_settings(mut self, amnezia_settings: AmneziaSettings) -> Self {
237        self.amnezia_settings = Some(amnezia_settings);
238        self
239    }
240
241    /// Creates [`Peer`].
242    pub fn build(self) -> Peer {
243        let key = self
244            .key
245            .unwrap_or_else(|| Either::Left(PrivateKey::random()));
246
247        Peer {
248            endpoint: self.endpoint,
249            allowed_ips: self.allowed_ips,
250            key,
251
252            #[cfg(feature = "amneziawg")]
253            amnezia_settings: self.amnezia_settings,
254        }
255    }
256}