1use derive_builder::Builder;
2use std::net::{IpAddr, SocketAddr};
3use std::str::FromStr;
4use std::time::Duration;
5
6#[derive(Builder, Debug, PartialEq, Eq)]
7pub struct Device {
8 pub ifindex: u32,
9 pub ifname: String,
10 #[builder(default)]
11 pub private_key: Option<[u8; 32]>,
12 #[builder(default)]
13 pub public_key: Option<[u8; 32]>,
14 pub listen_port: u16,
15 pub fwmark: u32,
16 #[builder(default)]
17 pub peers: Vec<Peer>,
18}
19
20#[derive(Builder, Clone, Debug, PartialEq, Eq)]
21pub struct Peer {
22 #[builder(field(public))]
25 pub public_key: [u8; 32],
26 pub preshared_key: [u8; 32],
27 #[builder(default)]
28 pub endpoint: Option<SocketAddr>,
29 pub persistent_keepalive_interval: u16,
30 pub last_handshake_time: Duration,
31 pub rx_bytes: u64,
32 pub tx_bytes: u64,
33 #[builder(default, field(public))]
34 pub allowed_ips: Vec<AllowedIp>,
35 pub protocol_version: u32,
36}
37
38#[derive(Builder, Clone, Debug, PartialEq, Eq)]
39pub struct AllowedIp {
40 pub family: u16,
41 pub ipaddr: IpAddr,
42 pub cidr_mask: u8,
43}
44
45#[derive(Debug, thiserror::Error, PartialEq, Eq)]
46pub enum ParseAllowedIpError {
47 #[error("String is missing CIDR mask: `${0}`")]
48 MissingCidrMask(String),
49 #[error(transparent)]
50 AddrParseError(#[from] std::net::AddrParseError),
51 #[error(transparent)]
52 InvalidCidrMask(#[from] std::num::ParseIntError),
53}
54
55impl FromStr for AllowedIp {
56 type Err = ParseAllowedIpError;
57
58 fn from_str(s: &str) -> Result<Self, Self::Err> {
59 let mut tokens = s.splitn(2, '/');
60
61 let ipaddr = tokens.next().unwrap().parse()?;
63 let cidr_mask = tokens
64 .next()
65 .filter(|s| !s.is_empty())
66 .ok_or_else(|| Self::Err::MissingCidrMask(s.to_string()))?
67 .parse()?;
68
69 Ok(AllowedIp {
70 family: match ipaddr {
71 IpAddr::V4(_) => 2, IpAddr::V6(_) => 10, },
76 ipaddr,
77 cidr_mask,
78 })
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85 use std::net::Ipv4Addr;
86 use std::net::Ipv6Addr;
87
88 #[test]
89 fn parse_invalid_allowed_ip() {
90 assert!(matches!(
91 "".parse::<AllowedIp>(),
92 Err(ParseAllowedIpError::AddrParseError(_))
93 ));
94
95 assert!(matches!(
96 "10.24.24.3".parse::<AllowedIp>(),
97 Err(ParseAllowedIpError::MissingCidrMask(_))
98 ));
99
100 assert!(matches!(
101 "10.24.24.3/".parse::<AllowedIp>(),
102 Err(ParseAllowedIpError::MissingCidrMask(_))
103 ));
104
105 assert!(matches!(
106 "10.24.24.3/a".parse::<AllowedIp>(),
107 Err(ParseAllowedIpError::InvalidCidrMask(_))
108 ));
109 }
110
111 #[test]
112 fn parse_allowed_ip_ipv4() {
113 let actual = "10.24.24.3/32".parse();
114 let expected = Ok(AllowedIp {
115 family: 2,
116 ipaddr: IpAddr::V4(Ipv4Addr::new(10, 24, 24, 3)),
117 cidr_mask: 32,
118 });
119 assert_eq!(actual, expected);
120 }
121
122 #[test]
123 fn parse_allowed_ip_ipv6() {
124 let actual = "::1/128".parse();
125 let expected = Ok(AllowedIp {
126 family: 10,
127 ipaddr: IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)),
128 cidr_mask: 128,
129 });
130 assert_eq!(actual, expected);
131 }
132}