Skip to main content

sidedns_core/
runner.rs

1use std::sync::Arc;
2
3use tokio::sync::broadcast;
4use tokio_util::sync::CancellationToken;
5
6use crate::certs;
7use crate::ipc::IpcServer;
8use crate::state::AppState;
9use crate::{DnsEvent, dns, proxy};
10
11/// Run the daemon until a shutdown signal is received.
12#[tracing::instrument(skip(token), name = "Daemon")]
13pub async fn run(token: Option<CancellationToken>) -> anyhow::Result<()> {
14    tracing::info!("Starting");
15
16    let ca = certs::ca::load()
17        .map_err(|e| {
18            tracing::error!("Failed to load CA certificate: {e}");
19            tracing::warn!("HTTPS proxy disabled. Run 'sidedns cert install'.");
20            e
21        })
22        .ok();
23
24    let token = token.unwrap_or_default();
25    let state = Arc::new(AppState::new(token.clone()));
26    let resolver = Arc::new(dns::DomainResolver::new(state.clone(), ca));
27
28    let rules = state.load_rules();
29    if resolver.is_cert_installed() {
30        for rule in rules.iter().filter(|r| r.https && !r.is_wildcard()) {
31            if resolver.sign_domain(&rule.domain).is_none() {
32                tracing::warn!("failed to restore cert for {}", rule.domain);
33            }
34        }
35    }
36
37    let ipc_task = {
38        let state = state.clone();
39        let token = token.clone();
40        tokio::spawn(async move {
41            if let Err(e) = IpcServer::default().serve(state, token).await {
42                tracing::error!("Ipc Server Run Error: {e}")
43            }
44        })
45    };
46
47    let dns_task = {
48        let token = token.clone();
49        let resolver = resolver.clone();
50        tokio::spawn(async move {
51            if let Err(e) = dns::run_dns_server(resolver, token).await {
52                tracing::error!("DNS Server Run Error: {e}")
53            }
54        })
55    };
56
57    let proxy_task = {
58        let token = token.clone();
59        let resolver = resolver.clone();
60        tokio::spawn(async move {
61            if let Err(e) = proxy::run_proxy_server(resolver, token).await {
62                tracing::error!("Proxy Server Run Error: {e}")
63            }
64        })
65    };
66
67    let dns_manager_task = {
68        let state = state.clone();
69        let token = token.clone();
70        tokio::spawn(async move {
71            if let Err(e) = dns::run_system_dns_manager(state, token).await {
72                tracing::error!("System DNS manager task error: {e}");
73            }
74        })
75    };
76
77    let rules_watch_task = {
78        let mut events = state.events.subscribe();
79        let state = state.clone();
80        let token = token.clone();
81        let resolver = resolver.clone();
82        tokio::spawn(async move {
83            loop {
84                tokio::select! {
85                    _ = token.cancelled() => {
86                        break;
87                    }
88                    event = events.recv() => {
89                        match event {
90                            Ok(event) => match event {
91                                crate::ipc::DnsEvent::RuleAdded(rule)
92                                | crate::ipc::DnsEvent::RuleRemoved(rule) => {
93                                    resolver.invalidate(&rule);
94                                    state.save();
95                                }
96                                crate::ipc::DnsEvent::EphemeralAdded(rule)
97                                | crate::ipc::DnsEvent::EphemeralRemoved(rule) => {
98                                    resolver.invalidate(&rule);
99                                }
100                                _ => {}
101                            },
102                            Err(broadcast::error::RecvError::Lagged(_)) => continue,
103                            Err(broadcast::error::RecvError::Closed) => break,
104                        }
105                    }
106                };
107            }
108        })
109    };
110
111    #[cfg(unix)]
112    let mut sigterm = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())?;
113
114    #[cfg(not(unix))]
115    let sigterm_recv = std::future::pending::<()>();
116    #[cfg(unix)]
117    let sigterm_recv = sigterm.recv();
118
119    tokio::select! {
120        biased;
121        _ = tokio::signal::ctrl_c() => {
122            tracing::info!("Received SIGINT, shutting down");
123            token.cancel();
124        }
125        _ = token.cancelled() => {
126            tracing::info!("Shutdown requested");
127            state.dispatch(DnsEvent::DaemonStopped);
128        }
129        _ = sigterm_recv => {
130            tracing::info!("Received SIGTERM, shutting down");
131            token.cancel();
132        }
133    }
134
135    let (ipc_res, dns_res, proxy_res, dns_manager_res, rules_watch_res) = tokio::join!(
136        ipc_task,
137        dns_task,
138        proxy_task,
139        dns_manager_task,
140        rules_watch_task
141    );
142    if let Err(e) = ipc_res {
143        tracing::error!("IPC task error: {e}");
144    }
145    if let Err(e) = dns_res {
146        tracing::error!("DNS task error: {e}");
147    }
148    if let Err(e) = proxy_res {
149        tracing::error!("Proxy task error: {e}");
150    }
151    if let Err(e) = dns_manager_res {
152        tracing::error!("System DNS manager task error: {e}");
153    }
154    if let Err(e) = rules_watch_res {
155        tracing::error!("Rules watch task error: {e}");
156    }
157
158    tracing::info!("Daemon stopped");
159    Ok(())
160}