electrum_client/socks/
v5.rs

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