1use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
2use std::cmp;
3use std::io::{self, Read, Write};
4use std::net::{
5 Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, TcpStream, ToSocketAddrs, UdpSocket,
6};
7use std::ptr;
8use std::time::Duration;
9
10use super::writev::WritevExt;
11use super::{TargetAddr, ToTargetAddr};
12
13const MAX_ADDR_LEN: usize = 260;
14
15fn read_addr<R: Read>(socket: &mut R) -> io::Result<TargetAddr> {
16 match socket.read_u8()? {
17 1 => {
18 let ip = Ipv4Addr::from(socket.read_u32::<BigEndian>()?);
19 let port = socket.read_u16::<BigEndian>()?;
20 Ok(TargetAddr::Ip(SocketAddr::V4(SocketAddrV4::new(ip, port))))
21 }
22 3 => {
23 let len = socket.read_u8()?;
24 let mut domain = vec![0; len as usize];
25 socket.read_exact(&mut domain)?;
26 let domain = String::from_utf8(domain)
27 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
28 let port = socket.read_u16::<BigEndian>()?;
29 Ok(TargetAddr::Domain(domain, port))
30 }
31 4 => {
32 let mut ip = [0; 16];
33 socket.read_exact(&mut ip)?;
34 let ip = Ipv6Addr::from(ip);
35 let port = socket.read_u16::<BigEndian>()?;
36 Ok(TargetAddr::Ip(SocketAddr::V6(SocketAddrV6::new(
37 ip, port, 0, 0,
38 ))))
39 }
40 _ => Err(io::Error::other("unsupported address type")),
41 }
42}
43
44fn read_response(socket: &mut TcpStream) -> io::Result<TargetAddr> {
45 if socket.read_u8()? != 5 {
46 return Err(io::Error::new(
47 io::ErrorKind::InvalidData,
48 "invalid response version",
49 ));
50 }
51
52 match socket.read_u8()? {
53 0 => {}
54 1 => return Err(io::Error::other("general SOCKS server failure")),
55 2 => return Err(io::Error::other("connection not allowed by ruleset")),
56 3 => return Err(io::Error::other("network unreachable")),
57 4 => return Err(io::Error::other("host unreachable")),
58 5 => return Err(io::Error::other("connection refused")),
59 6 => return Err(io::Error::other("TTL expired")),
60 7 => return Err(io::Error::other("command not supported")),
61 8 => return Err(io::Error::other("address kind not supported")),
62 _ => return Err(io::Error::other("unknown error")),
63 }
64
65 if socket.read_u8()? != 0 {
66 return Err(io::Error::new(
67 io::ErrorKind::InvalidData,
68 "invalid reserved byte",
69 ));
70 }
71
72 read_addr(socket)
73}
74
75fn write_addr(mut packet: &mut [u8], target: &TargetAddr) -> io::Result<usize> {
76 let start_len = packet.len();
77 match *target {
78 TargetAddr::Ip(SocketAddr::V4(addr)) => {
79 packet.write_u8(1).unwrap();
80 packet.write_u32::<BigEndian>((*addr.ip()).into()).unwrap();
81 packet.write_u16::<BigEndian>(addr.port()).unwrap();
82 }
83 TargetAddr::Ip(SocketAddr::V6(addr)) => {
84 packet.write_u8(4).unwrap();
85 packet.write_all(&addr.ip().octets()).unwrap();
86 packet.write_u16::<BigEndian>(addr.port()).unwrap();
87 }
88 TargetAddr::Domain(ref domain, port) => {
89 packet.write_u8(3).unwrap();
90 if domain.len() > u8::MAX as usize {
91 return Err(io::Error::new(
92 io::ErrorKind::InvalidInput,
93 "domain name too long",
94 ));
95 }
96 packet.write_u8(domain.len() as u8).unwrap();
97 packet.write_all(domain.as_bytes()).unwrap();
98 packet.write_u16::<BigEndian>(port).unwrap();
99 }
100 }
101
102 Ok(start_len - packet.len())
103}
104
105#[derive(Debug)]
107enum Authentication<'a> {
108 Password {
109 username: &'a str,
110 password: &'a str,
111 },
112 None,
113}
114
115impl Authentication<'_> {
116 fn id(&self) -> u8 {
117 match *self {
118 Authentication::Password { .. } => 2,
119 Authentication::None => 0,
120 }
121 }
122
123 fn is_no_auth(&self) -> bool {
124 matches!(*self, Authentication::None)
125 }
126}
127
128#[derive(Debug)]
130pub struct Socks5Stream {
131 socket: TcpStream,
132 proxy_addr: TargetAddr,
133}
134
135impl Socks5Stream {
136 pub fn connect<T, U>(proxy: T, target: U, timeout: Option<Duration>) -> io::Result<Socks5Stream>
138 where
139 T: ToSocketAddrs,
140 U: ToTargetAddr,
141 {
142 Self::connect_raw(1, proxy, target, &Authentication::None, timeout)
143 }
144
145 pub fn connect_with_password<T, U>(
148 proxy: T,
149 target: U,
150 username: &str,
151 password: &str,
152 timeout: Option<Duration>,
153 ) -> io::Result<Socks5Stream>
154 where
155 T: ToSocketAddrs,
156 U: ToTargetAddr,
157 {
158 let auth = Authentication::Password { username, password };
159 Self::connect_raw(1, proxy, target, &auth, timeout)
160 }
161
162 fn connect_raw<T, U>(
163 command: u8,
164 proxy: T,
165 target: U,
166 auth: &Authentication,
167 timeout: Option<Duration>,
168 ) -> io::Result<Socks5Stream>
169 where
170 T: ToSocketAddrs,
171 U: ToTargetAddr,
172 {
173 let mut socket = if let Some(timeout) = timeout {
174 let addr = proxy.to_socket_addrs()?.next().unwrap();
175 TcpStream::connect_timeout(&addr, timeout)?
176 } else {
177 TcpStream::connect(proxy)?
178 };
179
180 socket.set_read_timeout(timeout)?;
181 socket.set_write_timeout(timeout)?;
182
183 let target = target.to_target_addr()?;
184
185 let packet_len = if auth.is_no_auth() { 3 } else { 4 };
186 let packet = [
187 5, if auth.is_no_auth() { 1 } else { 2 }, auth.id(), 0, ];
192 socket.write_all(&packet[..packet_len])?;
193
194 let mut buf = [0; 2];
195 socket.read_exact(&mut buf)?;
196 let response_version = buf[0];
197 let selected_method = buf[1];
198
199 if response_version != 5 {
200 return Err(io::Error::new(
201 io::ErrorKind::InvalidData,
202 "invalid response version",
203 ));
204 }
205
206 if selected_method == 0xff {
207 return Err(io::Error::other("no acceptable auth methods"));
208 }
209
210 if selected_method != auth.id() && selected_method != Authentication::None.id() {
211 return Err(io::Error::other("unknown auth method"));
212 }
213
214 match *auth {
215 Authentication::Password { username, password } if selected_method == auth.id() => {
216 Self::password_authentication(&mut socket, username, password)?
217 }
218 _ => (),
219 }
220
221 let mut packet = [0; MAX_ADDR_LEN + 3];
222 packet[0] = 5; packet[1] = command; packet[2] = 0; let len = write_addr(&mut packet[3..], &target)?;
226 socket.write_all(&packet[..len + 3])?;
227
228 let proxy_addr = read_response(&mut socket)?;
229
230 Ok(Socks5Stream { socket, proxy_addr })
231 }
232
233 fn password_authentication(
234 socket: &mut TcpStream,
235 username: &str,
236 password: &str,
237 ) -> io::Result<()> {
238 if username.is_empty() || username.len() > 255 {
239 return Err(io::Error::new(
240 io::ErrorKind::InvalidInput,
241 "invalid username",
242 ));
243 };
244 if password.is_empty() || password.len() > 255 {
245 return Err(io::Error::new(
246 io::ErrorKind::InvalidInput,
247 "invalid password",
248 ));
249 }
250
251 let mut packet = [0; 515];
252 let packet_size = 3 + username.len() + password.len();
253 packet[0] = 1; packet[1] = username.len() as u8;
255 packet[2..2 + username.len()].copy_from_slice(username.as_bytes());
256 packet[2 + username.len()] = password.len() as u8;
257 packet[3 + username.len()..packet_size].copy_from_slice(password.as_bytes());
258 socket.write_all(&packet[..packet_size])?;
259
260 let mut buf = [0; 2];
261 socket.read_exact(&mut buf)?;
262 if buf[0] != 1 {
263 return Err(io::Error::new(
264 io::ErrorKind::InvalidData,
265 "invalid response version",
266 ));
267 }
268 if buf[1] != 0 {
269 return Err(io::Error::new(
270 io::ErrorKind::PermissionDenied,
271 "password authentication failed",
272 ));
273 }
274
275 Ok(())
276 }
277
278 pub fn proxy_addr(&self) -> &TargetAddr {
281 &self.proxy_addr
282 }
283
284 pub fn get_ref(&self) -> &TcpStream {
286 &self.socket
287 }
288
289 pub fn get_mut(&mut self) -> &mut TcpStream {
291 &mut self.socket
292 }
293
294 pub fn into_inner(self) -> TcpStream {
296 self.socket
297 }
298}
299
300impl Read for Socks5Stream {
301 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
302 self.socket.read(buf)
303 }
304}
305
306impl Read for &Socks5Stream {
307 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
308 (&self.socket).read(buf)
309 }
310}
311
312impl Write for Socks5Stream {
313 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
314 self.socket.write(buf)
315 }
316
317 fn flush(&mut self) -> io::Result<()> {
318 self.socket.flush()
319 }
320}
321
322impl Write for &Socks5Stream {
323 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
324 (&self.socket).write(buf)
325 }
326
327 fn flush(&mut self) -> io::Result<()> {
328 (&self.socket).flush()
329 }
330}
331
332#[derive(Debug)]
334pub struct Socks5Listener(Socks5Stream);
335
336impl Socks5Listener {
337 pub fn bind<T, U>(proxy: T, target: U, timeout: Option<Duration>) -> io::Result<Socks5Listener>
342 where
343 T: ToSocketAddrs,
344 U: ToTargetAddr,
345 {
346 Socks5Stream::connect_raw(2, proxy, target, &Authentication::None, timeout)
347 .map(Socks5Listener)
348 }
349 pub fn bind_with_password<T, U>(
355 proxy: T,
356 target: U,
357 username: &str,
358 password: &str,
359 timeout: Option<Duration>,
360 ) -> io::Result<Socks5Listener>
361 where
362 T: ToSocketAddrs,
363 U: ToTargetAddr,
364 {
365 let auth = Authentication::Password { username, password };
366 Socks5Stream::connect_raw(2, proxy, target, &auth, timeout).map(Socks5Listener)
367 }
368
369 pub fn proxy_addr(&self) -> &TargetAddr {
374 &self.0.proxy_addr
375 }
376
377 pub fn accept(mut self) -> io::Result<Socks5Stream> {
382 self.0.proxy_addr = read_response(&mut self.0.socket)?;
383 Ok(self.0)
384 }
385}
386
387#[derive(Debug)]
389pub struct Socks5Datagram {
390 socket: UdpSocket,
391 stream: Socks5Stream,
393}
394
395impl Socks5Datagram {
396 pub fn bind<T, U>(proxy: T, addr: U, timeout: Option<Duration>) -> io::Result<Socks5Datagram>
399 where
400 T: ToSocketAddrs,
401 U: ToSocketAddrs,
402 {
403 Self::bind_internal(proxy, addr, &Authentication::None, timeout)
404 }
405 pub fn bind_with_password<T, U>(
409 proxy: T,
410 addr: U,
411 username: &str,
412 password: &str,
413 timeout: Option<Duration>,
414 ) -> io::Result<Socks5Datagram>
415 where
416 T: ToSocketAddrs,
417 U: ToSocketAddrs,
418 {
419 let auth = Authentication::Password { username, password };
420 Self::bind_internal(proxy, addr, &auth, timeout)
421 }
422
423 fn bind_internal<T, U>(
424 proxy: T,
425 addr: U,
426 auth: &Authentication,
427 timeout: Option<Duration>,
428 ) -> io::Result<Socks5Datagram>
429 where
430 T: ToSocketAddrs,
431 U: ToSocketAddrs,
432 {
433 let dst = TargetAddr::Ip(SocketAddr::V4(SocketAddrV4::new(
436 Ipv4Addr::new(0, 0, 0, 0),
437 0,
438 )));
439 let stream = Socks5Stream::connect_raw(3, proxy, dst, auth, timeout)?;
440
441 let socket = UdpSocket::bind(addr)?;
442 socket.connect(&stream.proxy_addr)?;
443
444 Ok(Socks5Datagram { socket, stream })
445 }
446
447 pub fn send_to<A>(&self, buf: &[u8], addr: A) -> io::Result<usize>
455 where
456 A: ToTargetAddr,
457 {
458 let addr = addr.to_target_addr()?;
459
460 let mut header = [0; MAX_ADDR_LEN + 3];
461 let len = write_addr(&mut header[3..], &addr)?;
464
465 self.socket.writev([&header[..len + 3], buf])
466 }
467
468 pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, TargetAddr)> {
470 let mut header = [0; MAX_ADDR_LEN + 3];
471 let len = self.socket.readv([&mut header, buf])?;
472
473 let overflow = len.saturating_sub(header.len());
474
475 let header_len = cmp::min(header.len(), len);
476 let mut header = &mut &header[..header_len];
477
478 if header.read_u16::<BigEndian>()? != 0 {
479 return Err(io::Error::new(
480 io::ErrorKind::InvalidData,
481 "invalid reserved bytes",
482 ));
483 }
484 if header.read_u8()? != 0 {
485 return Err(io::Error::new(
486 io::ErrorKind::InvalidData,
487 "invalid fragment id",
488 ));
489 }
490 let addr = read_addr(&mut header)?;
491
492 unsafe {
493 ptr::copy(buf.as_ptr(), buf.as_mut_ptr().add(header.len()), overflow);
494 }
495 buf[..header.len()].copy_from_slice(header);
496
497 Ok((header.len() + overflow, addr))
498 }
499
500 pub fn proxy_addr(&self) -> &TargetAddr {
503 &self.stream.proxy_addr
504 }
505
506 pub fn get_ref(&self) -> &UdpSocket {
508 &self.socket
509 }
510
511 pub fn get_mut(&mut self) -> &mut UdpSocket {
513 &mut self.socket
514 }
515}
516
517#[cfg(test)]
518mod test {
519 use std::io::{Read, Write};
520 use std::net::{TcpStream, ToSocketAddrs, UdpSocket};
521
522 use super::*;
523
524 const SOCKS_PROXY_NO_AUTH_ONLY: &str = "127.0.0.1:1080";
525 const SOCKS_PROXY_PASSWD_ONLY: &str = "127.0.0.1:1081";
526
527 #[test]
528 #[ignore]
529 fn google_no_auth() {
530 let addr = "google.com:80".to_socket_addrs().unwrap().next().unwrap();
531 let socket = Socks5Stream::connect(SOCKS_PROXY_NO_AUTH_ONLY, addr, None).unwrap();
532 google(socket);
533 }
534
535 #[test]
536 #[ignore]
537 fn google_with_password() {
538 let addr = "google.com:80".to_socket_addrs().unwrap().next().unwrap();
539 let socket = Socks5Stream::connect_with_password(
540 SOCKS_PROXY_PASSWD_ONLY,
541 addr,
542 "testuser",
543 "testpass",
544 None,
545 )
546 .unwrap();
547 google(socket);
548 }
549
550 fn google(mut socket: Socks5Stream) {
551 socket.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
552 let mut result = vec![];
553 socket.read_to_end(&mut result).unwrap();
554
555 println!("{}", String::from_utf8_lossy(&result));
556 assert!(result.starts_with(b"HTTP/1.0"));
557 assert!(result.ends_with(b"</HTML>\r\n") || result.ends_with(b"</html>"));
558 }
559
560 #[test]
561 #[ignore]
562 fn google_dns() {
563 let mut socket =
564 Socks5Stream::connect(SOCKS_PROXY_NO_AUTH_ONLY, "google.com:80", None).unwrap();
565
566 socket.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
567 let mut result = vec![];
568 socket.read_to_end(&mut result).unwrap();
569
570 println!("{}", String::from_utf8_lossy(&result));
571 assert!(result.starts_with(b"HTTP/1.0"));
572 assert!(result.ends_with(b"</HTML>\r\n") || result.ends_with(b"</html>"));
573 }
574
575 #[test]
576 #[ignore]
577 fn bind_no_auth() {
578 let addr = find_address();
579 let listener = Socks5Listener::bind(SOCKS_PROXY_NO_AUTH_ONLY, addr, None).unwrap();
580 bind(listener);
581 }
582
583 #[test]
584 #[ignore]
585 fn bind_with_password_supported_but_no_auth_used() {
586 let addr = find_address();
587 let listener = Socks5Listener::bind_with_password(
588 SOCKS_PROXY_NO_AUTH_ONLY,
589 addr,
590 "unused_and_invalid_username",
591 "unused_and_invalid_password",
592 None,
593 )
594 .unwrap();
595 bind(listener);
596 }
597
598 #[test]
599 #[ignore]
600 fn bind_with_password() {
601 let addr = find_address();
602 let listener = Socks5Listener::bind_with_password(
603 "127.0.0.1:1081",
604 addr,
605 "testuser",
606 "testpass",
607 None,
608 )
609 .unwrap();
610 bind(listener);
611 }
612
613 fn bind(listener: Socks5Listener) {
614 let addr = listener.proxy_addr().clone();
615 let mut end = TcpStream::connect(addr).unwrap();
616 let mut conn = listener.accept().unwrap();
617 conn.write_all(b"hello world").unwrap();
618 drop(conn);
619 let mut result = vec![];
620 end.read_to_end(&mut result).unwrap();
621 assert_eq!(result, b"hello world");
622 }
623
624 fn find_address() -> TargetAddr {
626 let socket =
627 Socks5Stream::connect(SOCKS_PROXY_NO_AUTH_ONLY, "google.com:80", None).unwrap();
628 socket.proxy_addr().to_owned()
629 }
630
631 #[test]
632 #[ignore]
633 fn associate_no_auth() {
634 let socks =
635 Socks5Datagram::bind(SOCKS_PROXY_NO_AUTH_ONLY, "127.0.0.1:15410", None).unwrap();
636 associate(socks, "127.0.0.1:15411");
637 }
638
639 #[test]
640 #[ignore]
641 fn associate_with_password() {
642 let socks = Socks5Datagram::bind_with_password(
643 SOCKS_PROXY_PASSWD_ONLY,
644 "127.0.0.1:15414",
645 "testuser",
646 "testpass",
647 None,
648 )
649 .unwrap();
650 associate(socks, "127.0.0.1:15415");
651 }
652
653 fn associate(socks: Socks5Datagram, socket_addr: &str) {
654 let socket = UdpSocket::bind(socket_addr).unwrap();
655
656 socks.send_to(b"hello world!", socket_addr).unwrap();
657 let mut buf = [0; 13];
658 let (len, addr) = socket.recv_from(&mut buf).unwrap();
659 assert_eq!(len, 12);
660 assert_eq!(&buf[..12], b"hello world!");
661
662 socket.send_to(b"hello world!", addr).unwrap();
663
664 let len = socks.recv_from(&mut buf).unwrap().0;
665 assert_eq!(len, 12);
666 assert_eq!(&buf[..12], b"hello world!");
667 }
668
669 #[test]
670 #[ignore]
671 fn associate_long() {
672 let socks =
673 Socks5Datagram::bind(SOCKS_PROXY_NO_AUTH_ONLY, "127.0.0.1:15412", None).unwrap();
674 let socket_addr = "127.0.0.1:15413";
675 let socket = UdpSocket::bind(socket_addr).unwrap();
676
677 let mut msg = vec![];
678 for i in 0..(MAX_ADDR_LEN + 100) {
679 msg.push(i as u8);
680 }
681
682 socks.send_to(&msg, socket_addr).unwrap();
683 let mut buf = vec![0; msg.len() + 1];
684 let (len, addr) = socket.recv_from(&mut buf).unwrap();
685 assert_eq!(len, msg.len());
686 assert_eq!(msg, &buf[..msg.len()]);
687
688 socket.send_to(&msg, addr).unwrap();
689
690 let mut buf = vec![0; msg.len() + 1];
691 let len = socks.recv_from(&mut buf).unwrap().0;
692 assert_eq!(len, msg.len());
693 assert_eq!(msg, &buf[..msg.len()]);
694 }
695
696 #[test]
697 #[ignore]
698 fn incorrect_password() {
699 let addr = "google.com:80".to_socket_addrs().unwrap().next().unwrap();
700 let err = Socks5Stream::connect_with_password(
701 SOCKS_PROXY_PASSWD_ONLY,
702 addr,
703 "testuser",
704 "invalid",
705 None,
706 )
707 .unwrap_err();
708
709 assert_eq!(err.kind(), io::ErrorKind::PermissionDenied);
710 assert_eq!(err.to_string(), "password authentication failed");
711 }
712
713 #[test]
714 #[ignore]
715 fn auth_method_not_supported() {
716 let addr = "google.com:80".to_socket_addrs().unwrap().next().unwrap();
717 let err = Socks5Stream::connect(SOCKS_PROXY_PASSWD_ONLY, addr, None).unwrap_err();
718
719 assert_eq!(err.kind(), io::ErrorKind::Other);
720 assert_eq!(err.to_string(), "no acceptable auth methods");
721 }
722
723 #[test]
724 #[ignore]
725 fn username_and_password_length() {
726 let addr = "google.com:80".to_socket_addrs().unwrap().next().unwrap();
727
728 let err = Socks5Stream::connect_with_password(
729 SOCKS_PROXY_PASSWD_ONLY,
730 addr,
731 &string_of_size(1),
732 &string_of_size(1),
733 None,
734 )
735 .unwrap_err();
736 assert_eq!(err.kind(), io::ErrorKind::PermissionDenied);
737 assert_eq!(err.to_string(), "password authentication failed");
738
739 let err = Socks5Stream::connect_with_password(
740 SOCKS_PROXY_PASSWD_ONLY,
741 addr,
742 &string_of_size(255),
743 &string_of_size(255),
744 None,
745 )
746 .unwrap_err();
747 assert_eq!(err.kind(), io::ErrorKind::PermissionDenied);
748 assert_eq!(err.to_string(), "password authentication failed");
749
750 let err = Socks5Stream::connect_with_password(
751 SOCKS_PROXY_PASSWD_ONLY,
752 addr,
753 &string_of_size(0),
754 &string_of_size(255),
755 None,
756 )
757 .unwrap_err();
758 assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
759 assert_eq!(err.to_string(), "invalid username");
760
761 let err = Socks5Stream::connect_with_password(
762 SOCKS_PROXY_PASSWD_ONLY,
763 addr,
764 &string_of_size(256),
765 &string_of_size(255),
766 None,
767 )
768 .unwrap_err();
769 assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
770 assert_eq!(err.to_string(), "invalid username");
771
772 let err = Socks5Stream::connect_with_password(
773 SOCKS_PROXY_PASSWD_ONLY,
774 addr,
775 &string_of_size(255),
776 &string_of_size(0),
777 None,
778 )
779 .unwrap_err();
780 assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
781 assert_eq!(err.to_string(), "invalid password");
782
783 let err = Socks5Stream::connect_with_password(
784 SOCKS_PROXY_PASSWD_ONLY,
785 addr,
786 &string_of_size(255),
787 &string_of_size(256),
788 None,
789 )
790 .unwrap_err();
791 assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
792 assert_eq!(err.to_string(), "invalid password");
793 }
794
795 fn string_of_size(size: usize) -> String {
796 (0..size).map(|_| 'x').collect()
797 }
798}