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
39    table: Option<Table>,
40    mtu: Option<usize>,
41
42    peers: Vec<Peer>,
43
44    #[cfg(feature = "amneziawg")]
45    #[cfg_attr(docsrs, doc(cfg(feature = "amneziawg")))]
46    amnezia_settings: Option<AmneziaSettings>,
47
48    pre_up: Vec<String>,
49    pre_down: Vec<String>,
50    post_up: Vec<String>,
51    post_down: Vec<String>,
52}
53
54impl InterfaceBuilder {
55    /// Create new [`InterfaceBuilder`].
56    pub fn new() -> InterfaceBuilder {
57        InterfaceBuilder::default()
58    }
59
60    /// Set the address.
61    ///
62    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#address)
63    pub fn address(mut self, address: Ipv4Net) -> Self {
64        self.address = address;
65        self
66    }
67
68    /// Set the listen port.
69    ///
70    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#listenport)
71    pub fn listen_port(mut self, listen_port: u16) -> Self {
72        self.listen_port = Some(listen_port);
73        self
74    }
75
76    /// Set the private key.
77    ///
78    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#privatekey)
79    pub fn private_key(mut self, private_key: PrivateKey) -> Self {
80        self.private_key = Some(private_key);
81        self
82    }
83
84    /// Set the DNS servers array.
85    ///
86    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#dns-2)
87    pub fn set_dns(mut self, dns: Vec<String>) -> Self {
88        self.dns = dns;
89        self
90    }
91
92    /// Add DNS server.
93    ///
94    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#dns-2)
95    pub fn add_dns(mut self, dns: String) -> Self {
96        self.dns.push(dns);
97        self
98    }
99
100    /// Set the endpoint.
101    ///
102    /// # Note
103    ///
104    /// - `[Interface]` section will have `# Name = <endpoint>` comment at the top.
105    /// - Exported [`Peer`] (via [`Interface::to_peer`]) will have this endpoint.
106    ///
107    /// [Wireguard Docs for `# Name`](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#-name-1);
108    /// [Wireguard Docs for endpoint](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#endpoint)
109    pub fn endpoint(mut self, endpoint: String) -> Self {
110        self.endpoint = Some(endpoint);
111        self
112    }
113
114    /// Set routing table. See [`Table`] for special values.
115    ///
116    /// [Wireguard docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#table)
117    pub fn set_table(mut self, value: Table) -> Self {
118        self.table = Some(value);
119        self
120    }
121
122    /// Set Maximum Transmission Unit (MTU, aka packet/frame size).
123    ///
124    /// [Wireguard docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#mtu)
125    pub fn set_mtu(mut self, value: usize) -> Self {
126        self.mtu = Some(value);
127        self
128    }
129
130    /// Set the Peers array.
131    ///
132    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#peer)
133    pub fn set_peers(mut self, peers: Vec<Peer>) -> Self {
134        self.peers = peers;
135        self
136    }
137
138    /// Add peer.
139    ///
140    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#peer)
141    pub fn add_peer(mut self, peer: Peer) -> Self {
142        self.peers.push(peer);
143        self
144    }
145
146    /// Sets AmneziaWG obfuscation values.
147    ///
148    /// [AmneziaWG Docs](https://github.com/amnezia-vpn/amneziawg-linux-kernel-module?tab=readme-ov-file#configuration)
149    #[cfg(feature = "amneziawg")]
150    #[cfg_attr(docsrs, doc(cfg(feature = "amneziawg")))]
151    pub fn amnezia_settings(mut self, amnezia_settings: AmneziaSettings) -> Self {
152        self.amnezia_settings = Some(amnezia_settings);
153        self
154    }
155
156    // TODO: refactor with macros
157
158    /// Set commands, that will be executed before the interface is brought up.
159    ///
160    /// [Wireguard docs](https://github.com/pirate/wireguard-docs#preup)
161    pub fn set_pre_up(mut self, snippets: Vec<String>) -> Self {
162        self.pre_up = snippets;
163        self
164    }
165
166    /// Add command, that will be executed before the interface is brought up.
167    ///
168    /// [Wireguard docs](https://github.com/pirate/wireguard-docs#$docs)
169    pub fn add_pre_up(mut self, snippet: String) -> Self {
170        self.pre_up.push(snippet);
171        self
172    }
173
174    /// Set commands, that will be executed before the interface is brought down.
175    ///
176    /// [Wireguard docs](https://github.com/pirate/wireguard-docs#predown)
177    pub fn set_pre_down(mut self, snippets: Vec<String>) -> Self {
178        self.pre_down = snippets;
179        self
180    }
181
182    /// Add command, that will be executed before the interface is brought down.
183    ///
184    /// [Wireguard docs](https://github.com/pirate/wireguard-docs#predown)
185    pub fn add_pre_down(mut self, snippet: String) -> Self {
186        self.pre_down.push(snippet);
187        self
188    }
189
190    /// Set commands, that will be executed after the interface is brought up.
191    ///
192    /// [Wireguard docs](https://github.com/pirate/wireguard-docs#postup)
193    pub fn set_post_up(mut self, snippets: Vec<String>) -> Self {
194        self.post_up = snippets;
195        self
196    }
197
198    /// Add command, that will be executed after the interface is brought up.
199    ///
200    /// [Wireguard docs](https://github.com/pirate/wireguard-docs#postup)
201    pub fn add_post_up(mut self, snippet: String) -> Self {
202        self.post_up.push(snippet);
203        self
204    }
205
206    /// Set commands, that will be executed after the interface is brought down.
207    ///
208    /// [Wireguard docs](https://github.com/pirate/wireguard-docs#postdown)
209    pub fn set_post_down(mut self, snippets: Vec<String>) -> Self {
210        self.post_down = snippets;
211        self
212    }
213
214    /// Add command, that will be executed after the interface is brought down.
215    ///
216    /// [Wireguard docs](https://github.com/pirate/wireguard-docs#postdown)
217    pub fn add_post_down(mut self, snippet: String) -> Self {
218        self.post_down.push(snippet);
219        self
220    }
221
222    /// Creates [`Interface`].
223    pub fn build(self) -> Interface {
224        Interface {
225            address: self.address,
226            listen_port: self.listen_port,
227            private_key: self.private_key.unwrap_or_else(PrivateKey::random),
228            dns: self.dns,
229
230            #[cfg(feature = "amneziawg")]
231            amnezia_settings: self.amnezia_settings,
232
233            endpoint: self.endpoint,
234
235            table: self.table,
236            mtu: self.mtu,
237
238            peers: self.peers,
239
240            pre_up: self.pre_up,
241            pre_down: self.pre_down,
242            post_up: self.post_up,
243            post_down: self.post_down,
244        }
245    }
246}
247
248/// Builder, that used for creating [`Peer`]s.
249///
250/// # Examples
251///
252/// ```
253/// use wireguard_conf::prelude::*;
254/// use either::Either;
255///
256/// let client_private_key = PrivateKey::random();
257///
258/// let peer = PeerBuilder::new()
259///     .endpoint("public.client.example.com".to_string())
260///     .add_allowed_ip("10.0.0.2/32".parse().unwrap())
261///     .private_key(client_private_key.clone())
262///     // you can provide public key, instead of private_key.
263///     // but you can't generate `Interface` out of `Peer`:
264///     //  .public_key(client_public_key)
265///     .persistent_keepalive(25)
266///     .build();
267///
268/// assert_eq!(peer.endpoint, Some("public.client.example.com".to_string()));
269/// assert_eq!(peer.allowed_ips, vec!["10.0.0.2/32".parse().unwrap()]);
270/// assert_eq!(peer.key, Either::Left(client_private_key));
271/// assert_eq!(peer.persistent_keepalive, 25);
272/// ```
273#[must_use]
274#[derive(Default)]
275pub struct PeerBuilder {
276    endpoint: Option<String>,
277    allowed_ips: Vec<Ipv4Net>,
278    key: Option<Either<PrivateKey, PublicKey>>,
279    persistent_keepalive: u16,
280
281    #[cfg(feature = "amneziawg")]
282    #[cfg_attr(docsrs, doc(cfg(feature = "amneziawg")))]
283    amnezia_settings: Option<AmneziaSettings>,
284}
285
286impl PeerBuilder {
287    /// Create new [`PeerBuilder`].
288    pub fn new() -> PeerBuilder {
289        PeerBuilder::default()
290    }
291
292    /// Sets endpoint.
293    ///
294    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#endpoint)
295    pub fn endpoint(mut self, endpoint: String) -> PeerBuilder {
296        self.endpoint = Some(endpoint);
297        self
298    }
299
300    /// Sets Allowed IPs array.
301    ///
302    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#allowedips)
303    pub fn set_allowed_ips(mut self, ip: Vec<Ipv4Net>) -> PeerBuilder {
304        self.allowed_ips = ip;
305        self
306    }
307
308    /// Adds allowed IP.
309    ///
310    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#allowedips)
311    pub fn add_allowed_ip(mut self, ip: Ipv4Net) -> PeerBuilder {
312        self.allowed_ips.push(ip);
313        self
314    }
315
316    /// Sets private key.
317    ///
318    /// # Note
319    ///
320    /// If you set private key (instead of public key), you can generate [`Interface`] from [`Peer`] (see [`Peer::to_interface()`]).
321    ///
322    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#privatekey)
323    pub fn private_key(mut self, private_key: PrivateKey) -> PeerBuilder {
324        self.key = Some(Either::Left(private_key));
325        self
326    }
327
328    /// Sets public key.
329    ///
330    /// [Wireguard Docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#publickey)
331    pub fn public_key(mut self, public_key: PublicKey) -> PeerBuilder {
332        self.key = Some(Either::Right(public_key));
333        self
334    }
335
336    /// Sets persistent keepalive.
337    ///
338    /// Represents in seconds how often to send an authenticated empty packet to the peer, for the
339    /// purpose of keeping a stateful firewall or NAT mapping valid persistently.
340    ///
341    /// Setting this value to `0` omits it in config.
342    ///
343    /// [Wireguard docs](https://github.com/pirate/wireguard-docs?tab=readme-ov-file#persistentkeepalive)
344    pub fn persistent_keepalive(mut self, persistent_keepalive: u16) -> PeerBuilder {
345        self.persistent_keepalive = persistent_keepalive;
346        self
347    }
348
349    /// Sets AmneziaWG obfuscation values.
350    ///
351    /// [AmneziaWG Docs](https://github.com/amnezia-vpn/amneziawg-linux-kernel-module?tab=readme-ov-file#configuration)
352    #[cfg(feature = "amneziawg")]
353    #[cfg_attr(docsrs, doc(cfg(feature = "amneziawg")))]
354    pub fn amnezia_settings(mut self, amnezia_settings: AmneziaSettings) -> Self {
355        self.amnezia_settings = Some(amnezia_settings);
356        self
357    }
358
359    /// Creates [`Peer`].
360    pub fn build(self) -> Peer {
361        let key = self
362            .key
363            .unwrap_or_else(|| Either::Left(PrivateKey::random()));
364
365        Peer {
366            endpoint: self.endpoint,
367            allowed_ips: self.allowed_ips,
368            key,
369            persistent_keepalive: self.persistent_keepalive,
370
371            #[cfg(feature = "amneziawg")]
372            amnezia_settings: self.amnezia_settings,
373        }
374    }
375}