1use std::{
2 io,
3 net::{SocketAddr, ToSocketAddrs},
4 ops::Range,
5 path::PathBuf,
6 time::Duration,
7};
8
9use clap::{Parser, ValueEnum};
10use hala_future::executor::future_spawn;
11use hala_io::sleep;
12use hala_quic::{Config, CongestionControlAlgorithm};
13use hala_rproxy::{Handshaker, Rproxy};
14
15type SocketAddrs = Vec<SocketAddr>;
16
17fn clap_parse_duration(s: &str) -> Result<Duration, String> {
18 let duration = duration_str::parse(s).map_err(|err| format!("{}", err))?;
19
20 Ok(duration)
21}
22
23#[derive(ValueEnum, Clone, Debug)]
24pub enum QuicCongestionControlAlgorithm {
25 Reno = 0,
27 CUBIC = 1,
29 BBR = 2,
31 BBR2 = 3,
33}
34
35impl From<QuicCongestionControlAlgorithm> for CongestionControlAlgorithm {
36 fn from(value: QuicCongestionControlAlgorithm) -> Self {
37 match value {
38 QuicCongestionControlAlgorithm::Reno => CongestionControlAlgorithm::Reno,
39 QuicCongestionControlAlgorithm::CUBIC => CongestionControlAlgorithm::CUBIC,
40 QuicCongestionControlAlgorithm::BBR => CongestionControlAlgorithm::BBR,
41 QuicCongestionControlAlgorithm::BBR2 => CongestionControlAlgorithm::BBR2,
42 }
43 }
44}
45
46fn clap_parse_ports(s: &str) -> Result<Range<u16>, String> {
48 let splites = s.split("-");
49
50 let splites = splites.collect::<Vec<_>>();
51
52 if splites.len() == 2 {
53 Ok(Range {
54 start: splites[0].parse().map_err(|err| format!("{}", err))?,
55 end: splites[1].parse().map_err(|err| format!("{}", err))?,
56 })
57 } else if splites.len() == 1 {
58 let start = splites[0].parse().map_err(|err| format!("{}", err))?;
59 Ok(Range {
60 start,
61 end: start + 1,
62 })
63 } else {
64 Err(format!(
65 "Invalid port-range arg, the desired format is `a-b` or `a`"
66 ))
67 }
68}
69
70fn clap_parse_sockaddrs(s: &str) -> Result<Vec<SocketAddr>, String> {
71 let splits = s.split(":").collect::<Vec<_>>();
72
73 if splits.len() != 2 {
74 return Err(format!(
75 "Invalid address string: {}. the desired format is `ip_or_domain_name:port-range`",
76 s
77 ));
78 }
79
80 let mut parsed_addrs = vec![];
81
82 for port in clap_parse_ports(splits[1])? {
83 let mut addrs = (splits[0], port)
84 .to_socket_addrs()
85 .map_err(|err| err.to_string())?
86 .collect::<Vec<_>>();
87
88 parsed_addrs.append(&mut addrs);
89 }
90
91 Ok(parsed_addrs)
92}
93
94#[derive(Parser, Debug, Clone)]
95#[command(author, version, about, long_about = None)]
96pub struct QuicTunnelConfig {
97 #[arg(long, value_parser = clap_parse_sockaddrs)]
99 pub laddrs: SocketAddrs,
100
101 #[arg(long, value_parser = clap_parse_sockaddrs)]
103 pub raddrs: SocketAddrs,
104
105 #[arg(long)]
108 pub ca_file: Option<PathBuf>,
109
110 #[arg(long)]
115 pub cert_chain_file: PathBuf,
116
117 #[arg(long)]
121 pub key_file: PathBuf,
122
123 #[arg(long, default_value_t = 1350)]
125 pub mtu: usize,
126
127 #[arg(long, value_enum, default_value_t = QuicCongestionControlAlgorithm::CUBIC)]
129 pub cc: QuicCongestionControlAlgorithm,
130
131 #[arg(long, default_value_t = 1048576)]
133 pub buf: u64,
134
135 #[arg(long, default_value_t = 100)]
137 pub mux: u64,
138
139 #[arg(long, value_parser = clap_parse_duration, default_value="5s")]
141 pub timeout: Duration,
142
143 #[arg(long, default_value_t = 100)]
145 pub max_conns: usize,
146
147 #[arg(long, default_value_t = 24 * 1024 * 1024)]
149 pub max_conn_win: u64,
150
151 #[arg(long, default_value_t = 16 * 1024 * 1024)]
153 pub max_stream_win: u64,
154
155 #[arg(long, value_parser = clap_parse_duration, default_value="1m")]
158 pub print_stats: Duration,
159}
160
161fn make_config(quic_tunn_config: &QuicTunnelConfig) -> Config {
162 let mut config = Config::new().unwrap();
163
164 config
165 .load_cert_chain_from_pem_file(quic_tunn_config.cert_chain_file.to_str().unwrap())
166 .unwrap();
167
168 config
169 .load_priv_key_from_pem_file(quic_tunn_config.key_file.to_str().unwrap())
170 .unwrap();
171
172 if let Some(ca_file) = &quic_tunn_config.ca_file {
173 config.verify_peer(true);
174
175 config
176 .load_verify_locations_from_file(ca_file.to_str().unwrap())
177 .unwrap();
178 }
179
180 config.set_application_protos(&[b"qtun"]).unwrap();
181
182 config.set_max_idle_timeout(quic_tunn_config.timeout.as_millis() as u64);
183 config.set_max_datagram_size(quic_tunn_config.mtu);
184 config.set_initial_max_data(quic_tunn_config.buf * quic_tunn_config.mux);
185 config.set_initial_max_stream_data_bidi_local(quic_tunn_config.buf);
186 config.set_initial_max_stream_data_bidi_remote(quic_tunn_config.buf);
187 config.set_initial_max_streams_bidi(quic_tunn_config.mux);
188 config.set_initial_max_streams_uni(quic_tunn_config.mux);
189 config.set_disable_active_migration(false);
190 config.set_cc_algorithm(quic_tunn_config.cc.clone().into());
191 config.set_max_connection_window(quic_tunn_config.max_conn_win);
192 config.set_max_stream_window(quic_tunn_config.max_stream_win);
193
194 config
195}
196
197fn print_stats<H: Handshaker + Sync + Send + 'static>(
198 quic_tun_config: &QuicTunnelConfig,
199 rproxy: Rproxy<H>,
200) {
201 if !quic_tun_config.print_stats.is_zero() {
202 let duration = quic_tun_config.print_stats.clone();
203
204 future_spawn(async move {
205 loop {
206 let stats = rproxy.stats();
207
208 log::info!("{}", stats);
209
210 sleep(duration).await.unwrap();
211 }
212 });
213 }
214}
215
216#[cfg(feature = "server")]
217pub async fn run_server() -> io::Result<()> {
218 use crate::server::TcpForwardHandshaker;
219 use hala_quic::QuicListener;
220 use hala_rproxy::listener::quic::QuicStreamListener;
221
222 let quic_tun_config = QuicTunnelConfig::parse();
223
224 let rproxy = Rproxy::new(TcpForwardHandshaker::new(
225 quic_tun_config.raddrs.as_slice(),
226 )?);
227
228 let quic_config = make_config(&quic_tun_config);
229
230 let quic_listener = QuicListener::bind(quic_tun_config.laddrs.as_slice(), quic_config)?;
231
232 print_stats(&quic_tun_config, rproxy.clone());
233
234 rproxy.accept(QuicStreamListener::from(quic_listener)).await;
235
236 Ok(())
237}
238
239#[cfg(feature = "client")]
240pub async fn run_client() -> io::Result<()> {
241 use hala_quic::QuicConnPool;
242 use hala_tcp::TcpListener;
243
244 use crate::client::QuicTunnHandshaker;
245
246 let quic_tun_config = QuicTunnelConfig::parse();
247
248 let quic_config = make_config(&quic_tun_config);
249
250 let quic_conn_pool = QuicConnPool::new(
251 quic_tun_config.max_conns,
252 quic_tun_config.raddrs.as_slice(),
253 quic_config,
254 )?;
255
256 let rproxy = Rproxy::new(QuicTunnHandshaker::from(quic_conn_pool));
257
258 let tcp_listener = TcpListener::bind(quic_tun_config.laddrs.as_slice())?;
259
260 print_stats(&quic_tun_config, rproxy.clone());
261
262 rproxy.accept(tcp_listener).await;
263
264 Ok(())
265}