use std::{
convert::TryFrom,
fmt,
io::{self, Cursor, Read, Write},
net::{
AddrParseError, IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr as StdSocketAddr, SocketAddrV4,
SocketAddrV6,
},
num::ParseIntError,
str::FromStr,
};
use koibumi_base32 as base32;
#[cfg(feature = "koibumi-socks")]
use koibumi_socks::{Addr as SocksAddr, DomainName, SocketAddr as SocksSocketAddr};
use crate::{
hash::sha3_256,
io::{ReadFrom, WriteTo},
};
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct OnionV2Addr {
bytes: [u8; 10],
}
impl OnionV2Addr {
const STR_LEN: usize = 22;
pub fn new(bytes: [u8; 10]) -> Self {
Self { bytes }
}
}
impl fmt::Display for OnionV2Addr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut s = base32::encode(self.bytes).unwrap();
s.push_str(".onion");
s.fmt(f)
}
}
impl AsRef<[u8]> for OnionV2Addr {
fn as_ref(&self) -> &[u8] {
&self.bytes
}
}
impl From<[u8; 10]> for OnionV2Addr {
fn from(bytes: [u8; 10]) -> Self {
Self { bytes }
}
}
#[cfg(feature = "koibumi-socks")]
impl From<OnionV2Addr> for DomainName {
fn from(addr: OnionV2Addr) -> Self {
addr.to_string().parse().unwrap()
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum ParseOnionV2AddrError {
InvalidLength { expected: usize, actual: usize },
InvalidTld,
InvalidEncoding(base32::DecodeError),
}
impl fmt::Display for ParseOnionV2AddrError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidLength { expected, actual } => {
write!(f, "length should be {}, but {}", expected, actual)
}
Self::InvalidTld => write!(f, "Onion address must end with \".onion\""),
Self::InvalidEncoding(err) => err.fmt(f),
}
}
}
impl std::error::Error for ParseOnionV2AddrError {}
impl FromStr for OnionV2Addr {
type Err = ParseOnionV2AddrError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.as_bytes().len() != Self::STR_LEN {
return Err(Self::Err::InvalidLength {
expected: Self::STR_LEN,
actual: s.as_bytes().len(),
});
}
if !s.ends_with(".onion") {
return Err(Self::Err::InvalidTld);
}
let body = String::from_utf8(s.as_bytes()[0..16].to_vec()).unwrap();
match base32::decode(&body) {
Ok(b) => {
let mut bytes = [0; 10];
bytes.copy_from_slice(&b);
Ok(Self { bytes })
}
Err(err) => Err(Self::Err::InvalidEncoding(err)),
}
}
}
#[test]
fn test_onion_v2_addr_parse() {
let test: OnionV2Addr = "aerukz4jvpg677w4.onion".parse().unwrap();
let expected = OnionV2Addr::new([0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc]);
assert_eq!(test, expected);
}
#[test]
fn test_onion_v2_addr_to_string() {
let test =
&OnionV2Addr::new([0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc]).to_string();
let expected = "aerukz4jvpg677w4.onion";
assert_eq!(test, expected);
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct OnionV3Addr {
bytes: Vec<u8>,
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum ParseOnionV3AddrError {
InvalidLength { expected: usize, actual: usize },
InvalidTld,
InvalidEncoding(base32::DecodeError),
InvalidChecksum { expected: [u8; 2], actual: [u8; 2] },
InvalidVersion(u8),
}
impl fmt::Display for ParseOnionV3AddrError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidLength { expected, actual } => {
write!(f, "length should be {}, but {}", expected, actual)
}
Self::InvalidTld => write!(f, "Onion address must end with \".onion\""),
Self::InvalidEncoding(err) => err.fmt(f),
Self::InvalidChecksum { expected, actual } => write!(
f,
"checksum should be {:#02x}{:02x}, but {:#02x}{:02x}",
expected[0], expected[1], actual[0], actual[1]
),
Self::InvalidVersion(version) => {
write!(f, "version must be 0x03, but {:#02x}", version)
}
}
}
}
impl std::error::Error for ParseOnionV3AddrError {}
impl OnionV3Addr {
const STR_LEN: usize = 62;
pub fn new(bytes: [u8; 35]) -> Result<Self, ParseOnionV3AddrError> {
let addr = Self {
bytes: bytes.to_vec(),
};
addr.validate()?;
Ok(addr)
}
fn validate(&self) -> Result<(), ParseOnionV3AddrError> {
let pubkey = &self.bytes[0..32];
let checksum = &self.bytes[32..34];
let version = self.bytes[34];
let mut bytes = Vec::with_capacity(15 + 32 + 1);
bytes.extend_from_slice(b".onion checksum");
bytes.extend_from_slice(pubkey);
bytes.push(version);
let mut c = [0; 2];
c.copy_from_slice(&sha3_256(&bytes)[0..2]);
if c != checksum {
let mut expected = [0; 2];
expected.copy_from_slice(checksum);
return Err(ParseOnionV3AddrError::InvalidChecksum {
expected,
actual: c,
});
}
if version != 0x03 {
return Err(ParseOnionV3AddrError::InvalidVersion(version));
}
Ok(())
}
}
impl fmt::Display for OnionV3Addr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut s = base32::encode(&self.bytes).unwrap();
s.push_str(".onion");
s.fmt(f)
}
}
impl AsRef<[u8]> for OnionV3Addr {
fn as_ref(&self) -> &[u8] {
&self.bytes
}
}
impl From<[u8; 35]> for OnionV3Addr {
fn from(bytes: [u8; 35]) -> Self {
Self {
bytes: bytes.to_vec(),
}
}
}
#[cfg(feature = "koibumi-socks")]
impl From<OnionV3Addr> for DomainName {
fn from(addr: OnionV3Addr) -> Self {
addr.to_string().parse().unwrap()
}
}
impl FromStr for OnionV3Addr {
type Err = ParseOnionV3AddrError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.as_bytes().len() != Self::STR_LEN {
return Err(Self::Err::InvalidLength {
expected: Self::STR_LEN,
actual: s.as_bytes().len(),
});
}
if !s.ends_with(".onion") {
return Err(Self::Err::InvalidTld);
}
let body = String::from_utf8(s.as_bytes()[0..56].to_vec()).unwrap();
match base32::decode(&body) {
Ok(b) => {
let mut bytes = [0; 35];
bytes.copy_from_slice(&b);
Ok(Self::new(bytes)?)
}
Err(err) => Err(Self::Err::InvalidEncoding(err)),
}
}
}
#[test]
fn test_onion_v3_addr_parse() {
let test: OnionV3Addr = "aerukz4jvpg677w4xkmhmvbscaabcirtirkwm54itgvlxtg5537uyyad.onion"
.parse()
.unwrap();
let expected = OnionV3Addr::new([
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32,
0x10, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
0xee, 0xff, 0x4c, 0x60, 0x03,
])
.unwrap();
assert_eq!(test, expected);
}
#[test]
fn test_onion_v3_addr_to_string() {
let test = OnionV3Addr::new([
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32,
0x10, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
0xee, 0xff, 0x4c, 0x60, 0x03,
])
.unwrap()
.to_string();
let expected = "aerukz4jvpg677w4xkmhmvbscaabcirtirkwm54itgvlxtg5537uyyad.onion";
assert_eq!(test, expected);
}
#[test]
fn test_onion_v3_addr_validate() {
let _test: OnionV3Addr = "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion"
.parse()
.unwrap();
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Addr {
Ipv4(Ipv4Addr),
Ipv6(Ipv6Addr),
OnionV2(OnionV2Addr),
}
impl fmt::Display for Addr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Addr::Ipv4(addr) => addr.fmt(f),
Addr::Ipv6(addr) => addr.fmt(f),
Addr::OnionV2(addr) => addr.fmt(f),
}
}
}
const IPV4_PREFIX: [u8; 12] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff];
const ONION_PREFIX: [u8; 6] = [0xfd, 0x87, 0xd8, 0x7e, 0xeb, 0x43];
impl From<[u8; 16]> for Addr {
fn from(bytes: [u8; 16]) -> Self {
if bytes[0..12] == IPV4_PREFIX {
let mut b: [u8; 4] = [0; 4];
b.copy_from_slice(&bytes[12..]);
Self::Ipv4(b.into())
} else if bytes[0..6] == ONION_PREFIX {
let mut b: [u8; 10] = [0; 10];
b.copy_from_slice(&bytes[6..]);
Self::OnionV2(b.into())
} else {
Self::Ipv6(bytes.into())
}
}
}
impl From<IpAddr> for Addr {
fn from(addr: IpAddr) -> Self {
match addr {
IpAddr::V4(addr) => Self::Ipv4(addr),
IpAddr::V6(addr) => Self::Ipv6(addr),
}
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum TryFromAddrError {
OnionV2(OnionV2Addr),
}
impl fmt::Display for TryFromAddrError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::OnionV2(_addr) => write!(f, "Onion V2 address not supported"),
}
}
}
impl std::error::Error for TryFromAddrError {}
impl TryFrom<Addr> for IpAddr {
type Error = TryFromAddrError;
fn try_from(addr: Addr) -> Result<Self, <Self as TryFrom<Addr>>::Error> {
match addr {
Addr::Ipv4(addr) => Ok(Self::V4(addr)),
Addr::Ipv6(addr) => Ok(Self::V6(addr)),
Addr::OnionV2(addr) => Err(Self::Error::OnionV2(addr)),
}
}
}
#[cfg(feature = "koibumi-socks")]
impl From<Addr> for SocksAddr {
fn from(addr: Addr) -> Self {
match addr {
Addr::Ipv4(addr) => Self::Ipv4(addr),
Addr::Ipv6(addr) => Self::Ipv6(addr),
Addr::OnionV2(addr) => Self::DomainName(addr.into()),
}
}
}
impl WriteTo for Addr {
fn write_to(&self, w: &mut dyn Write) -> io::Result<()> {
match self {
Self::Ipv4(addr) => {
IPV4_PREFIX.write_to(w)?;
addr.octets().write_to(w)
}
Self::Ipv6(addr) => addr.octets().write_to(w),
Self::OnionV2(addr) => {
ONION_PREFIX.write_to(w)?;
addr.as_ref().write_to(w)
}
}
}
}
impl ReadFrom for Addr {
fn read_from(r: &mut dyn Read) -> io::Result<Self>
where
Self: Sized,
{
let bytes = <[u8; 16]>::read_from(r)?;
Ok(bytes.into())
}
}
#[test]
fn test_addr_write_to() {
let test = Addr::Ipv4(Ipv4Addr::LOCALHOST);
let mut bytes = Vec::new();
test.write_to(&mut bytes).unwrap();
let expected = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 127, 0, 0, 1];
assert_eq!(bytes, expected);
let test = Addr::Ipv6(Ipv6Addr::new(
0x0123, 0x4567, 0x89ab, 0xcdef, 0xfedc, 0xba98, 0x7654, 0x3210,
));
let mut bytes = Vec::new();
test.write_to(&mut bytes).unwrap();
let expected = [
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32,
0x10,
];
assert_eq!(bytes, expected);
let test = Addr::OnionV2(OnionV2Addr::new([
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc,
]));
let mut bytes = Vec::new();
test.write_to(&mut bytes).unwrap();
let expected = [
0xfd, 0x87, 0xd8, 0x7e, 0xeb, 0x43, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe,
0xdc,
];
assert_eq!(bytes, expected);
}
#[test]
fn test_addr_read_from() {
let mut bytes = Cursor::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 127, 0, 0, 1]);
let test = Addr::read_from(&mut bytes).unwrap();
let expected = Addr::Ipv4(Ipv4Addr::LOCALHOST);
assert_eq!(test, expected);
let mut bytes = Cursor::new([
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32,
0x10,
]);
let test = Addr::read_from(&mut bytes).unwrap();
let expected = Addr::Ipv6(Ipv6Addr::new(
0x0123, 0x4567, 0x89ab, 0xcdef, 0xfedc, 0xba98, 0x7654, 0x3210,
));
assert_eq!(test, expected);
let mut bytes = Cursor::new([
0xfd, 0x87, 0xd8, 0x7e, 0xeb, 0x43, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe,
0xdc,
]);
let test = Addr::read_from(&mut bytes).unwrap();
let expected = Addr::OnionV2(OnionV2Addr::new([
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc,
]));
assert_eq!(test, expected);
}
type Port = u16;
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct SocketAddrOnionV2 {
onion_addr: OnionV2Addr,
port: Port,
}
impl fmt::Display for SocketAddrOnionV2 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}", self.onion_addr, self.port)
}
}
impl SocketAddrOnionV2 {
pub fn new(onion_addr: OnionV2Addr, port: Port) -> Self {
Self { onion_addr, port }
}
pub fn onion_addr(&self) -> &OnionV2Addr {
&self.onion_addr
}
pub fn port(&self) -> Port {
self.port
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum SocketAddr {
Ipv4(SocketAddrV4),
Ipv6(SocketAddrV6),
OnionV2(SocketAddrOnionV2),
}
impl fmt::Display for SocketAddr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SocketAddr::Ipv4(addr) => addr.fmt(f),
SocketAddr::Ipv6(addr) => addr.fmt(f),
SocketAddr::OnionV2(addr) => addr.fmt(f),
}
}
}
impl SocketAddr {
pub fn new(addr: Addr, port: Port) -> Self {
match addr {
Addr::Ipv4(addr) => Self::Ipv4(SocketAddrV4::new(addr, port)),
Addr::Ipv6(addr) => Self::Ipv6(SocketAddrV6::new(addr, port, 0, 0)),
Addr::OnionV2(addr) => Self::OnionV2(SocketAddrOnionV2::new(addr, port)),
}
}
}
impl From<[u8; 18]> for SocketAddr {
fn from(bytes: [u8; 18]) -> Self {
let mut bytes = Cursor::new(bytes);
let addr = Addr::read_from(&mut bytes).unwrap();
let port = Port::read_from(&mut bytes).unwrap();
match addr {
Addr::Ipv4(addr) => Self::Ipv4(SocketAddrV4::new(addr, port)),
Addr::Ipv6(addr) => Self::Ipv6(SocketAddrV6::new(addr, port, 0, 0)),
Addr::OnionV2(addr) => Self::OnionV2(SocketAddrOnionV2::new(addr, port)),
}
}
}
impl From<StdSocketAddr> for SocketAddr {
fn from(addr: StdSocketAddr) -> Self {
match addr {
StdSocketAddr::V4(addr) => Self::Ipv4(addr),
StdSocketAddr::V6(addr) => Self::Ipv6(addr),
}
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum TryFromSocketAddrError {
OnionV2(SocketAddrOnionV2),
}
impl fmt::Display for TryFromSocketAddrError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::OnionV2(_addr) => write!(f, "Onion V2 address not supported"),
}
}
}
impl std::error::Error for TryFromSocketAddrError {}
impl TryFrom<SocketAddr> for StdSocketAddr {
type Error = TryFromSocketAddrError;
fn try_from(addr: SocketAddr) -> Result<Self, <Self as TryFrom<SocketAddr>>::Error> {
match addr {
SocketAddr::Ipv4(addr) => Ok(Self::V4(addr)),
SocketAddr::Ipv6(addr) => Ok(Self::V6(addr)),
SocketAddr::OnionV2(addr) => Err(Self::Error::OnionV2(addr)),
}
}
}
#[cfg(feature = "koibumi-socks")]
impl From<SocketAddr> for SocksSocketAddr {
fn from(addr: SocketAddr) -> Self {
match addr {
SocketAddr::Ipv4(addr) => Self::new(SocksAddr::Ipv4(*addr.ip()), addr.port()),
SocketAddr::Ipv6(addr) => Self::new(SocksAddr::Ipv6(*addr.ip()), addr.port()),
SocketAddr::OnionV2(addr) => Self::new(
SocksAddr::DomainName(
DomainName::new(addr.onion_addr().to_string().as_bytes().to_vec()).unwrap(),
),
addr.port(),
),
}
}
}
impl WriteTo for SocketAddr {
fn write_to(&self, w: &mut dyn Write) -> io::Result<()> {
match self {
Self::Ipv4(addr) => {
IPV4_PREFIX.write_to(w)?;
addr.ip().octets().write_to(w)?;
addr.port().write_to(w)?;
Ok(())
}
Self::Ipv6(addr) => {
addr.ip().octets().write_to(w)?;
addr.port().write_to(w)?;
Ok(())
}
Self::OnionV2(addr) => {
ONION_PREFIX.write_to(w)?;
addr.onion_addr().as_ref().write_to(w)?;
addr.port().write_to(w)?;
Ok(())
}
}
}
}
impl ReadFrom for SocketAddr {
fn read_from(r: &mut dyn Read) -> io::Result<Self>
where
Self: Sized,
{
let bytes = <[u8; 18]>::read_from(r)?;
Ok(bytes.into())
}
}
#[test]
fn test_socket_addr_write_to() {
let test = SocketAddr::Ipv4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 8444));
let mut bytes = Vec::new();
test.write_to(&mut bytes).unwrap();
let expected = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 127, 0, 0, 1, 0x20, 0xfc,
];
assert_eq!(bytes, expected);
}
#[test]
fn test_socket_addr_read_from() {
let mut bytes = Cursor::new([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 127, 0, 0, 1, 0x20, 0xfc,
]);
let test = SocketAddr::read_from(&mut bytes).unwrap();
let expected = SocketAddr::Ipv4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 8444));
assert_eq!(test, expected);
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum AddrExt {
Ipv4(Ipv4Addr),
Ipv6(Ipv6Addr),
OnionV2(OnionV2Addr),
OnionV3(OnionV3Addr),
}
impl fmt::Display for AddrExt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AddrExt::Ipv4(addr) => addr.fmt(f),
AddrExt::Ipv6(addr) => addr.fmt(f),
AddrExt::OnionV2(addr) => addr.fmt(f),
AddrExt::OnionV3(addr) => addr.fmt(f),
}
}
}
impl From<Addr> for AddrExt {
fn from(addr: Addr) -> Self {
match addr {
Addr::Ipv4(addr) => Self::Ipv4(addr),
Addr::Ipv6(addr) => Self::Ipv6(addr),
Addr::OnionV2(addr) => Self::OnionV2(addr),
}
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum TryFromAddrExtError {
OnionV3(OnionV3Addr),
}
impl fmt::Display for TryFromAddrExtError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::OnionV3(_addr) => write!(f, "Onion address not supported"),
}
}
}
impl std::error::Error for TryFromAddrExtError {}
impl TryFrom<AddrExt> for Addr {
type Error = TryFromAddrExtError;
fn try_from(addr: AddrExt) -> Result<Self, <Self as TryFrom<AddrExt>>::Error> {
match addr {
AddrExt::Ipv4(addr) => Ok(Self::Ipv4(addr)),
AddrExt::Ipv6(addr) => Ok(Self::Ipv6(addr)),
AddrExt::OnionV2(addr) => Ok(Self::OnionV2(addr)),
AddrExt::OnionV3(addr) => Err(Self::Error::OnionV3(addr)),
}
}
}
#[cfg(feature = "koibumi-socks")]
impl From<AddrExt> for SocksAddr {
fn from(addr: AddrExt) -> Self {
match addr {
AddrExt::Ipv4(addr) => Self::Ipv4(addr),
AddrExt::Ipv6(addr) => Self::Ipv6(addr),
AddrExt::OnionV2(addr) => Self::DomainName(addr.into()),
AddrExt::OnionV3(addr) => Self::DomainName(addr.into()),
}
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum ParseAddrExtError {
OnionV2(ParseOnionV2AddrError),
OnionV3(ParseOnionV3AddrError),
UnsupportedOnion,
Ip {
v4: AddrParseError,
v6: AddrParseError,
},
}
impl fmt::Display for ParseAddrExtError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::OnionV2(err) => err.fmt(f),
Self::OnionV3(err) => err.fmt(f),
Self::UnsupportedOnion => write!(f, "unsupported version of Onion address"),
Self::Ip { v4, v6 } => write!(f, "v4: {}, v6: {}", v4, v6),
}
}
}
impl std::error::Error for ParseAddrExtError {}
impl FromStr for AddrExt {
type Err = ParseAddrExtError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.ends_with(".onion") {
if s.as_bytes().len() == 22 {
match s.parse() {
Ok(addr) => Ok(Self::OnionV2(addr)),
Err(err) => Err(Self::Err::OnionV2(err)),
}
} else if s.as_bytes().len() == 62 {
match s.parse() {
Ok(addr) => Ok(Self::OnionV3(addr)),
Err(err) => Err(Self::Err::OnionV3(err)),
}
} else {
Err(ParseAddrExtError::UnsupportedOnion)
}
} else {
let err_v4;
match s.parse() {
Ok(addr) => return Ok(Self::Ipv4(addr)),
Err(err) => err_v4 = err,
}
let err_v6;
match s.parse::<Ipv6Addr>() {
Ok(addr) => {
let addr = addr.octets().into();
match addr {
Addr::Ipv4(addr) => return Ok(Self::Ipv4(addr)),
Addr::Ipv6(addr) => return Ok(Self::Ipv6(addr)),
Addr::OnionV2(addr) => return Ok(Self::OnionV2(addr)),
}
}
Err(err) => err_v6 = err,
}
Err(Self::Err::Ip {
v4: err_v4,
v6: err_v6,
})
}
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct SocketAddrOnionV3 {
onion_addr: OnionV3Addr,
port: Port,
}
impl fmt::Display for SocketAddrOnionV3 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}", self.onion_addr, self.port)
}
}
impl SocketAddrOnionV3 {
pub fn new(onion_addr: OnionV3Addr, port: Port) -> Self {
Self { onion_addr, port }
}
pub fn onion_addr(&self) -> &OnionV3Addr {
&self.onion_addr
}
pub fn port(&self) -> Port {
self.port
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum SocketAddrExt {
Ipv4(SocketAddrV4),
Ipv6(SocketAddrV6),
OnionV2(SocketAddrOnionV2),
OnionV3(SocketAddrOnionV3),
}
impl fmt::Display for SocketAddrExt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SocketAddrExt::Ipv4(addr) => addr.fmt(f),
SocketAddrExt::Ipv6(addr) => addr.fmt(f),
SocketAddrExt::OnionV2(addr) => addr.fmt(f),
SocketAddrExt::OnionV3(addr) => addr.fmt(f),
}
}
}
impl SocketAddrExt {
pub fn new(addr: AddrExt, port: Port) -> Self {
match addr {
AddrExt::Ipv4(addr) => Self::Ipv4(SocketAddrV4::new(addr, port)),
AddrExt::Ipv6(addr) => Self::Ipv6(SocketAddrV6::new(addr, port, 0, 0)),
AddrExt::OnionV2(addr) => Self::OnionV2(SocketAddrOnionV2::new(addr, port)),
AddrExt::OnionV3(addr) => Self::OnionV3(SocketAddrOnionV3::new(addr, port)),
}
}
}
impl From<SocketAddr> for SocketAddrExt {
fn from(addr: SocketAddr) -> Self {
match addr {
SocketAddr::Ipv4(addr) => Self::Ipv4(addr),
SocketAddr::Ipv6(addr) => Self::Ipv6(addr),
SocketAddr::OnionV2(addr) => Self::OnionV2(addr),
}
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum TryFromSocketAddrExtError {
OnionV2(SocketAddrOnionV2),
OnionV3(SocketAddrOnionV3),
}
impl fmt::Display for TryFromSocketAddrExtError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::OnionV2(_addr) => write!(f, "Onion V2 address not supported"),
Self::OnionV3(_addr) => write!(f, "Onion V3 address not supported"),
}
}
}
impl std::error::Error for TryFromSocketAddrExtError {}
impl TryFrom<SocketAddrExt> for SocketAddr {
type Error = TryFromSocketAddrExtError;
fn try_from(addr: SocketAddrExt) -> Result<Self, <Self as TryFrom<SocketAddrExt>>::Error> {
match addr {
SocketAddrExt::Ipv4(addr) => Ok(Self::Ipv4(addr)),
SocketAddrExt::Ipv6(addr) => Ok(Self::Ipv6(addr)),
SocketAddrExt::OnionV2(addr) => Ok(Self::OnionV2(addr)),
SocketAddrExt::OnionV3(addr) => Err(Self::Error::OnionV3(addr)),
}
}
}
impl From<StdSocketAddr> for SocketAddrExt {
fn from(addr: StdSocketAddr) -> Self {
match addr {
StdSocketAddr::V4(addr) => Self::Ipv4(addr),
StdSocketAddr::V6(addr) => Self::Ipv6(addr),
}
}
}
impl TryFrom<SocketAddrExt> for StdSocketAddr {
type Error = TryFromSocketAddrExtError;
fn try_from(addr: SocketAddrExt) -> Result<Self, <Self as TryFrom<SocketAddrExt>>::Error> {
match addr {
SocketAddrExt::Ipv4(addr) => Ok(addr.into()),
SocketAddrExt::Ipv6(addr) => Ok(addr.into()),
SocketAddrExt::OnionV2(addr) => Err(Self::Error::OnionV2(addr)),
SocketAddrExt::OnionV3(addr) => Err(Self::Error::OnionV3(addr)),
}
}
}
#[cfg(feature = "koibumi-socks")]
impl From<SocketAddrExt> for SocksSocketAddr {
fn from(addr: SocketAddrExt) -> Self {
match addr {
SocketAddrExt::Ipv4(addr) => Self::new(SocksAddr::Ipv4(*addr.ip()), addr.port()),
SocketAddrExt::Ipv6(addr) => Self::new(SocksAddr::Ipv6(*addr.ip()), addr.port()),
SocketAddrExt::OnionV2(addr) => Self::new(
SocksAddr::DomainName(
DomainName::new(addr.onion_addr().to_string().as_bytes().to_vec()).unwrap(),
),
addr.port(),
),
SocketAddrExt::OnionV3(addr) => Self::new(
SocksAddr::DomainName(
DomainName::new(addr.onion_addr().to_string().as_bytes().to_vec()).unwrap(),
),
addr.port(),
),
}
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum ParseSocketAddrExtError {
PortNotFound,
InvalidPort(ParseIntError),
InvalidAddr(ParseAddrExtError),
}
impl fmt::Display for ParseSocketAddrExtError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::PortNotFound => write!(f, "port not found"),
Self::InvalidPort(err) => err.fmt(f),
Self::InvalidAddr(err) => err.fmt(f),
}
}
}
impl std::error::Error for ParseSocketAddrExtError {}
impl FromStr for SocketAddrExt {
type Err = ParseSocketAddrExtError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let colon = s.rfind(':');
if colon.is_none() {
return Err(Self::Err::PortNotFound);
}
let colon = colon.unwrap();
let addr_part = &s[..colon];
let port_part = &s[colon + 1..];
let port = port_part.parse::<Port>();
if let Err(err) = port {
return Err(Self::Err::InvalidPort(err));
}
let port = port.unwrap();
let addr = addr_part.parse();
if let Err(err) = addr {
return Err(Self::Err::InvalidAddr(err));
}
let addr = addr.unwrap();
Ok(Self::new(addr, port))
}
}