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