electrum_client/socks/
v4.rs1use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
4use std::io::{self, Read, Write};
5use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, SocketAddrV6, TcpStream, ToSocketAddrs};
6
7use super::{TargetAddr, ToTargetAddr};
8
9fn read_response(socket: &mut TcpStream) -> io::Result<SocketAddrV4> {
10 let mut response = [0u8; 8];
11 socket.read_exact(&mut response)?;
12 let mut response = &response[..];
13
14 if response.read_u8()? != 0 {
15 return Err(io::Error::new(
16 io::ErrorKind::InvalidData,
17 "invalid response version",
18 ));
19 }
20
21 match response.read_u8()? {
22 90 => {}
23 91 => return Err(io::Error::other("request rejected or failed")),
24 92 => {
25 return Err(io::Error::new(
26 io::ErrorKind::PermissionDenied,
27 "request rejected because SOCKS server cannot connect to \
28 idnetd on the client",
29 ))
30 }
31 93 => {
32 return Err(io::Error::new(
33 io::ErrorKind::PermissionDenied,
34 "request rejected because the client program and identd \
35 report different user-ids",
36 ))
37 }
38 _ => {
39 return Err(io::Error::new(
40 io::ErrorKind::InvalidData,
41 "invalid response code",
42 ))
43 }
44 }
45
46 let port = response.read_u16::<BigEndian>()?;
47 let ip = Ipv4Addr::from(response.read_u32::<BigEndian>()?);
48
49 Ok(SocketAddrV4::new(ip, port))
50}
51
52#[derive(Debug)]
54pub struct Socks4Stream {
55 socket: TcpStream,
56 proxy_addr: SocketAddrV4,
57}
58
59impl Socks4Stream {
60 pub fn connect<T, U>(proxy: T, target: U, userid: &str) -> io::Result<Socks4Stream>
69 where
70 T: ToSocketAddrs,
71 U: ToTargetAddr,
72 {
73 Self::connect_raw(1, proxy, target, userid)
74 }
75
76 fn connect_raw<T, U>(command: u8, proxy: T, target: U, userid: &str) -> io::Result<Socks4Stream>
77 where
78 T: ToSocketAddrs,
79 U: ToTargetAddr,
80 {
81 let mut socket = TcpStream::connect(proxy)?;
82
83 let target = target.to_target_addr()?;
84
85 let mut packet = vec![];
86 let _ = packet.write_u8(4); let _ = packet.write_u8(command); match target.to_target_addr()? {
89 TargetAddr::Ip(addr) => {
90 let addr = match addr {
91 SocketAddr::V4(addr) => addr,
92 SocketAddr::V6(_) => {
93 return Err(io::Error::new(
94 io::ErrorKind::InvalidInput,
95 "SOCKS4 does not support IPv6",
96 ));
97 }
98 };
99 let _ = packet.write_u16::<BigEndian>(addr.port());
100 let _ = packet.write_u32::<BigEndian>((*addr.ip()).into());
101 let _ = packet.write_all(userid.as_bytes());
102 let _ = packet.write_u8(0);
103 }
104 TargetAddr::Domain(ref host, port) => {
105 let _ = packet.write_u16::<BigEndian>(port);
106 let _ = packet.write_u32::<BigEndian>(Ipv4Addr::new(0, 0, 0, 1).into());
107 let _ = packet.write_all(userid.as_bytes());
108 let _ = packet.write_u8(0);
109 packet.extend(host.as_bytes());
110 let _ = packet.write_u8(0);
111 }
112 }
113
114 socket.write_all(&packet)?;
115 let proxy_addr = read_response(&mut socket)?;
116
117 Ok(Socks4Stream { socket, proxy_addr })
118 }
119
120 pub fn proxy_addr(&self) -> SocketAddrV4 {
123 self.proxy_addr
124 }
125
126 pub fn get_ref(&self) -> &TcpStream {
128 &self.socket
129 }
130
131 pub fn get_mut(&mut self) -> &mut TcpStream {
133 &mut self.socket
134 }
135
136 pub fn into_inner(self) -> TcpStream {
138 self.socket
139 }
140}
141
142impl Read for Socks4Stream {
143 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
144 self.socket.read(buf)
145 }
146}
147
148impl Read for &Socks4Stream {
149 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
150 (&self.socket).read(buf)
151 }
152}
153
154impl Write for Socks4Stream {
155 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
156 self.socket.write(buf)
157 }
158
159 fn flush(&mut self) -> io::Result<()> {
160 self.socket.flush()
161 }
162}
163
164impl Write for &Socks4Stream {
165 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
166 (&self.socket).write(buf)
167 }
168
169 fn flush(&mut self) -> io::Result<()> {
170 (&self.socket).flush()
171 }
172}
173
174#[derive(Debug)]
176pub struct Socks4Listener(Socks4Stream);
177
178impl Socks4Listener {
179 pub fn bind<T, U>(proxy: T, target: U, userid: &str) -> io::Result<Socks4Listener>
184 where
185 T: ToSocketAddrs,
186 U: ToTargetAddr,
187 {
188 Socks4Stream::connect_raw(2, proxy, target, userid).map(Socks4Listener)
189 }
190
191 pub fn proxy_addr(&self) -> io::Result<SocketAddr> {
196 if self.0.proxy_addr.ip().octets() != [0, 0, 0, 0] {
197 Ok(SocketAddr::V4(self.0.proxy_addr()))
198 } else {
199 let port = self.0.proxy_addr.port();
200 let peer = match self.0.socket.peer_addr()? {
201 SocketAddr::V4(addr) => SocketAddr::V4(SocketAddrV4::new(*addr.ip(), port)),
202 SocketAddr::V6(addr) => SocketAddr::V6(SocketAddrV6::new(*addr.ip(), port, 0, 0)),
203 };
204 Ok(peer)
205 }
206 }
207
208 pub fn accept(mut self) -> io::Result<Socks4Stream> {
213 self.0.proxy_addr = read_response(&mut self.0.socket)?;
214 Ok(self.0)
215 }
216}
217
218#[cfg(test)]
219mod test {
220 use std::io::{Read, Write};
221 use std::net::{SocketAddr, SocketAddrV4, TcpStream, ToSocketAddrs};
222
223 use super::*;
224
225 fn google_ip() -> SocketAddrV4 {
226 "google.com:80"
227 .to_socket_addrs()
228 .unwrap()
229 .filter_map(|a| match a {
230 SocketAddr::V4(a) => Some(a),
231 SocketAddr::V6(_) => None,
232 })
233 .next()
234 .unwrap()
235 }
236
237 #[test]
238 #[ignore]
239 fn google() {
240 let mut socket = Socks4Stream::connect("127.0.0.1:1080", google_ip(), "").unwrap();
241
242 socket.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
243 let mut result = vec![];
244 socket.read_to_end(&mut result).unwrap();
245
246 println!("{}", String::from_utf8_lossy(&result));
247 assert!(result.starts_with(b"HTTP/1.0"));
248 assert!(result.ends_with(b"</HTML>\r\n") || result.ends_with(b"</html>"));
249 }
250
251 #[test]
252 #[ignore] fn google_dns() {
254 let mut socket = Socks4Stream::connect("127.0.0.1:8080", "google.com:80", "").unwrap();
255
256 socket.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
257 let mut result = vec![];
258 socket.read_to_end(&mut result).unwrap();
259
260 println!("{}", String::from_utf8_lossy(&result));
261 assert!(result.starts_with(b"HTTP/1.0"));
262 assert!(result.ends_with(b"</HTML>\r\n") || result.ends_with(b"</html>"));
263 }
264
265 #[test]
266 #[ignore]
267 fn bind() {
268 let socket = Socks4Stream::connect("127.0.0.1:1080", google_ip(), "").unwrap();
270 let addr = socket.proxy_addr();
271
272 let listener = Socks4Listener::bind("127.0.0.1:1080", addr, "").unwrap();
273 let addr = listener.proxy_addr().unwrap();
274 let mut end = TcpStream::connect(addr).unwrap();
275 let mut conn = listener.accept().unwrap();
276 conn.write_all(b"hello world").unwrap();
277 drop(conn);
278 let mut result = vec![];
279 end.read_to_end(&mut result).unwrap();
280 assert_eq!(result, b"hello world");
281 }
282}