Skip to main content

electrum_client/socks/
mod.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! SOCKS proxy clients
4
5use std::io;
6use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
7use std::vec;
8
9pub use self::v4::{Socks4Listener, Socks4Stream};
10pub use self::v5::{Socks5Datagram, Socks5Listener, Socks5Stream};
11
12mod v4;
13mod v5;
14mod writev;
15
16/// A description of a connection target.
17#[derive(Debug, Clone)]
18pub enum TargetAddr {
19    /// Connect to an IP address.
20    Ip(SocketAddr),
21    /// Connect to a fully qualified domain name.
22    ///
23    /// The domain name will be passed along to the proxy server and DNS lookup
24    /// will happen there.
25    Domain(String, u16),
26}
27
28impl ToSocketAddrs for TargetAddr {
29    type Iter = Iter;
30
31    fn to_socket_addrs(&self) -> io::Result<Iter> {
32        let inner = match *self {
33            TargetAddr::Ip(addr) => IterInner::Ip(Some(addr)),
34            TargetAddr::Domain(ref domain, port) => {
35                let it = (&**domain, port).to_socket_addrs()?;
36                IterInner::Domain(it)
37            }
38        };
39        Ok(Iter(inner))
40    }
41}
42
43enum IterInner {
44    Ip(Option<SocketAddr>),
45    Domain(vec::IntoIter<SocketAddr>),
46}
47
48/// An iterator over `SocketAddr`s associated with a `TargetAddr`.
49pub struct Iter(IterInner);
50
51impl Iterator for Iter {
52    type Item = SocketAddr;
53
54    fn next(&mut self) -> Option<SocketAddr> {
55        match self.0 {
56            IterInner::Ip(ref mut addr) => addr.take(),
57            IterInner::Domain(ref mut it) => it.next(),
58        }
59    }
60}
61
62/// A trait for objects that can be converted to `TargetAddr`.
63pub trait ToTargetAddr {
64    /// Converts the value of `self` to a `TargetAddr`.
65    fn to_target_addr(&self) -> io::Result<TargetAddr>;
66}
67
68impl ToTargetAddr for TargetAddr {
69    fn to_target_addr(&self) -> io::Result<TargetAddr> {
70        Ok(self.clone())
71    }
72}
73
74impl ToTargetAddr for SocketAddr {
75    fn to_target_addr(&self) -> io::Result<TargetAddr> {
76        Ok(TargetAddr::Ip(*self))
77    }
78}
79
80impl ToTargetAddr for SocketAddrV4 {
81    fn to_target_addr(&self) -> io::Result<TargetAddr> {
82        SocketAddr::V4(*self).to_target_addr()
83    }
84}
85
86impl ToTargetAddr for SocketAddrV6 {
87    fn to_target_addr(&self) -> io::Result<TargetAddr> {
88        SocketAddr::V6(*self).to_target_addr()
89    }
90}
91
92impl ToTargetAddr for (Ipv4Addr, u16) {
93    fn to_target_addr(&self) -> io::Result<TargetAddr> {
94        SocketAddrV4::new(self.0, self.1).to_target_addr()
95    }
96}
97
98impl ToTargetAddr for (Ipv6Addr, u16) {
99    fn to_target_addr(&self) -> io::Result<TargetAddr> {
100        SocketAddrV6::new(self.0, self.1, 0, 0).to_target_addr()
101    }
102}
103
104impl ToTargetAddr for (&str, u16) {
105    fn to_target_addr(&self) -> io::Result<TargetAddr> {
106        // try to parse as an IP first
107        if let Ok(addr) = self.0.parse::<Ipv4Addr>() {
108            return (addr, self.1).to_target_addr();
109        }
110
111        if let Ok(addr) = self.0.parse::<Ipv6Addr>() {
112            return (addr, self.1).to_target_addr();
113        }
114
115        Ok(TargetAddr::Domain(self.0.to_owned(), self.1))
116    }
117}
118
119impl ToTargetAddr for &str {
120    fn to_target_addr(&self) -> io::Result<TargetAddr> {
121        // try to parse as an IP first
122        if let Ok(addr) = self.parse::<SocketAddrV4>() {
123            return addr.to_target_addr();
124        }
125
126        if let Ok(addr) = self.parse::<SocketAddrV6>() {
127            return addr.to_target_addr();
128        }
129
130        // split the string by ':' and convert the second part to u16
131        let mut parts_iter = self.rsplitn(2, ':');
132        let port_str = match parts_iter.next() {
133            Some(s) => s,
134            None => {
135                return Err(io::Error::new(
136                    io::ErrorKind::InvalidInput,
137                    "invalid socket address",
138                ))
139            }
140        };
141
142        let host = match parts_iter.next() {
143            Some(s) => s,
144            None => {
145                return Err(io::Error::new(
146                    io::ErrorKind::InvalidInput,
147                    "invalid socket address",
148                ))
149            }
150        };
151
152        let port: u16 = match port_str.parse() {
153            Ok(p) => p,
154            Err(_) => {
155                return Err(io::Error::new(
156                    io::ErrorKind::InvalidInput,
157                    "invalid port value",
158                ))
159            }
160        };
161
162        (host, port).to_target_addr()
163    }
164}