optimize domain name match

This commit is contained in:
wyhaya
2019-11-22 17:34:38 +08:00
parent b1c0cf82c2
commit 00da8351d4
2 changed files with 67 additions and 12 deletions

View File

@@ -37,7 +37,7 @@ fn cap_socket_addr(reg: &Regex, text: &str) -> Option<result::Result<SocketAddr,
} }
} }
fn cap_ip_addr(text: &str) -> Option<result::Result<(Regex, IpAddr), InvalidType>> { fn cap_ip_addr(text: &str) -> Option<result::Result<(Host, IpAddr), InvalidType>> {
let cap = match (&REG_DOMAIN_IP as &Regex).captures(text) { let cap = match (&REG_DOMAIN_IP as &Regex).captures(text) {
Some(cap) => cap, Some(cap) => cap,
None => return None, None => return None,
@@ -52,8 +52,8 @@ fn cap_ip_addr(text: &str) -> Option<result::Result<(Regex, IpAddr), InvalidType
// ip domain // ip domain
if let Ok(ip) = val1.parse() { if let Ok(ip) = val1.parse() {
return match Regex::new(val2) { return match Host::new(val2) {
Ok(reg) => Some(Ok((reg, ip))), Ok(host) => Some(Ok((host, ip))),
Err(_) => Some(Err(InvalidType::Regex)), Err(_) => Some(Err(InvalidType::Regex)),
}; };
} }
@@ -64,12 +64,12 @@ fn cap_ip_addr(text: &str) -> Option<result::Result<(Regex, IpAddr), InvalidType
Err(_) => return Some(Err(InvalidType::IpAddr)), Err(_) => return Some(Err(InvalidType::IpAddr)),
}; };
let reg = match Regex::new(val1) { let host = match Host::new(val1) {
Ok(reg) => reg, Ok(reg) => reg,
Err(_) => return Some(Err(InvalidType::Regex)), Err(_) => return Some(Err(InvalidType::Regex)),
}; };
Some(Ok((reg, ip))) Some(Ok((host, ip)))
} }
#[derive(Debug)] #[derive(Debug)]
@@ -102,7 +102,7 @@ impl InvalidType {
#[derive(Debug)] #[derive(Debug)]
pub struct Hosts { pub struct Hosts {
record: Vec<(Regex, IpAddr)>, record: Vec<(Host, IpAddr)>,
} }
impl Hosts { impl Hosts {
@@ -110,8 +110,8 @@ impl Hosts {
Hosts { record: Vec::new() } Hosts { record: Vec::new() }
} }
fn push(&mut self, domain: Regex, ip: IpAddr) { fn push(&mut self, host: Host, ip: IpAddr) {
self.record.push((domain, ip)); self.record.push((host, ip));
} }
fn extend(&mut self, hosts: Hosts) { 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() 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<Host, regex::Error> {
// 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)] #[derive(Debug)]
pub struct ParseConfig { pub struct ParseConfig {
pub bind: Vec<SocketAddr>, pub bind: Vec<SocketAddr>,
@@ -280,7 +335,7 @@ impl Config {
// host // host
if let Some(d) = cap_ip_addr(&line) { if let Some(d) = cap_ip_addr(&line) {
match d { match d {
Ok((domain, ip)) => parse.hosts.push(domain, ip), Ok((host, ip)) => parse.hosts.push(host, ip),
Err(kind) => parse.invalid.push(Invalid { Err(kind) => parse.invalid.push(Invalid {
line: n + 1, line: n + 1,
source: line.to_string(), source: line.to_string(),

View File

@@ -139,8 +139,8 @@ async fn main() {
.map(|(r, _)| r.as_str().len()) .map(|(r, _)| r.as_str().len())
.fold(0, |a, b| a.max(b)); .fold(0, |a, b| a.max(b));
for (domain, ip) in config.hosts.iter() { for (host, ip) in config.hosts.iter() {
println!("{:domain$} {}", domain.as_str(), ip, domain = n); println!("{:domain$} {}", host.as_str(), ip, domain = n);
} }
} }
"config" => { "config" => {