+ match addr.ip() {
+ IpAddr::V6(v6addr) if v6addr.octets()[..6] == [0xFD,0x87,0xD8,0x7E,0xEB,0x43][..] => {
+ future::Either::A(connect_timeout.select(TcpStream::connect(&tor_proxy)
+ .and_then(move |mut stream: TcpStream| {
+ try_write_small!(stream, &[5u8, 1u8, 0u8]); // SOCKS5 with 1 method and no auth
+ future::Either::B(read_exact(stream, [0u8; 2]).and_then(move |(mut stream, response)| {
+ if response != [5, 0] { // SOCKS5 with no auth successful
+ future::Either::B(future::Either::A(future::err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Failed to authenticate"))))
+ } else {
+ let hostname = encode_base32(&v6addr.octets()[6..]) + ".onion";
+ let mut connect_msg = Vec::with_capacity(7 + hostname.len());
+ // SOCKS5 command CONNECT (+ reserved byte) to hostname with given len
+ connect_msg.extend_from_slice(&[5u8, 1u8, 0u8, 3u8, hostname.len() as u8]);
+ connect_msg.extend_from_slice(hostname.as_bytes());
+ connect_msg.push((addr.port() >> 8) as u8);
+ connect_msg.push((addr.port() >> 0) as u8);
+ try_write_small!(stream, &connect_msg);
+ future::Either::B(future::Either::B(read_exact(stream, [0u8; 4]).and_then(move |(stream, response)| {
+ if response[..3] != [5, 0, 0] {
+ future::Either::B(future::err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Failed to authenticate")))
+ } else {
+ if response[3] == 1 {
+ future::Either::A(future::Either::A(read_exact(stream, [0; 6]).and_then(|(stream, _)| future::ok(stream))))
+ } else if response[3] == 4 {
+ future::Either::A(future::Either::B(read_exact(stream, [0; 18]).and_then(|(stream, _)| future::ok(stream))))
+ } else {
+ future::Either::B(future::err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Bogus proxy address value")))
+ }
+ }
+ })))
+ }
+ }))
+ })
+ ).and_then(|(stream, _)| future::ok(stream)).or_else(|(e, _)| future::err(e)))
+ },
+ _ => future::Either::B(connect_timeout.select(TcpStream::connect(&addr))
+ .and_then(|(stream, _)| future::ok(stream)).or_else(|(e, _)| future::err(e))),
+ }.and_then(move |stream| {
+ let (write, read) = Framed::new(stream, MsgCoder(printer)).split();