1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
use crate::{
device::{AllowedIp, PeerConfig},
key::Key,
};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
/// Builds and represents a single peer in a WireGuard interface configuration.
///
/// Note that if a peer with that public key already exists on the interface,
/// the settings specified here will be applied _on top_ of the existing settings,
/// similarly to interface-wide settings.
///
/// If this is not what you want, use [`DeviceConfigBuilder::replace_peers`](DeviceConfigBuilder::replace_peers)
/// to replace all peer settings on the interface, or use
/// [`DeviceConfigBuilder::remove_peer_by_key`](DeviceConfigBuilder::remove_peer_by_key) first
/// to remove the peer from the interface, and then apply a second configuration to re-add it.
///
/// # Example
/// ```rust
/// # use wireguard_control::*;
/// # use std::net::AddrParseError;
/// # fn try_main() -> Result<(), AddrParseError> {
/// let peer_keypair = KeyPair::generate();
///
/// // create a new peer and allow it to connect from 192.168.1.2
/// let peer = PeerConfigBuilder::new(&peer_keypair.public)
/// .replace_allowed_ips()
/// .add_allowed_ip("192.168.1.2".parse()?, 32);
///
/// // update our existing configuration with the new peer
/// DeviceUpdate::new().add_peer(peer).apply(&"wg-example".parse().unwrap(), Backend::Userspace);
///
/// println!("Send these keys to your peer: {:#?}", peer_keypair);
///
/// # Ok(())
/// # }
/// # fn main() { try_main(); }
/// ```
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct PeerConfigBuilder {
pub(crate) public_key: Key,
pub(crate) preshared_key: Option<Key>,
pub(crate) endpoint: Option<SocketAddr>,
pub(crate) persistent_keepalive_interval: Option<u16>,
pub(crate) allowed_ips: Vec<AllowedIp>,
pub(crate) replace_allowed_ips: bool,
pub(crate) remove_me: bool,
}
impl PeerConfigBuilder {
/// Creates a new `PeerConfigBuilder` that does nothing when applied.
pub fn new(public_key: &Key) -> Self {
PeerConfigBuilder {
public_key: public_key.clone(),
preshared_key: None,
endpoint: None,
persistent_keepalive_interval: None,
allowed_ips: vec![],
replace_allowed_ips: false,
remove_me: false,
}
}
pub fn into_peer_config(self) -> PeerConfig {
PeerConfig {
public_key: self.public_key,
preshared_key: self.preshared_key,
endpoint: self.endpoint,
persistent_keepalive_interval: self.persistent_keepalive_interval,
allowed_ips: self.allowed_ips,
__cant_construct_me: (),
}
}
/// The public key used in this builder.
pub fn public_key(&self) -> &Key {
&self.public_key
}
/// Creates a `PeerConfigBuilder` from a [`PeerConfig`](PeerConfig).
///
/// This is mostly a convenience method for cases when you want to copy
/// some or most of the existing peer configuration to a new configuration.
///
/// This returns a `PeerConfigBuilder`, so you can still call any methods
/// you need to override the imported settings.
pub fn from_peer_config(config: PeerConfig) -> Self {
let mut builder = Self::new(&config.public_key);
if let Some(k) = config.preshared_key {
builder = builder.set_preshared_key(k);
}
if let Some(e) = config.endpoint {
builder = builder.set_endpoint(e);
}
if let Some(k) = config.persistent_keepalive_interval {
builder = builder.set_persistent_keepalive_interval(k);
}
builder
.replace_allowed_ips()
.add_allowed_ips(&config.allowed_ips)
}
/// Specifies a preshared key to be set for this peer.
pub fn set_preshared_key(mut self, key: Key) -> Self {
self.preshared_key = Some(key);
self
}
/// Specifies that this peer's preshared key should be unset.
pub fn unset_preshared_key(self) -> Self {
self.set_preshared_key(Key::zero())
}
/// Specifies an exact endpoint that this peer should be allowed to connect from.
pub fn set_endpoint(mut self, address: SocketAddr) -> Self {
self.endpoint = Some(address);
self
}
/// Specifies the interval between keepalive packets to be sent to this peer.
pub fn set_persistent_keepalive_interval(mut self, interval: u16) -> Self {
self.persistent_keepalive_interval = Some(interval);
self
}
/// Specifies that this peer does not require keepalive packets.
pub fn unset_persistent_keepalive(self) -> Self {
self.set_persistent_keepalive_interval(0)
}
/// Specifies an IP address this peer will be allowed to connect from/to.
///
/// See [`AllowedIp`](AllowedIp) for details. This method can be called
/// more than once, and all IP addresses will be added to the configuration.
pub fn add_allowed_ip(mut self, address: IpAddr, cidr: u8) -> Self {
self.allowed_ips.push(AllowedIp { address, cidr });
self
}
/// Specifies multiple IP addresses this peer will be allowed to connect from/to.
///
/// See [`AllowedIp`](AllowedIp) for details. This method can be called
/// more than once, and all IP addresses will be added to the configuration.
pub fn add_allowed_ips(mut self, ips: &[AllowedIp]) -> Self {
self.allowed_ips.extend_from_slice(ips);
self
}
/// Specifies this peer should be allowed to connect to all IP addresses.
///
/// This is a convenience method for cases when you want to connect to a server
/// that all traffic should be routed through.
pub fn allow_all_ips(self) -> Self {
self.add_allowed_ip(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0)
.add_allowed_ip(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), 0)
}
/// Specifies that the allowed IP addresses in this configuration should replace
/// the existing configuration of the interface, not be appended to it.
pub fn replace_allowed_ips(mut self) -> Self {
self.replace_allowed_ips = true;
self
}
/// Mark peer for removal from interface.
pub fn remove(mut self) -> Self {
self.remove_me = true;
self
}
}