1mod plain;
2#[cfg(test)]
3mod tests;
4#[cfg(feature = "direct_tls")]
5mod tls;
6mod unix;
7
8#[cfg(unix)]
9use std::{borrow::Cow, os::unix::net::UnixListener};
10use std::{
11 iter::once,
12 net::{Ipv4Addr, SocketAddr, TcpListener},
13 path::Path,
14 sync::{Arc, atomic::Ordering},
15};
16
17use tokio::task::JoinSet;
18use tuwunel_core::{Err, Result, debug_info, error, info};
19#[cfg(unix)]
20use tuwunel_core::{itertools::Itertools, utils::sys::is_ipv6_only};
21use tuwunel_service::Services;
22
23use super::layers;
24use crate::handle::ServerHandle;
25
26pub(super) async fn serve(services: Arc<Services>, handle: ServerHandle) -> Result {
28 let server = &services.server;
29 let config = &server.config;
30
31 let (app, _guard) = layers::build(&services)?;
32
33 let mut join_set = JoinSet::new();
34
35 let socket_path = &config.unix_socket_path;
36
37 #[cfg(unix)]
38 let (passed_tcp_listeners, passed_unix_listeners) = systemd_listeners()?;
39 #[cfg(not(unix))]
40 let passed_tcp_listeners: Vec<TcpListener> = Vec::new();
41
42 let addrs = config.get_bind_addrs();
43
44 #[cfg(unix)]
45 let mut listening = passed_addrs(&passed_tcp_listeners)?;
46 #[cfg(not(unix))]
47 let mut listening: Vec<SocketAddr> = Vec::new();
48
49 #[cfg(unix)]
50 let socket_path = unpassed_path(socket_path.as_deref(), &passed_unix_listeners)?;
51 #[cfg(not(unix))]
52 let socket_path = socket_path.as_deref();
53
54 let defaulted = config.is_address_defaulted();
55 let tcp_listeners = bind_addrs(&addrs, &mut listening, defaulted)?;
56
57 #[cfg(unix)]
58 let log_addrs = make_log_addrs(
59 &tcp_listeners,
60 socket_path,
61 &passed_tcp_listeners,
62 &passed_unix_listeners,
63 )?;
64 #[cfg(not(unix))]
65 let log_addrs = make_log_addrs(&tcp_listeners, socket_path, &passed_tcp_listeners)?;
66
67 let mut futures = vec![];
68
69 #[cfg(unix)]
70 {
71 let socket_perms = config.get_unix_socket_perms()?;
72
73 let unix_futures = unix::serve(
74 &app,
75 &handle.handle_unix,
76 passed_unix_listeners.into_iter(),
77 socket_path,
78 socket_perms,
79 )
80 .await?;
81
82 futures.extend(unix_futures);
83 };
84
85 #[cfg_attr(
86 not(feature = "direct_tls"),
87 expect(clippy::redundant_else, unused_variables)
88 )]
89 if let Some((cert, key)) = config.tls.get_tls_cert_key() {
90 #[cfg(feature = "direct_tls")]
91 {
92 services.globals.init_rustls_provider()?;
93
94 let listeners = tcp_listeners
95 .into_iter()
96 .chain(passed_tcp_listeners);
97
98 let tls_futures = tls::serve(
99 &app,
100 &handle.handle_ip,
101 cert,
102 key,
103 config.tls.dual_protocol,
104 listeners,
105 )
106 .await?;
107
108 futures.extend(tls_futures);
109 }
110
111 #[cfg(not(feature = "direct_tls"))]
112 return tuwunel_core::Err!(Config(
113 "tls",
114 "tuwunel was not built with direct TLS support (\"direct_tls\")"
115 ));
116 } else {
117 let listeners = tcp_listeners
118 .into_iter()
119 .chain(passed_tcp_listeners);
120
121 let plain_futures = plain::serve(&app, &handle.handle_ip, listeners)?;
122
123 futures.extend(plain_futures);
124 }
125
126 for future in futures {
127 join_set.spawn_on(future, server.runtime());
128 }
129
130 if join_set.is_empty() {
131 return Err!("at least one listener should be installed");
132 }
133
134 info!("Listening on {log_addrs:?}");
135
136 join_set
137 .join_all()
138 .await
139 .into_iter()
140 .filter_map(Result::err)
141 .for_each(|e| error!("Listener stopped: {e}"));
142
143 let handle_active = server
144 .metrics
145 .requests_handle_active
146 .load(Ordering::Acquire);
147
148 debug_info!(
149 handle_finished = server
150 .metrics
151 .requests_handle_finished
152 .load(Ordering::Acquire),
153 panics = server
154 .metrics
155 .requests_panic
156 .load(Ordering::Acquire),
157 handle_active,
158 "Stopped listening on {log_addrs:?}",
159 );
160
161 debug_assert_eq!(0, handle_active, "active request handles still pending");
162
163 Ok(())
164}
165
166#[cfg(unix)]
168fn passed_addrs(listeners: &[TcpListener]) -> Result<Vec<SocketAddr>> {
169 listeners
170 .iter()
171 .map(listening_addrs)
172 .flatten_ok()
173 .try_collect()
174}
175
176fn listening_addrs(listener: &TcpListener) -> Result<impl Iterator<Item = SocketAddr> + use<>> {
180 let addr = listener.local_addr()?;
181
182 #[cfg(unix)]
183 let dual_stack = addr.is_ipv6() && addr.ip().is_unspecified() && !is_ipv6_only(listener)?;
184 #[cfg(not(unix))]
185 let dual_stack = false;
186
187 let wildcard = dual_stack.then(|| SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), addr.port()));
188
189 Ok(wildcard.into_iter().chain(once(addr)))
190}
191
192fn covers(listening: &SocketAddr, addr: &SocketAddr) -> bool {
195 listening.port() == addr.port()
196 && (listening.ip() == addr.ip()
197 || (listening.ip().is_unspecified() && listening.is_ipv6() == addr.is_ipv6()))
198}
199
200#[cfg(unix)]
203fn unpassed_path<'a>(
204 path: Option<&'a Path>,
205 listeners: &[UnixListener],
206) -> Result<Option<&'a Path>> {
207 let Some(configured) = path else {
208 return Ok(None);
209 };
210
211 let covered = listeners
212 .iter()
213 .map(UnixListener::local_addr)
214 .process_results(|mut addrs| {
215 addrs.any(|addr| {
216 addr.as_pathname()
217 .is_some_and(|passed| same_path(configured, passed))
218 })
219 })?;
220
221 if covered {
222 info!(?configured, "Not binding: the service manager passed a listener for it.");
223 }
224
225 Ok(path.filter(|_| !covered))
226}
227
228#[cfg(unix)]
230fn same_path(configured: &Path, passed: &Path) -> bool {
231 configured == passed
232 || matches!(
233 (configured.canonicalize(), passed.canonicalize()),
234 (Ok(configured), Ok(passed)) if configured == passed
235 )
236}
237
238fn bind_addrs(
245 addrs: &[SocketAddr],
246 listening: &mut Vec<SocketAddr>,
247 defaulted: bool,
248) -> Result<Vec<TcpListener>> {
249 let mut listeners = Vec::with_capacity(addrs.len());
250
251 let mut addrs = addrs.to_vec();
255 addrs.sort_by_key(SocketAddr::is_ipv4);
256
257 for addr in &addrs {
258 if listening.iter().any(|other| covers(other, addr)) {
259 info!(%addr, "Not binding: a listener already answers for it.");
260 continue;
261 }
262
263 let listener = match TcpListener::bind(addr) {
264 | Ok(listener) => listener,
265 | Err(e) if defaulted => {
266 error!(%addr, %e, "Not binding: the default address is unavailable.");
267 continue;
268 },
269 | Err(e) => return Err!(Config("address", "Failed to bind {addr}: {e}")),
270 };
271
272 listener.set_nonblocking(true)?;
273 listening.extend(listening_addrs(&listener)?);
274 listeners.push(listener);
275 }
276
277 Ok(listeners)
278}
279
280#[cfg(unix)]
281fn make_log_addrs(
282 tcp_listeners: &[TcpListener],
283 unix_path: Option<&Path>,
284 passed_tcp_listeners: &[TcpListener],
285 passed_unix_listeners: &[UnixListener],
286) -> Result<Vec<String>> {
287 let tcp_log_addrs = tcp_listeners
288 .iter()
289 .map(|listener| Ok(format!("tcp:{}", listener.local_addr()?)));
290
291 let unix_log_addr = unix_path.as_ref().map(|socket_path| {
292 let path = socket_path.to_string_lossy();
293
294 format!("unix:{path}")
295 });
296
297 let passed_tcp_log_addrs = passed_tcp_listeners.iter().map(|listener| {
298 let addr = listener.local_addr()?;
299
300 Ok(format!("passed:tcp:{addr}"))
301 });
302
303 let passed_unix_log_addrs = passed_unix_listeners.iter().map(|listener| {
304 let addr = listener.local_addr()?;
305 let log_path = addr
306 .as_pathname()
307 .map_or(Cow::Borrowed("?"), Path::to_string_lossy);
308
309 Ok(format!("passed:unix:{log_path}"))
310 });
311
312 tcp_log_addrs
313 .chain(unix_log_addr.into_iter().map(Ok))
314 .chain(passed_tcp_log_addrs)
315 .chain(passed_unix_log_addrs)
316 .collect()
317}
318
319#[cfg(all(unix, feature = "systemd", target_os = "linux"))]
320fn systemd_listeners() -> Result<(Vec<TcpListener>, Vec<UnixListener>)> {
321 use std::os::fd::FromRawFd;
322
323 use tuwunel_core::utils::sys::{SocketFamily, get_socket_family};
324
325 let mut tcp = vec![];
326 let mut unix = vec![];
327
328 for fd in sd_notify::listen_fds()? {
329 debug_assert!(fd >= 3, "fdno probably not a listener socket");
330
331 let family = get_socket_family(fd)?;
332
333 match family {
334 | SocketFamily::Inet => {
335 let listener = unsafe { TcpListener::from_raw_fd(fd) };
338
339 listener.set_nonblocking(true)?;
340
341 tcp.push(listener);
342 },
343 | SocketFamily::Unix => {
344 let listener = unsafe { UnixListener::from_raw_fd(fd) };
347
348 listener.set_nonblocking(true)?;
349
350 unix.push(listener);
351 },
352 }
353 }
354
355 Ok((tcp, unix))
356}
357
358#[cfg(all(
359 unix,
360 any(not(feature = "systemd"), not(target_os = "linux"))
361))]
362fn systemd_listeners() -> Result<(Vec<TcpListener>, Vec<UnixListener>)> { Ok((vec![], vec![])) }
363
364#[cfg(not(unix))]
365fn make_log_addrs(
366 tcp_listeners: &[TcpListener],
367 unix_path: Option<&Path>,
368 passed_tcp_listeners: &[TcpListener],
369) -> Result<Vec<String>> {
370 let tcp_log_addrs = tcp_listeners
371 .iter()
372 .map(|listener| Ok(format!("tcp:{}", listener.local_addr()?)));
373
374 let unix_log_addr = unix_path.as_ref().map(|socket_path| {
375 let path = socket_path.to_string_lossy();
376 format!("unix:{path}")
377 });
378
379 let passed_tcp_log_addrs = passed_tcp_listeners.iter().map(|listener| {
380 let addr = listener.local_addr()?;
381 Ok(format!("passed:tcp:{addr}"))
382 });
383
384 tcp_log_addrs
385 .chain(unix_log_addr.into_iter().map(Ok))
386 .chain(passed_tcp_log_addrs)
387 .collect()
388}