chrootable_https/
socks5.rs1use byteorder::{NetworkEndian, WriteBytesExt};
2use hyper::client::connect;
3use std::io;
4use std::net::SocketAddr;
5use std::net::{Ipv4Addr, Ipv6Addr};
6use tokio::net::tcp::TcpStream;
7use tokio::prelude::*;
8
9
10pub enum ProxyDest {
11 Ipv4Addr(Ipv4Addr),
12 Ipv6Addr(Ipv6Addr),
13 Domain(String),
14}
15
16impl ProxyDest {
17 fn apply_ipv4(buf: &mut Vec<u8>, addr: Ipv4Addr) {
18 info!("Setting socks5 destination as ipv4: {:?}", addr);
19 buf.push(0x01); buf.extend(&addr.octets());
21 }
22
23 fn apply_ipv6(buf: &mut Vec<u8>, addr: Ipv6Addr) {
24 info!("Setting socks5 destination as ipv6: {:?}", addr);
25 buf.push(0x04); buf.extend(&addr.octets());
27 }
28
29 fn apply_domain(buf: &mut Vec<u8>, domain: &str) {
30 info!("Setting socks5 destination as domain: {:?}", domain);
31 let domain = domain.bytes();
32 buf.push(0x03); buf.push(domain.len() as u8);
34 buf.extend(domain);
35 }
36
37 fn apply(&self, buf: &mut Vec<u8>) {
38 match self {
39 ProxyDest::Ipv4Addr(addr) => Self::apply_ipv4(buf, *addr),
40 ProxyDest::Ipv6Addr(addr) => Self::apply_ipv6(buf, *addr),
41 ProxyDest::Domain(domain) => Self::apply_domain(buf, domain),
42 }
43 }
44
45 pub fn from_hyper(dest: connect::Destination) -> (ProxyDest, u16) {
46 let port = match (dest.scheme(), dest.port()) {
47 (_, Some(port)) => port,
48 ("https", None) => 443,
49 ("http", None) => 80,
50 (_, None) => 443, };
52
53 let host = dest.host();
54 let host = match host.parse::<Ipv4Addr>() {
55 Ok(ipaddr) => ProxyDest::Ipv4Addr(ipaddr),
56 _ => ProxyDest::Domain(host.to_string()),
57 };
58
59 (host, port)
60 }
61}
62
63#[must_use = "futures do nothing unless polled"]
65pub struct ConnectionFuture(Box<dyn Future<Item = TcpStream, Error = io::Error> + Send>);
66
67impl Future for ConnectionFuture {
68 type Item = TcpStream;
69 type Error = io::Error;
70
71 fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
72 self.0.poll()
73 }
74}
75
76#[must_use = "futures do nothing unless polled"]
78pub struct SkipFuture(Box<dyn Future<Item = (TcpStream, usize), Error = io::Error> + Send>);
79
80impl Future for SkipFuture {
81 type Item = (TcpStream, usize);
82 type Error = io::Error;
83
84 fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
85 self.0.poll()
86 }
87}
88
89fn err<T: 'static + Send>(msg: &str) -> Box<dyn Future<Item = T, Error = io::Error> + Send> {
90 Box::new(future::err(io::Error::new(io::ErrorKind::InvalidData, msg)))
91}
92
93fn socks5_request_connect(stream: TcpStream, buf: Vec<u8>, dest: &ProxyDest, port: u16) -> ConnectionFuture {
94 info!("Reading socks5 server hello");
95
96 if buf[0] != 0x05 {
98 return ConnectionFuture(err("wrong version"));
99 }
100
101 if buf[1] != 0x00 {
103 return ConnectionFuture(err("auth failed"));
104 }
105
106 info!("Socks5 authentication successful");
107
108 let mut buf = vec![
109 0x05, 0x01, 0x00, ];
113
114 dest.apply(&mut buf);
115 buf.write_u16::<NetworkEndian>(port).unwrap();
116 info!("Sending connect request");
117 let fut = tokio::io::write_all(stream, buf)
118 .and_then(|(stream, _)| future::ok(stream));
119 ConnectionFuture(Box::new(fut))
120}
121
122pub fn connect(addr: &SocketAddr, dest: ProxyDest, port: u16) -> ConnectionFuture {
123 let fut = TcpStream::connect(&addr)
124 .and_then(|stream| {
125 info!("Sending socks5 hello");
126 tokio::io::write_all(stream, &[
127 0x05, 0x01, 0x00, ])
131 })
132 .and_then(|(stream, _)| {
133 let buf = vec![0; 2];
134 tokio::io::read_exact(stream, buf)
135 })
136 .and_then(move |(stream, buf)| socks5_request_connect(stream, buf, &dest, port))
137 .and_then(|stream| {
138 let buf = vec![0; 4];
139 tokio::io::read_exact(stream, buf)
140 })
141 .and_then(|(stream, buf)| {
142 info!("Reading connect response");
143
144 if buf[0] != 0x05 {
146 return SkipFuture(err("wrong version"));
147 }
148 match buf[1] {
150 0x00 => (),
151 0x01 => return SkipFuture(err("general failure")),
152 0x02 => return SkipFuture(err("connection not allowed by ruleset")),
153 0x03 => return SkipFuture(err("network unreachable")),
154 0x04 => return SkipFuture(err("host unreachable")),
155 0x05 => return SkipFuture(err("connection refused by destination host")),
156 0x06 => return SkipFuture(err("TTL expired")),
157 0x07 => return SkipFuture(err("command not supported / protocol error")),
158 0x08 => return SkipFuture(err("address type not supported")),
159 _ => return SkipFuture(err("unknown connection error")),
160 }
161 if buf[2] != 0x00 {
163 return SkipFuture(err("wrong reserved bytes"));
164 }
165 info!("Connection successful");
166
167 match buf[3] {
168 0x01 => SkipFuture(Box::new(future::ok((stream, 4)))), 0x03 => {
170 let buf = vec![0; 1];
171 let fut = tokio::io::read_exact(stream, buf)
172 .and_then(|(stream, buf)| {
173 Ok((stream, buf[0] as usize))
174 });
175 SkipFuture(Box::new(fut))
176 },
177 0x04 => SkipFuture(Box::new(future::ok((stream, 16)))), _ => SkipFuture(err("wrong address type")),
179 }
180 })
181 .and_then(|(stream, n)| {
182 let buf = vec![0; n + 2];
183 tokio::io::read_exact(stream, buf)
184 })
185 .and_then(|(stream, _)| {
186 info!("Socks5 tunnel established");
187 future::ok(stream)
188 });
189 ConnectionFuture(Box::new(fut))
190}