use derive_builder::Builder;
use either::Either;
use ipnet::IpNet;
use std::fmt;
use std::net::{IpAddr, Ipv6Addr};
use std::{convert::Infallible, net::Ipv4Addr};
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
use serde::{Deserialize, Serialize};
use crate::prelude::*;
#[derive(Clone, Copy, Debug, PartialEq, Default)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct ToInterfaceOptions {
default_gateway: bool,
persistent_keepalive: u16,
}
impl ToInterfaceOptions {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn default_gateway(mut self, value: bool) -> Self {
self.default_gateway = value;
self
}
#[must_use]
pub fn persistent_keepalive(mut self, value: u16) -> Self {
self.persistent_keepalive = value;
self
}
}
#[must_use]
#[derive(Clone, Debug, PartialEq, Builder)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[builder(build_fn(private, name = "fallible_build", error = "Infallible"))]
pub struct Peer {
#[builder(setter(into, strip_option), default)]
pub endpoint: Option<String>,
#[builder(setter(into), default)]
pub allowed_ips: Vec<IpNet>,
#[builder(default)]
pub persistent_keepalive: u16,
#[builder(default = Either::Left(PrivateKey::random()))]
pub key: Either<PrivateKey, PublicKey>,
#[builder(setter(strip_option), default)]
pub preshared_key: Option<PresharedKey>,
}
impl Peer {
#[must_use]
pub fn builder() -> PeerBuilder {
PeerBuilder::default()
}
}
impl PeerBuilder {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn private_key(&mut self, value: PrivateKey) -> &mut Self {
self.key = Some(Either::Left(value));
self
}
pub fn public_key(&mut self, value: PublicKey) -> &mut Self {
self.key = Some(Either::Right(value));
self
}
pub fn build(&self) -> Peer {
self.fallible_build().unwrap_or_else(|_| unreachable!())
}
}
impl Peer {
pub fn to_interface(
&self,
server_interface: &Interface,
options: ToInterfaceOptions,
) -> WireguardResult<Interface> {
let Either::Left(private_key) = self.key.clone() else {
return Err(WireguardError::NoPrivateKeyProvided);
};
let assigned_ips: Vec<IpNet> = self
.allowed_ips
.iter()
.filter_map(|allowed_ip| {
for server_address in &server_interface.address {
if server_address.contains(allowed_ip) {
return IpNet::new(allowed_ip.addr(), server_address.prefix_len()).ok();
}
}
None
})
.collect();
if assigned_ips.is_empty() {
return Err(WireguardError::NoAssignedIP);
}
let mut client_interface = Interface {
endpoint: None,
address: assigned_ips.clone(),
listen_port: None,
private_key,
dns: server_interface.dns.clone(),
table: None,
mtu: None,
#[cfg(feature = "amneziawg")]
amnezia_settings: server_interface.amnezia_settings.clone(),
pre_up: vec![],
pre_down: vec![],
post_up: vec![],
post_down: vec![],
peers: vec![server_interface.to_peer()],
};
if options.default_gateway {
client_interface.peers[0].allowed_ips = {
let mut allowed_ips = Vec::with_capacity(1);
if assigned_ips.iter().any(|ip| ip.addr().is_ipv4()) {
allowed_ips.push(IpNet::new_assert(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0));
}
if assigned_ips.iter().any(|ip| ip.addr().is_ipv6()) {
allowed_ips.push(IpNet::new_assert(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0));
}
allowed_ips
};
}
if options.persistent_keepalive != 0 {
client_interface.peers[0].persistent_keepalive = options.persistent_keepalive;
}
Ok(client_interface)
}
}
impl fmt::Display for Peer {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "[Peer]")?;
if let Some(endpoint) = self.endpoint.clone() {
writeln!(f, "Endpoint = {endpoint}")?;
}
writeln!(
f,
"AllowedIPs = {}",
self.allowed_ips
.iter()
.map(std::string::ToString::to_string)
.collect::<Vec<String>>()
.join(",")
)?;
writeln!(
f,
"PublicKey = {}",
self.key.clone().right_or_else(|key| PublicKey::from(&key))
)?;
if let Some(preshared_key) = &self.preshared_key {
writeln!(f, "PresharedKey = {preshared_key}")?;
}
if self.persistent_keepalive != 0 {
writeln!(f, "PersistentKeepalive = {}", self.persistent_keepalive)?;
}
Ok(())
}
}