use pyo3::prelude::*;
use std::net::{IpAddr, SocketAddr};
use std::str::FromStr;
#[pyfunction]
pub fn is_valid_ip(ip: &str) -> bool {
IpAddr::from_str(ip).is_ok()
}
#[pyfunction]
pub fn is_valid_ipv4(ip: &str) -> bool {
match IpAddr::from_str(ip) {
Ok(IpAddr::V4(_)) => true,
_ => false,
}
}
#[pyfunction]
pub fn is_valid_ipv6(ip: &str) -> bool {
match IpAddr::from_str(ip) {
Ok(IpAddr::V6(_)) => true,
_ => false,
}
}
#[pyfunction]
pub fn is_valid_domain(domain: &str) -> bool {
if domain.is_empty() || domain.len() > 253 {
return false;
}
if domain.starts_with('.') || domain.ends_with('.') {
return false;
}
if domain.contains("..") {
return false;
}
for label in domain.split('.') {
if label.is_empty() || label.len() > 63 {
return false;
}
if label.starts_with('-') || label.ends_with('-') {
return false;
}
if !label.chars().all(|c| c.is_ascii_alphanumeric() || c == '-') {
return false;
}
}
true
}
#[pyfunction]
pub fn is_valid_socket_addr(address: &str) -> bool {
SocketAddr::from_str(address).is_ok()
}
#[pyfunction]
pub fn parse_socket_addr(address: &str) -> pyo3::PyResult<Option<(String, u16)>> {
match SocketAddr::from_str(address) {
Ok(addr) => Ok(Some((addr.ip().to_string(), addr.port()))),
Err(_) => Ok(None),
}
}
#[pyfunction]
pub fn format_duration(duration_ms: f64) -> String {
if duration_ms >= 1000.0 {
format!("{:.2}s", duration_ms / 1000.0)
} else {
format!("{:.1}ms", duration_ms)
}
}
#[pyfunction]
pub fn get_default_dns_servers() -> Vec<(String, String)> {
vec![
("Google Primary".to_string(), "8.8.8.8:53".to_string()),
("Google Secondary".to_string(), "8.8.4.4:53".to_string()),
("Cloudflare Primary".to_string(), "1.1.1.1:53".to_string()),
("Cloudflare Secondary".to_string(), "1.0.0.1:53".to_string()),
("Quad9 Primary".to_string(), "9.9.9.9:53".to_string()),
("Quad9 Secondary".to_string(), "149.112.112.112:53".to_string()),
("OpenDNS Primary".to_string(), "208.67.222.222:53".to_string()),
("OpenDNS Secondary".to_string(), "208.67.220.220:53".to_string()),
]
}
#[pyfunction]
pub fn get_default_doh_servers() -> Vec<(String, String)> {
vec![
("Cloudflare".to_string(), "https://1.1.1.1/dns-query".to_string()),
("Google".to_string(), "https://8.8.8.8/dns-query".to_string()),
("Quad9".to_string(), "https://9.9.9.9/dns-query".to_string()),
("AdGuard".to_string(), "https://dns.adguard.com/dns-query".to_string()),
]
}
#[pyfunction]
pub fn get_default_dot_servers() -> Vec<(String, String, String)> {
vec![
("Cloudflare".to_string(), "1.1.1.1:853".to_string(), "one.one.one.one".to_string()),
("Google".to_string(), "8.8.8.8:853".to_string(), "dns.google".to_string()),
("Quad9".to_string(), "9.9.9.9:853".to_string(), "dns.quad9.net".to_string()),
]
}
#[pyfunction]
pub fn create_preset_builder(preset: &str) -> pyo3::PyResult<crate::python_api::builder::PyDnsResolverBuilder> {
use crate::python_api::builder::PyDnsResolverBuilder;
use crate::python_api::types::PyQueryStrategy;
let mut builder = PyDnsResolverBuilder::new();
match preset {
"fast" => {
builder.query_strategy(&PyQueryStrategy::FIFO);
builder.add_udp_upstream("阿里DNS".to_string(), "223.5.5.5:53".to_string());
builder.add_udp_upstream("腾讯DNS".to_string(), "119.29.29.29:53".to_string());
builder.timeout(3.0);
builder.enable_edns(true);
},
"secure" => {
builder.query_strategy(&PyQueryStrategy::SMART);
builder.add_doh_upstream("阿里DNS".to_string(), "https://dns.alidns.com/dns-query".to_string())?;
builder.add_doh_upstream("腾讯DNS".to_string(), "https://doh.pub/dns-query".to_string())?;
builder.add_dot_upstream("阿里DoT".to_string(), "223.5.5.5:853".to_string());
builder.add_dot_upstream("腾讯DoT".to_string(), "1.12.12.12:853".to_string());
builder.timeout(5.0);
builder.enable_edns(true);
builder.enable_upstream_monitoring(true);
},
"balanced" => {
builder.query_strategy(&PyQueryStrategy::SMART);
builder.add_udp_upstream("阿里DNS".to_string(), "223.5.5.5:53".to_string());
builder.add_udp_upstream("腾讯DNS".to_string(), "119.29.29.29:53".to_string());
builder.add_doh_upstream("阿里DoH".to_string(), "https://dns.alidns.com/dns-query".to_string())?;
builder.add_dot_upstream("腾讯DoT".to_string(), "1.12.12.12:853".to_string());
builder.timeout(4.0);
builder.enable_edns(true);
builder.enable_upstream_monitoring(true);
},
_ => {
return Err(PyErr::new::<pyo3::exceptions::PyValueError, _>(
format!("Unknown preset '{}'. Available presets: fast, secure, balanced", preset)
));
}
}
Ok(builder)
}