#![recursion_limit = "256"]
#![deny(
non_upper_case_globals,
non_camel_case_types,
non_snake_case,
unused_mut,
unused_imports,
dead_code,
missing_docs
)]
#[allow(unused_imports)]
#[macro_use]
extern crate amplify;
#[macro_use]
extern crate amplify_derive;
#[cfg(feature = "stringly_conversions")]
#[macro_use]
extern crate stringly_conversions;
#[cfg(feature = "strict_encoding")]
extern crate strict_encoding;
#[cfg(feature = "serde")]
#[macro_use]
extern crate serde_crate as serde;
#[cfg(feature = "strict_encoding")]
mod encoding;
use std::cmp::Ordering;
use std::convert::TryFrom;
use std::fmt;
use std::net::{
IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6,
};
use std::num::ParseIntError;
use std::str::FromStr;
#[cfg(feature = "tor")]
use torut::onion::{OnionAddressV2, OnionAddressV3, TorPublicKeyV3};
#[derive(
Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display, Error,
)]
#[display(doc_comments)]
pub struct NoOnionSupportError;
#[derive(
Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display, Error, From,
)]
#[display(doc_comments)]
pub enum AddrParseError {
#[from(ParseIntError)]
WrongPortNumber,
WrongAddrFormat(String),
WrongSocketFormat(String),
WrongSocketExtFormat(String),
UnknownProtocolError(String),
NeedsTorFeature,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(
all(feature = "serde", feature = "serde_str_helpers"),
derive(Serialize, Deserialize),
serde(
try_from = "serde_str_helpers::DeserBorrowStr",
into = "String",
crate = "serde_crate"
)
)]
#[cfg_attr(
all(feature = "serde", not(feature = "serde_str_helpers")),
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
)]
#[non_exhaustive]
pub enum InetAddr {
IPv4(Ipv4Addr),
IPv6(Ipv6Addr),
#[cfg(feature = "tor")]
TorV2(OnionAddressV2),
#[cfg(feature = "tor")]
Tor(TorPublicKeyV3),
}
impl PartialOrd for InetAddr {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (self, other) {
(InetAddr::IPv4(addr1), InetAddr::IPv4(addr2)) => {
addr1.partial_cmp(addr2)
}
(InetAddr::IPv6(addr1), InetAddr::IPv6(addr2)) => {
addr1.partial_cmp(addr2)
}
#[cfg(feature = "tor")]
(InetAddr::TorV2(addr1), InetAddr::TorV2(addr2)) => {
addr1.get_raw_bytes().partial_cmp(&addr2.get_raw_bytes())
}
#[cfg(feature = "tor")]
(InetAddr::Tor(addr1), InetAddr::Tor(addr2)) => {
addr1.partial_cmp(addr2)
}
(InetAddr::IPv4(_), _) => Some(Ordering::Greater),
(_, InetAddr::IPv4(_)) => Some(Ordering::Less),
#[cfg(feature = "tor")]
(InetAddr::IPv6(_), _) => Some(Ordering::Greater),
#[cfg(feature = "tor")]
(_, InetAddr::IPv6(_)) => Some(Ordering::Less),
#[cfg(feature = "tor")]
(InetAddr::TorV2(_), _) => Some(Ordering::Greater),
#[cfg(feature = "tor")]
(_, InetAddr::TorV2(_)) => Some(Ordering::Less),
}
}
}
impl Ord for InetAddr {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).unwrap_or(Ordering::Equal)
}
}
impl std::hash::Hash for InetAddr {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
state.write(self.to_string().as_bytes())
}
}
impl InetAddr {
#[inline]
pub fn to_ipv6(&self) -> Option<Ipv6Addr> {
match self {
InetAddr::IPv4(ipv4_addr) => Some(ipv4_addr.to_ipv6_mapped()),
InetAddr::IPv6(ipv6_addr) => Some(*ipv6_addr),
#[cfg(feature = "tor")]
_ => None,
}
}
#[inline]
pub fn to_ipv4(&self) -> Option<Ipv6Addr> {
match self {
InetAddr::IPv4(ipv4_addr) => Some(ipv4_addr.to_ipv6_mapped()),
InetAddr::IPv6(ipv6_addr) => Some(*ipv6_addr),
#[cfg(feature = "tor")]
_ => None,
}
}
#[cfg(not(feature = "tor"))]
#[inline]
pub fn is_tor(&self) -> bool {
false
}
#[cfg(not(feature = "tor"))]
#[inline]
pub fn to_onion_v2(&self) -> Option<()> {
None
}
#[cfg(not(feature = "tor"))]
#[inline]
pub fn to_onion(&self) -> Option<()> {
None
}
#[cfg(feature = "tor")]
#[inline]
pub fn is_tor(&self) -> bool {
match self {
InetAddr::Tor(_) => true,
InetAddr::TorV2(_) => true,
_ => false,
}
}
#[cfg(feature = "tor")]
#[inline]
pub fn to_onion_v2(&self) -> Option<OnionAddressV2> {
match self {
InetAddr::IPv4(_) | InetAddr::IPv6(_) | InetAddr::Tor(_) => None,
InetAddr::TorV2(onion) => Some(*onion),
}
}
#[cfg(feature = "tor")]
#[inline]
pub fn to_onion(&self) -> Option<OnionAddressV3> {
match self {
InetAddr::IPv4(_) | InetAddr::IPv6(_) | InetAddr::TorV2(_) => None,
InetAddr::Tor(key) => Some(OnionAddressV3::from(key)),
}
}
}
impl Default for InetAddr {
#[inline]
fn default() -> Self {
InetAddr::IPv4(Ipv4Addr::from(0))
}
}
impl fmt::Display for InetAddr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
InetAddr::IPv4(addr) => write!(f, "{}", addr),
InetAddr::IPv6(addr) => write!(f, "{}", addr),
#[cfg(feature = "tor")]
InetAddr::Tor(addr) => write!(f, "{}", addr),
#[cfg(feature = "tor")]
InetAddr::TorV2(addr) => write!(f, "{}", addr),
}
}
}
#[cfg(feature = "tor")]
impl TryFrom<InetAddr> for IpAddr {
type Error = NoOnionSupportError;
#[inline]
fn try_from(addr: InetAddr) -> Result<Self, Self::Error> {
Ok(match addr {
InetAddr::IPv4(addr) => IpAddr::V4(addr),
InetAddr::IPv6(addr) => IpAddr::V6(addr),
#[cfg(feature = "tor")]
InetAddr::Tor(_) => Err(NoOnionSupportError)?,
#[cfg(feature = "tor")]
InetAddr::TorV2(_) => Err(NoOnionSupportError)?,
})
}
}
#[cfg(not(feature = "tor"))]
impl From<InetAddr> for IpAddr {
#[inline]
fn from(addr: InetAddr) -> Self {
match addr {
InetAddr::IPv4(addr) => IpAddr::V4(addr),
InetAddr::IPv6(addr) => IpAddr::V6(addr),
}
}
}
impl From<IpAddr> for InetAddr {
#[inline]
fn from(value: IpAddr) -> Self {
match value {
IpAddr::V4(v4) => InetAddr::from(v4),
IpAddr::V6(v6) => InetAddr::from(v6),
}
}
}
impl From<Ipv4Addr> for InetAddr {
#[inline]
fn from(addr: Ipv4Addr) -> Self {
InetAddr::IPv4(addr)
}
}
impl From<Ipv6Addr> for InetAddr {
#[inline]
fn from(addr: Ipv6Addr) -> Self {
InetAddr::IPv6(addr)
}
}
#[cfg(feature = "tor")]
impl From<TorPublicKeyV3> for InetAddr {
#[inline]
fn from(value: TorPublicKeyV3) -> Self {
InetAddr::Tor(value)
}
}
#[cfg(feature = "tor")]
impl From<OnionAddressV3> for InetAddr {
#[inline]
fn from(addr: OnionAddressV3) -> Self {
InetAddr::Tor(addr.get_public_key())
}
}
#[cfg(feature = "tor")]
impl From<OnionAddressV2> for InetAddr {
#[inline]
fn from(addr: OnionAddressV2) -> Self {
InetAddr::TorV2(addr)
}
}
#[cfg(feature = "stringly_conversions")]
impl_try_from_stringly_standard!(InetAddr);
#[cfg(feature = "stringly_conversions")]
impl_into_stringly_standard!(InetAddr);
impl FromStr for InetAddr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
#[cfg(feature = "tor")]
match (
IpAddr::from_str(s),
OnionAddressV3::from_str(s),
OnionAddressV2::from_str(s),
) {
(Ok(_), Ok(_), _) | (Ok(_), _, Ok(_)) | (_, Ok(_), Ok(_)) => {
Err(AddrParseError::WrongAddrFormat(s.to_owned()))
}
(Ok(ip_addr), _, _) => Ok(Self::from(ip_addr)),
(_, Ok(onionv3), _) => Ok(Self::from(onionv3)),
(_, _, Ok(onionv2)) => Ok(Self::from(onionv2)),
_ => Err(AddrParseError::WrongAddrFormat(s.to_owned())),
}
#[cfg(not(feature = "tor"))]
match IpAddr::from_str(s) {
Ok(ip_addr) => Ok(InetAddr::from(ip_addr)),
_ => Err(AddrParseError::NeedsTorFeature),
}
}
}
#[cfg(feature = "parse_arg")]
impl parse_arg::ParseArgFromStr for InetAddr {
fn describe_type<W: std::fmt::Write>(mut writer: W) -> std::fmt::Result {
#[cfg(not(feature = "tor"))]
{
write!(writer, "IPv4 or IPv6 address")
}
#[cfg(feature = "tor")]
{
write!(writer, "IPv4, IPv6, or Tor (onion) address")
}
}
}
impl From<[u8; 4]> for InetAddr {
#[inline]
fn from(value: [u8; 4]) -> Self {
InetAddr::from(Ipv4Addr::from(value))
}
}
impl From<[u8; 16]> for InetAddr {
#[inline]
fn from(value: [u8; 16]) -> Self {
InetAddr::from(Ipv6Addr::from(value))
}
}
impl From<[u16; 8]> for InetAddr {
#[inline]
fn from(value: [u16; 8]) -> Self {
InetAddr::from(Ipv6Addr::from(value))
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate", rename = "lowercase")
)]
#[non_exhaustive]
#[repr(u8)]
pub enum Transport {
#[display("tcp")]
Tcp = 1,
#[display("udp")]
Udp = 2,
#[display("mtcp")]
Mtcp = 3,
#[display("quic")]
Quic = 4,
}
impl Default for Transport {
#[inline]
fn default() -> Self {
Transport::Tcp
}
}
impl FromStr for Transport {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s.to_lowercase().as_str() {
"tcp" => Transport::Tcp,
"udp" => Transport::Udp,
"mtcp" => Transport::Mtcp,
"quic" => Transport::Quic,
_ => Err(AddrParseError::UnknownProtocolError(s.to_owned()))?,
})
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[cfg_attr(
all(feature = "serde", feature = "serde_str_helpers"),
derive(Serialize, Deserialize),
serde(
try_from = "serde_str_helpers::DeserBorrowStr",
into = "String",
crate = "serde_crate"
)
)]
#[cfg_attr(
all(feature = "serde", not(feature = "serde_str_helpers")),
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
)]
pub struct InetSocketAddr {
pub address: InetAddr,
pub port: u16,
}
#[cfg(feature = "stringly_conversions")]
impl_try_from_stringly_standard!(InetSocketAddr);
#[cfg(feature = "stringly_conversions")]
impl_into_stringly_standard!(InetSocketAddr);
impl InetSocketAddr {
#[inline]
pub fn new(address: InetAddr, port: u16) -> Self {
Self { address, port }
}
#[inline]
pub fn is_tor(&self) -> bool {
self.address.is_tor()
}
}
impl fmt::Display for InetSocketAddr {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}", self.address, self.port)
}
}
impl FromStr for InetSocketAddr {
type Err = AddrParseError;
#[allow(unreachable_code)]
fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Ok(socket_addr) = SocketAddrV6::from_str(s) {
return Ok(Self::new(
(*socket_addr.ip()).into(),
socket_addr.port(),
));
} else if let Ok(socket_addr) = SocketAddrV4::from_str(s) {
return Ok(Self::new(
(*socket_addr.ip()).into(),
socket_addr.port(),
));
} else {
#[cfg(not(feature = "tor"))]
return Err(AddrParseError::NeedsTorFeature);
}
let mut vals = s.split(':');
match (vals.next(), vals.next(), vals.next()) {
(Some(addr), Some(port), None) => Ok(Self {
address: addr.parse()?,
port: u16::from_str(port)?,
}),
(Some(addr), None, _) => Ok(Self {
address: addr.parse()?,
port: 0,
}),
_ => Err(AddrParseError::WrongSocketFormat(s.to_owned())),
}
}
}
#[cfg(feature = "tor")]
impl TryFrom<InetSocketAddr> for SocketAddr {
type Error = NoOnionSupportError;
#[inline]
fn try_from(socket_addr: InetSocketAddr) -> Result<Self, Self::Error> {
Ok(Self::new(
IpAddr::try_from(socket_addr.address)?,
socket_addr.port,
))
}
}
#[cfg(not(feature = "tor"))]
impl From<InetSocketAddr> for SocketAddr {
#[inline]
fn from(socket_addr: InetSocketAddr) -> Self {
Self::new(IpAddr::from(socket_addr.address), socket_addr.port)
}
}
impl From<SocketAddr> for InetSocketAddr {
#[inline]
fn from(addr: SocketAddr) -> Self {
Self::new(addr.ip().into(), addr.port())
}
}
impl From<SocketAddrV4> for InetSocketAddr {
#[inline]
fn from(addr: SocketAddrV4) -> Self {
Self::new((*addr.ip()).into(), addr.port())
}
}
impl From<SocketAddrV6> for InetSocketAddr {
#[inline]
fn from(addr: SocketAddrV6) -> Self {
Self::new((*addr.ip()).into(), addr.port())
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[cfg_attr(
all(feature = "serde", feature = "serde_str_helpers"),
derive(Serialize, Deserialize),
serde(
try_from = "serde_str_helpers::DeserBorrowStr",
into = "String",
crate = "serde_crate"
)
)]
#[cfg_attr(
all(feature = "serde", not(feature = "serde_str_helpers")),
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
)]
pub struct InetSocketAddrExt(
pub Transport,
pub InetSocketAddr,
);
#[cfg(feature = "stringly_conversions")]
impl_try_from_stringly_standard!(InetSocketAddrExt);
#[cfg(feature = "stringly_conversions")]
impl_into_stringly_standard!(InetSocketAddrExt);
impl InetSocketAddrExt {
#[inline]
pub fn tcp(address: InetAddr, port: u16) -> Self {
Self(Transport::Tcp, InetSocketAddr::new(address, port))
}
#[inline]
pub fn udp(address: InetAddr, port: u16) -> Self {
Self(Transport::Udp, InetSocketAddr::new(address, port))
}
}
impl fmt::Display for InetSocketAddrExt {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}://{}", self.0, self.1)
}
}
impl FromStr for InetSocketAddrExt {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut vals = s.split("://");
if let (Some(transport), Some(addr), None) =
(vals.next(), vals.next(), vals.next())
{
Ok(Self(transport.parse()?, addr.parse()?))
} else {
Err(AddrParseError::WrongSocketExtFormat(s.to_owned()))
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_inet_addr() {
let ip4a = "127.0.0.1".parse().unwrap();
let ip6a = "::1".parse().unwrap();
let ip4 = InetAddr::IPv4(ip4a);
let ip6 = InetAddr::IPv6(ip6a);
assert_eq!(
ip4.to_ipv6().unwrap(),
Ipv6Addr::from_str("::ffff:127.0.0.1").unwrap()
);
assert_eq!(ip6.to_ipv6().unwrap(), ip6a);
assert_eq!(InetAddr::from(IpAddr::V4(ip4a)), ip4);
assert_eq!(InetAddr::from(IpAddr::V6(ip6a)), ip6);
assert_eq!(InetAddr::from(ip4a), ip4);
assert_eq!(InetAddr::from(ip6a), ip6);
assert_eq!(InetAddr::default(), InetAddr::from_str("0.0.0.0").unwrap());
#[cfg(feature = "tor")]
assert_eq!(IpAddr::try_from(ip4.clone()).unwrap(), IpAddr::V4(ip4a));
#[cfg(feature = "tor")]
assert_eq!(IpAddr::try_from(ip6.clone()).unwrap(), IpAddr::V6(ip6a));
#[cfg(not(feature = "tor"))]
assert_eq!(IpAddr::from(ip4.clone()), IpAddr::V4(ip4a));
#[cfg(not(feature = "tor"))]
assert_eq!(IpAddr::from(ip6.clone()), IpAddr::V6(ip6a));
assert_eq!(InetAddr::from_str("127.0.0.1").unwrap(), ip4);
assert_eq!(InetAddr::from_str("::1").unwrap(), ip6);
assert_eq!(format!("{}", ip4), "127.0.0.1");
assert_eq!(format!("{}", ip6), "::1");
assert!(!ip4.is_tor());
assert!(!ip6.is_tor());
}
#[test]
fn test_transport() {
assert_eq!(format!("{}", Transport::Tcp), "tcp");
assert_eq!(format!("{}", Transport::Udp), "udp");
assert_eq!(format!("{}", Transport::Quic), "quic");
assert_eq!(format!("{}", Transport::Mtcp), "mtcp");
assert_eq!(Transport::from_str("tcp").unwrap(), Transport::Tcp);
assert_eq!(Transport::from_str("Tcp").unwrap(), Transport::Tcp);
assert_eq!(Transport::from_str("TCP").unwrap(), Transport::Tcp);
assert_eq!(Transport::from_str("udp").unwrap(), Transport::Udp);
assert_eq!(Transport::from_str("quic").unwrap(), Transport::Quic);
assert_eq!(Transport::from_str("mtcp").unwrap(), Transport::Mtcp);
assert!(Transport::from_str("xtp").is_err());
}
#[test]
fn test_inet_socket_addr() {
let ip4a = "127.0.0.1".parse().unwrap();
let ip6a = "::1".parse().unwrap();
let socket4a = "127.0.0.1:6865".parse().unwrap();
let socket6a = "[::1]:6865".parse().unwrap();
let ip4 = InetSocketAddr::new(ip4a, 6865);
let ip6 = InetSocketAddr::new(ip6a, 6865);
assert_eq!(InetSocketAddr::from(SocketAddr::V4(socket4a)), ip4);
assert_eq!(InetSocketAddr::from(SocketAddr::V6(socket6a)), ip6);
assert_eq!(InetSocketAddr::from(socket4a), ip4);
assert_eq!(InetSocketAddr::from(socket6a), ip6);
assert_eq!(
InetSocketAddr::default(),
InetSocketAddr::from_str("0.0.0.0:0").unwrap()
);
#[cfg(feature = "tor")]
assert_eq!(
SocketAddr::try_from(ip4.clone()).unwrap(),
SocketAddr::V4(socket4a)
);
#[cfg(feature = "tor")]
assert_eq!(
SocketAddr::try_from(ip6.clone()).unwrap(),
SocketAddr::V6(socket6a)
);
#[cfg(not(feature = "tor"))]
assert_eq!(SocketAddr::from(ip4.clone()), SocketAddr::V4(socket4a));
#[cfg(not(feature = "tor"))]
assert_eq!(SocketAddr::from(ip6.clone()), SocketAddr::V6(socket6a));
assert_eq!(InetSocketAddr::from_str("127.0.0.1:6865").unwrap(), ip4);
assert_eq!(InetSocketAddr::from_str("[::1]:6865").unwrap(), ip6);
assert_eq!(format!("{}", ip4), "127.0.0.1:6865");
assert_eq!(format!("{}", ip6), "::1:6865");
assert!(!ip4.is_tor());
assert!(!ip6.is_tor());
}
#[test]
fn test_inet_socket_addr_ext() {
let ip4a = "127.0.0.1".parse().unwrap();
let ip6a = "::1".parse().unwrap();
let ip4 = InetSocketAddrExt::tcp(ip4a, 6865);
let ip6 = InetSocketAddrExt::udp(ip6a, 6865);
assert_eq!(
InetSocketAddrExt::default(),
InetSocketAddrExt::from_str("tcp://0.0.0.0:0").unwrap()
);
#[cfg(feature = "tor")]
assert_eq!(
InetSocketAddrExt::from_str("tcp://127.0.0.1:6865").unwrap(),
ip4
);
#[cfg(feature = "tor")]
assert_eq!(
InetSocketAddrExt::from_str("udp://[::1]:6865").unwrap(),
ip6
);
assert_eq!(format!("{}", ip4), "tcp://127.0.0.1:6865");
assert_eq!(format!("{}", ip6), "udp://::1:6865");
}
}