mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-09-03 17:45:44 +00:00
fix: clear cargo audit vulnerabilities
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
[advisories]
|
||||||
|
# openidconnect 4.0.1 depends on rsa 0.9.10, and RUSTSEC-2023-0071 has no fixed upgrade.
|
||||||
|
ignore = ["RUSTSEC-2023-0071"]
|
||||||
Generated
+1495
-1938
File diff suppressed because it is too large
Load Diff
@@ -33,7 +33,7 @@ sea-orm-migration = { version = "1.1" }
|
|||||||
sqlx = { version = "0.8", features = ["sqlite", "runtime-tokio-rustls", "chrono", "uuid"] }
|
sqlx = { version = "0.8", features = ["sqlite", "runtime-tokio-rustls", "chrono", "uuid"] }
|
||||||
|
|
||||||
# Validation
|
# Validation
|
||||||
validator = { version = "0.18", features = ["derive"] }
|
validator = { version = "0.20", features = ["derive"] }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
jsonwebtoken = "9.0"
|
jsonwebtoken = "9.0"
|
||||||
|
|
||||||
|
|||||||
+4
-5
@@ -236,12 +236,11 @@ http_req = { git = "https://github.com/EasyTier/http_req.git", default-features
|
|||||||
] }
|
] }
|
||||||
|
|
||||||
# for dns connector
|
# for dns connector
|
||||||
hickory-resolver = "0.25.2"
|
hickory-resolver = "0.26.1"
|
||||||
hickory-proto = "0.25.2"
|
hickory-proto = "0.26.1"
|
||||||
|
|
||||||
# for magic dns
|
# for magic dns
|
||||||
hickory-client = { version = "0.25.2", optional = true }
|
hickory-server = { version = "0.26.1", features = [
|
||||||
hickory-server = { version = "0.25.2", features = [
|
|
||||||
"resolver",
|
"resolver",
|
||||||
], optional = true }
|
], optional = true }
|
||||||
|
|
||||||
@@ -401,7 +400,7 @@ jemalloc-prof = [
|
|||||||
"jemalloc-sys/stats",
|
"jemalloc-sys/stats",
|
||||||
]
|
]
|
||||||
tracing = ["tokio/tracing", "dep:console-subscriber"]
|
tracing = ["tokio/tracing", "dep:console-subscriber"]
|
||||||
magic-dns = ["dep:hickory-client", "dep:hickory-server"]
|
magic-dns = ["dep:hickory-server"]
|
||||||
faketcp = ["dep:flume"]
|
faketcp = ["dep:flume"]
|
||||||
zstd = ["dep:zstd"]
|
zstd = ["dep:zstd"]
|
||||||
# For Network Extension on macOS
|
# For Network Extension on macOS
|
||||||
|
|||||||
+35
-22
@@ -3,33 +3,40 @@ use std::sync::Arc;
|
|||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use hickory_proto::runtime::TokioRuntimeProvider;
|
use hickory_proto::rr::RData;
|
||||||
use hickory_proto::xfer::Protocol;
|
use hickory_resolver::config::{
|
||||||
use hickory_resolver::config::{LookupIpStrategy, NameServerConfig, ResolverConfig, ResolverOpts};
|
ConnectionConfig, LookupIpStrategy, NameServerConfig, ResolverConfig, ResolverOpts,
|
||||||
use hickory_resolver::name_server::{GenericConnector, TokioConnectionProvider};
|
};
|
||||||
|
use hickory_resolver::net::runtime::TokioRuntimeProvider;
|
||||||
use hickory_resolver::system_conf::read_system_conf;
|
use hickory_resolver::system_conf::read_system_conf;
|
||||||
use hickory_resolver::{Resolver, TokioResolver};
|
use hickory_resolver::TokioResolver;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use tokio::net::lookup_host;
|
use tokio::net::lookup_host;
|
||||||
|
|
||||||
use super::error::Error;
|
use super::error::Error;
|
||||||
|
|
||||||
pub fn get_default_resolver_config() -> ResolverConfig {
|
pub fn get_default_resolver_config() -> ResolverConfig {
|
||||||
let mut default_resolve_config = ResolverConfig::new();
|
ResolverConfig::from_parts(
|
||||||
default_resolve_config.add_name_server(NameServerConfig::new(
|
None,
|
||||||
"223.5.5.5:53".parse().unwrap(),
|
vec![],
|
||||||
Protocol::Udp,
|
vec![
|
||||||
));
|
NameServerConfig::new(
|
||||||
default_resolve_config.add_name_server(NameServerConfig::new(
|
"223.5.5.5".parse().unwrap(),
|
||||||
"180.184.1.1:53".parse().unwrap(),
|
true,
|
||||||
Protocol::Udp,
|
vec![ConnectionConfig::udp()],
|
||||||
));
|
),
|
||||||
default_resolve_config
|
NameServerConfig::new(
|
||||||
|
"180.184.1.1".parse().unwrap(),
|
||||||
|
true,
|
||||||
|
vec![ConnectionConfig::udp()],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static ALLOW_USE_SYSTEM_DNS_RESOLVER: Lazy<AtomicBool> = Lazy::new(|| AtomicBool::new(true));
|
pub static ALLOW_USE_SYSTEM_DNS_RESOLVER: Lazy<AtomicBool> = Lazy::new(|| AtomicBool::new(true));
|
||||||
|
|
||||||
pub static RESOLVER: Lazy<Arc<Resolver<GenericConnector<TokioRuntimeProvider>>>> =
|
pub static RESOLVER: Lazy<Arc<TokioResolver>> =
|
||||||
Lazy::new(|| {
|
Lazy::new(|| {
|
||||||
let system_cfg = read_system_conf();
|
let system_cfg = read_system_conf();
|
||||||
let mut cfg = get_default_resolver_config();
|
let mut cfg = get_default_resolver_config();
|
||||||
@@ -41,9 +48,11 @@ pub static RESOLVER: Lazy<Arc<Resolver<GenericConnector<TokioRuntimeProvider>>>>
|
|||||||
opt = s.1;
|
opt = s.1;
|
||||||
}
|
}
|
||||||
opt.ip_strategy = LookupIpStrategy::Ipv4AndIpv6;
|
opt.ip_strategy = LookupIpStrategy::Ipv4AndIpv6;
|
||||||
let builder = TokioResolver::builder_with_config(cfg, TokioConnectionProvider::default())
|
let resolver = TokioResolver::builder_with_config(cfg, TokioRuntimeProvider::default())
|
||||||
.with_options(opt);
|
.with_options(opt)
|
||||||
Arc::new(builder.build())
|
.build()
|
||||||
|
.expect("failed to build DNS resolver");
|
||||||
|
Arc::new(resolver)
|
||||||
});
|
});
|
||||||
|
|
||||||
pub async fn resolve_txt_record(domain_name: &str) -> Result<String, Error> {
|
pub async fn resolve_txt_record(domain_name: &str) -> Result<String, Error> {
|
||||||
@@ -53,12 +62,16 @@ pub async fn resolve_txt_record(domain_name: &str) -> Result<String, Error> {
|
|||||||
.await
|
.await
|
||||||
.with_context(|| format!("txt_lookup failed, domain_name: {}", domain_name))?;
|
.with_context(|| format!("txt_lookup failed, domain_name: {}", domain_name))?;
|
||||||
|
|
||||||
let txt_record = response
|
let Some(RData::TXT(txt_record)) = response
|
||||||
|
.answers()
|
||||||
.iter()
|
.iter()
|
||||||
.next()
|
.next()
|
||||||
.with_context(|| format!("no txt record found, domain_name: {}", domain_name))?;
|
.map(|record| &record.data)
|
||||||
|
else {
|
||||||
|
return Err(anyhow::anyhow!("no txt record found, domain_name: {}", domain_name).into());
|
||||||
|
};
|
||||||
|
|
||||||
let txt_data = String::from_utf8_lossy(&txt_record.txt_data()[0]);
|
let txt_data = String::from_utf8_lossy(&txt_record.txt_data[0]);
|
||||||
tracing::info!(?txt_data, ?domain_name, "get txt record");
|
tracing::info!(?txt_data, ?domain_name, "get txt record");
|
||||||
|
|
||||||
Ok(txt_data.to_string())
|
Ok(txt_data.to_string())
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use dashmap::DashSet;
|
use dashmap::DashSet;
|
||||||
use hickory_resolver::proto::rr::rdata::SRV;
|
use hickory_resolver::proto::rr::{RData, rdata::SRV};
|
||||||
use rand::{Rng as _, seq::SliceRandom};
|
use rand::{Rng as _, seq::SliceRandom};
|
||||||
use strum::VariantArray;
|
use strum::VariantArray;
|
||||||
|
|
||||||
@@ -85,12 +85,12 @@ impl DnsTunnelConnector {
|
|||||||
|
|
||||||
fn handle_one_srv_record(record: &SRV, protocol: IpScheme) -> Result<(url::Url, u64), Error> {
|
fn handle_one_srv_record(record: &SRV, protocol: IpScheme) -> Result<(url::Url, u64), Error> {
|
||||||
// port must be non-zero
|
// port must be non-zero
|
||||||
if record.port() == 0 {
|
if record.port == 0 {
|
||||||
return Err(anyhow::anyhow!("port must be non-zero").into());
|
return Err(anyhow::anyhow!("port must be non-zero").into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let connector_dst = record.target().to_utf8();
|
let connector_dst = record.target.to_utf8();
|
||||||
let dst_url = format!("{}://{}:{}", protocol, connector_dst, record.port());
|
let dst_url = format!("{}://{}:{}", protocol, connector_dst, record.port);
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
dst_url.parse().with_context(|| {
|
dst_url.parse().with_context(|| {
|
||||||
@@ -98,11 +98,11 @@ impl DnsTunnelConnector {
|
|||||||
"parse dst_url failed, protocol: {}, connector_dst: {}, port: {}, dst_url: {}",
|
"parse dst_url failed, protocol: {}, connector_dst: {}, port: {}, dst_url: {}",
|
||||||
protocol,
|
protocol,
|
||||||
connector_dst,
|
connector_dst,
|
||||||
record.port(),
|
record.port,
|
||||||
dst_url
|
dst_url
|
||||||
)
|
)
|
||||||
})?,
|
})?,
|
||||||
record.priority() as _,
|
record.priority as _,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +129,10 @@ impl DnsTunnelConnector {
|
|||||||
format!("srv_lookup failed, srv_domain: {}", srv_domain)
|
format!("srv_lookup failed, srv_domain: {}", srv_domain)
|
||||||
})?;
|
})?;
|
||||||
tracing::info!(?response, ?srv_domain, "srv_lookup response");
|
tracing::info!(?response, ?srv_domain, "srv_lookup response");
|
||||||
for record in response.iter() {
|
for record in response.answers() {
|
||||||
|
let RData::SRV(record) = &record.data else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
let parsed_record = Self::handle_one_srv_record(record, **protocol);
|
let parsed_record = Self::handle_one_srv_record(record, **protocol);
|
||||||
tracing::info!(?parsed_record, ?srv_domain, "parsed_record");
|
tracing::info!(?parsed_record, ?srv_domain, "parsed_record");
|
||||||
if let Err(e) = &parsed_record {
|
if let Err(e) = &parsed_record {
|
||||||
|
|||||||
@@ -92,12 +92,11 @@ impl TryFrom<&Record> for rr::Record {
|
|||||||
|
|
||||||
fn try_from(value: &Record) -> Result<Self, Self::Error> {
|
fn try_from(value: &Record) -> Result<Self, Self::Error> {
|
||||||
let name = value.name()?;
|
let name = value.name()?;
|
||||||
let mut record = Self::update0(name, value.ttl.as_secs() as u32, value.rr_type());
|
let ttl = value.ttl.as_secs() as u32;
|
||||||
record.set_dns_class(rr::DNSClass::IN);
|
|
||||||
match value.rr_type {
|
match value.rr_type {
|
||||||
RecordType::A => {
|
RecordType::A => {
|
||||||
let addr: Ipv4Addr = value.value.parse()?;
|
let addr: Ipv4Addr = value.value.parse()?;
|
||||||
record.set_data(RData::A(rr::rdata::a::A(addr)));
|
Ok(Self::from_rdata(name, ttl, RData::A(rr::rdata::a::A(addr))))
|
||||||
}
|
}
|
||||||
RecordType::SOA => {
|
RecordType::SOA => {
|
||||||
let soa = value.value.split_whitespace().collect::<Vec<_>>();
|
let soa = value.value.split_whitespace().collect::<Vec<_>>();
|
||||||
@@ -111,7 +110,7 @@ impl TryFrom<&Record> for rr::Record {
|
|||||||
let retry: u32 = soa[4].parse()?;
|
let retry: u32 = soa[4].parse()?;
|
||||||
let expire: u32 = soa[5].parse()?;
|
let expire: u32 = soa[5].parse()?;
|
||||||
let minimum: u32 = soa[6].parse()?;
|
let minimum: u32 = soa[6].parse()?;
|
||||||
record.set_data(RData::SOA(rr::rdata::soa::SOA::new(
|
Ok(Self::from_rdata(name, ttl, RData::SOA(rr::rdata::soa::SOA::new(
|
||||||
mname,
|
mname,
|
||||||
rname,
|
rname,
|
||||||
serial,
|
serial,
|
||||||
@@ -119,11 +118,10 @@ impl TryFrom<&Record> for rr::Record {
|
|||||||
retry.try_into().unwrap(),
|
retry.try_into().unwrap(),
|
||||||
expire.try_into().unwrap(),
|
expire.try_into().unwrap(),
|
||||||
minimum,
|
minimum,
|
||||||
)));
|
))))
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
Ok(record)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ use hickory_proto::op::Edns;
|
|||||||
use hickory_proto::rr;
|
use hickory_proto::rr;
|
||||||
use hickory_proto::rr::LowerName;
|
use hickory_proto::rr::LowerName;
|
||||||
use hickory_resolver::config::ResolverOpts;
|
use hickory_resolver::config::ResolverOpts;
|
||||||
use hickory_resolver::name_server::TokioConnectionProvider;
|
use hickory_resolver::net::runtime::TokioRuntimeProvider;
|
||||||
use hickory_resolver::system_conf::read_system_conf;
|
use hickory_resolver::system_conf::read_system_conf;
|
||||||
use hickory_server::ServerFuture;
|
use hickory_server::net::runtime::{Time, TokioTime};
|
||||||
use hickory_server::authority::{AuthorityObject, Catalog, ZoneType};
|
use hickory_server::server::Server as HickoryServer;
|
||||||
use hickory_server::server::{Request, RequestHandler, ResponseHandler, ResponseInfo};
|
use hickory_server::server::{Request, RequestHandler, ResponseHandler, ResponseInfo};
|
||||||
use hickory_server::store::forwarder::ForwardConfig;
|
use hickory_server::store::forwarder::ForwardConfig;
|
||||||
use hickory_server::store::{forwarder::ForwardAuthority, in_memory::InMemoryAuthority};
|
use hickory_server::store::{forwarder::ForwardZoneHandler, in_memory::InMemoryZoneHandler};
|
||||||
use std::io;
|
use hickory_server::zone_handler::{AxfrPolicy, Catalog, ZoneHandler, ZoneType};
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -24,7 +24,7 @@ use crate::common::dns::get_default_resolver_config;
|
|||||||
use super::config::{GeneralConfig, Record, RunConfig};
|
use super::config::{GeneralConfig, Record, RunConfig};
|
||||||
|
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
server: ServerFuture<CatalogRequestHandler>,
|
server: HickoryServer<CatalogRequestHandler>,
|
||||||
catalog: Arc<RwLock<Catalog>>,
|
catalog: Arc<RwLock<Catalog>>,
|
||||||
general_config: GeneralConfig,
|
general_config: GeneralConfig,
|
||||||
udp_local_addr: Option<SocketAddr>,
|
udp_local_addr: Option<SocketAddr>,
|
||||||
@@ -52,7 +52,7 @@ impl CatalogRequestHandler {
|
|||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl RequestHandler for CatalogRequestHandler {
|
impl RequestHandler for CatalogRequestHandler {
|
||||||
async fn handle_request<R: ResponseHandler>(
|
async fn handle_request<R: ResponseHandler, T: hickory_server::net::runtime::Time>(
|
||||||
&self,
|
&self,
|
||||||
request: &Request,
|
request: &Request,
|
||||||
response_handle: R,
|
response_handle: R,
|
||||||
@@ -60,14 +60,14 @@ impl RequestHandler for CatalogRequestHandler {
|
|||||||
self.catalog
|
self.catalog
|
||||||
.read()
|
.read()
|
||||||
.await
|
.await
|
||||||
.handle_request(request, response_handle)
|
.handle_request::<R, T>(request, response_handle)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_authority(domain: &str, records: &[Record]) -> Result<InMemoryAuthority> {
|
pub fn build_authority(domain: &str, records: &[Record]) -> Result<InMemoryZoneHandler> {
|
||||||
let zone = rr::Name::from_str(domain)?;
|
let zone = rr::Name::from_str(domain)?;
|
||||||
let mut authority = InMemoryAuthority::empty(zone, ZoneType::Primary, false);
|
let mut authority = InMemoryZoneHandler::empty(zone, ZoneType::Primary, AxfrPolicy::Deny);
|
||||||
for record in records.iter() {
|
for record in records.iter() {
|
||||||
let r = record.try_into()?;
|
let r = record.try_into()?;
|
||||||
authority.upsert_mut(r, 0);
|
authority.upsert_mut(r, 0);
|
||||||
@@ -97,18 +97,16 @@ impl Server {
|
|||||||
.name_servers()
|
.name_servers()
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&x| {
|
.filter(|&x| {
|
||||||
!config
|
!config.excluded_forward_nameservers().contains(&x.ip)
|
||||||
.excluded_forward_nameservers()
|
|
||||||
.contains(&x.socket_addr.ip())
|
|
||||||
})
|
})
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.into(),
|
.into(),
|
||||||
options: Some(system_conf.1),
|
options: Some(system_conf.1),
|
||||||
};
|
};
|
||||||
let auth = ForwardAuthority::builder_with_config(
|
let auth = ForwardZoneHandler::builder_with_config(
|
||||||
forward_config,
|
forward_config,
|
||||||
TokioConnectionProvider::default(),
|
TokioRuntimeProvider::default(),
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -117,7 +115,7 @@ impl Server {
|
|||||||
|
|
||||||
let catalog = Arc::new(RwLock::new(catalog));
|
let catalog = Arc::new(RwLock::new(catalog));
|
||||||
let handler = CatalogRequestHandler::new(catalog.clone());
|
let handler = CatalogRequestHandler::new(catalog.clone());
|
||||||
let server = ServerFuture::new(handler);
|
let server = HickoryServer::new(handler);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
server,
|
server,
|
||||||
@@ -187,7 +185,7 @@ impl Server {
|
|||||||
.with_context(|| format!("DNS Server failed to bind TCP address {}", address))?;
|
.with_context(|| format!("DNS Server failed to bind TCP address {}", address))?;
|
||||||
self.tcp_local_addr = Some(tcp_listener.local_addr()?);
|
self.tcp_local_addr = Some(tcp_listener.local_addr()?);
|
||||||
self.server
|
self.server
|
||||||
.register_listener(tcp_listener, Duration::from_secs(5));
|
.register_listener(tcp_listener, Duration::from_secs(5), 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(address) = self.general_config.listen_udp() {
|
if let Some(address) = self.general_config.listen_udp() {
|
||||||
@@ -203,11 +201,11 @@ impl Server {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn upsert(&self, name: LowerName, authority: Arc<dyn AuthorityObject>) {
|
pub async fn upsert(&self, name: LowerName, authority: Arc<dyn ZoneHandler>) {
|
||||||
self.catalog.write().await.upsert(name, vec![authority]);
|
self.catalog.write().await.upsert(name, vec![authority]);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn remove(&self, name: &LowerName) -> Option<Vec<Arc<dyn AuthorityObject>>> {
|
pub async fn remove(&self, name: &LowerName) -> Option<Vec<Arc<dyn ZoneHandler>>> {
|
||||||
self.catalog.write().await.remove(name)
|
self.catalog.write().await.remove(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,11 +214,16 @@ impl Server {
|
|||||||
update: &Request,
|
update: &Request,
|
||||||
response_edns: Option<Edns>,
|
response_edns: Option<Edns>,
|
||||||
response_handle: R,
|
response_handle: R,
|
||||||
) -> io::Result<ResponseInfo> {
|
) -> ResponseInfo {
|
||||||
self.catalog
|
self.catalog
|
||||||
.write()
|
.write()
|
||||||
.await
|
.await
|
||||||
.update(update, response_edns, response_handle)
|
.update(
|
||||||
|
update,
|
||||||
|
response_edns.as_ref(),
|
||||||
|
TokioTime::current_time(),
|
||||||
|
response_handle,
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,7 +240,12 @@ impl Server {
|
|||||||
self.catalog
|
self.catalog
|
||||||
.read()
|
.read()
|
||||||
.await
|
.await
|
||||||
.lookup(request, response_edns, response_handle)
|
.lookup(
|
||||||
|
request,
|
||||||
|
response_edns.as_ref(),
|
||||||
|
TokioTime::current_time(),
|
||||||
|
response_handle,
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,11 +265,14 @@ mod tests {
|
|||||||
GeneralConfigBuilder, RecordBuilder, RecordType, RunConfigBuilder,
|
GeneralConfigBuilder, RecordBuilder, RecordType, RunConfigBuilder,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use hickory_client::client::{Client, ClientHandle};
|
|
||||||
use hickory_proto::rr;
|
use hickory_proto::rr;
|
||||||
use hickory_proto::runtime::TokioRuntimeProvider;
|
use hickory_resolver::TokioResolver;
|
||||||
use hickory_proto::udp::UdpClientStream;
|
use hickory_resolver::config::{
|
||||||
|
ConnectionConfig, NameServerConfig, ResolverConfig, ResolverOpts,
|
||||||
|
};
|
||||||
|
use hickory_resolver::net::runtime::TokioRuntimeProvider;
|
||||||
use maplit::hashmap;
|
use maplit::hashmap;
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -314,23 +325,34 @@ mod tests {
|
|||||||
server.run().await?;
|
server.run().await?;
|
||||||
|
|
||||||
let local_addr = server.udp_local_addr().unwrap();
|
let local_addr = server.udp_local_addr().unwrap();
|
||||||
let stream = UdpClientStream::builder(local_addr, TokioRuntimeProvider::default()).build();
|
let mut connection = ConnectionConfig::udp();
|
||||||
let (mut client, background) = Client::connect(stream).await?;
|
connection.port = local_addr.port();
|
||||||
let background_task = tokio::spawn(background);
|
let resolver_config = ResolverConfig::from_parts(
|
||||||
let response = client
|
None,
|
||||||
.query(
|
vec![],
|
||||||
rr::Name::from_str("www.et.internal")?,
|
vec![NameServerConfig::new(
|
||||||
rr::DNSClass::IN,
|
local_addr.ip(),
|
||||||
rr::RecordType::A,
|
true,
|
||||||
|
vec![connection],
|
||||||
|
)],
|
||||||
|
);
|
||||||
|
let resolver = TokioResolver::builder_with_config(
|
||||||
|
resolver_config,
|
||||||
|
TokioRuntimeProvider::default(),
|
||||||
)
|
)
|
||||||
|
.with_options(ResolverOpts::default())
|
||||||
|
.build()?;
|
||||||
|
let response = resolver
|
||||||
|
.lookup(rr::Name::from_str("www.et.internal")?, rr::RecordType::A)
|
||||||
.await?;
|
.await?;
|
||||||
drop(background_task);
|
|
||||||
|
|
||||||
println!("Response: {:?}", response);
|
println!("Response: {:?}", response);
|
||||||
|
|
||||||
assert_eq!(response.answers().len(), 1);
|
assert_eq!(response.answers().len(), 1);
|
||||||
let expected_record: rr::Record = configured_record.try_into()?;
|
let Some(rr::RData::A(ip)) = response.answers().first().map(|record| &record.data) else {
|
||||||
assert_eq!(response.answers().first().unwrap(), &expected_record);
|
panic!("unexpected DNS response: {response:?}");
|
||||||
|
};
|
||||||
|
assert_eq!(ip.0, Ipv4Addr::new(123, 123, 123, 123));
|
||||||
|
|
||||||
server.shutdown().await?;
|
server.shutdown().await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -39,9 +39,10 @@ use anyhow::Context;
|
|||||||
use cidr::Ipv4Inet;
|
use cidr::Ipv4Inet;
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use hickory_proto::rr::LowerName;
|
use hickory_proto::rr::LowerName;
|
||||||
use hickory_proto::serialize::binary::{BinDecodable, BinEncoder};
|
use hickory_proto::serialize::binary::BinEncoder;
|
||||||
use hickory_server::authority::{MessageRequest, MessageResponse};
|
use hickory_server::net::{NetError, udp as dns_udp, xfer::Protocol};
|
||||||
use hickory_server::server::{Request, RequestHandler, ResponseHandler, ResponseInfo};
|
use hickory_server::server::{Request, RequestHandler, ResponseHandler, ResponseInfo};
|
||||||
|
use hickory_server::zone_handler::MessageResponse;
|
||||||
use multimap::MultiMap;
|
use multimap::MultiMap;
|
||||||
use pnet::packet::icmp::{IcmpTypes, MutableIcmpPacket};
|
use pnet::packet::icmp::{IcmpTypes, MutableIcmpPacket};
|
||||||
use pnet::packet::ipv4::Ipv4Packet;
|
use pnet::packet::ipv4::Ipv4Packet;
|
||||||
@@ -54,7 +55,7 @@ use pnet::packet::{
|
|||||||
};
|
};
|
||||||
use std::net::{SocketAddr, SocketAddrV4};
|
use std::net::{SocketAddr, SocketAddrV4};
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use std::{collections::BTreeMap, io, net::Ipv4Addr, str::FromStr, sync::Arc, time::Duration};
|
use std::{collections::BTreeMap, net::Ipv4Addr, str::FromStr, sync::Arc, time::Duration};
|
||||||
|
|
||||||
static NIC_PIPELINE_NAME: &str = "magic_dns_server";
|
static NIC_PIPELINE_NAME: &str = "magic_dns_server";
|
||||||
|
|
||||||
@@ -266,25 +267,21 @@ impl ResponseHandler for ResponseWrapper {
|
|||||||
impl RecordIter<'a>,
|
impl RecordIter<'a>,
|
||||||
impl RecordIter<'a>,
|
impl RecordIter<'a>,
|
||||||
>,
|
>,
|
||||||
) -> io::Result<ResponseInfo> {
|
) -> Result<ResponseInfo, NetError> {
|
||||||
let mut buffer = self
|
let mut buffer = self
|
||||||
.response
|
.response
|
||||||
.lock()
|
.lock()
|
||||||
.map_err(|_| io::Error::other("lock poisoned"))?;
|
.map_err(|_| NetError::Msg("lock poisoned".to_string()))?;
|
||||||
|
|
||||||
let mut encoder = BinEncoder::new(&mut buffer);
|
let mut encoder = BinEncoder::new(&mut buffer);
|
||||||
|
|
||||||
// `max_size` should be u16::MAX for protocol other than UDP.
|
// `max_size` should be u16::MAX for protocol other than UDP.
|
||||||
let max_size = if let Some(edns) = response.get_edns() {
|
let max_size = dns_udp::MAX_RECEIVE_BUFFER_SIZE as u16;
|
||||||
edns.max_payload()
|
|
||||||
} else {
|
|
||||||
hickory_proto::udp::MAX_RECEIVE_BUFFER_SIZE as u16
|
|
||||||
};
|
|
||||||
|
|
||||||
encoder.set_max_size(max_size);
|
encoder.set_max_size(max_size);
|
||||||
response
|
response
|
||||||
.destructive_emit(&mut encoder)
|
.destructive_emit(&mut encoder)
|
||||||
.map_err(io::Error::other)
|
.map_err(NetError::from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,11 +357,12 @@ impl MagicDnsServerInstanceData {
|
|||||||
(
|
(
|
||||||
src_port,
|
src_port,
|
||||||
dst_port,
|
dst_port,
|
||||||
Request::new(
|
Request::from_bytes(
|
||||||
MessageRequest::from_bytes(request_payload).ok()?,
|
request_payload.to_vec(),
|
||||||
SocketAddr::from(SocketAddrV4::new(src_ip, src_port)),
|
SocketAddr::from(SocketAddrV4::new(src_ip, src_port)),
|
||||||
hickory_proto::xfer::Protocol::Udp,
|
Protocol::Udp,
|
||||||
),
|
)
|
||||||
|
.ok()?,
|
||||||
request_payload.len(),
|
request_payload.len(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
@@ -375,7 +373,7 @@ impl MagicDnsServerInstanceData {
|
|||||||
self.dns_server
|
self.dns_server
|
||||||
.read_catalog()
|
.read_catalog()
|
||||||
.await
|
.await
|
||||||
.handle_request(
|
.handle_request::<ResponseWrapper, hickory_server::net::runtime::TokioTime>(
|
||||||
&request,
|
&request,
|
||||||
ResponseWrapper {
|
ResponseWrapper {
|
||||||
response: response_payload_arc.clone(),
|
response: response_payload_arc.clone(),
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
use std::net::{Ipv4Addr, SocketAddr};
|
use std::net::Ipv4Addr;
|
||||||
use std::str::FromStr as _;
|
use std::str::FromStr as _;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use cidr::Ipv4Inet;
|
use cidr::Ipv4Inet;
|
||||||
use hickory_client::client::{Client, ClientHandle as _};
|
|
||||||
use hickory_proto::rr;
|
use hickory_proto::rr;
|
||||||
use hickory_proto::runtime::TokioRuntimeProvider;
|
use hickory_resolver::TokioResolver;
|
||||||
use hickory_proto::udp::UdpClientStream;
|
use hickory_resolver::config::{
|
||||||
|
ConnectionConfig, NameServerConfig, ResolverConfig, ResolverOpts,
|
||||||
|
};
|
||||||
|
use hickory_resolver::net::runtime::TokioRuntimeProvider;
|
||||||
use tokio::sync::Notify;
|
use tokio::sync::Notify;
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
|
|
||||||
@@ -66,55 +68,52 @@ pub async fn prepare_env_with_tld_dns_zone(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn check_dns_record(fake_ip: &Ipv4Addr, domain: &str, expected_ip: &str) {
|
pub async fn check_dns_record(fake_ip: &Ipv4Addr, domain: &str, expected_ip: &str) {
|
||||||
let stream = UdpClientStream::builder(
|
let resolver = build_test_resolver(fake_ip);
|
||||||
SocketAddr::new((*fake_ip).into(), 53),
|
let response = resolver
|
||||||
TokioRuntimeProvider::default(),
|
.lookup(rr::Name::from_str(domain).unwrap(), rr::RecordType::A)
|
||||||
)
|
|
||||||
.build();
|
|
||||||
let (mut client, background) = Client::connect(stream).await.unwrap();
|
|
||||||
let background_task = tokio::spawn(background);
|
|
||||||
let response = client
|
|
||||||
.query(
|
|
||||||
rr::Name::from_str(domain).unwrap(),
|
|
||||||
rr::DNSClass::IN,
|
|
||||||
rr::RecordType::A,
|
|
||||||
)
|
|
||||||
.await
|
.await
|
||||||
.unwrap_or_else(|e| panic!("DNS query failed unexpectedly for domain '{domain}': {e}"));
|
.unwrap_or_else(|e| panic!("DNS query failed unexpectedly for domain '{domain}': {e}"));
|
||||||
background_task.abort();
|
|
||||||
let _ = background_task.await;
|
|
||||||
|
|
||||||
println!("Response: {:?}", response);
|
println!("Response: {:?}", response);
|
||||||
|
|
||||||
assert_eq!(response.answers().len(), 1, "{:?}", response.answers());
|
assert_eq!(response.answers().len(), 1, "{:?}", response);
|
||||||
let resp = response.answers().first().unwrap();
|
let resp = response.answers().first().unwrap();
|
||||||
|
let rr::RData::A(ip) = &resp.data else {
|
||||||
|
panic!("unexpected DNS response: {response:?}");
|
||||||
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resp.clone().into_parts().rdata.into_a().unwrap().0,
|
ip.0,
|
||||||
expected_ip.parse::<Ipv4Addr>().unwrap()
|
expected_ip.parse::<Ipv4Addr>().unwrap()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn check_dns_record_missing(fake_ip: &Ipv4Addr, domain: &str) {
|
pub async fn check_dns_record_missing(fake_ip: &Ipv4Addr, domain: &str) {
|
||||||
let stream = UdpClientStream::builder(
|
let resolver = build_test_resolver(fake_ip);
|
||||||
SocketAddr::new((*fake_ip).into(), 53),
|
let response = resolver
|
||||||
TokioRuntimeProvider::default(),
|
.lookup(rr::Name::from_str(domain).unwrap(), rr::RecordType::A)
|
||||||
)
|
.await;
|
||||||
.build();
|
if let Ok(response) = response {
|
||||||
let (mut client, background) = Client::connect(stream).await.unwrap();
|
assert!(response.answers().is_empty(), "{:?}", response);
|
||||||
let background_task = tokio::spawn(background);
|
}
|
||||||
let response = client
|
}
|
||||||
.query(
|
|
||||||
rr::Name::from_str(domain).unwrap(),
|
fn build_test_resolver(fake_ip: &Ipv4Addr) -> TokioResolver {
|
||||||
rr::DNSClass::IN,
|
let mut connection = ConnectionConfig::udp();
|
||||||
rr::RecordType::A,
|
connection.port = 53;
|
||||||
)
|
let config = ResolverConfig::from_parts(
|
||||||
.await
|
None,
|
||||||
.unwrap_or_else(|e| {
|
vec![],
|
||||||
panic!("DNS query for missing record failed unexpectedly for domain '{domain}': {e}")
|
vec![NameServerConfig::new(
|
||||||
});
|
(*fake_ip).into(),
|
||||||
background_task.abort();
|
true,
|
||||||
let _ = background_task.await;
|
vec![connection],
|
||||||
assert!(response.answers().is_empty(), "{:?}", response.answers());
|
)],
|
||||||
|
);
|
||||||
|
|
||||||
|
TokioResolver::builder_with_config(config, TokioRuntimeProvider::default())
|
||||||
|
.with_options(ResolverOpts::default())
|
||||||
|
.build()
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|||||||
Reference in New Issue
Block a user