mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-08-06 12:39:51 +00:00
add fallthrough flag
zone test log
This commit is contained in:
@@ -1,14 +1,14 @@
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Default)]
|
||||
#[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize)]
|
||||
#[serde(default)]
|
||||
pub struct AclPolicy {
|
||||
pub whitelist: Option<Vec<String>>,
|
||||
pub blacklist: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Default, Deref, DerefMut)]
|
||||
#[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize, Deref, DerefMut)]
|
||||
#[serde(default)]
|
||||
pub struct FunctionalityPolicy {
|
||||
#[serde(flatten)]
|
||||
@@ -18,7 +18,7 @@ pub struct FunctionalityPolicy {
|
||||
pub disabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Default, Deref, DerefMut)]
|
||||
#[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize, Deref, DerefMut)]
|
||||
#[serde(default)]
|
||||
pub struct DnsPolicy<P = FunctionalityPolicy> {
|
||||
#[serde(flatten)]
|
||||
@@ -32,16 +32,15 @@ pub type ZoneExportPolicy = FunctionalityPolicy;
|
||||
pub type DnsExportPolicy = DnsPolicy<ZoneExportPolicy>;
|
||||
pub type DnsImportPolicy = DnsPolicy<FunctionalityPolicy>;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Default)]
|
||||
#[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize)]
|
||||
#[serde(default)]
|
||||
pub struct DnsPolicyConfig {
|
||||
pub import: DnsImportPolicy,
|
||||
pub export: Option<DnsExportPolicy>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Default)]
|
||||
#[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize)]
|
||||
#[serde(default)]
|
||||
pub struct ZonePolicyConfig {
|
||||
#[serde(default)]
|
||||
pub export: Option<DnsExportPolicy>,
|
||||
}
|
||||
|
||||
@@ -69,20 +69,21 @@ impl ZoneConfig {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Default)]
|
||||
#[derive(Derivative, Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||
#[derivative(Default)]
|
||||
#[serde(default)]
|
||||
pub struct ZoneConfigInner {
|
||||
#[serde(default = "Uuid::new_v4")]
|
||||
#[derivative(Default(value = "Uuid::new_v4()"))]
|
||||
#[serde(skip_serializing)]
|
||||
id: Uuid,
|
||||
pub origin: LowerName,
|
||||
#[serde(default)]
|
||||
pub ttl: u32,
|
||||
#[serde(default)]
|
||||
pub records: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub forwarders: NameServerAddrGroup,
|
||||
#[serde(flatten)]
|
||||
pub policy: ZonePolicyConfig,
|
||||
#[derivative(Default(value = "true"))]
|
||||
pub fallthrough: bool,
|
||||
}
|
||||
|
||||
impl From<ZoneConfigInner> for ZoneData {
|
||||
@@ -93,6 +94,7 @@ impl From<ZoneConfigInner> for ZoneData {
|
||||
ttl: value.ttl,
|
||||
records: value.records,
|
||||
forwarders: value.forwarders.into(),
|
||||
fallthrough: value.fallthrough,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,6 +250,7 @@ mod tests {
|
||||
ttl: 60,
|
||||
records: vec!["@ IN A 10.0.0.11".to_string()],
|
||||
forwarders: vec![],
|
||||
fallthrough: false,
|
||||
}],
|
||||
fqdn: "invalid.peer.test".to_string(),
|
||||
};
|
||||
|
||||
@@ -114,6 +114,7 @@ pub fn zone_data_a_with_forwarders(origin: &str, record: &str, forwarders: Vec<&
|
||||
.into_iter()
|
||||
.map(|f| Url::from_str(f).expect("invalid forwarder"))
|
||||
.collect(),
|
||||
fallthrough: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,8 +345,10 @@ async fn wait_peer_zone_visibility(
|
||||
|
||||
loop {
|
||||
dns.refresh(target_peer_id).await;
|
||||
let visible = dns
|
||||
.snapshot()
|
||||
|
||||
let snapshot = dns.snapshot();
|
||||
|
||||
let visible = snapshot
|
||||
.zones
|
||||
.iter()
|
||||
.any(|z| z.origin.contains(zone_origin_substr));
|
||||
@@ -354,12 +357,19 @@ async fn wait_peer_zone_visibility(
|
||||
return;
|
||||
}
|
||||
|
||||
let origins = snapshot
|
||||
.zones
|
||||
.iter()
|
||||
.map(|z| z.origin.clone())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert!(
|
||||
Instant::now() < deadline,
|
||||
"zone visibility mismatch for '{}': expected {}, got {}",
|
||||
"zone visibility mismatch for '{}': expected {}, got {}, current origins: {:?}",
|
||||
zone_origin_substr,
|
||||
expected_visible,
|
||||
visible
|
||||
visible,
|
||||
origins
|
||||
);
|
||||
tokio::time::sleep(Duration::from_millis(200)).await;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::common::dns::get_default_resolver_config;
|
||||
use crate::dns::utils::addr::{NameServerAddr, NameServerAddrGroup};
|
||||
use crate::dns::utils::zone_handler::ArcZoneHandler;
|
||||
use crate::dns::utils::zone_handler::{ArcZoneHandler, ChainedZoneHandler};
|
||||
use crate::proto;
|
||||
use crate::proto::utils::RepeatedMessageModel;
|
||||
use hickory_net::runtime::TokioRuntimeProvider;
|
||||
@@ -23,6 +23,7 @@ pub struct Zone {
|
||||
origin: LowerName,
|
||||
records: BTreeMap<RrKey, RecordSet>,
|
||||
pub forward: Option<ForwardConfig>,
|
||||
fallthrough: bool,
|
||||
}
|
||||
|
||||
impl Zone {
|
||||
@@ -35,6 +36,7 @@ impl Zone {
|
||||
};
|
||||
let mut zone = Self::new(".".parse().unwrap());
|
||||
zone.forward = Some(forward);
|
||||
zone.fallthrough = false;
|
||||
zone
|
||||
}
|
||||
}
|
||||
@@ -46,6 +48,7 @@ impl Zone {
|
||||
origin: name,
|
||||
records: BTreeMap::new(),
|
||||
forward: None,
|
||||
fallthrough: true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +67,11 @@ impl Zone {
|
||||
.map(|(k, v)| (k, Arc::new(v))),
|
||||
);
|
||||
|
||||
Arc::new(memory) as ArcZoneHandler
|
||||
if self.fallthrough {
|
||||
Arc::new(ChainedZoneHandler::from(memory)) as _
|
||||
} else {
|
||||
Arc::new(memory) as _
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -77,7 +84,13 @@ impl Zone {
|
||||
.build()
|
||||
.inspect_err(|e| tracing::error!("failed to create forward zone_handler: {:?}", e))
|
||||
.ok()
|
||||
.map(|f| Arc::new(f) as ArcZoneHandler)
|
||||
.map(|f| {
|
||||
if self.fallthrough {
|
||||
Arc::new(ChainedZoneHandler::from(f)) as _
|
||||
} else {
|
||||
Arc::new(f) as _
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -111,6 +124,7 @@ impl TryFrom<&proto::dns::ZoneData> for Zone {
|
||||
origin: origin.into(),
|
||||
records,
|
||||
forward,
|
||||
fallthrough: value.fallthrough,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -139,6 +153,7 @@ impl From<Zone> for proto::dns::ZoneData {
|
||||
ttl: 0,
|
||||
records,
|
||||
forwarders,
|
||||
fallthrough: value.fallthrough,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -195,7 +210,12 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn zone_data(origin: &str, records: Vec<&str>, forwarders: Vec<&str>) -> ZoneData {
|
||||
fn zone_data_with_fallthrough(
|
||||
origin: &str,
|
||||
records: Vec<&str>,
|
||||
forwarders: Vec<&str>,
|
||||
fallthrough: bool,
|
||||
) -> ZoneData {
|
||||
ZoneData {
|
||||
id: Some(Uuid::new_v4().into()),
|
||||
origin: origin.to_string(),
|
||||
@@ -205,9 +225,14 @@ mod tests {
|
||||
.into_iter()
|
||||
.map(|f| Url::from_str(f).expect("invalid forwarder"))
|
||||
.collect(),
|
||||
fallthrough,
|
||||
}
|
||||
}
|
||||
|
||||
fn zone_data(origin: &str, records: Vec<&str>, forwarders: Vec<&str>) -> ZoneData {
|
||||
zone_data_with_fallthrough(origin, records, forwarders, true)
|
||||
}
|
||||
|
||||
fn build_catalog(zones: ZoneGroup) -> Catalog {
|
||||
zones
|
||||
.into_groups()
|
||||
@@ -273,6 +298,7 @@ mod tests {
|
||||
ttl: 60,
|
||||
records: vec!["@ IN A 10.0.0.1".to_string()],
|
||||
forwarders: vec![],
|
||||
fallthrough: false,
|
||||
};
|
||||
|
||||
let err = Zone::try_from(&data).expect_err("missing id should fail");
|
||||
@@ -416,6 +442,67 @@ mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn catalog_lookup_falls_back_to_later_zone_handler_with_same_origin() -> anyhow::Result<()>
|
||||
{
|
||||
let zones: ZoneGroup = vec![
|
||||
// First matching zone exists but does not contain the queried name.
|
||||
Zone::try_from(&zone_data(
|
||||
"fallback.test",
|
||||
vec!["first IN A 10.20.30.1"],
|
||||
vec![],
|
||||
))?,
|
||||
// Second matching zone should be queried as fallback and answer.
|
||||
Zone::try_from(&zone_data(
|
||||
"fallback.test",
|
||||
vec!["target IN A 10.20.30.2"],
|
||||
vec![],
|
||||
))?,
|
||||
]
|
||||
.into();
|
||||
let catalog = build_catalog(zones);
|
||||
|
||||
let (rcode, message) =
|
||||
lookup_message(&catalog, "target.fallback.test.", RecordType::A).await?;
|
||||
assert_eq!(rcode, ResponseCode::NoError);
|
||||
assert!(has_a_answer(
|
||||
&message.expect("response should exist"),
|
||||
Ipv4Addr::new(10, 20, 30, 2)
|
||||
));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn catalog_lookup_does_not_fall_back_when_fallthrough_disabled() -> anyhow::Result<()> {
|
||||
let zones: ZoneGroup = vec![
|
||||
Zone::try_from(&zone_data_with_fallthrough(
|
||||
"fallback-disabled.test",
|
||||
vec!["first IN A 10.20.31.1"],
|
||||
vec![],
|
||||
false,
|
||||
))?,
|
||||
Zone::try_from(&zone_data_with_fallthrough(
|
||||
"fallback-disabled.test",
|
||||
vec!["target IN A 10.20.31.2"],
|
||||
vec![],
|
||||
false,
|
||||
))?,
|
||||
]
|
||||
.into();
|
||||
let catalog = build_catalog(zones);
|
||||
|
||||
let (rcode, message) =
|
||||
lookup_message(&catalog, "target.fallback-disabled.test.", RecordType::A).await?;
|
||||
|
||||
assert_ne!(rcode, ResponseCode::NoError);
|
||||
if let Some(message) = message.as_ref() {
|
||||
assert!(!has_a_answer(message, Ipv4Addr::new(10, 20, 31, 2)));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn catalog_forward_only_zone_queries_upstream() -> anyhow::Result<()> {
|
||||
let (upstream_addr, upstream_handle) = start_upstream_server().await?;
|
||||
|
||||
@@ -10,6 +10,7 @@ message ZoneData {
|
||||
uint32 ttl = 3;
|
||||
repeated string records = 4;
|
||||
repeated common.Url forwarders = 5;
|
||||
bool fallthrough = 6;
|
||||
}
|
||||
|
||||
message GetExportConfigRequest {}
|
||||
|
||||
Reference in New Issue
Block a user