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