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#[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}