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}