1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use futures::{future, Future, Poll};
use hyper::client::connect::{Connect, Connected, Destination};
use socks::{Socks4Stream, Socks5Stream};
use std::{io, net::ToSocketAddrs};
use tokio::{net::TcpStream, reactor::Handle};
pub struct Connection(Box<Future<Item = (TcpStream, Connected), Error = io::Error> + Send>);
impl Connection {
fn new<F>(f: F) -> Self
where
F: Future<Item = (TcpStream, Connected), Error = io::Error> + Send + 'static,
{
Connection(Box::new(f))
}
}
impl Future for Connection {
type Item = (TcpStream, Connected);
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
self.0.poll()
}
}
#[derive(Debug)]
pub enum Proxy<T: ToSocketAddrs> {
Socks4 { addrs: T, user_id: String },
Socks5 { addrs: T, auth: Option<Auth> },
}
#[derive(Debug)]
pub struct Auth {
pub user: String,
pub pass: String,
}
pub struct Connector<T: ToSocketAddrs>(Proxy<T>);
impl<T> Connector<T>
where
T: ToSocketAddrs,
{
pub fn new(proxy: Proxy<T>) -> Self {
Connector(proxy)
}
}
impl<T> Connect for Connector<T>
where
T: ToSocketAddrs + Send + Sync,
{
type Transport = TcpStream;
type Error = io::Error;
type Future = Connection;
fn connect(&self, dst: Destination) -> Self::Future {
let scheme = dst.scheme();
let port = if let Some(p) = dst.port() {
p
} else if scheme == "http" {
80
} else if scheme == "https" {
443
} else {
return Connection::new(future::err(io::Error::new(
io::ErrorKind::InvalidInput,
"missing port",
)));
};
let target = (dst.host(), port);
let fut = match self.0 {
Proxy::Socks4 {
ref addrs,
ref user_id,
} => {
let res = Socks4Stream::connect(addrs, target, user_id.as_str())
.map(|stream| stream.into_inner());
future::result(res)
}
Proxy::Socks5 {
ref addrs,
ref auth,
} => {
let res = match auth {
Some(auth) => {
Socks5Stream::connect_with_password(addrs, target, &auth.user, &auth.pass)
}
None => Socks5Stream::connect(addrs, target),
};
let res = res.map(|stream| stream.into_inner());
future::result(res)
}
};
let fut = fut
.and_then(|stream| TcpStream::from_std(stream, &Handle::default()))
.map(|stream| (stream, Connected::new().proxy(true)));
Connection::new(fut)
}
}