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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
use std::fmt::Debug;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use async_trait::async_trait;
use crate::address::{NetLocation, ResolvedLocation};
use crate::async_stream::{AsyncMessageStream, AsyncStream, AsyncTargetedMessageStream};
use crate::client_proxy_selector::ClientProxySelector;
pub enum TcpServerSetupResult {
TcpForward {
remote_location: NetLocation,
stream: Box<dyn AsyncStream>,
need_initial_flush: bool,
/// Response to write to the server stream after connection to remote location succeeds
connection_success_response: Option<Box<[u8]>>,
/// Initial data to send to the remote location
initial_remote_data: Option<Box<[u8]>>,
/// The proxy selector to use for routing this connection
proxy_selector: Arc<ClientProxySelector>,
},
BidirectionalUdp {
need_initial_flush: bool,
remote_location: NetLocation,
stream: Box<dyn AsyncMessageStream>,
/// The proxy selector to use for routing this connection
proxy_selector: Arc<ClientProxySelector>,
},
MultiDirectionalUdp {
need_initial_flush: bool,
stream: Box<dyn AsyncTargetedMessageStream>,
/// The proxy selector to use for routing this connection
proxy_selector: Arc<ClientProxySelector>,
},
SessionBasedUdp {
need_initial_flush: bool,
stream: Box<dyn crate::async_stream::AsyncSessionMessageStream>,
/// The proxy selector to use for routing this connection
proxy_selector: Arc<ClientProxySelector>,
},
/// Long-lived work, polled outside the setup deadline and cancelled with its owner.
Session(Pin<Box<dyn Future<Output = ()> + Send>>),
}
impl TcpServerSetupResult {
pub fn set_need_initial_flush(&mut self, need_initial_flush: bool) {
match self {
TcpServerSetupResult::TcpForward {
need_initial_flush: flush,
..
}
| TcpServerSetupResult::BidirectionalUdp {
need_initial_flush: flush,
..
}
| TcpServerSetupResult::MultiDirectionalUdp {
need_initial_flush: flush,
..
}
| TcpServerSetupResult::SessionBasedUdp {
need_initial_flush: flush,
..
} => {
*flush = need_initial_flush;
}
TcpServerSetupResult::Session(_) => {}
}
}
}
#[async_trait]
#[allow(
clippy::double_must_use,
reason = "async-trait adds must_use to boxed futures"
)]
pub trait TcpServerHandler: Send + Sync + Debug {
async fn setup_server_stream(
&self,
server_stream: Box<dyn AsyncStream>,
) -> std::io::Result<TcpServerSetupResult>;
}
pub struct TcpClientSetupResult {
pub client_stream: Box<dyn AsyncStream>,
/// Early application data that was buffered during protocol handshake.
/// Only expected from the final destination - intermediate hops should not
/// return early data (all proxy protocols are client-initiated).
pub early_data: Option<Vec<u8>>,
}
#[async_trait]
#[allow(
clippy::double_must_use,
reason = "async-trait adds must_use to boxed futures"
)]
pub trait TcpClientHandler: Send + Sync + Debug {
/// Setup a client connection through this proxy.
///
/// # Arguments
/// * `client_stream` - The transport stream to the proxy server
/// * `remote_location` - The destination to connect to through the proxy.
/// May include pre-resolved address to avoid duplicate DNS lookups.
///
/// # Returns
/// * `client_stream` - The wrapped stream ready for application data
/// * `early_data` - Any application data received during handshake (from final destination)
async fn setup_client_tcp_stream(
&self,
client_stream: Box<dyn AsyncStream>,
remote_location: ResolvedLocation,
) -> std::io::Result<TcpClientSetupResult>;
/// Returns true if this handler supports UDP-over-TCP tunneling.
fn supports_udp_over_tcp(&self) -> bool {
false
}
/// Setup a bidirectional UDP message stream over a TCP connection.
/// Only called if `supports_udp_over_tcp()` returns true.
///
/// # Arguments
/// * `client_stream` - The transport stream to the proxy server
/// * `target` - The destination for UDP packets.
/// May include pre-resolved address to avoid duplicate DNS lookups.
///
/// # Returns
/// A message stream for sending/receiving UDP packets to the target.
async fn setup_client_udp_bidirectional(
&self,
_client_stream: Box<dyn AsyncStream>,
_target: ResolvedLocation,
) -> std::io::Result<Box<dyn AsyncMessageStream>> {
Err(std::io::Error::new(
std::io::ErrorKind::Unsupported,
"UDP-over-TCP not supported by this protocol",
))
}
}