sidedns_core/ipc/
handler.rs1use async_trait::async_trait;
2use tokio::sync::broadcast;
3
4use crate::DnsRule;
5use crate::ipc::message::{DnsEvent, IpcRequest, IpcResponse};
6use crate::ipc::server::IpcHandler;
7use crate::state::AppState;
8
9macro_rules! validate_domain {
10 ($domain:ident) => {
11 if !crate::validate_domain(&$domain) {
12 tracing::warn!("Invalid domain name: {}", $domain);
13 return IpcResponse::Error(format!("Invalid domain name: {}", $domain));
14 }
15 let $domain = $domain.to_lowercase();
16 };
17}
18
19#[async_trait]
20impl IpcHandler for AppState {
21 async fn handle(&self, request: IpcRequest) -> IpcResponse {
22 match request {
23 IpcRequest::Add {
24 domain,
25 target,
26 https,
27 } => {
28 validate_domain!(domain);
29 let rule = self.store.add(DnsRule::new(domain.clone(), target, https));
30 tracing::info!("Rule {rule} added");
31 self.events.send(DnsEvent::RuleAdded(rule)).ok();
32 IpcResponse::Ok
33 },
34
35 IpcRequest::AddEphemeral {
36 domain,
37 target,
38 https,
39 } => {
40 validate_domain!(domain);
41 let rule = self
42 .store
43 .add_ephemeral(DnsRule::new(domain.clone(), target, https));
44 tracing::info!("Ephemeral rule {rule} added");
45 self.events.send(DnsEvent::EphemeralAdded(rule)).ok();
46 IpcResponse::Ok
47 },
48
49 IpcRequest::Remove { domain } => {
50 validate_domain!(domain);
51 let removed = self.store.remove(&domain);
52 if let Some(rule) = removed {
53 tracing::info!("Rule {rule} removed");
54 self.events.send(DnsEvent::RuleRemoved(rule)).ok();
55 IpcResponse::Ok
56 } else {
57 IpcResponse::Error(format!("No rule found for '{domain}'"))
58 }
59 },
60
61 IpcRequest::RemoveEphemeral { domain } => {
62 validate_domain!(domain);
63 let removed = self.store.remove_ephemeral(&domain);
64 if let Some(rule) = removed {
65 tracing::info!("Ephemeral rule {rule} removed");
66 self.events.send(DnsEvent::EphemeralRemoved(rule)).ok();
67 IpcResponse::Ok
68 } else {
69 IpcResponse::Error(format!("No ephemeral rule found for '{domain}'"))
70 }
71 },
72
73 IpcRequest::List => {
74 let rules = self.store.snapshot_persistent();
75 IpcResponse::Rules(rules)
76 },
77
78 IpcRequest::Resolve { domain } => {
79 validate_domain!(domain);
80 IpcResponse::Resolved(self.store.resolve(&domain))
81 },
82
83 IpcRequest::Status => IpcResponse::Status {
84 running: true,
85 rule_count: self.store.len(),
86 },
87
88 IpcRequest::Stop => {
89 tracing::info!("Stop requested via IPC");
90 self.events.send(DnsEvent::DaemonStopped).ok();
91 self.token.cancel();
92 IpcResponse::Ok
93 },
94 IpcRequest::Subscribe => IpcResponse::Ok,
95 }
96 }
97
98 fn subscribe_events(&self) -> broadcast::Receiver<DnsEvent> {
99 self.events.subscribe()
100 }
101}