1pub use crate::args::Args;
2pub use crate::error::{BoxError, Error, Result};
3use crate::udp_server::UdpServer;
4#[cfg(target_os = "windows")]
5pub use crate::windows::start_service;
6use futures::stream::StreamExt;
7use std::net::SocketAddr;
8use tokio::net::UdpSocket;
9use tokio_util::sync::CancellationToken;
10
11mod args;
12mod error;
13mod udp_server;
14mod upstream;
15mod windows;
16
17static SHUTTING_DOWN_TOKEN: std::sync::Mutex<Option<CancellationToken>> = std::sync::Mutex::new(None);
18
19pub async fn main_loop(args: &Args) -> Result<()> {
20 let shutdown_token = CancellationToken::new();
21 if let Ok(mut lock) = SHUTTING_DOWN_TOKEN.lock() {
22 if lock.is_some() {
23 return Err("dns-over-https already started".into());
24 }
25 *lock = Some(shutdown_token.clone());
26 }
27
28 let mut tasks = Vec::new();
29
30 for bind in args.bind.clone() {
31 let shutdown_token = shutdown_token.clone();
32 let args = args.clone();
33 let task = tokio::spawn(async move { _main_loop(shutdown_token, bind, &args).await });
34 tasks.push(task);
35 }
36
37 let results = futures::future::join_all(tasks).await;
38
39 for result in results {
40 if let Err(e) = result {
41 log::error!("Error in main loop: {:?}", e);
42 }
43 }
44 Ok(())
45}
46
47#[no_mangle]
51pub unsafe extern "C" fn dns_over_https_stop() -> std::ffi::c_int {
52 log::info!("Shutting down...");
53 if let Ok(mut token) = SHUTTING_DOWN_TOKEN.lock() {
54 if let Some(token) = token.take() {
55 token.cancel();
56 }
57 }
58 0
59}
60
61async fn _main_loop(quit: CancellationToken, bind: SocketAddr, args: &Args) -> Result<()> {
62 log::info!("Listening for DNS requests on {}...", bind);
63
64 let socket = UdpSocket::bind(bind).await?;
65
66 let mut server = UdpServer::new(&socket);
67
68 let client = reqwest::Client::new();
69 let upstreams = args.upstreams(&client);
70
71 loop {
72 tokio::select! {
73 _ = quit.cancelled() => {
74 log::info!("Listener on {} is shutting down...", bind);
75 break;
76 }
77 result = server.next() => {
78 match result.ok_or("error during receiving request")? {
79 Ok(request) => {
80 for upstream in upstreams.iter() {
81 match upstream.send(&request).await {
82 Ok(response) => {
83 server.reply(&request, &response).await?;
84 break;
85 }
86 Err(e) => {
87 log::error!("error during sending request: {:?}", e);
88 continue;
89 }
90 }
91 }
92 }
93 Err(e) => log::trace!("error during DNS request: {:?}", e),
94 }
95 }
96 }
97 }
98 Ok(())
99}