ntp_daemon/config/
subnet.rs1use serde::{de, Deserialize, Deserializer};
2use std::net::{AddrParseError, IpAddr};
3use thiserror::Error;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub struct IpSubnet {
7 pub addr: IpAddr,
8 pub mask: u8,
9}
10
11#[derive(Debug, Clone, PartialEq, Eq, Error)]
12pub enum SubnetParseError {
13 #[error("Invalid subnet syntax")]
14 InvalidSubnet,
15 #[error("{0} in subnet")]
16 InvalidIp(#[from] AddrParseError),
17 #[error("Invalid subnet mask")]
18 InvalidMask,
19}
20
21impl std::str::FromStr for IpSubnet {
22 type Err = SubnetParseError;
23
24 fn from_str(s: &str) -> Result<Self, Self::Err> {
25 let (addr, mask) = s.split_once('/').ok_or(SubnetParseError::InvalidSubnet)?;
26 let addr: IpAddr = addr.parse()?;
27 let mask: u8 = mask.parse().map_err(|_| SubnetParseError::InvalidMask)?;
28 let max_mask = match addr {
29 IpAddr::V4(_) => 32,
30 IpAddr::V6(_) => 128,
31 };
32 if mask > max_mask {
33 return Err(SubnetParseError::InvalidMask);
34 }
35 Ok(IpSubnet { addr, mask })
36 }
37}
38
39impl<'de> Deserialize<'de> for IpSubnet {
40 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
41 where
42 D: Deserializer<'de>,
43 {
44 let s = String::deserialize(deserializer)?;
45 std::str::FromStr::from_str(&s).map_err(de::Error::custom)
46 }
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 #[test]
54 fn test_subnet_parsing() {
55 let a = "0.0.0.0/0".parse::<IpSubnet>().unwrap();
56 assert_eq!(a.mask, 0);
57 }
58}