From 185eb1e4c26ec37754f42bd959e04674fc46622b Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Sat, 18 Apr 2026 23:03:46 +0200 Subject: [PATCH] move sanitize and parse fmt dns dns utils fmt unit test unit test --- easytier/src/dns/config/dns.rs | 2 +- easytier/src/dns/utils/mod.rs | 39 ------------------ easytier/src/utils/dns.rs | 72 ++++++++++++++++++++++++++++++---- 3 files changed, 66 insertions(+), 47 deletions(-) diff --git a/easytier/src/dns/config/dns.rs b/easytier/src/dns/config/dns.rs index 3b77e0d3..57d2817a 100644 --- a/easytier/src/dns/config/dns.rs +++ b/easytier/src/dns/config/dns.rs @@ -3,8 +3,8 @@ use crate::dns::config::zone::ZoneConfig; use crate::dns::config::{DNS_DEFAULT_ADDRESS, DNS_DEFAULT_DOMAIN}; use crate::dns::server::DnsServer; use crate::dns::utils::addr::NameServerAddrGroup; -use crate::dns::utils::parse; use crate::proto::dns::GetExportConfigResponse; +use crate::utils::dns::parse; use derivative::Derivative; use hickory_net::xfer::Protocol; use hickory_proto::rr::{LowerName, Name}; diff --git a/easytier/src/dns/utils/mod.rs b/easytier/src/dns/utils/mod.rs index ee103359..d969700b 100644 --- a/easytier/src/dns/utils/mod.rs +++ b/easytier/src/dns/utils/mod.rs @@ -1,42 +1,3 @@ -use hickory_proto::rr::LowerName; -use idna::AsciiDenyList; - pub mod addr; pub mod response; pub mod zone_handler; - -pub fn sanitize(name: &str) -> String { - let dot = name.ends_with('.'); - let mut name = idna::domain_to_ascii_cow(name.as_ref(), AsciiDenyList::EMPTY) - .unwrap_or_default() - .into_owned() - .to_lowercase() - .split('.') - .map(|label| { - label - .chars() - .map(|c| if c.is_ascii_alphanumeric() { c } else { '-' }) - .take(63) - .collect::() - .trim_matches('-') - .to_string() - }) - .filter(|label| !label.is_empty()) - .collect::>() - .join("."); - name.truncate(253); - if dot { - name.push('.'); - } - name -} - -pub fn parse(name: &str) -> LowerName { - if let Ok(name) = name.parse() { - name - } else { - let sanitized = sanitize(name); - tracing::debug!("invalid name: {}, sanitized to: {}", name, sanitized); - sanitized.parse().unwrap_or_default() - } -} diff --git a/easytier/src/utils/dns.rs b/easytier/src/utils/dns.rs index e190777e..81c37572 100644 --- a/easytier/src/utils/dns.rs +++ b/easytier/src/utils/dns.rs @@ -1,24 +1,57 @@ -use std::fmt::Debug; -use std::net::SocketAddr; -use std::sync::atomic::AtomicBool; -use std::sync::Arc; - +use crate::common::error::Error; use anyhow::Context; use hickory_net::runtime::TokioRuntimeProvider; use hickory_proto::rr::rdata::SRV; -use hickory_proto::rr::{IntoName, RData}; +use hickory_proto::rr::{IntoName, LowerName, RData}; use hickory_resolver::config::{ ConnectionConfig, LookupIpStrategy, NameServerConfig, ResolverConfig, ResolverOpts, }; use hickory_resolver::system_conf::read_system_conf; use hickory_resolver::{Resolver, TokioResolver}; +use idna::AsciiDenyList; use once_cell::sync::Lazy; use std::net::SocketAddr; use std::sync::Arc; use std::sync::atomic::AtomicBool; use tokio::net::lookup_host; -use crate::common::error::Error; +pub fn sanitize(name: impl AsRef) -> String { + let name = name.as_ref(); + let dot = name.ends_with('.'); + let mut name = idna::domain_to_ascii_cow(name.as_ref(), AsciiDenyList::EMPTY) + .unwrap_or_default() + .into_owned() + .to_lowercase() + .split('.') + .map(|label| { + label + .chars() + .map(|c| if c.is_ascii_alphanumeric() { c } else { '-' }) + .take(63) + .collect::() + .trim_matches('-') + .to_string() + }) + .filter(|label| !label.is_empty()) + .collect::>() + .join("."); + name.truncate(253); + if dot { + name.push('.'); + } + name +} + +pub fn parse(name: impl AsRef) -> LowerName { + let name = name.as_ref(); + if let Ok(name) = name.parse() { + name + } else { + let sanitized = sanitize(name); + tracing::debug!("invalid name: {}, sanitized to: {}", name, sanitized); + sanitized.parse().unwrap_or_default() + } +} pub fn resolver_conf() -> (ResolverConfig, ResolverOpts) { let mut config = ResolverConfig::default(); @@ -161,6 +194,31 @@ mod tests { use super::*; + #[test] + fn parse_matrix_cases() { + let cases = [ + ["Example.COM.", "example.com."], + ["a_b!.et.net.", "a-b.et.net."], + ["foo..bar.com.", "foo.bar.com."], + [ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com.", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com.", + ], + ["___", "___"], + ["!", ""], + ["", ""], + ]; + + for [input, expected] in cases { + let parsed = parse(input); + let expected: LowerName = expected.parse().unwrap(); + assert_eq!( + parsed, expected, + "parse({input:?}) should equal {expected:?}, got {parsed:?}" + ); + } + } + #[tokio::test] async fn test_socket_addrs() { let url = url::Url::parse("tcp://github-ci-test.easytier.cn:80").unwrap();