mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-09-02 17:15:43 +00:00
upgrade hickory-dns to 0.26.0
fix zone test
This commit is contained in:
+5
-7
@@ -237,14 +237,12 @@ http_req = { git = "https://github.com/EasyTier/http_req.git", default-features
|
|||||||
] }
|
] }
|
||||||
|
|
||||||
# for dns connector
|
# for dns connector
|
||||||
hickory-resolver = "0.25.2"
|
hickory-proto = "0.26.0"
|
||||||
hickory-proto = "0.25.2"
|
hickory-net = { version = "0.26.0", features = ["serde"] }
|
||||||
|
hickory-resolver = "0.26.0"
|
||||||
|
|
||||||
# for magic dns
|
# for magic dns
|
||||||
hickory-client = { version = "0.25.2", optional = true }
|
hickory-server = { version = "0.26.0", features = ["resolver"], optional = true }
|
||||||
hickory-server = { version = "0.25.2", features = [
|
|
||||||
"resolver",
|
|
||||||
], optional = true }
|
|
||||||
|
|
||||||
bon = "3.9.1"
|
bon = "3.9.1"
|
||||||
derive_builder = "0.20.2"
|
derive_builder = "0.20.2"
|
||||||
@@ -403,7 +401,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
|
||||||
|
|||||||
+22
-16
@@ -3,10 +3,11 @@ 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_net::runtime::TokioRuntimeProvider;
|
||||||
use hickory_proto::xfer::Protocol;
|
use hickory_proto::rr::RData;
|
||||||
use hickory_resolver::config::{LookupIpStrategy, NameServerConfig, ResolverConfig, ResolverOpts};
|
use hickory_resolver::config::{
|
||||||
use hickory_resolver::name_server::{GenericConnector, TokioConnectionProvider};
|
ConnectionConfig, LookupIpStrategy, NameServerConfig, ResolverConfig, ResolverOpts,
|
||||||
|
};
|
||||||
use hickory_resolver::system_conf::read_system_conf;
|
use hickory_resolver::system_conf::read_system_conf;
|
||||||
use hickory_resolver::{Resolver, TokioResolver};
|
use hickory_resolver::{Resolver, TokioResolver};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
@@ -15,22 +16,23 @@ 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();
|
let mut default_resolve_config = ResolverConfig::default();
|
||||||
default_resolve_config.add_name_server(NameServerConfig::new(
|
default_resolve_config.add_name_server(NameServerConfig::new(
|
||||||
"223.5.5.5:53".parse().unwrap(),
|
"223.5.5.5".parse().unwrap(),
|
||||||
Protocol::Udp,
|
true,
|
||||||
|
vec![ConnectionConfig::udp()],
|
||||||
));
|
));
|
||||||
default_resolve_config.add_name_server(NameServerConfig::new(
|
default_resolve_config.add_name_server(NameServerConfig::new(
|
||||||
"180.184.1.1:53".parse().unwrap(),
|
"180.184.1.1".parse().unwrap(),
|
||||||
Protocol::Udp,
|
true,
|
||||||
|
vec![ConnectionConfig::udp()],
|
||||||
));
|
));
|
||||||
default_resolve_config
|
default_resolve_config
|
||||||
}
|
}
|
||||||
|
|
||||||
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<Resolver<TokioRuntimeProvider>>> = 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();
|
||||||
let mut opt = ResolverOpts::default();
|
let mut opt = ResolverOpts::default();
|
||||||
@@ -41,9 +43,9 @@ 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 builder =
|
||||||
.with_options(opt);
|
TokioResolver::builder_with_config(cfg, TokioRuntimeProvider::default()).with_options(opt);
|
||||||
Arc::new(builder.build())
|
Arc::new(builder.build().unwrap())
|
||||||
});
|
});
|
||||||
|
|
||||||
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 +55,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 txt_data = response
|
||||||
|
.answers()
|
||||||
.iter()
|
.iter()
|
||||||
|
.filter_map(|record| match record.data {
|
||||||
|
RData::TXT(ref txt) => Some(txt),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
.next()
|
.next()
|
||||||
.with_context(|| format!("no txt record found, domain_name: {}", domain_name))?;
|
.with_context(|| format!("no txt record found, domain_name: {}", domain_name))?;
|
||||||
|
|
||||||
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,6 +13,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use dashmap::DashSet;
|
use dashmap::DashSet;
|
||||||
|
use hickory_proto::rr::RData;
|
||||||
use hickory_resolver::proto::rr::rdata::SRV;
|
use hickory_resolver::proto::rr::rdata::SRV;
|
||||||
use rand::{Rng as _, seq::SliceRandom};
|
use rand::{Rng as _, seq::SliceRandom};
|
||||||
use strum::VariantArray;
|
use strum::VariantArray;
|
||||||
@@ -85,24 +86,21 @@ 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(|| {
|
||||||
format!(
|
format!(
|
||||||
"parse dst_url failed, protocol: {}, connector_dst: {}, port: {}, dst_url: {}",
|
"parse dst_url failed, protocol: {}, connector_dst: {}, port: {}, dst_url: {}",
|
||||||
protocol,
|
protocol, connector_dst, record.port, dst_url
|
||||||
connector_dst,
|
|
||||||
record.port(),
|
|
||||||
dst_url
|
|
||||||
)
|
)
|
||||||
})?,
|
})?,
|
||||||
record.priority() as _,
|
record.priority as _,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +127,14 @@ 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()
|
||||||
|
.iter()
|
||||||
|
.filter_map(|record| match record.data {
|
||||||
|
RData::SRV(ref srv) => Some(srv),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
{
|
||||||
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 {
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ use crate::dns::utils::addr::NameServerAddrGroup;
|
|||||||
use crate::dns::utils::parse;
|
use crate::dns::utils::parse;
|
||||||
use crate::proto::dns::GetExportConfigResponse;
|
use crate::proto::dns::GetExportConfigResponse;
|
||||||
use derivative::Derivative;
|
use derivative::Derivative;
|
||||||
|
use hickory_net::xfer::Protocol;
|
||||||
use hickory_proto::rr::{LowerName, Name};
|
use hickory_proto::rr::{LowerName, Name};
|
||||||
use hickory_proto::xfer::Protocol;
|
|
||||||
use serde::{Deserialize, Deserializer, Serialize};
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::dns::utils::addr::NameServerAddr;
|
use crate::dns::utils::addr::NameServerAddr;
|
||||||
|
use hickory_net::xfer::Protocol;
|
||||||
use hickory_proto::rr::LowerName;
|
use hickory_proto::rr::LowerName;
|
||||||
use hickory_proto::xfer::Protocol;
|
|
||||||
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
@@ -19,15 +19,6 @@ pub const DNS_DEFAULT_ADDRESS: NameServerAddr = NameServerAddr {
|
|||||||
addr: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(100, 100, 100, 101), 53)),
|
addr: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(100, 100, 100, 101), 53)),
|
||||||
};
|
};
|
||||||
|
|
||||||
pub static DNS_SUPPORTED_PROTOCOLS: [Protocol; 2] = [
|
|
||||||
Protocol::Udp,
|
|
||||||
Protocol::Tcp,
|
|
||||||
// Protocol::Tls,
|
|
||||||
// Protocol::Https,
|
|
||||||
// Protocol::Quic,
|
|
||||||
// Protocol::H3,
|
|
||||||
];
|
|
||||||
|
|
||||||
pub static DNS_SERVER_RPC_ADDR: LazyLock<Url> =
|
pub static DNS_SERVER_RPC_ADDR: LazyLock<Url> =
|
||||||
LazyLock::new(|| Url::parse("tcp://127.0.0.1:49813").unwrap());
|
LazyLock::new(|| Url::parse("tcp://127.0.0.1:49813").unwrap());
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use crate::proto::rpc_types;
|
|||||||
use crate::proto::rpc_types::controller::BaseController;
|
use crate::proto::rpc_types::controller::BaseController;
|
||||||
use crate::proto::utils::TransientDigest;
|
use crate::proto::utils::TransientDigest;
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
use hickory_server::authority::Catalog;
|
use hickory_server::zone_handler::Catalog;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use moka::future::Cache;
|
use moka::future::Cache;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
@@ -73,7 +73,7 @@ impl DnsNodeMgr {
|
|||||||
groups
|
groups
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.fold(Catalog::new(), |mut catalog, (origin, zones)| {
|
.fold(Catalog::new(), |mut catalog, (origin, zones)| {
|
||||||
catalog.upsert(origin.clone(), zones.iter_authorities().collect());
|
catalog.upsert(origin.clone(), zones.iter_zone_handlers().collect());
|
||||||
catalog
|
catalog
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -172,7 +172,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
use crate::dns::utils::response::ResponseHandle;
|
use crate::dns::utils::response::ResponseHandle;
|
||||||
use hickory_proto::op::{Message, ResponseCode};
|
use hickory_proto::op::{Message, ResponseCode};
|
||||||
use hickory_proto::rr::{RData, RecordType, rdata};
|
use hickory_proto::rr::{RData, RecordType};
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
use tokio::time::{Duration, sleep};
|
use tokio::time::{Duration, sleep};
|
||||||
|
|
||||||
@@ -203,9 +203,12 @@ mod tests {
|
|||||||
async fn lookup_a_record(mgr: &DnsNodeMgr, name: &str) -> anyhow::Result<Message> {
|
async fn lookup_a_record(mgr: &DnsNodeMgr, name: &str) -> anyhow::Result<Message> {
|
||||||
let request = new_request(name, RecordType::A)?;
|
let request = new_request(name, RecordType::A)?;
|
||||||
let response = ResponseHandle::new(512);
|
let response = ResponseHandle::new(512);
|
||||||
let info = mgr.catalog().lookup(&request, None, response.clone()).await;
|
let info = mgr
|
||||||
|
.catalog()
|
||||||
|
.lookup(&request, None, 0, response.clone())
|
||||||
|
.await;
|
||||||
|
|
||||||
assert_eq!(info.response_code(), ResponseCode::NoError);
|
assert_eq!(info.response_code, ResponseCode::NoError);
|
||||||
|
|
||||||
let response = response.into_inner().expect("response should exist");
|
let response = response.into_inner().expect("response should exist");
|
||||||
Message::from_vec(&response).map_err(Into::into)
|
Message::from_vec(&response).map_err(Into::into)
|
||||||
@@ -224,10 +227,10 @@ mod tests {
|
|||||||
let _ = send_heartbeat(&mgr, heartbeat_with_snapshot(id, snapshot)).await;
|
let _ = send_heartbeat(&mgr, heartbeat_with_snapshot(id, snapshot)).await;
|
||||||
|
|
||||||
let message = lookup_a_record(&mgr, "catalog.test.").await?;
|
let message = lookup_a_record(&mgr, "catalog.test.").await?;
|
||||||
assert!(message.answers().iter().any(|record| {
|
assert!(message.answers.iter().any(|record| {
|
||||||
matches!(
|
matches!(
|
||||||
record.data(),
|
record.data,
|
||||||
RData::A(addr) if *addr == rdata::a::A(Ipv4Addr::new(10, 20, 30, 40))
|
RData::A(addr) if *addr == Ipv4Addr::new(10, 20, 30, 40)
|
||||||
)
|
)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -255,16 +258,16 @@ mod tests {
|
|||||||
let message_a = lookup_a_record(&mgr, "node-a.test.").await?;
|
let message_a = lookup_a_record(&mgr, "node-a.test.").await?;
|
||||||
let message_b = lookup_a_record(&mgr, "node-b.test.").await?;
|
let message_b = lookup_a_record(&mgr, "node-b.test.").await?;
|
||||||
|
|
||||||
assert!(message_a.answers().iter().any(|record| {
|
assert!(message_a.answers.iter().any(|record| {
|
||||||
matches!(
|
matches!(
|
||||||
record.data(),
|
record.data,
|
||||||
RData::A(addr) if *addr == rdata::a::A(Ipv4Addr::new(10, 11, 12, 13))
|
RData::A(addr) if *addr == Ipv4Addr::new(10, 11, 12, 13)
|
||||||
)
|
)
|
||||||
}));
|
}));
|
||||||
assert!(message_b.answers().iter().any(|record| {
|
assert!(message_b.answers.iter().any(|record| {
|
||||||
matches!(
|
matches!(
|
||||||
record.data(),
|
record.data,
|
||||||
RData::A(addr) if *addr == rdata::a::A(Ipv4Addr::new(10, 21, 22, 23))
|
RData::A(addr) if *addr == Ipv4Addr::new(10, 21, 22, 23)
|
||||||
)
|
)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ forwarders = [
|
|||||||
3. - [x] (`moka::Cache`) 持续检查是否有过期(丢失心跳)的 DnsNode,需要把这些 DnsNode 提供的所有配置清除
|
3. - [x] (`moka::Cache`) 持续检查是否有过期(丢失心跳)的 DnsNode,需要把这些 DnsNode 提供的所有配置清除
|
||||||
4. - [x] 每次更新 zone 时自动添加 root zone
|
4. - [x] 每次更新 zone 时自动添加 root zone
|
||||||
- [x] (`Zone::system`) 并把它的 forwarder 设置为系统 DNS
|
- [x] (`Zone::system`) 并把它的 forwarder 设置为系统 DNS
|
||||||
5. - [x] 使用 snapshot 更新 zone。不用合并同名 zone,直接用 Zone 结构体提供的 ChainedAuthority 按顺序插入 Catalog 就行,不过注意要先插入 MemoryAuthority,这些都是 records,后插入 ForwardAuthority,这都是 forwarders
|
5. - [x] 使用 snapshot 更新 zone。不用合并同名 zone,直接用 Zone 结构体提供的 ChainedZoneHandler 按顺序插入 Catalog 就行,不过注意要先插入 MemoryZoneHandler,这些都是 records,后插入 ForwardZoneHandler,这都是 forwarders
|
||||||
6. - [x] 更新 zone 的时候自动去掉 forwarder 中导致回环的那些,就是把 addresses 和 listeners 去掉(root zone 也需要这个逻辑)
|
6. - [x] 更新 zone 的时候自动去掉 forwarder 中导致回环的那些,就是把 addresses 和 listeners 去掉(root zone 也需要这个逻辑)
|
||||||
7. - [x] 内部接口,控制 DnsServer 是否 bind 到某些 socket(也就是配置中的 listeners)
|
7. - [x] 内部接口,控制 DnsServer 是否 bind 到某些 socket(也就是配置中的 listeners)
|
||||||
8. - [x] Listeners 绑定失败打印日志(失败一个打印一次然后就跳过),即便这时 addresses 为空也不要停机。(否则释放 socket 绑定后会有 instance 抢占 socket 试图启动 server,然后就死循环)
|
8. - [x] Listeners 绑定失败打印日志(失败一个打印一次然后就跳过),即便这时 addresses 为空也不要停机。(否则释放 socket 绑定后会有 instance 抢占 socket 试图启动 server,然后就死循环)
|
||||||
|
|||||||
+14
-14
@@ -35,7 +35,7 @@
|
|||||||
- **服务层(数据面)**(`server.rs` + `node_mgr.rs` + `zone.rs`)
|
- **服务层(数据面)**(`server.rs` + `node_mgr.rs` + `zone.rs`)
|
||||||
- `DnsServer`:真正处理 DNS 请求、维护监听 socket、管理 hijack addresses。
|
- `DnsServer`:真正处理 DNS 请求、维护监听 socket、管理 hijack addresses。
|
||||||
- `DnsNodeMgr`:服务端的快照管理器,接收 Node 心跳,维护节点 TTL 与 dirty 状态。
|
- `DnsNodeMgr`:服务端的快照管理器,接收 Node 心跳,维护节点 TTL 与 dirty 状态。
|
||||||
- `Zone`/`ZoneGroup`:把 records + forwarders 变成 Hickory `Authority` 并装配 `Catalog`。
|
- `Zone`/`ZoneGroup`:把 records + forwarders 变成 Hickory `ZoneHandler` 并装配 `Catalog`。
|
||||||
|
|
||||||
- **系统集成层**(`system/*`)
|
- **系统集成层**(`system/*`)
|
||||||
- 将当前 DNS 配置下发到 OS(`SystemConfigurator` 抽象)。
|
- 将当前 DNS 配置下发到 OS(`SystemConfigurator` 抽象)。
|
||||||
@@ -52,9 +52,9 @@
|
|||||||
- **`ZoneData` / `Zone`**(`proto/dns.proto` + `zone.rs`)
|
- **`ZoneData` / `Zone`**(`proto/dns.proto` + `zone.rs`)
|
||||||
- `ZoneData` 是网络传输模型(protobuf),含 `id/origin/ttl/records/forwarders`。
|
- `ZoneData` 是网络传输模型(protobuf),含 `id/origin/ttl/records/forwarders`。
|
||||||
- `Zone` 是运行期模型:
|
- `Zone` 是运行期模型:
|
||||||
- `records -> InMemoryAuthority`
|
- `records -> InMemoryZoneHandler`
|
||||||
- `forwarders -> ForwardAuthority`
|
- `forwarders -> ForwardZoneHandler`
|
||||||
- 同 origin 可链式共存(ChainedAuthority 语义)。
|
- 同 origin 可链式共存(ChainedZoneHandler 语义)。
|
||||||
|
|
||||||
- **`DnsSnapshot`**(`proto/dns.proto`)
|
- **`DnsSnapshot`**(`proto/dns.proto`)
|
||||||
- Node 发给 Server 的完整状态:`zones + addresses + listeners`。
|
- Node 发给 Server 的完整状态:`zones + addresses + listeners`。
|
||||||
@@ -324,7 +324,7 @@ Node 发送 heartbeat 时:
|
|||||||
2. 追加 `Zone::system()` 作为 root zone。
|
2. 追加 `Zone::system()` 作为 root zone。
|
||||||
3. 收集本地所有 `addresses + listeners` 形成 `local` 集合。
|
3. 收集本地所有 `addresses + listeners` 形成 `local` 集合。
|
||||||
4. 遍历每个 zone 的 forwarders,剔除命中 `local` 的 nameserver(避免显式回环)。
|
4. 遍历每个 zone 的 forwarders,剔除命中 `local` 的 nameserver(避免显式回环)。
|
||||||
5. 以 `origin -> authorities[]` 方式 `upsert` 到 Hickory `Catalog`。
|
5. 以 `origin -> zone_handlers[]` 方式 `upsert` 到 Hickory `Catalog`。
|
||||||
|
|
||||||
### 10.3 `DnsServer::run`:三路热重载
|
### 10.3 `DnsServer::run`:三路热重载
|
||||||
|
|
||||||
@@ -380,12 +380,12 @@ Node 发送 heartbeat 时:
|
|||||||
2. 用 Hickory `Parser` 解析 zone 文本(origin + RR)。
|
2. 用 Hickory `Parser` 解析 zone 文本(origin + RR)。
|
||||||
3. 把 `forwarders` URL 转成 `NameServerAddr`,为空则 `forward=None`。
|
3. 把 `forwarders` URL 转成 `NameServerAddr`,为空则 `forward=None`。
|
||||||
|
|
||||||
这确保网络收到的 `ZoneData` 能直接映射成可执行 authority。
|
这确保网络收到的 `ZoneData` 能直接映射成可执行 zone_handler。
|
||||||
|
|
||||||
### 11.3 Authority 构建策略
|
### 11.3 ZoneHandler 构建策略
|
||||||
|
|
||||||
- `create_memory_authority()`:仅当 records 非空时创建 `InMemoryAuthority`。
|
- `create_memory_zone_handler()`:仅当 records 非空时创建 `InMemoryZoneHandler`。
|
||||||
- `create_forward_authority()`:仅当 forward 非空时创建 `ForwardAuthority`。
|
- `create_forward_zone_handler()`:仅当 forward 非空时创建 `ForwardZoneHandler`。
|
||||||
|
|
||||||
因此允许 3 种 zone 形态:
|
因此允许 3 种 zone 形态:
|
||||||
|
|
||||||
@@ -396,10 +396,10 @@ Node 发送 heartbeat 时:
|
|||||||
### 11.4 `ZoneGroup` 与同源链式行为
|
### 11.4 `ZoneGroup` 与同源链式行为
|
||||||
|
|
||||||
- `ZoneGroup::into_groups()` 按 `origin` 分组。
|
- `ZoneGroup::into_groups()` 按 `origin` 分组。
|
||||||
- `iter_authorities()` 对每个 zone 按顺序产出:先 memory,再 forward。
|
- `iter_zone_handlers()` 对每个 zone 按顺序产出:先 memory,再 forward。
|
||||||
- `DnsNodeMgr::catalog()` 把同 origin 的多个 zone authority 以数组形式 `upsert`。
|
- `DnsNodeMgr::catalog()` 把同 origin 的多个 zone zone_handler 以数组形式 `upsert`。
|
||||||
|
|
||||||
结果是同 origin 下可自然形成 ChainedAuthority,不做“硬合并单 Zone”,与 `plan.md` 一致。
|
结果是同 origin 下可自然形成 ChainedZoneHandler,不做“硬合并单 Zone”,与 `plan.md` 一致。
|
||||||
|
|
||||||
### 11.5 `Zone::system()` 的作用边界
|
### 11.5 `Zone::system()` 的作用边界
|
||||||
|
|
||||||
@@ -473,7 +473,7 @@ Node 发送 heartbeat 时:
|
|||||||
- `dns/tests.rs`:测试基建与辅助函数(构造环境、启动 `DnsNode`、DNS 查询断言工具)。
|
- `dns/tests.rs`:测试基建与辅助函数(构造环境、启动 `DnsNode`、DNS 查询断言工具)。
|
||||||
- `dns/server.rs`:数据面与 server 行为主测试集。
|
- `dns/server.rs`:数据面与 server 行为主测试集。
|
||||||
- `dns/node_mgr.rs`:聚合 catalog 的基本可用性测试。
|
- `dns/node_mgr.rs`:聚合 catalog 的基本可用性测试。
|
||||||
- `dns/zone.rs`:配置解析、记录转换、authority 装配测试。
|
- `dns/zone.rs`:配置解析、记录转换、zone_handler 装配测试。
|
||||||
|
|
||||||
> 说明:`system/*` 也有测试,但本轮文档按约定不展开。
|
> 说明:`system/*` 也有测试,但本轮文档按约定不展开。
|
||||||
|
|
||||||
@@ -504,7 +504,7 @@ Node 发送 heartbeat 时:
|
|||||||
- TOML `DnsConfig` 解析。
|
- TOML `DnsConfig` 解析。
|
||||||
- `ZoneConfig -> ZoneData -> Zone` 转换链。
|
- `ZoneConfig -> ZoneData -> Zone` 转换链。
|
||||||
- record 解析/TTL 基本行为。
|
- record 解析/TTL 基本行为。
|
||||||
- memory/forward authority 构建,以及通过 server 查询验证。
|
- memory/forward zone_handler 构建,以及通过 server 查询验证。
|
||||||
|
|
||||||
该测试更多是“模型与解析正确性”,不是策略执行链路完整验证。
|
该测试更多是“模型与解析正确性”,不是策略执行链路完整验证。
|
||||||
|
|
||||||
|
|||||||
+57
-60
@@ -12,13 +12,12 @@ use crate::tunnel::packet_def::ZCPacket;
|
|||||||
use crate::tunnel::tcp::TcpTunnelListener;
|
use crate::tunnel::tcp::TcpTunnelListener;
|
||||||
use crate::utils::task::AsyncRuntime;
|
use crate::utils::task::AsyncRuntime;
|
||||||
use derivative::Derivative;
|
use derivative::Derivative;
|
||||||
use hickory_proto::serialize::binary::BinDecodable;
|
use hickory_net::runtime::{Time, TokioTime};
|
||||||
use hickory_proto::xfer::Protocol;
|
use hickory_net::xfer::Protocol;
|
||||||
use hickory_server::authority::MessageRequest;
|
|
||||||
use hickory_server::{
|
use hickory_server::{
|
||||||
ServerFuture,
|
Server,
|
||||||
authority::Catalog,
|
|
||||||
server::{Request, RequestHandler, ResponseHandler, ResponseInfo},
|
server::{Request, RequestHandler, ResponseHandler, ResponseInfo},
|
||||||
|
zone_handler::Catalog,
|
||||||
};
|
};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use pnet::packet::icmp::{IcmpTypes, MutableIcmpPacket};
|
use pnet::packet::icmp::{IcmpTypes, MutableIcmpPacket};
|
||||||
@@ -55,7 +54,7 @@ impl DynamicCatalog {
|
|||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl RequestHandler for DynamicCatalog {
|
impl RequestHandler for DynamicCatalog {
|
||||||
async fn handle_request<R: ResponseHandler>(
|
async fn handle_request<R: ResponseHandler, T: Time>(
|
||||||
&self,
|
&self,
|
||||||
request: &Request,
|
request: &Request,
|
||||||
response_handle: R,
|
response_handle: R,
|
||||||
@@ -63,7 +62,7 @@ impl RequestHandler for DynamicCatalog {
|
|||||||
self.inner
|
self.inner
|
||||||
.read()
|
.read()
|
||||||
.await
|
.await
|
||||||
.handle_request(request, response_handle)
|
.handle_request::<_, T>(request, response_handle)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,6 +86,7 @@ pub struct DnsServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const DNS_SERVER_LISTENER_TCP_TIMEOUT: Duration = Duration::from_secs(5);
|
const DNS_SERVER_LISTENER_TCP_TIMEOUT: Duration = Duration::from_secs(5);
|
||||||
|
const DNS_SERVER_LISTENER_TCP_BUFFER_SIZE: usize = 32;
|
||||||
|
|
||||||
impl DnsServer {
|
impl DnsServer {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
@@ -187,15 +187,18 @@ impl DnsServer {
|
|||||||
|
|
||||||
let runtime = runtime.get_or_insert_default();
|
let runtime = runtime.get_or_insert_default();
|
||||||
|
|
||||||
let mut server = ServerFuture::new(self.catalog.clone());
|
let mut server = Server::new(self.catalog.clone());
|
||||||
for listener in &listeners {
|
for listener in &listeners {
|
||||||
let addr = listener.addr;
|
let addr = listener.addr;
|
||||||
tracing::info!(?addr, "binding listener");
|
tracing::info!(?addr, "binding listener");
|
||||||
if let Err(error) = match listener.protocol {
|
if let Err(error) = match listener.protocol {
|
||||||
Protocol::Tcp => bind()
|
Protocol::Tcp => bind().addr(addr).call().map(|s| {
|
||||||
.addr(addr)
|
server.register_listener(
|
||||||
.call()
|
s,
|
||||||
.map(|s| server.register_listener(s, DNS_SERVER_LISTENER_TCP_TIMEOUT)),
|
DNS_SERVER_LISTENER_TCP_TIMEOUT,
|
||||||
|
DNS_SERVER_LISTENER_TCP_BUFFER_SIZE,
|
||||||
|
)
|
||||||
|
}),
|
||||||
Protocol::Udp => bind().addr(addr).call().map(|s| server.register_socket(s)),
|
Protocol::Udp => bind().addr(addr).call().map(|s| server.register_socket(s)),
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
} {
|
} {
|
||||||
@@ -395,11 +398,12 @@ impl DnsServer {
|
|||||||
(
|
(
|
||||||
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)),
|
||||||
Protocol::Udp,
|
Protocol::Udp,
|
||||||
),
|
)
|
||||||
|
.ok()?,
|
||||||
request_payload.len(),
|
request_payload.len(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
@@ -412,7 +416,7 @@ impl DnsServer {
|
|||||||
let response = ResponseHandle::new(512);
|
let response = ResponseHandle::new(512);
|
||||||
|
|
||||||
self.catalog
|
self.catalog
|
||||||
.handle_request(&request, response.clone())
|
.handle_request::<_, TokioTime>(&request, response.clone())
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
response.into_inner()?
|
response.into_inner()?
|
||||||
@@ -480,15 +484,15 @@ mod tests {
|
|||||||
use crate::peers::tests::create_mock_peer_manager;
|
use crate::peers::tests::create_mock_peer_manager;
|
||||||
use crate::proto::dns::DnsNodeMgrRpc;
|
use crate::proto::dns::DnsNodeMgrRpc;
|
||||||
use crate::proto::rpc_types::controller::BaseController;
|
use crate::proto::rpc_types::controller::BaseController;
|
||||||
use hickory_client::client::{Client, ClientHandle};
|
use hickory_net::client::{Client, ClientHandle};
|
||||||
|
use hickory_net::runtime::TokioRuntimeProvider;
|
||||||
|
use hickory_net::udp::UdpClientStream;
|
||||||
use hickory_proto::op::{Message, MessageType, OpCode, Query};
|
use hickory_proto::op::{Message, MessageType, OpCode, Query};
|
||||||
use hickory_proto::rr::{DNSClass, Name, RData, Record, RecordType, rdata};
|
use hickory_proto::rr::{DNSClass, Name, RData, Record, RecordType, rdata};
|
||||||
use hickory_proto::runtime::TokioRuntimeProvider;
|
|
||||||
use hickory_proto::serialize::binary::BinEncodable;
|
use hickory_proto::serialize::binary::BinEncodable;
|
||||||
use hickory_proto::udp::UdpClientStream;
|
use hickory_server::store::in_memory::InMemoryZoneHandler;
|
||||||
use hickory_server::authority::Catalog;
|
use hickory_server::zone_handler::ZoneType;
|
||||||
use hickory_server::authority::ZoneType;
|
use hickory_server::zone_handler::{AxfrPolicy, Catalog};
|
||||||
use hickory_server::store::in_memory::InMemoryAuthority;
|
|
||||||
use pnet::packet::icmp::{IcmpPacket, IcmpTypes, MutableIcmpPacket};
|
use pnet::packet::icmp::{IcmpPacket, IcmpTypes, MutableIcmpPacket};
|
||||||
use pnet::packet::ip::IpNextHeaderProtocols;
|
use pnet::packet::ip::IpNextHeaderProtocols;
|
||||||
use pnet::packet::ipv4::{Ipv4Packet, MutableIpv4Packet};
|
use pnet::packet::ipv4::{Ipv4Packet, MutableIpv4Packet};
|
||||||
@@ -504,7 +508,11 @@ mod tests {
|
|||||||
/// Build a `Catalog` containing a single A record: `test.example.com -> 1.2.3.4`.
|
/// Build a `Catalog` containing a single A record: `test.example.com -> 1.2.3.4`.
|
||||||
fn build_test_catalog() -> Catalog {
|
fn build_test_catalog() -> Catalog {
|
||||||
let origin = Name::from_str("example.com.").unwrap();
|
let origin = Name::from_str("example.com.").unwrap();
|
||||||
let mut authority = InMemoryAuthority::empty(origin.clone(), ZoneType::Primary, false);
|
let mut zone_handler = InMemoryZoneHandler::<TokioRuntimeProvider>::empty(
|
||||||
|
origin.clone(),
|
||||||
|
ZoneType::Primary,
|
||||||
|
AxfrPolicy::default(),
|
||||||
|
);
|
||||||
|
|
||||||
let record = Record::from_rdata(
|
let record = Record::from_rdata(
|
||||||
Name::from_str("test.example.com.").unwrap(),
|
Name::from_str("test.example.com.").unwrap(),
|
||||||
@@ -512,16 +520,18 @@ mod tests {
|
|||||||
RData::A(rdata::a::A(Ipv4Addr::new(1, 2, 3, 4))),
|
RData::A(rdata::a::A(Ipv4Addr::new(1, 2, 3, 4))),
|
||||||
);
|
);
|
||||||
let rr_key =
|
let rr_key =
|
||||||
hickory_proto::rr::RrKey::new(record.name().clone().into(), record.record_type());
|
hickory_proto::rr::RrKey::new(record.name.clone().into(), record.record_type());
|
||||||
let mut rr_set =
|
let mut rr_set =
|
||||||
hickory_proto::rr::RecordSet::new(record.name().clone(), record.record_type(), 0);
|
hickory_proto::rr::RecordSet::new(record.name.clone(), record.record_type(), 0);
|
||||||
rr_set.insert(record, 0);
|
rr_set.insert(record, 0);
|
||||||
authority.records_get_mut().insert(rr_key, Arc::new(rr_set));
|
zone_handler
|
||||||
|
.records_get_mut()
|
||||||
|
.insert(rr_key, Arc::new(rr_set));
|
||||||
|
|
||||||
let mut catalog = Catalog::new();
|
let mut catalog = Catalog::new();
|
||||||
catalog.upsert(
|
catalog.upsert(
|
||||||
origin.into(),
|
origin.into(),
|
||||||
vec![Arc::new(authority) as Arc<dyn hickory_server::authority::AuthorityObject>],
|
vec![Arc::new(zone_handler) as Arc<dyn hickory_server::zone_handler::ZoneHandler>],
|
||||||
);
|
);
|
||||||
catalog
|
catalog
|
||||||
}
|
}
|
||||||
@@ -578,11 +588,8 @@ mod tests {
|
|||||||
|
|
||||||
/// Build a minimal DNS query message for `name` and encode it to bytes.
|
/// Build a minimal DNS query message for `name` and encode it to bytes.
|
||||||
fn build_dns_query_bytes(name: &str) -> Vec<u8> {
|
fn build_dns_query_bytes(name: &str) -> Vec<u8> {
|
||||||
let mut msg = Message::new();
|
let mut msg = Message::new(0x1234, MessageType::Query, OpCode::Query);
|
||||||
msg.set_id(0x1234);
|
msg.metadata.recursion_desired = true;
|
||||||
msg.set_message_type(MessageType::Query);
|
|
||||||
msg.set_op_code(OpCode::Query);
|
|
||||||
msg.set_recursion_desired(true);
|
|
||||||
let mut query = Query::new();
|
let mut query = Query::new();
|
||||||
query.set_name(Name::from_str(name).unwrap());
|
query.set_name(Name::from_str(name).unwrap());
|
||||||
query.set_query_type(RecordType::A);
|
query.set_query_type(RecordType::A);
|
||||||
@@ -796,17 +803,17 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let dns_reply = Message::from_vec(udp_reply.payload()).unwrap();
|
let dns_reply = Message::from_vec(udp_reply.payload()).unwrap();
|
||||||
assert_eq!(dns_reply.id(), 0x1234);
|
assert_eq!(dns_reply.id, 0x1234);
|
||||||
assert!(
|
assert!(
|
||||||
!dns_reply.answers().is_empty(),
|
!dns_reply.answers.is_empty(),
|
||||||
"DNS reply should contain answers"
|
"DNS reply should contain answers"
|
||||||
);
|
);
|
||||||
|
|
||||||
let answer = &dns_reply.answers()[0];
|
let answer = &dns_reply.answers[0];
|
||||||
if let RData::A(a) = answer.data() {
|
if let RData::A(a) = answer.data {
|
||||||
assert_eq!(a.0, Ipv4Addr::new(1, 2, 3, 4));
|
assert_eq!(a.0, Ipv4Addr::new(1, 2, 3, 4));
|
||||||
} else {
|
} else {
|
||||||
panic!("expected A record in answer, got {:?}", answer.data());
|
panic!("expected A record in answer, got {:?}", answer.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -814,7 +821,7 @@ mod tests {
|
|||||||
/// send a query with a `hickory_client`, and verify the response.
|
/// send a query with a `hickory_client`, and verify the response.
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn should_resolve_record_via_real_udp_listener() {
|
async fn should_resolve_record_via_real_udp_listener() {
|
||||||
use hickory_server::ServerFuture;
|
use hickory_server::Server;
|
||||||
use tokio::net::UdpSocket;
|
use tokio::net::UdpSocket;
|
||||||
use tokio::time::timeout;
|
use tokio::time::timeout;
|
||||||
|
|
||||||
@@ -825,7 +832,7 @@ mod tests {
|
|||||||
let socket = UdpSocket::bind("127.0.0.1:0").await.unwrap();
|
let socket = UdpSocket::bind("127.0.0.1:0").await.unwrap();
|
||||||
let addr = socket.local_addr().unwrap();
|
let addr = socket.local_addr().unwrap();
|
||||||
|
|
||||||
let mut server = ServerFuture::new(catalog);
|
let mut server = Server::new(catalog);
|
||||||
server.register_socket(socket);
|
server.register_socket(socket);
|
||||||
|
|
||||||
let shutdown_token = server.shutdown_token().clone();
|
let shutdown_token = server.shutdown_token().clone();
|
||||||
@@ -834,15 +841,10 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Send a real DNS query using hickory_client.
|
// Send a real DNS query using hickory_client.
|
||||||
let conn = UdpClientStream::builder(addr, TokioRuntimeProvider::default()).build();
|
let stream = UdpClientStream::builder(addr, TokioRuntimeProvider::default()).build();
|
||||||
let (mut client, bg) = timeout(Duration::from_secs(2), Client::connect(conn))
|
let (mut client, bg) = Client::<TokioRuntimeProvider>::from_sender(stream);
|
||||||
.await
|
|
||||||
.expect("client connect timeout")
|
|
||||||
.expect("client connect failed");
|
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(bg);
|
||||||
bg.await.ok();
|
|
||||||
});
|
|
||||||
|
|
||||||
let response = timeout(
|
let response = timeout(
|
||||||
Duration::from_secs(2),
|
Duration::from_secs(2),
|
||||||
@@ -856,12 +858,12 @@ mod tests {
|
|||||||
.expect("query timeout")
|
.expect("query timeout")
|
||||||
.expect("query failed");
|
.expect("query failed");
|
||||||
|
|
||||||
assert!(!response.answers().is_empty(), "should get answers");
|
assert!(!response.answers.is_empty(), "should get answers");
|
||||||
let a_record = &response.answers()[0];
|
let a_record = &response.answers[0];
|
||||||
if let RData::A(a) = a_record.data() {
|
if let RData::A(a) = a_record.data {
|
||||||
assert_eq!(a.0, Ipv4Addr::new(1, 2, 3, 4));
|
assert_eq!(a.0, Ipv4Addr::new(1, 2, 3, 4));
|
||||||
} else {
|
} else {
|
||||||
panic!("expected A record, got {:?}", a_record.data());
|
panic!("expected A record, got {:?}", a_record.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shutdown the server.
|
// Shutdown the server.
|
||||||
@@ -1028,14 +1030,9 @@ mod tests {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let conn = UdpClientStream::builder(good_addr, TokioRuntimeProvider::default()).build();
|
let stream = UdpClientStream::builder(good_addr, TokioRuntimeProvider::default()).build();
|
||||||
let (mut client, bg) = timeout(Duration::from_secs(2), Client::connect(conn))
|
let (mut client, bg) = Client::<TokioRuntimeProvider>::from_sender(stream);
|
||||||
.await
|
tokio::spawn(bg);
|
||||||
.expect("client connect timeout")
|
|
||||||
.expect("client connect failed");
|
|
||||||
tokio::spawn(async move {
|
|
||||||
let _ = bg.await;
|
|
||||||
});
|
|
||||||
|
|
||||||
let response = timeout(
|
let response = timeout(
|
||||||
Duration::from_secs(2),
|
Duration::from_secs(2),
|
||||||
@@ -1049,7 +1046,7 @@ mod tests {
|
|||||||
.expect("query timeout")
|
.expect("query timeout")
|
||||||
.expect("query failed");
|
.expect("query failed");
|
||||||
|
|
||||||
assert!(!response.answers().is_empty());
|
assert!(!response.answers.is_empty());
|
||||||
|
|
||||||
if let Some(runtime) = runtime.take() {
|
if let Some(runtime) = runtime.take() {
|
||||||
let _ = runtime.stop(None).await;
|
let _ = runtime.stop(None).await;
|
||||||
|
|||||||
+28
-40
@@ -20,15 +20,14 @@ use crate::peers::tests::{connect_peer_manager, wait_route_appear};
|
|||||||
use crate::proto::common::{NatType, Url};
|
use crate::proto::common::{NatType, Url};
|
||||||
use crate::proto::dns::{DnsSnapshot, HeartbeatRequest, ZoneData};
|
use crate::proto::dns::{DnsSnapshot, HeartbeatRequest, ZoneData};
|
||||||
use cidr::Ipv4Inet;
|
use cidr::Ipv4Inet;
|
||||||
use hickory_client::client::{Client, ClientHandle as _};
|
use hickory_net::client::{Client, ClientHandle};
|
||||||
|
use hickory_net::runtime::TokioRuntimeProvider;
|
||||||
|
use hickory_net::udp::UdpClientStream;
|
||||||
|
use hickory_net::xfer::Protocol;
|
||||||
use hickory_proto::op::{Message, MessageType, OpCode, Query};
|
use hickory_proto::op::{Message, MessageType, OpCode, Query};
|
||||||
use hickory_proto::rr;
|
use hickory_proto::rr;
|
||||||
use hickory_proto::rr::{Name, RecordType};
|
use hickory_proto::rr::{DNSClass, Name, RData, RecordType};
|
||||||
use hickory_proto::runtime::TokioRuntimeProvider;
|
use hickory_proto::serialize::binary::{BinEncodable, BinEncoder};
|
||||||
use hickory_proto::serialize::binary::{BinDecodable, BinEncodable, BinEncoder};
|
|
||||||
use hickory_proto::udp::UdpClientStream;
|
|
||||||
use hickory_proto::xfer::Protocol;
|
|
||||||
use hickory_server::authority::MessageRequest;
|
|
||||||
use hickory_server::server::Request;
|
use hickory_server::server::Request;
|
||||||
use tokio::sync::Notify;
|
use tokio::sync::Notify;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
@@ -159,17 +158,17 @@ pub async fn check_dns_record(fake_ip: &Ipv4Addr, domain: &str, expected_ip: &st
|
|||||||
|
|
||||||
pub async fn check_dns_record_at(server_addr: SocketAddr, domain: &str, expected_ip: &str) {
|
pub async fn check_dns_record_at(server_addr: SocketAddr, domain: &str, expected_ip: &str) {
|
||||||
let expected = expected_ip.parse::<Ipv4Addr>().unwrap();
|
let expected = expected_ip.parse::<Ipv4Addr>().unwrap();
|
||||||
let name = rr::Name::from_str(domain).unwrap();
|
let name = Name::from_str(domain).unwrap();
|
||||||
let deadline = Instant::now() + Duration::from_secs(30);
|
let deadline = Instant::now() + Duration::from_secs(30);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let stream = UdpClientStream::builder(server_addr, TokioRuntimeProvider::default()).build();
|
let stream = UdpClientStream::builder(server_addr, TokioRuntimeProvider::default()).build();
|
||||||
let (mut client, background) = Client::connect(stream).await.unwrap();
|
let (mut client, background) = Client::<TokioRuntimeProvider>::from_sender(stream);
|
||||||
let background_task = tokio::spawn(background);
|
let background_task = tokio::spawn(background);
|
||||||
|
|
||||||
let query_result = tokio::time::timeout(
|
let query_result = tokio::time::timeout(
|
||||||
Duration::from_secs(2),
|
Duration::from_secs(2),
|
||||||
client.query(name.clone(), rr::DNSClass::IN, rr::RecordType::A),
|
client.query(name.clone(), DNSClass::IN, RecordType::A),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@@ -178,13 +177,13 @@ pub async fn check_dns_record_at(server_addr: SocketAddr, domain: &str, expected
|
|||||||
|
|
||||||
let attempt_err = match query_result {
|
let attempt_err = match query_result {
|
||||||
Ok(Ok(response)) => {
|
Ok(Ok(response)) => {
|
||||||
if response.answers().len() == 1
|
if response.answers.len() == 1
|
||||||
&& let Some(resp) = response.answers().first()
|
&& let Some(resp) = response.answers.first()
|
||||||
&& resp.clone().into_parts().rdata.into_a().unwrap().0 == expected
|
&& matches!(resp.clone().data, RData::A(a) if a.0 == expected)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
format!("unexpected response: {:?}", response.answers())
|
format!("unexpected response: {:?}", response.answers)
|
||||||
}
|
}
|
||||||
Ok(Err(e)) => {
|
Ok(Err(e)) => {
|
||||||
format!("DNS query failed for domain '{domain}': {e}")
|
format!("DNS query failed for domain '{domain}': {e}")
|
||||||
@@ -213,15 +212,11 @@ pub async fn check_dns_record_missing_at(server_addr: SocketAddr, domain: &str)
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
let stream = UdpClientStream::builder(server_addr, TokioRuntimeProvider::default()).build();
|
let stream = UdpClientStream::builder(server_addr, TokioRuntimeProvider::default()).build();
|
||||||
let (mut client, background) = Client::connect(stream).await.unwrap();
|
let (mut client, background) = Client::<TokioRuntimeProvider>::from_sender(stream);
|
||||||
let background_task = tokio::spawn(background);
|
let background_task = tokio::spawn(background);
|
||||||
let query_result = tokio::time::timeout(
|
let query_result = tokio::time::timeout(
|
||||||
Duration::from_secs(2),
|
Duration::from_secs(2),
|
||||||
client.query(
|
client.query(Name::from_str(domain).unwrap(), DNSClass::IN, RecordType::A),
|
||||||
rr::Name::from_str(domain).unwrap(),
|
|
||||||
rr::DNSClass::IN,
|
|
||||||
rr::RecordType::A,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
background_task.abort();
|
background_task.abort();
|
||||||
@@ -229,10 +224,10 @@ pub async fn check_dns_record_missing_at(server_addr: SocketAddr, domain: &str)
|
|||||||
|
|
||||||
let attempt_err = match query_result {
|
let attempt_err = match query_result {
|
||||||
Ok(Ok(response)) => {
|
Ok(Ok(response)) => {
|
||||||
if response.answers().is_empty() {
|
if response.answers.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
format!("unexpected non-empty response: {:?}", response.answers())
|
format!("unexpected non-empty response: {:?}", response.answers)
|
||||||
}
|
}
|
||||||
Ok(Err(e)) => {
|
Ok(Err(e)) => {
|
||||||
format!("DNS query for missing record failed for domain '{domain}': {e}")
|
format!("DNS query for missing record failed for domain '{domain}': {e}")
|
||||||
@@ -253,22 +248,19 @@ pub async fn check_dns_record_missing_at(server_addr: SocketAddr, domain: &str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_request(name: &str, rtype: RecordType) -> anyhow::Result<Request> {
|
pub fn new_request(name: &str, rtype: RecordType) -> anyhow::Result<Request> {
|
||||||
let mut query = Message::new();
|
let mut msg = Message::new(0, MessageType::Query, OpCode::Query);
|
||||||
query.set_id(0);
|
msg.metadata.recursion_desired = true;
|
||||||
query.set_message_type(MessageType::Query);
|
msg.add_query(Query::query(Name::from_ascii(name)?, rtype));
|
||||||
query.set_op_code(OpCode::Query);
|
|
||||||
query.set_recursion_desired(true);
|
|
||||||
query.add_query(Query::query(Name::from_ascii(name)?, rtype));
|
|
||||||
|
|
||||||
let mut request = Vec::new();
|
let mut request = Vec::new();
|
||||||
let mut encoder = BinEncoder::new(&mut request);
|
let mut encoder = BinEncoder::new(&mut request);
|
||||||
query.emit(&mut encoder)?;
|
msg.emit(&mut encoder)?;
|
||||||
|
|
||||||
Ok(Request::new(
|
Ok(Request::from_bytes(
|
||||||
MessageRequest::from_bytes(&request)?,
|
request,
|
||||||
SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0).into(),
|
SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0).into(),
|
||||||
Protocol::Udp,
|
Protocol::Udp,
|
||||||
))
|
)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn wait_route_disappear(peer_mgr: Arc<PeerManager>, target_peer_id: u32) {
|
async fn wait_route_disappear(peer_mgr: Arc<PeerManager>, target_peer_id: u32) {
|
||||||
@@ -313,13 +305,12 @@ async fn check_dns_unavailable_at(server_addr: SocketAddr, domain: &str) {
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
let stream = UdpClientStream::builder(server_addr, TokioRuntimeProvider::default()).build();
|
let stream = UdpClientStream::builder(server_addr, TokioRuntimeProvider::default()).build();
|
||||||
let connect = Client::connect(stream).await;
|
let (mut client, background) = Client::<TokioRuntimeProvider>::from_sender(stream);
|
||||||
|
|
||||||
if let Ok((mut client, background)) = connect {
|
|
||||||
let background_task = tokio::spawn(background);
|
let background_task = tokio::spawn(background);
|
||||||
let query_result = tokio::time::timeout(
|
let query_result = tokio::time::timeout(
|
||||||
Duration::from_secs(1),
|
Duration::from_secs(1),
|
||||||
client.query(name.clone(), rr::DNSClass::IN, rr::RecordType::A),
|
client.query(name.clone(), DNSClass::IN, RecordType::A),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@@ -327,19 +318,16 @@ async fn check_dns_unavailable_at(server_addr: SocketAddr, domain: &str) {
|
|||||||
let _ = background_task.await;
|
let _ = background_task.await;
|
||||||
|
|
||||||
match query_result {
|
match query_result {
|
||||||
Ok(Ok(response)) if !response.answers().is_empty() => {
|
Ok(Ok(response)) if !response.answers.is_empty() => {
|
||||||
if Instant::now() >= deadline {
|
if Instant::now() >= deadline {
|
||||||
panic!(
|
panic!(
|
||||||
"DNS endpoint {server_addr} still answered for '{domain}': {:?}",
|
"DNS endpoint {server_addr} still answered for '{domain}': {:?}",
|
||||||
response.answers()
|
response.answers
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => return,
|
_ => return,
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
tokio::time::sleep(Duration::from_millis(200)).await;
|
tokio::time::sleep(Duration::from_millis(200)).await;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
use crate::dns::config::DNS_SUPPORTED_PROTOCOLS;
|
|
||||||
use crate::proto;
|
use crate::proto;
|
||||||
use crate::proto::utils::RepeatedMessageModel;
|
use crate::proto::utils::RepeatedMessageModel;
|
||||||
use anyhow::{Error, anyhow};
|
use anyhow::{Error, anyhow};
|
||||||
use hickory_proto::xfer::Protocol;
|
use hickory_net::xfer::Protocol;
|
||||||
use hickory_resolver::config::{NameServerConfig, NameServerConfigGroup};
|
use hickory_resolver::config::{ConnectionConfig, NameServerConfig};
|
||||||
|
use serde::de::IntoDeserializer;
|
||||||
|
use serde::{Deserialize, de};
|
||||||
use serde_with::{DeserializeFromStr, SerializeDisplay};
|
use serde_with::{DeserializeFromStr, SerializeDisplay};
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::net::{IpAddr, SocketAddr};
|
use std::net::{IpAddr, SocketAddr};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use url::Url;
|
use url::{Host, Url};
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, SerializeDisplay, DeserializeFromStr)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, SerializeDisplay, DeserializeFromStr)]
|
||||||
pub struct NameServerAddr {
|
pub struct NameServerAddr {
|
||||||
@@ -18,15 +19,22 @@ pub struct NameServerAddr {
|
|||||||
|
|
||||||
impl From<NameServerAddr> for NameServerConfig {
|
impl From<NameServerAddr> for NameServerConfig {
|
||||||
fn from(value: NameServerAddr) -> Self {
|
fn from(value: NameServerAddr) -> Self {
|
||||||
Self::new(value.addr, value.protocol)
|
let mut config = match value.protocol {
|
||||||
|
Protocol::Udp => ConnectionConfig::udp(),
|
||||||
|
Protocol::Tcp => ConnectionConfig::tcp(),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
};
|
||||||
|
config.port = value.addr.port();
|
||||||
|
Self::new(value.addr.ip(), true, vec![config])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&NameServerConfig> for NameServerAddr {
|
impl From<&NameServerConfig> for NameServerAddr {
|
||||||
fn from(value: &NameServerConfig) -> Self {
|
fn from(value: &NameServerConfig) -> Self {
|
||||||
|
let connection = value.connections.first().unwrap();
|
||||||
Self {
|
Self {
|
||||||
protocol: value.protocol,
|
protocol: connection.protocol.to_protocol(),
|
||||||
addr: value.socket_addr,
|
addr: SocketAddr::new(value.ip, connection.port),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,29 +70,23 @@ impl TryFrom<&Url> for NameServerAddr {
|
|||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn try_from(value: &Url) -> Result<Self, Self::Error> {
|
fn try_from(value: &Url) -> Result<Self, Self::Error> {
|
||||||
let scheme = value.scheme();
|
let protocol = Protocol::deserialize(value.scheme().into_deserializer()).map_err(
|
||||||
let protocol = *DNS_SUPPORTED_PROTOCOLS
|
|e: de::value::Error| anyhow!("invalid protocol '{}': {}", value.scheme(), e),
|
||||||
.iter()
|
)?;
|
||||||
.find(|p| p.to_string() == scheme)
|
let port = value
|
||||||
.ok_or(anyhow!("unsupported scheme: {}", scheme))?;
|
.port()
|
||||||
let addr = value.host_str().ok_or(anyhow!("host not found"))?;
|
.or_else(|| matches!(protocol, Protocol::Udp | Protocol::Tcp).then_some(53))
|
||||||
let addr = addr
|
.ok_or_else(|| anyhow!("port not found"))?;
|
||||||
.trim_start_matches('[')
|
let ip = match value.host().ok_or(anyhow!("host not found"))? {
|
||||||
.trim_end_matches(']')
|
Host::Domain(_) => {
|
||||||
.parse::<IpAddr>()
|
return Err(anyhow!("unsupported host: {}", value.host_str().unwrap()));
|
||||||
.map_err(|e| anyhow!("invalid ip address '{}': {}", addr, e))?;
|
|
||||||
let port = if let Some(port) = value.port() {
|
|
||||||
port
|
|
||||||
} else {
|
|
||||||
match protocol {
|
|
||||||
Protocol::Udp | Protocol::Tcp => 53,
|
|
||||||
_ => return Err(anyhow!("port not found")),
|
|
||||||
}
|
}
|
||||||
|
Host::Ipv4(ip) => ip.into(),
|
||||||
|
Host::Ipv6(ip) => ip.into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
protocol,
|
protocol,
|
||||||
addr: SocketAddr::new(addr, port),
|
addr: SocketAddr::new(ip, port),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,20 +127,3 @@ impl Display for NameServerAddr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub type NameServerAddrGroup = RepeatedMessageModel<NameServerAddr>;
|
pub type NameServerAddrGroup = RepeatedMessageModel<NameServerAddr>;
|
||||||
|
|
||||||
impl From<NameServerAddrGroup> for NameServerConfigGroup {
|
|
||||||
fn from(value: NameServerAddrGroup) -> Self {
|
|
||||||
value.into_iter().map(Into::into).collect::<Vec<_>>().into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<NameServerConfigGroup> for NameServerAddrGroup {
|
|
||||||
fn from(value: NameServerConfigGroup) -> Self {
|
|
||||||
value
|
|
||||||
.into_inner()
|
|
||||||
.into_iter()
|
|
||||||
.map(Into::into)
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
use crate::utils::BoxExt;
|
|
||||||
use delegate::delegate;
|
|
||||||
use derive_more::{Deref, DerefMut, From};
|
|
||||||
use hickory_proto::rr::{LowerName, RecordType};
|
|
||||||
use hickory_server::authority::{
|
|
||||||
Authority, AuthorityObject, LookupControlFlow, LookupObject, LookupOptions, MessageRequest,
|
|
||||||
UpdateResult, ZoneType,
|
|
||||||
};
|
|
||||||
use hickory_server::server::RequestInfo;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
pub type ArcAuthority = Arc<dyn AuthorityObject>;
|
|
||||||
|
|
||||||
#[derive(From, Deref, DerefMut)]
|
|
||||||
pub struct ChainedAuthority<A>(A)
|
|
||||||
where
|
|
||||||
A: Authority,
|
|
||||||
A::Lookup: LookupObject + 'static;
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl<A> Authority for ChainedAuthority<A>
|
|
||||||
where
|
|
||||||
A: Authority,
|
|
||||||
A::Lookup: LookupObject + 'static,
|
|
||||||
{
|
|
||||||
type Lookup = A::Lookup;
|
|
||||||
|
|
||||||
delegate! {
|
|
||||||
to self.0 {
|
|
||||||
fn zone_type(&self) -> ZoneType;
|
|
||||||
fn is_axfr_allowed(&self) -> bool;
|
|
||||||
fn origin(&self) -> &LowerName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
async fn update(&self, update: &MessageRequest) -> UpdateResult<bool> {
|
|
||||||
self.0.update(update).await
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
async fn lookup(
|
|
||||||
&self,
|
|
||||||
name: &LowerName,
|
|
||||||
rtype: RecordType,
|
|
||||||
lookup_options: LookupOptions,
|
|
||||||
) -> LookupControlFlow<Self::Lookup> {
|
|
||||||
self.0.lookup(name, rtype, lookup_options).await
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
async fn consult(
|
|
||||||
&self,
|
|
||||||
name: &LowerName,
|
|
||||||
rtype: RecordType,
|
|
||||||
lookup_options: LookupOptions,
|
|
||||||
last_result: LookupControlFlow<Box<dyn LookupObject>>,
|
|
||||||
) -> LookupControlFlow<Box<dyn LookupObject>> {
|
|
||||||
if let Some(Ok(l)) = last_result.map_result() {
|
|
||||||
LookupControlFlow::Break(Ok(l))
|
|
||||||
} else {
|
|
||||||
self.0
|
|
||||||
.lookup(name, rtype, lookup_options)
|
|
||||||
.await
|
|
||||||
.map(|l| l.boxed() as _)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
async fn search(
|
|
||||||
&self,
|
|
||||||
request_info: RequestInfo<'_>,
|
|
||||||
lookup_options: LookupOptions,
|
|
||||||
) -> LookupControlFlow<Self::Lookup> {
|
|
||||||
self.0.search(request_info, lookup_options).await
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
async fn get_nsec_records(
|
|
||||||
&self,
|
|
||||||
name: &LowerName,
|
|
||||||
lookup_options: LookupOptions,
|
|
||||||
) -> LookupControlFlow<Self::Lookup> {
|
|
||||||
self.0.get_nsec_records(name, lookup_options).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,9 +2,9 @@ use hickory_proto::rr::LowerName;
|
|||||||
use idna::AsciiDenyList;
|
use idna::AsciiDenyList;
|
||||||
|
|
||||||
pub mod addr;
|
pub mod addr;
|
||||||
pub mod authority;
|
|
||||||
pub mod dirty;
|
pub mod dirty;
|
||||||
pub mod response;
|
pub mod response;
|
||||||
|
pub mod zone_handler;
|
||||||
|
|
||||||
pub fn sanitize(name: &str) -> String {
|
pub fn sanitize(name: &str) -> String {
|
||||||
let dot = name.ends_with('.');
|
let dot = name.ends_with('.');
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
use hickory_net::NetError;
|
||||||
use hickory_proto::rr::Record;
|
use hickory_proto::rr::Record;
|
||||||
use hickory_proto::serialize::binary::BinEncoder;
|
use hickory_proto::serialize::binary::BinEncoder;
|
||||||
use hickory_server::authority::MessageResponse;
|
|
||||||
use hickory_server::server::{ResponseHandler, ResponseInfo};
|
use hickory_server::server::{ResponseHandler, ResponseInfo};
|
||||||
|
use hickory_server::zone_handler::MessageResponse;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::io;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
// ResponseWrapper for serializing DNS responses into a byte buffer.
|
// ResponseWrapper for serializing DNS responses into a byte buffer.
|
||||||
@@ -41,11 +41,11 @@ impl ResponseHandler for ResponseHandle {
|
|||||||
impl RecordIter<'r>,
|
impl RecordIter<'r>,
|
||||||
impl RecordIter<'r>,
|
impl RecordIter<'r>,
|
||||||
>,
|
>,
|
||||||
) -> io::Result<ResponseInfo> {
|
) -> Result<ResponseInfo, NetError> {
|
||||||
let max_size = if let Some(edns) = response.get_edns() {
|
let max_size = if let Some(edns) = response.edns() {
|
||||||
edns.max_payload()
|
edns.max_payload()
|
||||||
} else {
|
} else {
|
||||||
hickory_proto::udp::MAX_RECEIVE_BUFFER_SIZE as u16
|
hickory_net::udp::MAX_RECEIVE_BUFFER_SIZE as u16
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
@@ -54,6 +54,6 @@ impl ResponseHandler for ResponseHandle {
|
|||||||
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::Proto)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
use delegate::delegate;
|
||||||
|
use derive_more::{Deref, DerefMut, From};
|
||||||
|
use hickory_proto::op::ResponseCode;
|
||||||
|
use hickory_proto::rr::{LowerName, RecordType, TSigResponseContext};
|
||||||
|
use hickory_server::server::{Request, RequestInfo};
|
||||||
|
use hickory_server::zone_handler::{
|
||||||
|
AuthLookup, AxfrPolicy, LookupControlFlow, LookupOptions, ZoneHandler, ZoneType,
|
||||||
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub type ArcZoneHandler = Arc<dyn ZoneHandler>;
|
||||||
|
|
||||||
|
#[derive(From, Deref, DerefMut)]
|
||||||
|
pub struct ChainedZoneHandler<H>(H)
|
||||||
|
where
|
||||||
|
H: ZoneHandler;
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl<H> ZoneHandler for ChainedZoneHandler<H>
|
||||||
|
where
|
||||||
|
H: ZoneHandler,
|
||||||
|
{
|
||||||
|
delegate! {
|
||||||
|
to self.0 {
|
||||||
|
fn zone_type(&self) -> ZoneType;
|
||||||
|
fn axfr_policy(&self) -> AxfrPolicy;
|
||||||
|
fn origin(&self) -> &LowerName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
async fn update(
|
||||||
|
&self,
|
||||||
|
update: &Request,
|
||||||
|
now: u64,
|
||||||
|
) -> (Result<bool, ResponseCode>, Option<TSigResponseContext>) {
|
||||||
|
self.0.update(update, now).await
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
async fn lookup(
|
||||||
|
&self,
|
||||||
|
name: &LowerName,
|
||||||
|
rtype: RecordType,
|
||||||
|
request_info: Option<&RequestInfo<'_>>,
|
||||||
|
lookup_options: LookupOptions,
|
||||||
|
) -> LookupControlFlow<AuthLookup> {
|
||||||
|
self.0
|
||||||
|
.lookup(name, rtype, request_info, lookup_options)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
async fn consult(
|
||||||
|
&self,
|
||||||
|
name: &LowerName,
|
||||||
|
rtype: RecordType,
|
||||||
|
request_info: Option<&RequestInfo<'_>>,
|
||||||
|
lookup_options: LookupOptions,
|
||||||
|
last_result: LookupControlFlow<AuthLookup>,
|
||||||
|
) -> (LookupControlFlow<AuthLookup>, Option<TSigResponseContext>) {
|
||||||
|
let result = if let Some(Ok(l)) = last_result.map_result() {
|
||||||
|
LookupControlFlow::Break(Ok(l))
|
||||||
|
} else {
|
||||||
|
self.0
|
||||||
|
.lookup(name, rtype, request_info, lookup_options)
|
||||||
|
.await
|
||||||
|
};
|
||||||
|
(result, None)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
async fn search(
|
||||||
|
&self,
|
||||||
|
request: &Request,
|
||||||
|
lookup_options: LookupOptions,
|
||||||
|
) -> (LookupControlFlow<AuthLookup>, Option<TSigResponseContext>) {
|
||||||
|
self.0.search(request, lookup_options).await
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
async fn nsec_records(
|
||||||
|
&self,
|
||||||
|
name: &LowerName,
|
||||||
|
lookup_options: LookupOptions,
|
||||||
|
) -> LookupControlFlow<AuthLookup> {
|
||||||
|
self.0.nsec_records(name, lookup_options).await
|
||||||
|
}
|
||||||
|
}
|
||||||
+44
-41
@@ -1,16 +1,16 @@
|
|||||||
use crate::common::dns::get_default_resolver_config;
|
use crate::common::dns::get_default_resolver_config;
|
||||||
use crate::dns::utils::addr::NameServerAddr;
|
use crate::dns::utils::addr::NameServerAddr;
|
||||||
use crate::dns::utils::authority::ArcAuthority;
|
use crate::dns::utils::zone_handler::ArcZoneHandler;
|
||||||
use crate::proto;
|
use crate::proto;
|
||||||
use crate::proto::utils::RepeatedMessageModel;
|
use crate::proto::utils::RepeatedMessageModel;
|
||||||
|
use hickory_net::runtime::TokioRuntimeProvider;
|
||||||
use hickory_proto::rr::{LowerName, RecordSet, RrKey};
|
use hickory_proto::rr::{LowerName, RecordSet, RrKey};
|
||||||
use hickory_proto::serialize::txt::Parser;
|
use hickory_proto::serialize::txt::Parser;
|
||||||
use hickory_resolver::config::ResolverOpts;
|
use hickory_resolver::config::ResolverOpts;
|
||||||
use hickory_resolver::name_server::TokioConnectionProvider;
|
|
||||||
use hickory_resolver::system_conf::read_system_conf;
|
use hickory_resolver::system_conf::read_system_conf;
|
||||||
use hickory_server::authority::ZoneType;
|
use hickory_server::store::forwarder::{ForwardConfig, ForwardZoneHandler};
|
||||||
use hickory_server::store::forwarder::{ForwardAuthority, ForwardConfig};
|
use hickory_server::store::in_memory::InMemoryZoneHandler;
|
||||||
use hickory_server::store::in_memory::InMemoryAuthority;
|
use hickory_server::zone_handler::{AxfrPolicy, ZoneType};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use itertools::chain;
|
use itertools::chain;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
@@ -30,7 +30,7 @@ impl Zone {
|
|||||||
let (config, opts) =
|
let (config, opts) =
|
||||||
read_system_conf().unwrap_or((get_default_resolver_config(), ResolverOpts::default()));
|
read_system_conf().unwrap_or((get_default_resolver_config(), ResolverOpts::default()));
|
||||||
let forward = ForwardConfig {
|
let forward = ForwardConfig {
|
||||||
name_servers: config.name_servers().to_vec().into(),
|
name_servers: config.name_servers().to_vec(),
|
||||||
options: Some(opts),
|
options: Some(opts),
|
||||||
};
|
};
|
||||||
let mut zone = Self::new(".".parse().unwrap());
|
let mut zone = Self::new(".".parse().unwrap());
|
||||||
@@ -49,10 +49,13 @@ impl Zone {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_memory_authority(&self) -> Option<ArcAuthority> {
|
pub fn create_memory_zone_handler(&self) -> Option<ArcZoneHandler> {
|
||||||
(!self.records.is_empty()).then(|| {
|
(!self.records.is_empty()).then(|| {
|
||||||
let mut memory =
|
let mut memory = InMemoryZoneHandler::<TokioRuntimeProvider>::empty(
|
||||||
InMemoryAuthority::empty(self.origin.clone().into(), ZoneType::External, false);
|
self.origin.clone().into(),
|
||||||
|
ZoneType::External,
|
||||||
|
AxfrPolicy::default(),
|
||||||
|
);
|
||||||
|
|
||||||
memory.records_get_mut().extend(
|
memory.records_get_mut().extend(
|
||||||
self.records
|
self.records
|
||||||
@@ -61,20 +64,20 @@ impl Zone {
|
|||||||
.map(|(k, v)| (k, Arc::new(v))),
|
.map(|(k, v)| (k, Arc::new(v))),
|
||||||
);
|
);
|
||||||
|
|
||||||
Arc::new(memory) as ArcAuthority
|
Arc::new(memory) as ArcZoneHandler
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_forward_authority(&self) -> Option<ArcAuthority> {
|
pub fn create_forward_zone_handler(&self) -> Option<ArcZoneHandler> {
|
||||||
self.forward.as_ref().and_then(|forward| {
|
self.forward.as_ref().and_then(|forward| {
|
||||||
ForwardAuthority::builder_with_config(
|
ForwardZoneHandler::builder_with_config(
|
||||||
forward.clone(),
|
forward.clone(),
|
||||||
TokioConnectionProvider::default(),
|
TokioRuntimeProvider::default(),
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
.inspect_err(|e| tracing::error!("failed to create forward authority: {:?}", e))
|
.inspect_err(|e| tracing::error!("failed to create forward zone_handler: {:?}", e))
|
||||||
.ok()
|
.ok()
|
||||||
.map(|f| Arc::new(f) as ArcAuthority)
|
.map(|f| Arc::new(f) as ArcZoneHandler)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,14 +95,14 @@ impl TryFrom<&proto::dns::ZoneData> for Zone {
|
|||||||
.parse()
|
.parse()
|
||||||
.map_err(|e| anyhow::anyhow!("failed to parse zone data: {e}"))?;
|
.map_err(|e| anyhow::anyhow!("failed to parse zone data: {e}"))?;
|
||||||
|
|
||||||
let servers = value
|
let name_servers = value
|
||||||
.forwarders
|
.forwarders
|
||||||
.iter()
|
.iter()
|
||||||
.map(TryInto::<NameServerAddr>::try_into)
|
.map(TryInto::<NameServerAddr>::try_into)
|
||||||
.map(|a| a.map(Into::into))
|
.map(|a| a.map(Into::into))
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
let forward = (!servers.is_empty()).then_some(ForwardConfig {
|
let forward = (!name_servers.is_empty()).then_some(ForwardConfig {
|
||||||
name_servers: servers.into(),
|
name_servers,
|
||||||
options: None,
|
options: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -124,7 +127,7 @@ impl From<Zone> for proto::dns::ZoneData {
|
|||||||
let forwarders = value
|
let forwarders = value
|
||||||
.forward
|
.forward
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|f| f.name_servers.into_inner().into_iter())
|
.flat_map(|f| f.name_servers.into_iter())
|
||||||
.map(Into::<NameServerAddr>::into)
|
.map(Into::<NameServerAddr>::into)
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
.collect();
|
.collect();
|
||||||
@@ -149,11 +152,11 @@ impl ZoneGroup {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_authorities(&self) -> impl Iterator<Item = ArcAuthority> + use<'_> {
|
pub fn iter_zone_handlers(&self) -> impl Iterator<Item = ArcZoneHandler> + use<'_> {
|
||||||
self.iter().flat_map(|zone| {
|
self.iter().flat_map(|zone| {
|
||||||
chain(
|
chain(
|
||||||
zone.create_memory_authority(),
|
zone.create_memory_zone_handler(),
|
||||||
zone.create_forward_authority(),
|
zone.create_forward_zone_handler(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -167,9 +170,9 @@ mod tests {
|
|||||||
use crate::proto::common::Url;
|
use crate::proto::common::Url;
|
||||||
use crate::proto::dns::ZoneData;
|
use crate::proto::dns::ZoneData;
|
||||||
use hickory_proto::op::{Message, ResponseCode};
|
use hickory_proto::op::{Message, ResponseCode};
|
||||||
use hickory_proto::rr::{RData, Record, RecordType, RrsetRecords, rdata};
|
use hickory_proto::rr::{RData, Record, RecordType, RrsetRecords};
|
||||||
use hickory_server::ServerFuture;
|
use hickory_server::Server;
|
||||||
use hickory_server::authority::Catalog;
|
use hickory_server::zone_handler::Catalog;
|
||||||
use std::net::{Ipv4Addr, SocketAddr};
|
use std::net::{Ipv4Addr, SocketAddr};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use tokio::net::UdpSocket;
|
use tokio::net::UdpSocket;
|
||||||
@@ -209,7 +212,7 @@ mod tests {
|
|||||||
.into_groups()
|
.into_groups()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.fold(Catalog::new(), |mut catalog, (origin, group)| {
|
.fold(Catalog::new(), |mut catalog, (origin, group)| {
|
||||||
catalog.upsert(origin, group.iter_authorities().collect());
|
catalog.upsert(origin, group.iter_zone_handlers().collect());
|
||||||
catalog
|
catalog
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -221,19 +224,19 @@ mod tests {
|
|||||||
) -> anyhow::Result<(ResponseCode, Option<Message>)> {
|
) -> anyhow::Result<(ResponseCode, Option<Message>)> {
|
||||||
let request = new_request(name, record_type)?;
|
let request = new_request(name, record_type)?;
|
||||||
let response = ResponseHandle::new(1024);
|
let response = ResponseHandle::new(1024);
|
||||||
let info = catalog.lookup(&request, None, response.clone()).await;
|
let info = catalog.lookup(&request, None, 0, response.clone()).await;
|
||||||
let message = response
|
let message = response
|
||||||
.into_inner()
|
.into_inner()
|
||||||
.map(|raw| Message::from_vec(&raw))
|
.map(|raw| Message::from_vec(&raw))
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
Ok((info.response_code(), message))
|
Ok((info.response_code, message))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_a_answer(message: &Message, expected: Ipv4Addr) -> bool {
|
fn has_a_answer(message: &Message, expected: Ipv4Addr) -> bool {
|
||||||
message
|
message
|
||||||
.answers()
|
.answers
|
||||||
.iter()
|
.iter()
|
||||||
.any(|record| matches!(record.data(), RData::A(addr) if *addr == rdata::a::A(expected)))
|
.any(|record| matches!(record.data, RData::A(addr) if *addr == expected))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn start_upstream_server() -> anyhow::Result<(SocketAddr, JoinHandle<()>)> {
|
async fn start_upstream_server() -> anyhow::Result<(SocketAddr, JoinHandle<()>)> {
|
||||||
@@ -246,13 +249,13 @@ mod tests {
|
|||||||
let mut catalog = Catalog::new();
|
let mut catalog = Catalog::new();
|
||||||
catalog.upsert(
|
catalog.upsert(
|
||||||
upstream.origin.clone(),
|
upstream.origin.clone(),
|
||||||
vec![upstream.create_memory_authority().unwrap()],
|
vec![upstream.create_memory_zone_handler().unwrap()],
|
||||||
);
|
);
|
||||||
|
|
||||||
let socket = UdpSocket::bind("127.0.0.1:0").await?;
|
let socket = UdpSocket::bind("127.0.0.1:0").await?;
|
||||||
let addr = socket.local_addr()?;
|
let addr = socket.local_addr()?;
|
||||||
|
|
||||||
let mut server = ServerFuture::new(catalog);
|
let mut server = Server::new(catalog);
|
||||||
server.register_socket(socket);
|
server.register_socket(socket);
|
||||||
let handle = tokio::spawn(async move {
|
let handle = tokio::spawn(async move {
|
||||||
let _ = server.block_until_done().await;
|
let _ = server.block_until_done().await;
|
||||||
@@ -292,11 +295,11 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_zone_creates_no_authority() -> anyhow::Result<()> {
|
fn empty_zone_creates_no_zone_handler() -> anyhow::Result<()> {
|
||||||
let zone = Zone::try_from(&zone_data("empty.test", vec![], vec![]))?;
|
let zone = Zone::try_from(&zone_data("empty.test", vec![], vec![]))?;
|
||||||
|
|
||||||
assert!(zone.create_memory_authority().is_none());
|
assert!(zone.create_memory_zone_handler().is_none());
|
||||||
assert!(zone.create_forward_authority().is_none());
|
assert!(zone.create_forward_zone_handler().is_none());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -356,16 +359,16 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn zone_group_iter_authorities_returns_memory_and_forward() -> anyhow::Result<()> {
|
fn zone_group_iter_zone_handlers_returns_memory_and_forward() -> anyhow::Result<()> {
|
||||||
let zones: ZoneGroup = vec![Zone::try_from(&zone_data(
|
let zones: ZoneGroup = vec![Zone::try_from(&zone_data(
|
||||||
"authority.test",
|
"zone-handler.test",
|
||||||
vec!["@ IN A 10.0.0.10"],
|
vec!["@ IN A 10.0.0.10"],
|
||||||
vec!["udp://1.1.1.1:53"],
|
vec!["udp://1.1.1.1:53"],
|
||||||
))?]
|
))?]
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
let authorities = zones.iter_authorities().collect::<Vec<_>>();
|
let zone_handlers = zones.iter_zone_handlers().collect::<Vec<_>>();
|
||||||
assert_eq!(authorities.len(), 2);
|
assert_eq!(zone_handlers.len(), 2);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -375,11 +378,11 @@ mod tests {
|
|||||||
let zone = Zone::system();
|
let zone = Zone::system();
|
||||||
assert_eq!(zone.origin.to_string(), ".");
|
assert_eq!(zone.origin.to_string(), ".");
|
||||||
assert!(zone.forward.is_some());
|
assert!(zone.forward.is_some());
|
||||||
assert!(zone.create_forward_authority().is_some());
|
assert!(zone.create_forward_zone_handler().is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn catalog_lookup_returns_a_record_from_memory_authority() -> anyhow::Result<()> {
|
async fn catalog_lookup_returns_a_record_from_memory_zone_handler() -> anyhow::Result<()> {
|
||||||
let zones: ZoneGroup = vec![Zone::try_from(&zone_data(
|
let zones: ZoneGroup = vec![Zone::try_from(&zone_data(
|
||||||
"memory.test",
|
"memory.test",
|
||||||
vec!["@ IN A 10.20.30.40"],
|
vec!["@ IN A 10.20.30.40"],
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ use std::{
|
|||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
net::{IpAddr, Ipv4Addr, Ipv6Addr},
|
net::{IpAddr, Ipv4Addr, Ipv6Addr},
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicBool, AtomicU32, Ordering}, Arc,
|
Arc, Weak,
|
||||||
Weak,
|
atomic::{AtomicBool, AtomicU32, Ordering},
|
||||||
},
|
},
|
||||||
time::{Duration, Instant, SystemTime},
|
time::{Duration, Instant, SystemTime},
|
||||||
};
|
};
|
||||||
@@ -14,12 +14,12 @@ use cidr::{IpCidr, Ipv4Cidr, Ipv6Cidr};
|
|||||||
use crossbeam::atomic::AtomicCell;
|
use crossbeam::atomic::AtomicCell;
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use ordered_hash_map::OrderedHashMap;
|
use ordered_hash_map::OrderedHashMap;
|
||||||
use parking_lot::{lock_api::RwLockUpgradableReadGuard, RwLock};
|
use parking_lot::{RwLock, lock_api::RwLockUpgradableReadGuard};
|
||||||
use petgraph::{
|
use petgraph::{
|
||||||
|
Directed,
|
||||||
algo::dijkstra,
|
algo::dijkstra,
|
||||||
graph::{Graph, NodeIndex},
|
graph::{Graph, NodeIndex},
|
||||||
visit::{EdgeRef, IntoNodeReferences},
|
visit::{EdgeRef, IntoNodeReferences},
|
||||||
Directed,
|
|
||||||
};
|
};
|
||||||
use prefix_trie::PrefixMap;
|
use prefix_trie::PrefixMap;
|
||||||
use prost::Message;
|
use prost::Message;
|
||||||
@@ -34,24 +34,24 @@ use crate::common::config::ConfigLoader;
|
|||||||
use crate::proto::utils::TransientDigest;
|
use crate::proto::utils::TransientDigest;
|
||||||
use crate::{
|
use crate::{
|
||||||
common::{
|
common::{
|
||||||
|
PeerId,
|
||||||
config::NetworkIdentity,
|
config::NetworkIdentity,
|
||||||
constants::EASYTIER_VERSION,
|
constants::EASYTIER_VERSION,
|
||||||
global_ctx::{ArcGlobalCtx, GlobalCtxEvent},
|
global_ctx::{ArcGlobalCtx, GlobalCtxEvent},
|
||||||
shrink_dashmap,
|
shrink_dashmap,
|
||||||
stun::StunInfoCollectorTrait,
|
stun::StunInfoCollectorTrait,
|
||||||
PeerId,
|
|
||||||
},
|
},
|
||||||
peers::route_trait::{Route, RouteInterfaceBox},
|
peers::route_trait::{Route, RouteInterfaceBox},
|
||||||
proto::{
|
proto::{
|
||||||
acl::GroupIdentity,
|
acl::GroupIdentity,
|
||||||
common::{Ipv4Inet, NatType, StunInfo},
|
common::{Ipv4Inet, NatType, StunInfo},
|
||||||
peer_rpc::{
|
peer_rpc::{
|
||||||
route_foreign_network_infos, route_foreign_network_summary, sync_route_info_request::ConnInfo,
|
ForeignNetworkRouteInfoEntry, ForeignNetworkRouteInfoKey, OspfRouteRpc,
|
||||||
ForeignNetworkRouteInfoEntry, ForeignNetworkRouteInfoKey, OspfRouteRpc, OspfRouteRpcClientFactory,
|
OspfRouteRpcClientFactory, OspfRouteRpcServer, PeerGroupInfo, PeerIdVersion,
|
||||||
OspfRouteRpcServer, PeerGroupInfo, PeerIdVersion, PeerIdentityType,
|
PeerIdentityType, RouteForeignNetworkInfos, RouteForeignNetworkSummary, RoutePeerInfo,
|
||||||
RouteForeignNetworkInfos, RouteForeignNetworkSummary, RoutePeerInfo, RoutePeerInfos,
|
RoutePeerInfos, SyncRouteInfoError, SyncRouteInfoRequest, SyncRouteInfoResponse,
|
||||||
SyncRouteInfoError, SyncRouteInfoRequest, SyncRouteInfoResponse,
|
TrustedCredentialPubkey, route_foreign_network_infos, route_foreign_network_summary,
|
||||||
TrustedCredentialPubkey,
|
sync_route_info_request::ConnInfo,
|
||||||
},
|
},
|
||||||
rpc_types::{
|
rpc_types::{
|
||||||
self,
|
self,
|
||||||
@@ -62,13 +62,13 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
PeerPacketFilter,
|
||||||
graph_algo::dijkstra_with_first_hop,
|
graph_algo::dijkstra_with_first_hop,
|
||||||
peer_rpc::PeerRpcManager,
|
peer_rpc::PeerRpcManager,
|
||||||
route_trait::{
|
route_trait::{
|
||||||
DefaultRouteCostCalculator, ForeignNetworkRouteInfoMap, NextHopPolicy, RouteCostCalculator,
|
DefaultRouteCostCalculator, ForeignNetworkRouteInfoMap, NextHopPolicy, RouteCostCalculator,
|
||||||
RouteCostCalculatorInterface,
|
RouteCostCalculatorInterface,
|
||||||
},
|
},
|
||||||
PeerPacketFilter,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use atomic_shim::AtomicU64;
|
use atomic_shim::AtomicU64;
|
||||||
@@ -3681,8 +3681,8 @@ mod tests {
|
|||||||
use std::{
|
use std::{
|
||||||
collections::{BTreeSet, HashMap},
|
collections::{BTreeSet, HashMap},
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicU32, Ordering},
|
|
||||||
Arc,
|
Arc,
|
||||||
|
atomic::{AtomicU32, Ordering},
|
||||||
},
|
},
|
||||||
time::{Duration, SystemTime},
|
time::{Duration, SystemTime},
|
||||||
};
|
};
|
||||||
@@ -3690,14 +3690,14 @@ mod tests {
|
|||||||
use super::{PeerRoute, REMOVE_DEAD_PEER_INFO_AFTER};
|
use super::{PeerRoute, REMOVE_DEAD_PEER_INFO_AFTER};
|
||||||
use crate::{
|
use crate::{
|
||||||
common::{
|
common::{
|
||||||
global_ctx::{tests::get_mock_global_ctx, GlobalCtxEvent, TrustedKeySource},
|
|
||||||
PeerId,
|
PeerId,
|
||||||
|
global_ctx::{GlobalCtxEvent, TrustedKeySource, tests::get_mock_global_ctx},
|
||||||
},
|
},
|
||||||
connector::udp_hole_punch::tests::replace_stun_info_collector,
|
connector::udp_hole_punch::tests::replace_stun_info_collector,
|
||||||
peers::{
|
peers::{
|
||||||
create_packet_recv_chan,
|
create_packet_recv_chan,
|
||||||
peer_manager::{PeerManager, RouteAlgoType},
|
peer_manager::{PeerManager, RouteAlgoType},
|
||||||
peer_ospf_route::{PeerIdVersion, PeerRouteServiceImpl, FORCE_USE_CONN_LIST},
|
peer_ospf_route::{FORCE_USE_CONN_LIST, PeerIdVersion, PeerRouteServiceImpl},
|
||||||
route_trait::{NextHopPolicy, Route, RouteCostCalculatorInterface, RouteInterface},
|
route_trait::{NextHopPolicy, Route, RouteCostCalculatorInterface, RouteInterface},
|
||||||
tests::{connect_peer_manager, create_mock_peer_manager, wait_route_appear},
|
tests::{connect_peer_manager, create_mock_peer_manager, wait_route_appear},
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user