diff --git a/src/config.rs b/src/config.rs index fe3ff71..e3c8912 100644 --- a/src/config.rs +++ b/src/config.rs @@ -37,7 +37,7 @@ fn cap_socket_addr(reg: &Regex, text: &str) -> Option Option> { +fn cap_ip_addr(text: &str) -> Option> { let cap = match (®_DOMAIN_IP as &Regex).captures(text) { Some(cap) => cap, None => return None, @@ -52,8 +52,8 @@ fn cap_ip_addr(text: &str) -> Option Some(Ok((reg, ip))), + return match Host::new(val2) { + Ok(host) => Some(Ok((host, ip))), Err(_) => Some(Err(InvalidType::Regex)), }; } @@ -64,12 +64,12 @@ fn cap_ip_addr(text: &str) -> Option return Some(Err(InvalidType::IpAddr)), }; - let reg = match Regex::new(val1) { + let host = match Host::new(val1) { Ok(reg) => reg, Err(_) => return Some(Err(InvalidType::Regex)), }; - Some(Ok((reg, ip))) + Some(Ok((host, ip))) } #[derive(Debug)] @@ -102,7 +102,7 @@ impl InvalidType { #[derive(Debug)] pub struct Hosts { - record: Vec<(Regex, IpAddr)>, + record: Vec<(Host, IpAddr)>, } impl Hosts { @@ -110,8 +110,8 @@ impl Hosts { Hosts { record: Vec::new() } } - fn push(&mut self, domain: Regex, ip: IpAddr) { - self.record.push((domain, ip)); + fn push(&mut self, host: Host, ip: IpAddr) { + self.record.push((host, ip)); } fn extend(&mut self, hosts: Hosts) { @@ -120,7 +120,7 @@ impl Hosts { } } - pub fn iter(&mut self) -> Iter<(Regex, IpAddr)> { + pub fn iter(&mut self) -> Iter<(Host, IpAddr)> { self.record.iter() } @@ -134,6 +134,61 @@ impl Hosts { } } +// domain match +#[derive(Debug)] +pub struct Host(MatchMode); + +#[derive(Debug)] +enum MatchMode { + Text(String), + Regex(Regex), +} + +impl Host { + fn new(domain: &str) -> result::Result { + // example.com + if Self::is_text(domain) { + return Ok(Host(MatchMode::Text(domain.to_string()))); + } + + // *.example.com + if Self::is_wildcard(domain) { + let s = format!( + "^{}$", + domain.replace(".", r"\.").replace("*", r"([a-z]|\d|-)+") + ); + return Ok(Host(MatchMode::Regex(Regex::new(&s)?))); + } + + // use regex + Ok(Host(MatchMode::Regex(Regex::new(domain)?))) + } + + fn is_text(domain: &str) -> bool { + const ALLOW: &str = "abcdefghijklmnopqrstuvwxyz0123456789-."; + domain.chars().all(|item| ALLOW.chars().any(|c| item == c)) + } + + fn is_wildcard(domain: &str) -> bool { + const ALLOW: &str = "abcdefghijklmnopqrstuvwxyz0123456789-.*"; + domain.chars().all(|item| ALLOW.chars().any(|c| item == c)) + } + + pub fn is_match(&self, domain: &str) -> bool { + match &self.0 { + MatchMode::Text(text) => text == domain, + MatchMode::Regex(reg) => reg.is_match(domain), + } + } + + pub fn as_str(&self) -> &str { + match &self.0 { + MatchMode::Text(text) => text, + MatchMode::Regex(reg) => reg.as_str(), + } + } +} + #[derive(Debug)] pub struct ParseConfig { pub bind: Vec, @@ -280,7 +335,7 @@ impl Config { // host if let Some(d) = cap_ip_addr(&line) { match d { - Ok((domain, ip)) => parse.hosts.push(domain, ip), + Ok((host, ip)) => parse.hosts.push(host, ip), Err(kind) => parse.invalid.push(Invalid { line: n + 1, source: line.to_string(), diff --git a/src/main.rs b/src/main.rs index 2388ccb..2bd5eea 100644 --- a/src/main.rs +++ b/src/main.rs @@ -139,8 +139,8 @@ async fn main() { .map(|(r, _)| r.as_str().len()) .fold(0, |a, b| a.max(b)); - for (domain, ip) in config.hosts.iter() { - println!("{:domain$} {}", domain.as_str(), ip, domain = n); + for (host, ip) in config.hosts.iter() { + println!("{:domain$} {}", host.as_str(), ip, domain = n); } } "config" => {