1use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
2use std::cmp;
3use std::io::{self, Read, Write};
4use std::net::{SocketAddr, ToSocketAddrs, SocketAddrV4, SocketAddrV6, TcpStream, Ipv4Addr,
5 Ipv6Addr, UdpSocket};
6use std::ptr;
7
8use {ToTargetAddr, TargetAddr};
9use writev::WritevExt;
10
11const MAX_ADDR_LEN: usize = 260;
12
13fn read_addr<R: Read>(socket: &mut R) -> io::Result<TargetAddr> {
14 match socket.read_u8()? {
15 1 => {
16 let ip = Ipv4Addr::from(socket.read_u32::<BigEndian>()?);
17 let port = socket.read_u16::<BigEndian>()?;
18 Ok(TargetAddr::Ip(SocketAddr::V4(SocketAddrV4::new(ip, port))))
19 }
20 3 => {
21 let len = socket.read_u8()?;
22 let mut domain = vec![0; len as usize];
23 socket.read_exact(&mut domain)?;
24 let domain = String::from_utf8(domain)
25 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
26 let port = socket.read_u16::<BigEndian>()?;
27 Ok(TargetAddr::Domain(domain, port))
28 }
29 4 => {
30 let mut ip = [0; 16];
31 socket.read_exact(&mut ip)?;
32 let ip = Ipv6Addr::from(ip);
33 let port = socket.read_u16::<BigEndian>()?;
34 Ok(TargetAddr::Ip(SocketAddr::V6(SocketAddrV6::new(ip, port, 0, 0))))
35 }
36 _ => Err(io::Error::new(io::ErrorKind::Other, "unsupported address type")),
37 }
38}
39
40fn read_response(socket: &mut TcpStream) -> io::Result<TargetAddr> {
41
42 if socket.read_u8()? != 5 {
43 return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid response version"));
44 }
45
46 match socket.read_u8()? {
47 0 => {}
48 1 => return Err(io::Error::new(io::ErrorKind::Other, "general SOCKS server failure")),
49 2 => return Err(io::Error::new(io::ErrorKind::Other, "connection not allowed by ruleset")),
50 3 => return Err(io::Error::new(io::ErrorKind::Other, "network unreachable")),
51 4 => return Err(io::Error::new(io::ErrorKind::Other, "host unreachable")),
52 5 => return Err(io::Error::new(io::ErrorKind::Other, "connection refused")),
53 6 => return Err(io::Error::new(io::ErrorKind::Other, "TTL expired")),
54 7 => return Err(io::Error::new(io::ErrorKind::Other, "command not supported")),
55 8 => return Err(io::Error::new(io::ErrorKind::Other, "address kind not supported")),
56 _ => return Err(io::Error::new(io::ErrorKind::Other, "unknown error")),
57 }
58
59 if socket.read_u8()? != 0 {
60 return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid reserved byte"));
61 }
62
63 read_addr(socket)
64}
65
66fn write_addr(mut packet: &mut [u8], target: &TargetAddr) -> io::Result<usize> {
67 let start_len = packet.len();
68 match *target {
69 TargetAddr::Ip(SocketAddr::V4(addr)) => {
70 packet.write_u8(1).unwrap();
71 packet.write_u32::<BigEndian>((*addr.ip()).into()).unwrap();
72 packet.write_u16::<BigEndian>(addr.port()).unwrap();
73 }
74 TargetAddr::Ip(SocketAddr::V6(addr)) => {
75 packet.write_u8(4).unwrap();
76 packet.write_all(&addr.ip().octets()).unwrap();
77 packet.write_u16::<BigEndian>(addr.port()).unwrap();
78 }
79 TargetAddr::Domain(ref domain, port) => {
80 packet.write_u8(3).unwrap();
81 if domain.len() > u8::max_value() as usize {
82 return Err(io::Error::new(io::ErrorKind::InvalidInput, "domain name too long"));
83 }
84 packet.write_u8(domain.len() as u8).unwrap();
85 packet.write_all(domain.as_bytes()).unwrap();
86 packet.write_u16::<BigEndian>(port).unwrap();
87 }
88 }
89
90 Ok(start_len - packet.len())
91}
92
93#[derive(Debug)]
95enum Authentication<'a> {
96 Password { username: &'a str, password: &'a str },
97 None
98}
99
100impl<'a> Authentication<'a> {
101 fn id(&self) -> u8 {
102 match *self {
103 Authentication::Password { .. } => 2,
104 Authentication::None => 0
105 }
106 }
107
108 fn is_no_auth(&self) -> bool {
109 if let Authentication::None = *self {
110 true
111 } else {
112 false
113 }
114 }
115}
116
117#[derive(Debug)]
119pub struct Socks5Stream {
120 socket: TcpStream,
121 proxy_addr: TargetAddr,
122}
123
124impl Socks5Stream {
125 pub fn connect<T, U>(proxy: T, target: U) -> io::Result<Socks5Stream>
127 where T: ToSocketAddrs,
128 U: ToTargetAddr
129 {
130 Self::connect_raw(1, proxy, target, &Authentication::None)
131 }
132
133 pub fn connect_with_password<T, U>(proxy: T, target: U, username: &str, password: &str) -> io::Result<Socks5Stream>
136 where T: ToSocketAddrs,
137 U: ToTargetAddr
138 {
139 let auth = Authentication::Password { username, password };
140 Self::connect_raw(1, proxy, target, &auth)
141 }
142
143 fn connect_raw<T, U>(command: u8, proxy: T, target: U, auth: &Authentication) -> io::Result<Socks5Stream>
144 where T: ToSocketAddrs,
145 U: ToTargetAddr
146 {
147 let mut socket = TcpStream::connect(proxy)?;
148
149 let target = target.to_target_addr()?;
150
151 let packet_len = if auth.is_no_auth() { 3 } else { 4 };
152 let packet = [
153 5, if auth.is_no_auth() { 1 } else { 2 }, auth.id(), 0, ];
158 socket.write_all(&packet[..packet_len])?;
159
160 let mut buf = [0; 2];
161 socket.read_exact(&mut buf)?;
162 let response_version = buf[0];
163 let selected_method = buf[1];
164
165 if response_version != 5 {
166 return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid response version"));
167 }
168
169 if selected_method == 0xff {
170 return Err(io::Error::new(io::ErrorKind::Other, "no acceptable auth methods"))
171 }
172
173 if selected_method != auth.id() && selected_method != Authentication::None.id() {
174 return Err(io::Error::new(io::ErrorKind::Other, "unknown auth method"))
175 }
176
177 match *auth {
178 Authentication::Password { username, password } if selected_method == auth.id() => {
179 Self::password_authentication(&mut socket, username, password)?
180 },
181 _ => ()
182 }
183
184 let mut packet = [0; MAX_ADDR_LEN + 3];
185 packet[0] = 5; packet[1] = command; packet[2] = 0; let len = write_addr(&mut packet[3..], &target)?;
189 socket.write_all(&packet[..len + 3])?;
190
191 let proxy_addr = read_response(&mut socket)?;
192
193 Ok(Socks5Stream {
194 socket: socket,
195 proxy_addr: proxy_addr,
196 })
197 }
198
199 fn password_authentication(socket: &mut TcpStream, username: &str, password: &str) -> io::Result<()> {
200 if username.len() < 1 || username.len() > 255 {
201 return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid username"))
202 };
203 if password.len() < 1 || password.len() > 255 {
204 return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid password"))
205 }
206
207 let mut packet = [0; 515];
208 let packet_size = 3 + username.len() + password.len();
209 packet[0] = 1; packet[1] = username.len() as u8;
211 packet[2..2 + username.len()].copy_from_slice(username.as_bytes());
212 packet[2 + username.len()] = password.len() as u8;
213 packet[3 + username.len()..packet_size].copy_from_slice(password.as_bytes());
214 socket.write_all(&packet[..packet_size])?;
215
216 let mut buf = [0; 2];
217 socket.read_exact(&mut buf)?;
218 if buf[0] != 1 {
219 return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid response version"));
220 }
221 if buf[1] != 0 {
222 return Err(io::Error::new(io::ErrorKind::PermissionDenied, "password authentication failed"));
223 }
224
225 Ok(())
226 }
227
228 pub fn proxy_addr(&self) -> &TargetAddr {
231 &self.proxy_addr
232 }
233
234 pub fn get_ref(&self) -> &TcpStream {
236 &self.socket
237 }
238
239 pub fn get_mut(&mut self) -> &mut TcpStream {
241 &mut self.socket
242 }
243
244 pub fn into_inner(self) -> TcpStream {
246 self.socket
247 }
248}
249
250impl Read for Socks5Stream {
251 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
252 self.socket.read(buf)
253 }
254}
255
256impl<'a> Read for &'a Socks5Stream {
257 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
258 (&self.socket).read(buf)
259 }
260}
261
262impl Write for Socks5Stream {
263 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
264 self.socket.write(buf)
265 }
266
267 fn flush(&mut self) -> io::Result<()> {
268 self.socket.flush()
269 }
270}
271
272impl<'a> Write for &'a Socks5Stream {
273 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
274 (&self.socket).write(buf)
275 }
276
277 fn flush(&mut self) -> io::Result<()> {
278 (&self.socket).flush()
279 }
280}
281
282#[derive(Debug)]
284pub struct Socks5Listener(Socks5Stream);
285
286impl Socks5Listener {
287 pub fn bind<T, U>(proxy: T, target: U) -> io::Result<Socks5Listener>
292 where T: ToSocketAddrs,
293 U: ToTargetAddr
294 {
295 Socks5Stream::connect_raw(2, proxy, target, &Authentication::None).map(Socks5Listener)
296 }
297 pub fn bind_with_password<T, U>(proxy: T, target: U, username: &str, password: &str) -> io::Result<Socks5Listener>
303 where T: ToSocketAddrs,
304 U: ToTargetAddr
305 {
306 let auth = Authentication::Password { username, password };
307 Socks5Stream::connect_raw(2, proxy, target, &auth).map(Socks5Listener)
308 }
309
310 pub fn proxy_addr(&self) -> &TargetAddr {
315 &self.0.proxy_addr
316 }
317
318 pub fn accept(mut self) -> io::Result<Socks5Stream> {
323 self.0.proxy_addr = read_response(&mut self.0.socket)?;
324 Ok(self.0)
325 }
326}
327
328#[derive(Debug)]
330pub struct Socks5Datagram {
331 socket: UdpSocket,
332 stream: Socks5Stream,
334}
335
336impl Socks5Datagram {
337 pub fn bind<T, U>(proxy: T, addr: U) -> io::Result<Socks5Datagram>
340 where T: ToSocketAddrs,
341 U: ToSocketAddrs
342 {
343 Self::bind_internal(proxy, addr, &Authentication::None)
344 }
345 pub fn bind_with_password<T, U>(proxy: T, addr: U, username: &str, password: &str) -> io::Result<Socks5Datagram>
349 where T: ToSocketAddrs,
350 U: ToSocketAddrs
351 {
352 let auth = Authentication::Password { username, password };
353 Self::bind_internal(proxy, addr, &auth)
354 }
355
356 fn bind_internal<T, U>(proxy: T, addr: U, auth: &Authentication) -> io::Result<Socks5Datagram>
357 where T: ToSocketAddrs,
358 U: ToSocketAddrs
359 {
360 let dst = TargetAddr::Ip(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 0)));
363 let stream = Socks5Stream::connect_raw(3, proxy, dst, auth)?;
364
365 let socket = UdpSocket::bind(addr)?;
366 socket.connect(&stream.proxy_addr)?;
367
368 Ok(Socks5Datagram {
369 socket: socket,
370 stream: stream,
371 })
372 }
373
374 pub fn send_to<A>(&self, buf: &[u8], addr: A) -> io::Result<usize>
382 where A: ToTargetAddr
383 {
384 let addr = addr.to_target_addr()?;
385
386 let mut header = [0; MAX_ADDR_LEN + 3];
387 let len = write_addr(&mut header[3..], &addr)?;
390
391 self.socket.writev([&header[..len + 3], buf])
392 }
393
394 pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, TargetAddr)> {
396 let mut header = [0; MAX_ADDR_LEN + 3];
397 let len = self.socket.readv([&mut header, buf])?;
398
399 let overflow = len.saturating_sub(header.len());
400
401 let header_len = cmp::min(header.len(), len);
402 let mut header = &mut &header[..header_len];
403
404 if header.read_u16::<BigEndian>()? != 0 {
405 return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid reserved bytes"));
406 }
407 if header.read_u8()? != 0 {
408 return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid fragment id"));
409 }
410 let addr = read_addr(&mut header)?;
411
412 unsafe {
413 ptr::copy(buf.as_ptr(), buf.as_mut_ptr().offset(header.len() as isize), overflow);
414 }
415 buf[..header.len()].copy_from_slice(header);
416
417 Ok((header.len() + overflow, addr))
418 }
419
420 pub fn proxy_addr(&self) -> &TargetAddr {
423 &self.stream.proxy_addr
424 }
425
426 pub fn get_ref(&self) -> &UdpSocket {
428 &self.socket
429 }
430
431 pub fn get_mut(&mut self) -> &mut UdpSocket {
433 &mut self.socket
434 }
435}
436
437#[cfg(test)]
438mod test {
439 use std::error::Error;
440 use std::io::{Read, Write};
441 use std::net::{ToSocketAddrs, TcpStream, UdpSocket};
442
443 use super::*;
444
445 const SOCKS_PROXY_NO_AUTH_ONLY: &str = "127.0.0.1:1080";
446 const SOCKS_PROXY_PASSWD_ONLY: &str = "127.0.0.1:1081";
447
448 #[test]
449 fn google_no_auth() {
450 let addr = "google.com:80".to_socket_addrs().unwrap().next().unwrap();
451 let socket = Socks5Stream::connect(SOCKS_PROXY_NO_AUTH_ONLY, addr).unwrap();
452 google(socket);
453 }
454
455 #[test]
456 fn google_with_password() {
457 let addr = "google.com:80".to_socket_addrs().unwrap().next().unwrap();
458 let socket = Socks5Stream::connect_with_password(
459 SOCKS_PROXY_PASSWD_ONLY,
460 addr,
461 "testuser",
462 "testpass"
463 ).unwrap();
464 google(socket);
465 }
466
467 fn google(mut socket: Socks5Stream) {
468 socket.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
469 let mut result = vec![];
470 socket.read_to_end(&mut result).unwrap();
471
472 println!("{}", String::from_utf8_lossy(&result));
473 assert!(result.starts_with(b"HTTP/1.0"));
474 assert!(result.ends_with(b"</HTML>\r\n") || result.ends_with(b"</html>"));
475 }
476
477 #[test]
478 fn google_dns() {
479 let mut socket = Socks5Stream::connect(SOCKS_PROXY_NO_AUTH_ONLY, "google.com:80").unwrap();
480
481 socket.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
482 let mut result = vec![];
483 socket.read_to_end(&mut result).unwrap();
484
485 println!("{}", String::from_utf8_lossy(&result));
486 assert!(result.starts_with(b"HTTP/1.0"));
487 assert!(result.ends_with(b"</HTML>\r\n") || result.ends_with(b"</html>"));
488 }
489
490 #[test]
491 fn bind_no_auth() {
492 let addr = find_address();
493 let listener = Socks5Listener::bind(SOCKS_PROXY_NO_AUTH_ONLY, addr).unwrap();
494 bind(listener);
495 }
496
497 #[test]
498 fn bind_with_password_supported_but_no_auth_used() {
499 let addr = find_address();
500 let listener = Socks5Listener::bind_with_password(
501 SOCKS_PROXY_NO_AUTH_ONLY,
502 addr,
503 "unused_and_invalid_username",
504 "unused_and_invalid_password"
505 ).unwrap();
506 bind(listener);
507 }
508
509 #[test]
510 fn bind_with_password() {
511 let addr = find_address();
512 let listener = Socks5Listener::bind_with_password(
513 "127.0.0.1:1081",
514 addr,
515 "testuser",
516 "testpass"
517 ).unwrap();
518 bind(listener);
519 }
520
521 fn bind(listener: Socks5Listener) {
522 let addr = listener.proxy_addr().clone();
523 let mut end = TcpStream::connect(addr).unwrap();
524 let mut conn = listener.accept().unwrap();
525 conn.write_all(b"hello world").unwrap();
526 drop(conn);
527 let mut result = vec![];
528 end.read_to_end(&mut result).unwrap();
529 assert_eq!(result, b"hello world");
530 }
531
532 fn find_address() -> TargetAddr {
534 let socket = Socks5Stream::connect(SOCKS_PROXY_NO_AUTH_ONLY, "google.com:80").unwrap();
535 socket.proxy_addr().to_owned()
536 }
537
538 #[test]
539 fn associate_no_auth() {
540 let socks = Socks5Datagram::bind(SOCKS_PROXY_NO_AUTH_ONLY, "127.0.0.1:15410").unwrap();
541 associate(socks, "127.0.0.1:15411");
542 }
543
544 #[test]
545 fn associate_with_password() {
546 let socks = Socks5Datagram::bind_with_password(
547 SOCKS_PROXY_PASSWD_ONLY,
548 "127.0.0.1:15414",
549 "testuser",
550 "testpass"
551 ).unwrap();
552 associate(socks, "127.0.0.1:15415");
553 }
554
555 fn associate(socks: Socks5Datagram, socket_addr: &str) {
556 let socket = UdpSocket::bind(socket_addr).unwrap();
557
558 socks.send_to(b"hello world!", socket_addr).unwrap();
559 let mut buf = [0; 13];
560 let (len, addr) = socket.recv_from(&mut buf).unwrap();
561 assert_eq!(len, 12);
562 assert_eq!(&buf[..12], b"hello world!");
563
564 socket.send_to(b"hello world!", addr).unwrap();
565
566 let len = socks.recv_from(&mut buf).unwrap().0;
567 assert_eq!(len, 12);
568 assert_eq!(&buf[..12], b"hello world!");
569 }
570
571 #[test]
572 fn associate_long() {
573 let socks = Socks5Datagram::bind(SOCKS_PROXY_NO_AUTH_ONLY, "127.0.0.1:15412").unwrap();
574 let socket_addr = "127.0.0.1:15413";
575 let socket = UdpSocket::bind(socket_addr).unwrap();
576
577 let mut msg = vec![];
578 for i in 0..(MAX_ADDR_LEN + 100) {
579 msg.push(i as u8);
580 }
581
582 socks.send_to(&msg, socket_addr).unwrap();
583 let mut buf = vec![0; msg.len() + 1];
584 let (len, addr) = socket.recv_from(&mut buf).unwrap();
585 assert_eq!(len, msg.len());
586 assert_eq!(msg, &buf[..msg.len()]);
587
588 socket.send_to(&msg, addr).unwrap();
589
590 let mut buf = vec![0; msg.len() + 1];
591 let len = socks.recv_from(&mut buf).unwrap().0;
592 assert_eq!(len, msg.len());
593 assert_eq!(msg, &buf[..msg.len()]);
594 }
595
596 #[test]
597 fn incorrect_password() {
598 let addr = "google.com:80".to_socket_addrs().unwrap().next().unwrap();
599 let err = Socks5Stream::connect_with_password(
600 SOCKS_PROXY_PASSWD_ONLY,
601 addr,
602 "testuser",
603 "invalid"
604 ).unwrap_err();
605
606 assert_eq!(err.kind(), io::ErrorKind::PermissionDenied);
607 assert_eq!(err.description(), "password authentication failed");
608 }
609
610 #[test]
611 fn auth_method_not_supported() {
612 let addr = "google.com:80".to_socket_addrs().unwrap().next().unwrap();
613 let err = Socks5Stream::connect(SOCKS_PROXY_PASSWD_ONLY, addr).unwrap_err();
614
615 assert_eq!(err.kind(), io::ErrorKind::Other);
616 assert_eq!(err.description(), "no acceptable auth methods");
617 }
618
619 #[test]
620 fn username_and_password_length() {
621 let addr = "google.com:80".to_socket_addrs().unwrap().next().unwrap();
622
623 let err = Socks5Stream::connect_with_password(
624 SOCKS_PROXY_PASSWD_ONLY,
625 addr,
626 &string_of_size(1),
627 &string_of_size(1)
628 ).unwrap_err();
629 assert_eq!(err.kind(), io::ErrorKind::PermissionDenied);
630 assert_eq!(err.description(), "password authentication failed");
631
632 let err = Socks5Stream::connect_with_password(
633 SOCKS_PROXY_PASSWD_ONLY,
634 addr,
635 &string_of_size(255),
636 &string_of_size(255)
637 ).unwrap_err();
638 assert_eq!(err.kind(), io::ErrorKind::PermissionDenied);
639 assert_eq!(err.description(), "password authentication failed");
640
641 let err = Socks5Stream::connect_with_password(
642 SOCKS_PROXY_PASSWD_ONLY,
643 addr,
644 &string_of_size(0),
645 &string_of_size(255)
646 ).unwrap_err();
647 assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
648 assert_eq!(err.description(), "invalid username");
649
650 let err = Socks5Stream::connect_with_password(
651 SOCKS_PROXY_PASSWD_ONLY,
652 addr,
653 &string_of_size(256),
654 &string_of_size(255)
655 ).unwrap_err();
656 assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
657 assert_eq!(err.description(), "invalid username");
658
659 let err = Socks5Stream::connect_with_password(
660 SOCKS_PROXY_PASSWD_ONLY,
661 addr,
662 &string_of_size(255),
663 &string_of_size(0)
664 ).unwrap_err();
665 assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
666 assert_eq!(err.description(), "invalid password");
667
668 let err = Socks5Stream::connect_with_password(
669 SOCKS_PROXY_PASSWD_ONLY,
670 addr,
671 &string_of_size(255),
672 &string_of_size(256)
673 ).unwrap_err();
674 assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
675 assert_eq!(err.description(), "invalid password");
676 }
677
678 fn string_of_size(size: usize) -> String {
679 (0..size).map(|_| 'x').collect()
680 }
681}