use crate::xplatform::protocol::SetKey;
use std::fmt::Display;
use std::net::IpAddr;
use std::net::SocketAddr;
#[derive(Debug, Default, PartialEq, Eq)]
pub struct Device {
pub private_key: Option<[u8; 32]>,
pub listen_port: Option<u16>,
pub fwmark: Option<u32>,
pub replace_peers: Option<bool>,
pub peers: Vec<Peer>,
}
impl Display for Device {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(private_key) = self.private_key {
let private_key = hex::encode(private_key);
writeln!(f, "{}={}", SetKey::PrivateKey, private_key)?;
}
if let Some(listen_port) = self.listen_port {
writeln!(f, "{}={}", SetKey::ListenPort, listen_port)?;
}
if let Some(fwmark) = self.fwmark {
writeln!(f, "{}={}", SetKey::Fwmark, fwmark)?;
}
if let Some(replace_peers) = self.replace_peers {
writeln!(f, "{}={}", SetKey::ReplacePeers, replace_peers)?;
}
for peer in &self.peers {
peer.fmt(f)?;
}
Ok(())
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct Peer {
pub public_key: [u8; 32],
pub remove: Option<bool>,
pub update_only: Option<bool>,
pub preshared_key: Option<[u8; 32]>,
pub endpoint: Option<SocketAddr>,
pub persistent_keepalive_interval: Option<u16>,
pub replace_allowed_ips: Option<bool>,
pub allowed_ips: Vec<AllowedIp>,
}
impl Peer {
pub fn from_public_key(public_key: [u8; 32]) -> Self {
Self {
public_key,
remove: None,
update_only: None,
preshared_key: None,
endpoint: None,
persistent_keepalive_interval: None,
replace_allowed_ips: None,
allowed_ips: vec![],
}
}
pub fn remove(mut self, remove: bool) -> Self {
self.remove = remove.then_some(true);
self
}
pub fn update_only(mut self, update_only: bool) -> Self {
self.update_only = update_only.then_some(true);
self
}
pub fn preshared_key(mut self, preshared_key: [u8; 32]) -> Self {
self.preshared_key = Some(preshared_key);
self
}
pub fn endpoint(mut self, endpoint: SocketAddr) -> Self {
self.endpoint = Some(endpoint);
self
}
pub fn persistent_keepalive_interval(mut self, persistent_keepalive_interval: u16) -> Self {
self.persistent_keepalive_interval = Some(persistent_keepalive_interval);
self
}
pub fn replace_allowed_ips(mut self, replace_allowed_ips: bool) -> Self {
self.replace_allowed_ips = replace_allowed_ips.then_some(true);
self
}
pub fn allowed_ips(mut self, allowed_ips: Vec<AllowedIp>) -> Self {
self.allowed_ips = allowed_ips;
self
}
}
impl Display for Peer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{}={}", SetKey::PublicKey, hex::encode(self.public_key))?;
if let Some(remove) = self.remove {
writeln!(f, "{}={}", SetKey::Remove, remove)?;
}
if let Some(update_only) = self.update_only {
writeln!(f, "{}={}", SetKey::UpdateOnly, update_only)?;
}
if let Some(preshared_key) = self.preshared_key {
let preshared_key = hex::encode(preshared_key);
writeln!(f, "{}={}", SetKey::PresharedKey, preshared_key)?;
}
if let Some(endpoint) = self.endpoint {
writeln!(f, "{}={}", SetKey::Endpoint, endpoint)?;
}
if let Some(interval) = self.persistent_keepalive_interval {
writeln!(f, "{}={}", SetKey::PersistentKeepaliveInterval, interval)?;
}
if let Some(replace_allowed_ips) = self.replace_allowed_ips {
writeln!(f, "{}={}", SetKey::ReplaceAllowedIps, replace_allowed_ips)?;
}
for allowed_ip in &self.allowed_ips {
allowed_ip.fmt(f)?;
}
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AllowedIp {
pub ipaddr: IpAddr,
pub cidr_mask: u8,
}
impl Display for AllowedIp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(
f,
"{}={}/{}",
SetKey::AllowedIp,
self.ipaddr,
self.cidr_mask
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn serialize_website_example() {
let expected = "\
private_key=e84b5a6d2717c1003a13b431570353dbaca9146cf150c5f8575680feba52027a\n\
listen_port=12912\n\
fwmark=0\n\
replace_peers=true\n\
public_key=b85996fecc9c7f1fc6d2572a76eda11d59bcd20be8e543b15ce4bd85a8e75a33\n\
preshared_key=188515093e952f5f22e865cef3012e72f8b5f0b598ac0309d5dacce3b70fcf52\n\
endpoint=[abcd:23::33%2]:51820\n\
replace_allowed_ips=true\n\
allowed_ip=192.168.4.4/32\n\
public_key=58402e695ba1772b1cc9309755f043251ea77fdcf10fbe63989ceb7e19321376\n\
endpoint=182.122.22.19:3233\n\
persistent_keepalive_interval=111\n\
replace_allowed_ips=true\n\
allowed_ip=192.168.4.6/32\n\
public_key=662e14fd594556f522604703340351258903b64f35553763f19426ab2a515c58\n\
endpoint=5.152.198.39:51820\n\
replace_allowed_ips=true\n\
allowed_ip=192.168.4.10/32\n\
allowed_ip=192.168.4.11/32\n\
public_key=e818b58db5274087fcc1be5dc728cf53d3b5726b4cef6b9bab8f8f8c2452c25c\n\
remove=true\n";
let set_request = Device {
private_key: Some([
0xe8, 0x4b, 0x5a, 0x6d, 0x27, 0x17, 0xc1, 0x00, 0x3a, 0x13, 0xb4, 0x31, 0x57, 0x03,
0x53, 0xdb, 0xac, 0xa9, 0x14, 0x6c, 0xf1, 0x50, 0xc5, 0xf8, 0x57, 0x56, 0x80, 0xfe,
0xba, 0x52, 0x02, 0x7a,
]),
listen_port: Some(12912),
fwmark: Some(0),
replace_peers: Some(true),
peers: vec![
Peer::from_public_key([
0xb8, 0x59, 0x96, 0xfe, 0xcc, 0x9c, 0x7f, 0x1f, 0xc6, 0xd2, 0x57, 0x2a, 0x76,
0xed, 0xa1, 0x1d, 0x59, 0xbc, 0xd2, 0x0b, 0xe8, 0xe5, 0x43, 0xb1, 0x5c, 0xe4,
0xbd, 0x85, 0xa8, 0xe7, 0x5a, 0x33,
])
.preshared_key([
0x18, 0x85, 0x15, 0x09, 0x3e, 0x95, 0x2f, 0x5f, 0x22, 0xe8, 0x65, 0xce, 0xf3,
0x01, 0x2e, 0x72, 0xf8, 0xb5, 0xf0, 0xb5, 0x98, 0xac, 0x03, 0x09, 0xd5, 0xda,
0xcc, 0xe3, 0xb7, 0x0f, 0xcf, 0x52,
])
.replace_allowed_ips(true)
.allowed_ips(vec![AllowedIp {
ipaddr: "192.168.4.4".parse().unwrap(),
cidr_mask: 32,
}])
.endpoint("[abcd:23::33%2]:51820".parse().unwrap()),
Peer::from_public_key([
0x58, 0x40, 0x2e, 0x69, 0x5b, 0xa1, 0x77, 0x2b, 0x1c, 0xc9, 0x30, 0x97, 0x55,
0xf0, 0x43, 0x25, 0x1e, 0xa7, 0x7f, 0xdc, 0xf1, 0x0f, 0xbe, 0x63, 0x98, 0x9c,
0xeb, 0x7e, 0x19, 0x32, 0x13, 0x76,
])
.replace_allowed_ips(true)
.allowed_ips(vec![AllowedIp {
ipaddr: "192.168.4.6".parse().unwrap(),
cidr_mask: 32,
}])
.persistent_keepalive_interval(111)
.endpoint("182.122.22.19:3233".parse().unwrap()),
Peer::from_public_key([
0x66, 0x2e, 0x14, 0xfd, 0x59, 0x45, 0x56, 0xf5, 0x22, 0x60, 0x47, 0x03, 0x34,
0x03, 0x51, 0x25, 0x89, 0x03, 0xb6, 0x4f, 0x35, 0x55, 0x37, 0x63, 0xf1, 0x94,
0x26, 0xab, 0x2a, 0x51, 0x5c, 0x58,
])
.endpoint("5.152.198.39:51820".parse().unwrap())
.replace_allowed_ips(true)
.allowed_ips(vec![
AllowedIp {
ipaddr: "192.168.4.10".parse().unwrap(),
cidr_mask: 32,
},
AllowedIp {
ipaddr: "192.168.4.11".parse().unwrap(),
cidr_mask: 32,
},
]),
Peer::from_public_key([
0xe8, 0x18, 0xb5, 0x8d, 0xb5, 0x27, 0x40, 0x87, 0xfc, 0xc1, 0xbe, 0x5d, 0xc7,
0x28, 0xcf, 0x53, 0xd3, 0xb5, 0x72, 0x6b, 0x4c, 0xef, 0x6b, 0x9b, 0xab, 0x8f,
0x8f, 0x8c, 0x24, 0x52, 0xc2, 0x5c,
])
.remove(true),
],
};
let actual = format!("{set_request}");
assert_eq!(expected, actual);
}
#[test]
fn serialize_update_only() {
let expected = [
"private_key=e84b5a6d2717c1003a13b431570353dbaca9146cf150c5f8575680feba52027a",
"public_key=b85996fecc9c7f1fc6d2572a76eda11d59bcd20be8e543b15ce4bd85a8e75a33",
"update_only=true",
"endpoint=[abcd:23::33%2]:51820",
"replace_allowed_ips=true",
"allowed_ip=192.168.4.4/32",
"",
]
.join("\n");
let set_request = Device {
private_key: Some([
0xe8, 0x4b, 0x5a, 0x6d, 0x27, 0x17, 0xc1, 0x00, 0x3a, 0x13, 0xb4, 0x31, 0x57, 0x03,
0x53, 0xdb, 0xac, 0xa9, 0x14, 0x6c, 0xf1, 0x50, 0xc5, 0xf8, 0x57, 0x56, 0x80, 0xfe,
0xba, 0x52, 0x02, 0x7a,
]),
peers: vec![Peer::from_public_key([
0xb8, 0x59, 0x96, 0xfe, 0xcc, 0x9c, 0x7f, 0x1f, 0xc6, 0xd2, 0x57, 0x2a, 0x76, 0xed,
0xa1, 0x1d, 0x59, 0xbc, 0xd2, 0x0b, 0xe8, 0xe5, 0x43, 0xb1, 0x5c, 0xe4, 0xbd, 0x85,
0xa8, 0xe7, 0x5a, 0x33,
])
.update_only(true)
.replace_allowed_ips(true)
.allowed_ips(vec![AllowedIp {
ipaddr: "192.168.4.4".parse().unwrap(),
cidr_mask: 32,
}])
.endpoint("[abcd:23::33%2]:51820".parse().unwrap())],
..Default::default()
};
let actual = format!("{set_request}");
assert_eq!(expected, actual);
}
#[test]
fn cover_derives() {
let device1 = Device::default();
let device2 = Device::default();
assert_eq!(device1, device2);
let _ = format!("{device1:?}");
let peer1 = Peer::from_public_key([
0xb8, 0x59, 0x96, 0xfe, 0xcc, 0x9c, 0x7f, 0x1f, 0xc6, 0xd2, 0x57, 0x2a, 0x76, 0xed,
0xa1, 0x1d, 0x59, 0xbc, 0xd2, 0x0b, 0xe8, 0xe5, 0x43, 0xb1, 0x5c, 0xe4, 0xbd, 0x85,
0xa8, 0xe7, 0x5a, 0x33,
]);
let peer2 = Peer::from_public_key([
0xb8, 0x59, 0x96, 0xfe, 0xcc, 0x9c, 0x7f, 0x1f, 0xc6, 0xd2, 0x57, 0x2a, 0x76, 0xed,
0xa1, 0x1d, 0x59, 0xbc, 0xd2, 0x0b, 0xe8, 0xe5, 0x43, 0xb1, 0x5c, 0xe4, 0xbd, 0x85,
0xa8, 0xe7, 0x5a, 0x33,
]);
assert_eq!(peer1, peer2);
let _ = format!("{peer1:?}");
let allowed_ip1 = AllowedIp {
ipaddr: "::1".parse().unwrap(),
cidr_mask: 64,
};
let allowed_ip2 = AllowedIp {
ipaddr: "::1".parse().unwrap(),
cidr_mask: 64,
};
assert_eq!(allowed_ip1, allowed_ip2);
let _ = format!("{allowed_ip1:?}");
}
}