From 172076eaad10830a97f75540fd63092512347bd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jalil=20David=20Salam=C3=A9=20Messina?= Date: Wed, 5 Feb 2025 23:13:32 +0100 Subject: [PATCH] feat(webnsupdate): parse IPv6 prefixes This allows us to better support IPv6 from fritzbox updates in the future. --- src/main.rs | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7718175..cf37707 100644 --- a/src/main.rs +++ b/src/main.rs @@ -285,6 +285,37 @@ fn load_ip(path: &Path) -> Result> { .map(Some) } +#[derive(Clone, Copy, Debug)] +struct Ipv6Prefix { + prefix: Ipv6Addr, + length: u32, +} + +impl std::fmt::Display for Ipv6Prefix { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { prefix, length } = self; + write!(f, "{prefix}/{length}") + } +} + +impl std::str::FromStr for Ipv6Prefix { + type Err = miette::Error; + + fn from_str(s: &str) -> std::result::Result { + let (addr, len) = s.split_once('/').wrap_err("missing `/` in ipv6 prefix")?; + Ok(Self { + prefix: addr + .parse() + .into_diagnostic() + .wrap_err("invalid ipv6 address for ipv6 prefix")?, + length: len + .parse() + .into_diagnostic() + .wrap_err("invalid length for ipv6 prefix")?, + }) + } +} + #[tracing::instrument(err)] fn main() -> Result<()> { // set panic hook to pretty print with miette's formatter @@ -437,7 +468,7 @@ where struct FritzBoxUpdateParams { /// The domain that should be updated #[allow(unused)] - #[serde(default)] + #[serde(default, deserialize_with = "empty_string_as_none")] domain: Option, /// IPv4 address for the domain #[serde(default, deserialize_with = "empty_string_as_none")] @@ -447,11 +478,11 @@ struct FritzBoxUpdateParams { ipv6: Option, /// IPv6 prefix for the home network #[allow(unused)] - #[serde(default)] - ipv6prefix: Option, + #[serde(default, deserialize_with = "empty_string_as_none")] + ipv6prefix: Option, /// Whether the networks uses both IPv4 and IPv6 #[allow(unused)] - #[serde(default)] + #[serde(default, deserialize_with = "empty_string_as_none")] dualstack: Option, }