node: Parse IPv6 addresses in square brackets
This commit is contained in:
parent
7c92360842
commit
df8e4e6c88
|
|
@ -36,6 +36,12 @@ 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.
|
||||
- Parsing addresses involving an IPv6 host failed if they were enclosed in
|
||||
square brackets, e.g. in `rad node connect z6Mk...@[::1]:8776`.
|
||||
Also, ambiguous addresses would parse, e.g. `::1:8776` would be
|
||||
indistinguishable from `[::1]:8776`. Since a port number is always required
|
||||
along a host when providing an address, IPv6 addresses now always require
|
||||
brackets to avoid confusion.
|
||||
|
||||
## Deprecations
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ pub mod timestamp;
|
|||
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque};
|
||||
use std::io::{BufRead, BufReader};
|
||||
use std::marker::PhantomData;
|
||||
use std::net::IpAddr;
|
||||
use std::net::Ipv6Addr;
|
||||
use std::ops::{ControlFlow, Deref};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
|
|
@ -30,7 +32,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 +424,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 +492,31 @@ 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 {
|
||||
// Require IPv6 addresses to always be enclosed in `[` and `]`.
|
||||
host.parse().and_then(|host| match host {
|
||||
HostName::Ip(IpAddr::V6(_)) => Err(AddrParseError::UnknownAddressFormat),
|
||||
host => Ok(host),
|
||||
})?
|
||||
};
|
||||
|
||||
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()
|
||||
|
|
@ -1448,6 +1475,22 @@ mod test {
|
|||
assert!(Alias::from_str("cloudhead\n").is_err());
|
||||
}
|
||||
|
||||
#[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("[::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());
|
||||
assert!(Address::from_str("::1:8776").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_command_result() {
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
|
|
|
|||
Loading…
Reference in New Issue