mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-09-01 08:49:16 +00:00
add fallthrough flag
zone test log
This commit is contained in:
@@ -1,14 +1,14 @@
|
|||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Default)]
|
#[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct AclPolicy {
|
pub struct AclPolicy {
|
||||||
pub whitelist: Option<Vec<String>>,
|
pub whitelist: Option<Vec<String>>,
|
||||||
pub blacklist: 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)]
|
#[serde(default)]
|
||||||
pub struct FunctionalityPolicy {
|
pub struct FunctionalityPolicy {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
@@ -18,7 +18,7 @@ pub struct FunctionalityPolicy {
|
|||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Default, Deref, DerefMut)]
|
#[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize, Deref, DerefMut)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct DnsPolicy<P = FunctionalityPolicy> {
|
pub struct DnsPolicy<P = FunctionalityPolicy> {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
@@ -32,16 +32,15 @@ pub type ZoneExportPolicy = FunctionalityPolicy;
|
|||||||
pub type DnsExportPolicy = DnsPolicy<ZoneExportPolicy>;
|
pub type DnsExportPolicy = DnsPolicy<ZoneExportPolicy>;
|
||||||
pub type DnsImportPolicy = DnsPolicy<FunctionalityPolicy>;
|
pub type DnsImportPolicy = DnsPolicy<FunctionalityPolicy>;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Default)]
|
#[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct DnsPolicyConfig {
|
pub struct DnsPolicyConfig {
|
||||||
pub import: DnsImportPolicy,
|
pub import: DnsImportPolicy,
|
||||||
pub export: Option<DnsExportPolicy>,
|
pub export: Option<DnsExportPolicy>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Default)]
|
#[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct ZonePolicyConfig {
|
pub struct ZonePolicyConfig {
|
||||||
#[serde(default)]
|
|
||||||
pub export: Option<DnsExportPolicy>,
|
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 {
|
pub struct ZoneConfigInner {
|
||||||
#[serde(default = "Uuid::new_v4")]
|
#[derivative(Default(value = "Uuid::new_v4()"))]
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
id: Uuid,
|
id: Uuid,
|
||||||
pub origin: LowerName,
|
pub origin: LowerName,
|
||||||
#[serde(default)]
|
|
||||||
pub ttl: u32,
|
pub ttl: u32,
|
||||||
#[serde(default)]
|
|
||||||
pub records: Vec<String>,
|
pub records: Vec<String>,
|
||||||
#[serde(default)]
|
|
||||||
pub forwarders: NameServerAddrGroup,
|
pub forwarders: NameServerAddrGroup,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub policy: ZonePolicyConfig,
|
pub policy: ZonePolicyConfig,
|
||||||
|
#[derivative(Default(value = "true"))]
|
||||||
|
pub fallthrough: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ZoneConfigInner> for ZoneData {
|
impl From<ZoneConfigInner> for ZoneData {
|
||||||
@@ -93,6 +94,7 @@ impl From<ZoneConfigInner> for ZoneData {
|
|||||||
ttl: value.ttl,
|
ttl: value.ttl,
|
||||||
records: value.records,
|
records: value.records,
|
||||||
forwarders: value.forwarders.into(),
|
forwarders: value.forwarders.into(),
|
||||||
|
fallthrough: value.fallthrough,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -250,6 +250,7 @@ mod tests {
|
|||||||
ttl: 60,
|
ttl: 60,
|
||||||
records: vec!["@ IN A 10.0.0.11".to_string()],
|
records: vec!["@ IN A 10.0.0.11".to_string()],
|
||||||
forwarders: vec![],
|
forwarders: vec![],
|
||||||
|
fallthrough: false,
|
||||||
}],
|
}],
|
||||||
fqdn: "invalid.peer.test".to_string(),
|
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()
|
.into_iter()
|
||||||
.map(|f| Url::from_str(f).expect("invalid forwarder"))
|
.map(|f| Url::from_str(f).expect("invalid forwarder"))
|
||||||
.collect(),
|
.collect(),
|
||||||
|
fallthrough: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,8 +345,10 @@ async fn wait_peer_zone_visibility(
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
dns.refresh(target_peer_id).await;
|
dns.refresh(target_peer_id).await;
|
||||||
let visible = dns
|
|
||||||
.snapshot()
|
let snapshot = dns.snapshot();
|
||||||
|
|
||||||
|
let visible = snapshot
|
||||||
.zones
|
.zones
|
||||||
.iter()
|
.iter()
|
||||||
.any(|z| z.origin.contains(zone_origin_substr));
|
.any(|z| z.origin.contains(zone_origin_substr));
|
||||||
@@ -354,12 +357,19 @@ async fn wait_peer_zone_visibility(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let origins = snapshot
|
||||||
|
.zones
|
||||||
|
.iter()
|
||||||
|
.map(|z| z.origin.clone())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
Instant::now() < deadline,
|
Instant::now() < deadline,
|
||||||
"zone visibility mismatch for '{}': expected {}, got {}",
|
"zone visibility mismatch for '{}': expected {}, got {}, current origins: {:?}",
|
||||||
zone_origin_substr,
|
zone_origin_substr,
|
||||||
expected_visible,
|
expected_visible,
|
||||||
visible
|
visible,
|
||||||
|
origins
|
||||||
);
|
);
|
||||||
tokio::time::sleep(Duration::from_millis(200)).await;
|
tokio::time::sleep(Duration::from_millis(200)).await;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::common::dns::get_default_resolver_config;
|
use crate::common::dns::get_default_resolver_config;
|
||||||
use crate::dns::utils::addr::{NameServerAddr, NameServerAddrGroup};
|
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;
|
||||||
use crate::proto::utils::RepeatedMessageModel;
|
use crate::proto::utils::RepeatedMessageModel;
|
||||||
use hickory_net::runtime::TokioRuntimeProvider;
|
use hickory_net::runtime::TokioRuntimeProvider;
|
||||||
@@ -23,6 +23,7 @@ pub struct Zone {
|
|||||||
origin: LowerName,
|
origin: LowerName,
|
||||||
records: BTreeMap<RrKey, RecordSet>,
|
records: BTreeMap<RrKey, RecordSet>,
|
||||||
pub forward: Option<ForwardConfig>,
|
pub forward: Option<ForwardConfig>,
|
||||||
|
fallthrough: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Zone {
|
impl Zone {
|
||||||
@@ -35,6 +36,7 @@ impl Zone {
|
|||||||
};
|
};
|
||||||
let mut zone = Self::new(".".parse().unwrap());
|
let mut zone = Self::new(".".parse().unwrap());
|
||||||
zone.forward = Some(forward);
|
zone.forward = Some(forward);
|
||||||
|
zone.fallthrough = false;
|
||||||
zone
|
zone
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,6 +48,7 @@ impl Zone {
|
|||||||
origin: name,
|
origin: name,
|
||||||
records: BTreeMap::new(),
|
records: BTreeMap::new(),
|
||||||
forward: None,
|
forward: None,
|
||||||
|
fallthrough: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +67,11 @@ impl Zone {
|
|||||||
.map(|(k, v)| (k, Arc::new(v))),
|
.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()
|
.build()
|
||||||
.inspect_err(|e| tracing::error!("failed to create forward zone_handler: {:?}", e))
|
.inspect_err(|e| tracing::error!("failed to create forward zone_handler: {:?}", e))
|
||||||
.ok()
|
.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(),
|
origin: origin.into(),
|
||||||
records,
|
records,
|
||||||
forward,
|
forward,
|
||||||
|
fallthrough: value.fallthrough,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,6 +153,7 @@ impl From<Zone> for proto::dns::ZoneData {
|
|||||||
ttl: 0,
|
ttl: 0,
|
||||||
records,
|
records,
|
||||||
forwarders,
|
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 {
|
ZoneData {
|
||||||
id: Some(Uuid::new_v4().into()),
|
id: Some(Uuid::new_v4().into()),
|
||||||
origin: origin.to_string(),
|
origin: origin.to_string(),
|
||||||
@@ -205,9 +225,14 @@ mod tests {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|f| Url::from_str(f).expect("invalid forwarder"))
|
.map(|f| Url::from_str(f).expect("invalid forwarder"))
|
||||||
.collect(),
|
.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 {
|
fn build_catalog(zones: ZoneGroup) -> Catalog {
|
||||||
zones
|
zones
|
||||||
.into_groups()
|
.into_groups()
|
||||||
@@ -273,6 +298,7 @@ mod tests {
|
|||||||
ttl: 60,
|
ttl: 60,
|
||||||
records: vec!["@ IN A 10.0.0.1".to_string()],
|
records: vec!["@ IN A 10.0.0.1".to_string()],
|
||||||
forwarders: vec![],
|
forwarders: vec![],
|
||||||
|
fallthrough: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let err = Zone::try_from(&data).expect_err("missing id should fail");
|
let err = Zone::try_from(&data).expect_err("missing id should fail");
|
||||||
@@ -416,6 +442,67 @@ mod tests {
|
|||||||
Ok(())
|
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]
|
#[tokio::test]
|
||||||
async fn catalog_forward_only_zone_queries_upstream() -> anyhow::Result<()> {
|
async fn catalog_forward_only_zone_queries_upstream() -> anyhow::Result<()> {
|
||||||
let (upstream_addr, upstream_handle) = start_upstream_server().await?;
|
let (upstream_addr, upstream_handle) = start_upstream_server().await?;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ message ZoneData {
|
|||||||
uint32 ttl = 3;
|
uint32 ttl = 3;
|
||||||
repeated string records = 4;
|
repeated string records = 4;
|
||||||
repeated common.Url forwarders = 5;
|
repeated common.Url forwarders = 5;
|
||||||
|
bool fallthrough = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetExportConfigRequest {}
|
message GetExportConfigRequest {}
|
||||||
|
|||||||
Reference in New Issue
Block a user