optimize domain name match
This commit is contained in:
@@ -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 (®_DOMAIN_IP as &Regex).captures(text) {
|
let cap = match (®_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(),
|
||||||
|
|||||||
@@ -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" => {
|
||||||
|
|||||||
Reference in New Issue
Block a user