Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
node: parse ipv6 addresses in square brackets correctly
Defelo committed 2 months ago
commit 120d004138a90f326de3d4615a45aad0adb9e902
parent e9245b630d728672d2b3d6ff9265fa4f1a86f13a
2 files changed +43 -2
modified CHANGELOG.md
@@ -36,6 +36,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
  This would result in timeouts when commands are run from the `rad` CLI.
  The `Service` has now learned to return results when an error occurs which
  will be reported back to the user.
+
- The parsing of IPv6 addresses failed if they were enclosed in square brackets
+
  (e.g. in `rad node connect z6Mk...@[::1]:8776`). This has been fixed so that
+
  IPv6 addresses are parsed correctly both with and without square brackets.

## Deprecations

modified crates/radicle/src/node.rs
@@ -19,6 +19,7 @@ pub mod timestamp;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque};
use std::io::{BufRead, BufReader};
use std::marker::PhantomData;
+
use std::net::Ipv6Addr;
use std::ops::{ControlFlow, Deref};
use std::path::{Path, PathBuf};
use std::str::FromStr;
@@ -30,7 +31,7 @@ use std::os::unix::net::UnixStream;
use uds_windows::UnixStream;

use amplify::WrapperMut;
-
use cyphernet::addr::NetAddr;
+
use cyphernet::addr::{AddrParseError, NetAddr};
use localtime::{LocalDuration, LocalTime};
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
@@ -422,7 +423,7 @@ impl TryFrom<&sqlite::Value> for Alias {

/// Peer public protocol address.
#[derive(Clone, Eq, PartialEq, Debug, Hash, From, Wrapper, WrapperMut, Serialize, Deserialize)]
-
#[wrapper(Deref, Display, FromStr)]
+
#[wrapper(Deref, Display)]
#[wrapper_mut(DerefMut)]
#[cfg_attr(
    feature = "schemars",
@@ -490,6 +491,27 @@ impl Address {
    }
}

+
impl FromStr for Address {
+
    type Err = AddrParseError;
+

+
    fn from_str(s: &str) -> Result<Self, Self::Err> {
+
        let (host, port) = s.rsplit_once(':').ok_or(AddrParseError::PortAbsent)?;
+

+
        let host = if let Some(host) = host
+
            .strip_prefix('[')
+
            .and_then(|host| host.strip_suffix(']'))
+
        {
+
            HostName::Ip(host.parse::<Ipv6Addr>()?.into())
+
        } else {
+
            host.parse()?
+
        };
+

+
        let port = port.parse().map_err(|_| AddrParseError::InvalidPort)?;
+

+
        Ok(Self(NetAddr::new(host, port)))
+
    }
+
}
+

impl cyphernet::addr::Host for Address {
    fn requires_proxy(&self) -> bool {
        self.0.requires_proxy()
@@ -1449,6 +1471,22 @@ mod test {
    }

    #[test]
+
    fn test_address() {
+
        assert!(Address::from_str("127.0.0.1:8776").is_ok());
+
        assert!(Address::from_str("::1:8776").is_ok());
+
        assert!(Address::from_str("[::1]:8776").is_ok());
+
        assert!(Address::from_str("[::ffff:127.0.0.1]:8776").is_ok());
+
        assert!(Address::from_str("localhost:8776").is_ok());
+

+
        assert!(Address::from_str("").is_err());
+
        assert!(Address::from_str(":").is_err());
+
        assert!(Address::from_str("127.0.0.1").is_err());
+
        assert!(Address::from_str("127.0.0.1:xyz").is_err());
+
        assert!(Address::from_str("[invalid]:8776").is_err());
+
        assert!(Address::from_str("[127.0.0.1]:8776").is_err());
+
    }
+

+
    #[test]
    fn test_command_result() {
        #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
        struct Test {