Skip to main content

sidedns_core/
rule.rs

1use serde::{Deserialize, Serialize};
2use std::{fmt::Display, net::SocketAddr};
3
4/// A single DNS routing rule mapping a domain to a target.
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
6pub struct DnsRule {
7    pub domain: String,
8    pub target: SocketAddr,
9    /// Whether SideDNS should terminate TLS for this domain and proxy HTTPS.
10    pub https: bool,
11}
12
13impl DnsRule {
14    pub fn is_wildcard(&self) -> bool {
15        self.domain.strip_prefix("*.").is_some()
16    }
17
18    pub fn matches(&self, domain: &str) -> bool {
19        match self.domain.strip_prefix("*.") {
20            Some(suffix) => {
21                domain.ends_with(suffix)
22                    && domain.len() > suffix.len()
23                    && domain.as_bytes()[domain.len() - suffix.len() - 1] == b'.'
24            },
25            None => self.domain == domain,
26        }
27    }
28    pub fn new(domain: String, target: SocketAddr, https: bool) -> Self {
29        Self {
30            domain,
31            target,
32            https,
33        }
34    }
35    pub fn with_https(mut self, https: bool) -> Self {
36        self.https = https;
37        self
38    }
39}
40
41impl Display for DnsRule {
42    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43        let scheme = if self.https { "https" } else { "http" };
44        write!(f, "{scheme}://{} → {}", self.domain, self.target)
45    }
46}