1mod constants;
2pub mod dns;
3mod dns_json;
4mod edns_ecs;
5mod errors;
6mod globals;
7pub mod odoh;
8#[cfg(feature = "tls")]
9mod tls;
10
11use std::net::{IpAddr, SocketAddr};
12use std::pin::Pin;
13use std::sync::Arc;
14use std::time::Duration;
15
16use base64::engine::Engine;
17use byteorder::{BigEndian, ByteOrder};
18use futures::prelude::*;
19use futures::task::{Context, Poll};
20use hyper::http;
21use hyper::server::conn::Http;
22use hyper::{Body, HeaderMap, Method, Request, Response, StatusCode};
23use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
24use tokio::net::{TcpListener, TcpSocket, UdpSocket};
25use tokio::runtime;
26
27use crate::constants::*;
28pub use crate::errors::*;
29pub use crate::globals::*;
30
31pub mod reexports {
32 pub use tokio;
33}
34
35const BASE64_URL_SAFE_NO_PAD: base64::engine::GeneralPurpose =
36 base64::engine::general_purpose::GeneralPurpose::new(
37 &base64::alphabet::URL_SAFE,
38 base64::engine::general_purpose::GeneralPurposeConfig::new()
39 .with_encode_padding(false)
40 .with_decode_padding_mode(base64::engine::DecodePaddingMode::Indifferent),
41 );
42
43#[derive(Clone, Debug)]
44struct DnsResponse {
45 packet: Vec<u8>,
46 ttl: u32,
47}
48
49#[derive(Clone, Debug)]
50enum DoHType {
51 Standard,
52 Oblivious,
53 Json,
54}
55
56impl DoHType {
57 fn as_str(&self) -> String {
58 match self {
59 DoHType::Standard => String::from("application/dns-message"),
60 DoHType::Oblivious => String::from("application/oblivious-dns-message"),
61 DoHType::Json => String::from("application/dns-json"),
62 }
63 }
64}
65
66#[derive(Clone, Debug)]
67pub struct DoH {
68 pub globals: Arc<Globals>,
69 pub remote_addr: Option<SocketAddr>,
70}
71
72#[allow(clippy::unnecessary_wraps)]
73fn http_error(status_code: StatusCode) -> Result<Response<Body>, http::Error> {
74 let response = Response::builder()
75 .status(status_code)
76 .body(Body::empty())
77 .unwrap();
78 Ok(response)
79}
80
81#[allow(clippy::unnecessary_wraps)]
82fn http_error_with_cache(status_code: StatusCode) -> Result<Response<Body>, http::Error> {
83 let response = Response::builder()
85 .status(status_code)
86 .header(hyper::header::CACHE_CONTROL, "max-age=31536000, immutable")
87 .body(Body::empty())
88 .unwrap();
89 Ok(response)
90}
91
92#[derive(Clone, Debug)]
93pub struct LocalExecutor {
94 runtime_handle: runtime::Handle,
95}
96
97impl LocalExecutor {
98 fn new(runtime_handle: runtime::Handle) -> Self {
99 LocalExecutor { runtime_handle }
100 }
101}
102
103impl<F> hyper::rt::Executor<F> for LocalExecutor
104where
105 F: std::future::Future + Send + 'static,
106 F::Output: Send,
107{
108 fn execute(&self, fut: F) {
109 self.runtime_handle.spawn(fut);
110 }
111}
112
113#[allow(clippy::type_complexity)]
114impl hyper::service::Service<http::Request<Body>> for DoH {
115 type Error = http::Error;
116 type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
117 type Response = Response<Body>;
118
119 fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
120 Poll::Ready(Ok(()))
121 }
122
123 fn call(&mut self, req: Request<Body>) -> Self::Future {
124 let globals = &self.globals;
125 let self_inner = self.clone();
126 if req.uri().path() == globals.path {
127 match *req.method() {
128 Method::POST => Box::pin(async move { self_inner.serve_post(req).await }),
129 Method::GET => Box::pin(async move { self_inner.serve_get(req).await }),
130 _ => Box::pin(async { http_error(StatusCode::METHOD_NOT_ALLOWED) }),
131 }
132 } else if req.uri().path() == globals.odoh_configs_path {
133 match *req.method() {
134 Method::GET => Box::pin(async move { self_inner.serve_odoh_configs().await }),
135 _ => Box::pin(async { http_error(StatusCode::METHOD_NOT_ALLOWED) }),
136 }
137 } else {
138 Box::pin(async { http_error(StatusCode::NOT_FOUND) })
139 }
140 }
141}
142
143impl DoH {
144 async fn serve_get(&self, req: Request<Body>) -> Result<Response<Body>, http::Error> {
145 match Self::parse_content_type(&req) {
146 Ok(DoHType::Standard) => self.serve_doh_get(req).await,
147 Ok(DoHType::Oblivious) => self.serve_odoh_get(req).await,
148 Ok(DoHType::Json) => self.serve_json_get(req).await,
149 Err(response) => Ok(*response),
150 }
151 }
152
153 async fn serve_post(&self, req: Request<Body>) -> Result<Response<Body>, http::Error> {
154 match Self::parse_content_type(&req) {
155 Ok(DoHType::Standard) => self.serve_doh_post(req).await,
156 Ok(DoHType::Oblivious) => self.serve_odoh_post(req).await,
157 Ok(DoHType::Json) => http_error(StatusCode::METHOD_NOT_ALLOWED),
158 Err(response) => Ok(*response),
159 }
160 }
161
162 async fn serve_doh_query(
163 &self,
164 query: Vec<u8>,
165 client_ip: Option<IpAddr>,
166 ) -> Result<Response<Body>, http::Error> {
167 let resp = match self.proxy(query, client_ip).await {
168 Ok(resp) => {
169 self.build_response(resp.packet, resp.ttl, DoHType::Standard.as_str(), true)
170 }
171 Err(e) => return http_error(StatusCode::from(e)),
172 };
173 match resp {
174 Ok(resp) => Ok(resp),
175 Err(e) => http_error(StatusCode::from(e)),
176 }
177 }
178
179 fn query_from_query_string(&self, req: Request<Body>) -> Option<Vec<u8>> {
180 let http_query = req.uri().query().unwrap_or("");
181 let mut question_str = None;
182 for parts in http_query.split('&') {
183 let mut kv = parts.split('=');
184 if let Some(k) = kv.next() {
185 if k == DNS_QUERY_PARAM {
186 question_str = kv.next();
187 }
188 }
189 }
190 if let Some(question_str) = question_str {
191 if question_str.len() > MAX_DNS_QUESTION_LEN * 4 / 3 {
192 return None;
193 }
194 }
195 let query = match question_str
196 .and_then(|question_str| BASE64_URL_SAFE_NO_PAD.decode(question_str).ok())
197 {
198 Some(query) => query,
199 _ => return None,
200 };
201 Some(query)
202 }
203
204 async fn serve_doh_get(&self, req: Request<Body>) -> Result<Response<Body>, http::Error> {
205 let client_ip = if self.globals.enable_ecs {
206 edns_ecs::extract_client_ip(req.headers(), self.remote_addr)
207 } else {
208 None
209 };
210
211 let query = match self.query_from_query_string(req) {
212 Some(query) => query,
213 _ => return http_error_with_cache(StatusCode::BAD_REQUEST),
214 };
215 self.serve_doh_query(query, client_ip).await
216 }
217
218 async fn serve_doh_post(&self, req: Request<Body>) -> Result<Response<Body>, http::Error> {
219 if self.globals.disable_post {
220 return http_error(StatusCode::METHOD_NOT_ALLOWED);
221 }
222
223 let client_ip = if self.globals.enable_ecs {
224 edns_ecs::extract_client_ip(req.headers(), self.remote_addr)
225 } else {
226 None
227 };
228
229 let query = match self.read_body(req.into_body()).await {
230 Ok(q) => q,
231 Err(e) => return http_error(StatusCode::from(e)),
232 };
233 self.serve_doh_query(query, client_ip).await
234 }
235
236 async fn serve_odoh(&self, encrypted_query: Vec<u8>) -> Result<Response<Body>, http::Error> {
237 let odoh_public_key = (*self.globals.odoh_rotator).clone().current_public_key();
238 let (query, context) = match (*odoh_public_key).clone().decrypt_query(encrypted_query) {
239 Ok((q, context)) => (q.to_vec(), context),
240 Err(e) => return http_error(StatusCode::from(e)),
241 };
242 let resp = match self.proxy(query, None).await {
243 Ok(resp) => resp,
244 Err(e) => return http_error(StatusCode::from(e)),
245 };
246 let encrypted_resp = match context.encrypt_response(resp.packet) {
247 Ok(resp) => self.build_response(resp, 0u32, DoHType::Oblivious.as_str(), false),
248 Err(e) => return http_error(StatusCode::from(e)),
249 };
250
251 match encrypted_resp {
252 Ok(resp) => Ok(resp),
253 Err(e) => http_error(StatusCode::from(e)),
254 }
255 }
256
257 async fn serve_odoh_get(&self, req: Request<Body>) -> Result<Response<Body>, http::Error> {
258 let encrypted_query = match self.query_from_query_string(req) {
259 Some(encrypted_query) => encrypted_query,
260 _ => return http_error_with_cache(StatusCode::BAD_REQUEST),
261 };
262 self.serve_odoh(encrypted_query).await
263 }
264
265 async fn serve_odoh_post(&self, req: Request<Body>) -> Result<Response<Body>, http::Error> {
266 if self.globals.disable_post && !self.globals.allow_odoh_post {
267 return http_error(StatusCode::METHOD_NOT_ALLOWED);
268 }
269 let encrypted_query = match self.read_body(req.into_body()).await {
270 Ok(q) => q,
271 Err(e) => return http_error(StatusCode::from(e)),
272 };
273 self.serve_odoh(encrypted_query).await
274 }
275
276 async fn serve_odoh_configs(&self) -> Result<Response<Body>, http::Error> {
277 let odoh_public_key = (*self.globals.odoh_rotator).clone().current_public_key();
278 let configs = (*odoh_public_key).clone().into_config();
279 match self.build_response(
280 configs,
281 ODOH_KEY_ROTATION_SECS,
282 "application/octet-stream".to_string(),
283 true,
284 ) {
285 Ok(resp) => Ok(resp),
286 Err(e) => http_error(StatusCode::from(e)),
287 }
288 }
289
290 async fn serve_json_get(&self, req: Request<Body>) -> Result<Response<Body>, http::Error> {
291 use serde_json::json;
292
293 let query_params = req.uri().query().unwrap_or("");
295 let mut json_query = dns_json::DnsJsonQuery {
296 name: String::new(),
297 qtype: None,
298 cd: None,
299 ct: None,
300 do_: None,
301 edns_client_subnet: None,
302 };
303
304 for parts in query_params.split('&') {
306 let mut kv = parts.split('=');
307 if let (Some(k), Some(v)) = (kv.next(), kv.next()) {
308 match k {
309 "name" => {
310 json_query.name = urlencoding::decode(v).unwrap_or_default().into_owned()
311 }
312 "type" => json_query.qtype = v.parse().ok(),
313 "cd" => json_query.cd = Some(v == "1" || v == "true"),
314 "ct" => json_query.ct = Some(v.to_string()),
315 "do" => json_query.do_ = Some(v == "1" || v == "true"),
316 "edns_client_subnet" => json_query.edns_client_subnet = Some(v.to_string()),
317 _ => {}
318 }
319 }
320 }
321
322 if json_query.name.is_empty() {
324 let error_response = json!({
325 "Status": 400,
326 "Comment": "Missing 'name' parameter"
327 });
328 return Response::builder()
329 .status(StatusCode::BAD_REQUEST)
330 .header(hyper::header::CONTENT_TYPE, "application/dns-json")
331 .body(Body::from(error_response.to_string()))
332 .or_else(|_| http_error(StatusCode::INTERNAL_SERVER_ERROR));
333 }
334
335 let query_packet = match dns_json::build_dns_query(&json_query) {
337 Ok(packet) => packet,
338 Err(e) => {
339 let error_response = json!({
340 "Status": 400,
341 "Comment": format!("Invalid query: {}", e)
342 });
343 return Response::builder()
344 .status(StatusCode::BAD_REQUEST)
345 .header(hyper::header::CONTENT_TYPE, "application/dns-json")
346 .body(Body::from(error_response.to_string()))
347 .or_else(|_| http_error(StatusCode::INTERNAL_SERVER_ERROR));
348 }
349 };
350
351 let client_ip = if self.globals.enable_ecs {
353 edns_ecs::extract_client_ip(req.headers(), self.remote_addr)
354 } else {
355 None
356 };
357
358 let dns_response = match self.proxy(query_packet, client_ip).await {
360 Ok(resp) => resp,
361 Err(e) => return http_error(StatusCode::from(e)),
362 };
363
364 match dns_json::parse_dns_to_json(&dns_response.packet) {
366 Ok(json_response) => {
367 let json_string = match serde_json::to_string(&json_response) {
368 Ok(s) => s,
369 Err(_) => return http_error(StatusCode::INTERNAL_SERVER_ERROR),
370 };
371
372 Response::builder()
373 .status(StatusCode::OK)
374 .header(hyper::header::CONTENT_TYPE, "application/dns-json")
375 .header(
376 hyper::header::CACHE_CONTROL,
377 format!(
378 "max-age={}, stale-if-error={}, stale-while-revalidate={}",
379 dns_response.ttl, STALE_IF_ERROR_SECS, STALE_WHILE_REVALIDATE_SECS
380 ),
381 )
382 .header(hyper::header::ACCESS_CONTROL_ALLOW_ORIGIN, "*")
383 .body(Body::from(json_string))
384 .or_else(|_| http_error(StatusCode::INTERNAL_SERVER_ERROR))
385 }
386 Err(e) => {
387 let error_response = json!({
388 "Status": 500,
389 "Comment": format!("Failed to parse DNS response: {}", e)
390 });
391 Response::builder()
392 .status(StatusCode::INTERNAL_SERVER_ERROR)
393 .header(hyper::header::CONTENT_TYPE, "application/dns-json")
394 .body(Body::from(error_response.to_string()))
395 .or_else(|_| http_error(StatusCode::INTERNAL_SERVER_ERROR))
396 }
397 }
398 }
399
400 fn acceptable_content_type(
401 headers: &HeaderMap,
402 content_types: &[&'static str],
403 ) -> Option<&'static str> {
404 let accept = headers.get(hyper::header::ACCEPT);
405 let accept = accept?;
406 for part in accept.to_str().unwrap_or("").split(',').map(|s| s.trim()) {
407 if let Some(found) = part
408 .split(';')
409 .next()
410 .map(|s| s.trim().to_ascii_lowercase())
411 {
412 if let Some(&content_type) = content_types
413 .iter()
414 .find(|&&content_type| content_type == found)
415 {
416 return Some(content_type);
417 }
418 }
419 }
420 None
421 }
422
423 fn parse_content_type(req: &Request<Body>) -> Result<DoHType, Box<Response<Body>>> {
424 const CT_DOH: &str = "application/dns-message";
425 const CT_ODOH: &str = "application/oblivious-dns-message";
426 const CT_JSON: &str = "application/dns-json";
427
428 let headers = req.headers();
429 let content_type = match headers.get(hyper::header::CONTENT_TYPE) {
430 None => {
431 let acceptable_content_type =
432 Self::acceptable_content_type(headers, &[CT_DOH, CT_ODOH, CT_JSON]);
433 match acceptable_content_type {
434 None => {
435 let response = Response::builder()
437 .status(StatusCode::NOT_ACCEPTABLE)
438 .header(hyper::header::CACHE_CONTROL, "max-age=31536000, immutable")
439 .body(Body::empty())
440 .unwrap();
441 return Err(Box::new(response));
442 }
443 Some(content_type) => content_type,
444 }
445 }
446 Some(content_type) => match content_type.to_str() {
447 Err(_) => {
448 let response = Response::builder()
450 .status(StatusCode::BAD_REQUEST)
451 .header(hyper::header::CACHE_CONTROL, "max-age=31536000, immutable")
452 .body(Body::empty())
453 .unwrap();
454 return Err(Box::new(response));
455 }
456 Ok(content_type) => content_type,
457 },
458 };
459
460 match content_type.to_ascii_lowercase().as_str() {
461 CT_DOH => Ok(DoHType::Standard),
462 CT_ODOH => Ok(DoHType::Oblivious),
463 CT_JSON => Ok(DoHType::Json),
464 _ => {
465 let response = Response::builder()
467 .status(StatusCode::UNSUPPORTED_MEDIA_TYPE)
468 .header(hyper::header::CACHE_CONTROL, "max-age=31536000, immutable")
469 .body(Body::empty())
470 .unwrap();
471 Err(Box::new(response))
472 }
473 }
474 }
475
476 async fn read_body(&self, mut body: Body) -> Result<Vec<u8>, DoHError> {
477 let mut sum_size = 0;
478 let mut query = vec![];
479 while let Some(chunk) = body.next().await {
480 let chunk = chunk.map_err(|_| DoHError::TooLarge)?;
481 sum_size += chunk.len();
482 if sum_size >= MAX_DNS_QUESTION_LEN {
483 return Err(DoHError::TooLarge);
484 }
485 query.extend(chunk);
486 }
487 Ok(query)
488 }
489
490 async fn proxy(
491 &self,
492 query: Vec<u8>,
493 client_ip: Option<IpAddr>,
494 ) -> Result<DnsResponse, DoHError> {
495 let proxy_timeout = self.globals.timeout;
496 let timeout_res = tokio::time::timeout(proxy_timeout, self._proxy(query, client_ip)).await;
497 timeout_res.map_err(|_| DoHError::UpstreamTimeout)?
498 }
499
500 async fn _proxy(
501 &self,
502 mut query: Vec<u8>,
503 client_ip: Option<IpAddr>,
504 ) -> Result<DnsResponse, DoHError> {
505 if query.len() < MIN_DNS_PACKET_LEN {
506 return Err(DoHError::Incomplete);
507 }
508 let _ = dns::set_edns_max_payload_size(&mut query, MAX_DNS_RESPONSE_LEN as _);
509
510 if self.globals.enable_ecs {
512 if let Some(client_ip) = client_ip {
513 if let Err(e) = edns_ecs::add_ecs_to_packet(
514 &mut query,
515 client_ip,
516 self.globals.ecs_prefix_v4,
517 self.globals.ecs_prefix_v6,
518 ) {
519 eprintln!("Failed to add EDNS Client Subnet: {}", e);
520 }
521 }
522 }
523 let globals = &self.globals;
524 let mut packet = vec![0; MAX_DNS_RESPONSE_LEN];
525 let (min_ttl, max_ttl, err_ttl) = (globals.min_ttl, globals.max_ttl, globals.err_ttl);
526
527 {
529 let socket = UdpSocket::bind(&globals.local_bind_address)
530 .await
531 .map_err(DoHError::Io)?;
532 let expected_server_address = globals.server_address;
533 socket
534 .send_to(&query, &globals.server_address)
535 .map_err(DoHError::Io)
536 .await?;
537 let (len, response_server_address) =
538 socket.recv_from(&mut packet).map_err(DoHError::Io).await?;
539 if len < MIN_DNS_PACKET_LEN || expected_server_address != response_server_address {
540 return Err(DoHError::UpstreamIssue);
541 }
542 packet.truncate(len);
543 }
544
545 if dns::is_truncated(&packet) {
547 let clients_count = self.globals.clients_count.current();
548 if self.globals.max_clients >= UDP_TCP_RATIO
549 && clients_count >= self.globals.max_clients / UDP_TCP_RATIO
550 {
551 return Err(DoHError::TooManyTcpSessions);
552 }
553 let socket = match globals.server_address {
554 SocketAddr::V4(_) => TcpSocket::new_v4(),
555 SocketAddr::V6(_) => TcpSocket::new_v6(),
556 }
557 .map_err(DoHError::Io)?;
558 let mut ext_socket = socket
559 .connect(globals.server_address)
560 .await
561 .map_err(DoHError::Io)?;
562 ext_socket.set_nodelay(true).map_err(DoHError::Io)?;
563 let mut binlen = [0u8, 0];
564 BigEndian::write_u16(&mut binlen, query.len() as u16);
565 ext_socket.write_all(&binlen).await.map_err(DoHError::Io)?;
566 ext_socket.write_all(&query).await.map_err(DoHError::Io)?;
567 ext_socket.flush().await.map_err(DoHError::Io)?;
568 ext_socket
569 .read_exact(&mut binlen)
570 .await
571 .map_err(DoHError::Io)?;
572 let packet_len = BigEndian::read_u16(&binlen) as usize;
573 if !(MIN_DNS_PACKET_LEN..=MAX_DNS_RESPONSE_LEN).contains(&packet_len) {
574 return Err(DoHError::UpstreamIssue);
575 }
576 packet = vec![0u8; packet_len];
577 ext_socket
578 .read_exact(&mut packet)
579 .await
580 .map_err(DoHError::Io)?;
581 }
582
583 let ttl = if dns::is_recoverable_error(&packet) {
584 err_ttl
585 } else {
586 match dns::min_ttl(&packet, min_ttl, max_ttl, err_ttl) {
587 Err(_) => return Err(DoHError::UpstreamIssue),
588 Ok(ttl) => ttl,
589 }
590 };
591 dns::add_edns_padding(&mut packet)
592 .map_err(|_| DoHError::TooLarge)
593 .ok();
594 Ok(DnsResponse { packet, ttl })
595 }
596
597 fn build_response(
598 &self,
599 packet: Vec<u8>,
600 ttl: u32,
601 content_type: String,
602 cors: bool,
603 ) -> Result<Response<Body>, DoHError> {
604 let packet_len = packet.len();
605 let mut response_builder = Response::builder()
606 .header(hyper::header::CONTENT_LENGTH, packet_len)
607 .header(hyper::header::CONTENT_TYPE, content_type.as_str())
608 .header(
609 hyper::header::CACHE_CONTROL,
610 format!(
611 "max-age={ttl}, stale-if-error={STALE_IF_ERROR_SECS}, \
612 stale-while-revalidate={STALE_WHILE_REVALIDATE_SECS}"
613 )
614 .as_str(),
615 );
616 if cors {
617 response_builder =
618 response_builder.header(hyper::header::ACCESS_CONTROL_ALLOW_ORIGIN, "*");
619 }
620 let response = response_builder
621 .body(Body::from(packet))
622 .map_err(|_| DoHError::InvalidData)?;
623 Ok(response)
624 }
625
626 async fn client_serve<I>(self, stream: I, server: Http<LocalExecutor>)
627 where
628 I: AsyncRead + AsyncWrite + Send + Unpin + 'static,
629 {
630 let clients_count = self.globals.clients_count.clone();
631 if clients_count.increment() > self.globals.max_clients {
632 clients_count.decrement();
633 return;
634 }
635 self.globals.runtime_handle.clone().spawn(async move {
636 tokio::time::timeout(
637 self.globals.timeout + Duration::from_secs(1),
638 server.serve_connection(stream, self),
639 )
640 .await
641 .ok();
642 clients_count.decrement();
643 });
644 }
645
646 async fn start_without_tls(
647 self,
648 listener: TcpListener,
649 server: Http<LocalExecutor>,
650 ) -> Result<(), DoHError> {
651 let listener_service = async {
652 while let Ok((stream, client_addr)) = listener.accept().await {
653 let mut doh = self.clone();
654 doh.remote_addr = Some(client_addr);
655 doh.client_serve(stream, server.clone()).await;
656 }
657 Ok(()) as Result<(), DoHError>
658 };
659 listener_service.await?;
660 Ok(())
661 }
662
663 pub async fn entrypoint(self) -> Result<(), DoHError> {
664 let listen_address = self.globals.listen_address;
665 let listener = TcpListener::bind(&listen_address)
666 .await
667 .map_err(DoHError::Io)?;
668 let path = &self.globals.path;
669
670 let tls_enabled: bool;
671 #[cfg(not(feature = "tls"))]
672 {
673 tls_enabled = false;
674 }
675 #[cfg(feature = "tls")]
676 {
677 tls_enabled =
678 self.globals.tls_cert_path.is_some() && self.globals.tls_cert_key_path.is_some();
679 }
680 if tls_enabled {
681 println!("Listening on https://{listen_address}{path}");
682 } else {
683 println!("Listening on http://{listen_address}{path}");
684 }
685
686 let mut server = Http::new();
687 server.http1_keep_alive(self.globals.keepalive);
688 server.http2_max_concurrent_streams(self.globals.max_concurrent_streams);
689 server.pipeline_flush(true);
690 let executor = LocalExecutor::new(self.globals.runtime_handle.clone());
691 let server = server.with_executor(executor);
692
693 #[cfg(feature = "tls")]
694 {
695 if tls_enabled {
696 self.start_with_tls(listener, server).await?;
697 return Ok(());
698 }
699 }
700 self.start_without_tls(listener, server).await?;
701 Ok(())
702 }
703}