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