mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-08-06 04:29:52 +00:00
zone: fallthrough policy
heartbeat test try_from
This commit is contained in:
@@ -71,6 +71,7 @@ tokio-util = { version = "0.7.9", features = ["codec", "net", "io", "rt"] }
|
||||
async-stream = "0.3.5"
|
||||
async-trait = "0.1.74"
|
||||
|
||||
maplit = "1.0.2"
|
||||
dashmap = "6.0"
|
||||
timedmap = "=1.0.1"
|
||||
|
||||
|
||||
@@ -735,7 +735,7 @@ impl DnsGlobalCtxExt for GlobalCtx {
|
||||
.clone()
|
||||
.unwrap_or_else(|| dns::parse(self.get_hostname()))
|
||||
.into();
|
||||
let fqdn = name.append_domain(&*dns.domain).unwrap_or_default().into();
|
||||
let fqdn = name.append_domain(&dns.domain).unwrap_or_default().into();
|
||||
let ipv4 = self.get_ipv4().map(|ip| ip.address());
|
||||
let ipv6 = self.get_ipv6().map(|ip| ip.address());
|
||||
let ipv6 = ipv6.map(|a| vec![a]).unwrap_or_default();
|
||||
|
||||
@@ -3,12 +3,40 @@ use crate::dns::config::policy::{DnsExportPolicy, ZonePolicyConfig};
|
||||
use crate::dns::utils::addr::NameServerAddrGroup;
|
||||
use crate::dns::zone::Zone;
|
||||
use crate::proto::dns::ZoneData;
|
||||
use derive_more::From;
|
||||
use hickory_proto::op::ResponseCode;
|
||||
use hickory_proto::rr::LowerName;
|
||||
use maplit::hashset;
|
||||
use optional_struct::{Applicable, optional_struct};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashSet;
|
||||
use std::convert::TryFrom;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
use url::Url;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Hash, From, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum Fallthrough {
|
||||
Any,
|
||||
ResponseCode(ResponseCode),
|
||||
}
|
||||
|
||||
impl From<Fallthrough> for i32 {
|
||||
fn from(value: Fallthrough) -> Self {
|
||||
match value {
|
||||
Fallthrough::ResponseCode(code) => u16::from(code).into(),
|
||||
Fallthrough::Any => -1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for Fallthrough {
|
||||
fn from(value: i32) -> Self {
|
||||
match u16::try_from(value) {
|
||||
Ok(value) => Self::ResponseCode(value.into()),
|
||||
Err(_) => Self::Any,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[optional_struct(ZoneConfigRaw)]
|
||||
#[derive(Debug, Clone, Default, PartialEq, Deserialize, Serialize)]
|
||||
@@ -21,7 +49,7 @@ pub struct ZoneConfigParsed {
|
||||
#[optional_skip_wrap]
|
||||
#[serde(flatten)]
|
||||
pub policy: ZonePolicyConfig,
|
||||
pub fallthrough: bool,
|
||||
pub fallthrough: HashSet<Fallthrough>,
|
||||
}
|
||||
|
||||
impl From<&ZoneConfigParsed> for ZoneData {
|
||||
@@ -30,8 +58,8 @@ impl From<&ZoneConfigParsed> for ZoneData {
|
||||
&value.origin,
|
||||
value.ttl,
|
||||
&value.records,
|
||||
value.forwarders.iter().map(Url::from),
|
||||
value.fallthrough,
|
||||
value.forwarders.iter().map(Into::into),
|
||||
value.fallthrough.iter().copied(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -43,7 +71,7 @@ impl TryFrom<ZoneConfigRaw> for ZoneConfig {
|
||||
|
||||
fn try_from(raw: ZoneConfigRaw) -> Result<Self, Self::Error> {
|
||||
let default = ZoneConfigParsed {
|
||||
fallthrough: true,
|
||||
fallthrough: hashset! {Fallthrough::Any},
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
||||
@@ -254,10 +254,10 @@ mod tests {
|
||||
use crate::peers::peer_manager::RouteAlgoType;
|
||||
use crate::peers::tests::{connect_peer_manager, wait_route_appear};
|
||||
use crate::proto::dns::GetExportConfigRequest;
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::net::Ipv4Addr;
|
||||
use tokio::time::{Duration, sleep};
|
||||
use url::Url;
|
||||
|
||||
async fn create_peer_manager_with_zone(
|
||||
host: &str,
|
||||
@@ -296,13 +296,7 @@ mod tests {
|
||||
#[test]
|
||||
fn dns_peer_info_try_from_invalid_zone_rejected() {
|
||||
let cfg = DnsExportConfig {
|
||||
zones: vec![ZoneData::new(
|
||||
&".".parse().unwrap(),
|
||||
60,
|
||||
["?"],
|
||||
Vec::<Url>::new(),
|
||||
false,
|
||||
)],
|
||||
zones: vec![ZoneData::new(&".".parse().unwrap(), 60, ["?"], [], [])],
|
||||
};
|
||||
|
||||
assert!(DnsPeerInfo::try_from(cfg).is_err());
|
||||
|
||||
@@ -28,6 +28,7 @@ use hickory_proto::rr;
|
||||
use hickory_proto::rr::{DNSClass, Name, RData, RecordType};
|
||||
use hickory_proto::serialize::binary::{BinEncodable, BinEncoder};
|
||||
use hickory_server::server::Request;
|
||||
use maplit::hashset;
|
||||
use tokio::sync::Notify;
|
||||
use uuid::Uuid;
|
||||
|
||||
@@ -108,10 +109,8 @@ pub fn zone_data_a_with_forwarders(origin: &str, record: &str, forwarders: Vec<&
|
||||
&origin.parse().unwrap(),
|
||||
60,
|
||||
[format!("@ IN A {record}")],
|
||||
forwarders
|
||||
.into_iter()
|
||||
.map(|f| Url::from_str(f).expect("invalid forwarder")),
|
||||
false,
|
||||
forwarders.into_iter().map(|f| Url::from_str(f).unwrap()),
|
||||
hashset! {},
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -39,31 +39,19 @@ impl From<(IpAddr, &ConnectionConfig)> for NameServerAddr {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&NameServerAddr> for Url {
|
||||
fn from(value: &NameServerAddr) -> Self {
|
||||
Url::parse(&format!("{}://{}", value.protocol, value.addr)).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NameServerAddr> for Url {
|
||||
fn from(value: NameServerAddr) -> Self {
|
||||
(&value).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&Url> for NameServerAddr {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: &Url) -> Result<Self, Self::Error> {
|
||||
let protocol = match Protocol::deserialize(value.scheme().into_deserializer()).map_err(
|
||||
|e: de::value::Error| anyhow!("invalid protocol '{}': {}", value.scheme(), e),
|
||||
)? {
|
||||
fn try_from(url: &Url) -> Result<Self, Self::Error> {
|
||||
let protocol = match Protocol::deserialize(url.scheme().into_deserializer())
|
||||
.map_err(|e: de::value::Error| anyhow!("invalid protocol '{}': {}", url.scheme(), e))?
|
||||
{
|
||||
Protocol::Udp => ProtocolConfig::Udp,
|
||||
Protocol::Tcp => ProtocolConfig::Tcp,
|
||||
p => return Err(anyhow!("unsupported protocol: {}", p)),
|
||||
};
|
||||
let host = value.host_str().ok_or(anyhow!("host not found"))?;
|
||||
let port = value.port().unwrap_or(protocol.default_port());
|
||||
let host = url.host_str().ok_or(anyhow!("host not found"))?;
|
||||
let port = url.port().unwrap_or(protocol.default_port());
|
||||
let addr = if let Ok(addr) = IpAddr::from_str(host) {
|
||||
SocketAddr::new(addr, port)
|
||||
} else {
|
||||
@@ -76,17 +64,35 @@ impl TryFrom<&Url> for NameServerAddr {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NameServerAddr> for proto::common::Url {
|
||||
fn from(value: NameServerAddr) -> Self {
|
||||
Url::from(value).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&proto::common::Url> for NameServerAddr {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: &proto::common::Url) -> Result<Self, Self::Error> {
|
||||
Self::try_from(&Url::try_from(value)?)
|
||||
(&Url::try_from(value)?).try_into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&NameServerAddr> for Url {
|
||||
fn from(value: &NameServerAddr) -> Self {
|
||||
Url::parse(&format!("{}://{}", value.protocol, value.addr)).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&NameServerAddr> for proto::common::Url {
|
||||
fn from(value: &NameServerAddr) -> Self {
|
||||
Url::from(value).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NameServerAddr> for Url {
|
||||
fn from(value: NameServerAddr) -> Self {
|
||||
(&value).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NameServerAddr> for proto::common::Url {
|
||||
fn from(value: NameServerAddr) -> Self {
|
||||
(&value).into()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,35 +1,27 @@
|
||||
use crate::dns::config::zone::Fallthrough;
|
||||
use delegate::delegate;
|
||||
use derive_more::{Deref, DerefMut, From};
|
||||
use derive_more::{Constructor, Deref, DerefMut};
|
||||
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, LookupError, LookupOptions, ZoneHandler, ZoneType,
|
||||
};
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub type ArcZoneHandler = Arc<dyn ZoneHandler>;
|
||||
|
||||
pub trait LookupControlFlowExt {
|
||||
fn skip_negative(self) -> Self;
|
||||
}
|
||||
|
||||
impl LookupControlFlowExt for LookupControlFlow<AuthLookup> {
|
||||
fn skip_negative(self) -> Self {
|
||||
match self {
|
||||
Self::Continue(e) | Self::Break(e) if matches!(e, Err(LookupError::NameExists)) => {
|
||||
Self::Continue(Ok(Default::default()))
|
||||
}
|
||||
Self::Continue(Err(_)) | Self::Break(Err(_)) => Self::Skip,
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(From, Deref, DerefMut)]
|
||||
pub struct ChainedZoneHandler<H>(H)
|
||||
#[derive(Constructor, Deref, DerefMut)]
|
||||
pub struct ChainedZoneHandler<H>
|
||||
where
|
||||
H: ZoneHandler;
|
||||
H: ZoneHandler,
|
||||
{
|
||||
#[deref]
|
||||
#[deref_mut]
|
||||
handler: H,
|
||||
fallthrough: HashSet<Fallthrough>,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<H> ZoneHandler for ChainedZoneHandler<H>
|
||||
@@ -37,7 +29,7 @@ where
|
||||
H: ZoneHandler,
|
||||
{
|
||||
delegate! {
|
||||
to self.0 {
|
||||
to self.handler {
|
||||
fn zone_type(&self) -> ZoneType;
|
||||
fn axfr_policy(&self) -> AxfrPolicy;
|
||||
fn origin(&self) -> &LowerName;
|
||||
@@ -50,7 +42,7 @@ where
|
||||
update: &Request,
|
||||
now: u64,
|
||||
) -> (Result<bool, ResponseCode>, Option<TSigResponseContext>) {
|
||||
self.0.update(update, now).await
|
||||
self.handler.update(update, now).await
|
||||
}
|
||||
#[inline]
|
||||
async fn lookup(
|
||||
@@ -60,29 +52,9 @@ where
|
||||
request_info: Option<&RequestInfo<'_>>,
|
||||
lookup_options: LookupOptions,
|
||||
) -> LookupControlFlow<AuthLookup> {
|
||||
self.0
|
||||
self.handler
|
||||
.lookup(name, rtype, request_info, lookup_options)
|
||||
.await
|
||||
.skip_negative()
|
||||
}
|
||||
#[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
|
||||
.skip_negative()
|
||||
};
|
||||
(result, None)
|
||||
}
|
||||
#[inline]
|
||||
async fn search(
|
||||
@@ -90,8 +62,17 @@ where
|
||||
request: &Request,
|
||||
lookup_options: LookupOptions,
|
||||
) -> (LookupControlFlow<AuthLookup>, Option<TSigResponseContext>) {
|
||||
let (result, tsig) = self.0.search(request, lookup_options).await;
|
||||
(result.skip_negative(), tsig)
|
||||
let (result, tsig) = self.handler.search(request, lookup_options).await;
|
||||
|
||||
match &result {
|
||||
LookupControlFlow::Continue(Err(e)) | LookupControlFlow::Break(Err(e))
|
||||
if self.fallthrough.contains(&Fallthrough::Any)
|
||||
|| matches!(e, LookupError::ResponseCode(c) if self.fallthrough.contains(&(*c).into())) =>
|
||||
{
|
||||
(LookupControlFlow::Skip, None)
|
||||
}
|
||||
_ => (result, tsig),
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
async fn nsec_records(
|
||||
@@ -99,6 +80,6 @@ where
|
||||
name: &LowerName,
|
||||
lookup_options: LookupOptions,
|
||||
) -> LookupControlFlow<AuthLookup> {
|
||||
self.0.nsec_records(name, lookup_options).await
|
||||
self.handler.nsec_records(name, lookup_options).await
|
||||
}
|
||||
}
|
||||
|
||||
+39
-45
@@ -1,3 +1,4 @@
|
||||
use crate::dns::config::zone::Fallthrough;
|
||||
use crate::dns::utils::addr::{NameServerAddr, NameServerAddrGroup};
|
||||
use crate::dns::utils::zone_handler::{ArcZoneHandler, ChainedZoneHandler};
|
||||
use crate::proto::dns::ZoneData;
|
||||
@@ -11,16 +12,16 @@ use hickory_server::store::in_memory::InMemoryZoneHandler;
|
||||
use hickory_server::zone_handler::{AxfrPolicy, ZoneType};
|
||||
use indexmap::IndexMap;
|
||||
use itertools::chain;
|
||||
use std::collections::BTreeMap;
|
||||
use maplit::hashset;
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
use std::sync::Arc;
|
||||
use url::Url;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Zone {
|
||||
origin: LowerName,
|
||||
records: BTreeMap<RrKey, RecordSet>,
|
||||
pub forward: Option<ForwardConfig>,
|
||||
fallthrough: bool,
|
||||
fallthrough: HashSet<Fallthrough>,
|
||||
}
|
||||
|
||||
impl Zone {
|
||||
@@ -30,23 +31,16 @@ impl Zone {
|
||||
name_servers: config.name_servers().to_vec(),
|
||||
options: Some(opts),
|
||||
};
|
||||
let mut zone = Self::new(".".parse().unwrap());
|
||||
zone.forward = Some(forward);
|
||||
zone.fallthrough = false;
|
||||
zone
|
||||
Self {
|
||||
origin: ".".parse().unwrap(),
|
||||
forward: Some(forward),
|
||||
fallthrough: hashset! {},
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Zone {
|
||||
pub fn new(name: LowerName) -> Self {
|
||||
Self {
|
||||
origin: name,
|
||||
records: BTreeMap::new(),
|
||||
forward: None,
|
||||
fallthrough: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_memory_zone_handler(&self) -> Option<ArcZoneHandler> {
|
||||
(!self.records.is_empty()).then(|| {
|
||||
let mut memory = InMemoryZoneHandler::<TokioRuntimeProvider>::empty(
|
||||
@@ -62,11 +56,7 @@ impl Zone {
|
||||
.map(|(k, v)| (k, Arc::new(v))),
|
||||
);
|
||||
|
||||
if self.fallthrough {
|
||||
Arc::new(ChainedZoneHandler::from(memory)) as _
|
||||
} else {
|
||||
Arc::new(memory) as _
|
||||
}
|
||||
Arc::new(ChainedZoneHandler::new(memory, self.fallthrough.clone())) as _
|
||||
})
|
||||
}
|
||||
|
||||
@@ -77,14 +67,10 @@ impl Zone {
|
||||
TokioRuntimeProvider::default(),
|
||||
)
|
||||
.build()
|
||||
.inspect_err(|e| tracing::error!("failed to create forward zone_handler: {:?}", e))
|
||||
.inspect_err(|error| tracing::error!(?error, "failed to create forward zone_handler"))
|
||||
.ok()
|
||||
.map(|f| {
|
||||
if self.fallthrough {
|
||||
Arc::new(ChainedZoneHandler::from(f)) as _
|
||||
} else {
|
||||
Arc::new(f) as _
|
||||
}
|
||||
.map(|handler| {
|
||||
Arc::new(ChainedZoneHandler::new(handler, self.fallthrough.clone())) as _
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -101,7 +87,7 @@ impl TryFrom<&ZoneData> for Zone {
|
||||
let name_servers = value
|
||||
.forwarders
|
||||
.iter()
|
||||
.map(TryInto::<NameServerAddr>::try_into)
|
||||
.map(NameServerAddr::try_from)
|
||||
.map(|a| a.map(Into::into))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let forward = (!name_servers.is_empty()).then_some(ForwardConfig {
|
||||
@@ -109,11 +95,13 @@ impl TryFrom<&ZoneData> for Zone {
|
||||
options: None,
|
||||
});
|
||||
|
||||
let fallthrough = value.fallthrough.iter().copied().map(Into::into).collect();
|
||||
|
||||
Ok(Self {
|
||||
origin: origin.into(),
|
||||
records,
|
||||
forward,
|
||||
fallthrough: value.fallthrough,
|
||||
fallthrough,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -132,7 +120,7 @@ impl From<Zone> for ZoneData {
|
||||
.flat_map(|f| f.name_servers.into_iter())
|
||||
.map(|ns| (&ns).into())
|
||||
.flat_map(NameServerAddrGroup::into_iter)
|
||||
.map(Url::from);
|
||||
.map(Into::into);
|
||||
|
||||
Self::new(&value.origin, 0, records, forwarders, value.fallthrough)
|
||||
}
|
||||
@@ -169,7 +157,9 @@ mod tests {
|
||||
use hickory_proto::rr::{RData, Record, RecordType, RrsetRecords};
|
||||
use hickory_server::Server;
|
||||
use hickory_server::zone_handler::Catalog;
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
use maplit::hashset;
|
||||
use std::collections::HashSet;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||
use std::str::FromStr;
|
||||
use tokio::net::UdpSocket;
|
||||
use tokio::task::JoinHandle;
|
||||
@@ -193,21 +183,21 @@ mod tests {
|
||||
origin: &str,
|
||||
records: Vec<&str>,
|
||||
forwarders: Vec<&str>,
|
||||
fallthrough: bool,
|
||||
fallthrough: HashSet<Fallthrough>,
|
||||
) -> ZoneData {
|
||||
ZoneData::new(
|
||||
&origin.parse().unwrap(),
|
||||
60,
|
||||
records,
|
||||
forwarders.into_iter().map(|url| Url {
|
||||
url: url.to_string(),
|
||||
}),
|
||||
forwarders
|
||||
.into_iter()
|
||||
.map(|url| Url::from_str(url).unwrap()),
|
||||
fallthrough,
|
||||
)
|
||||
}
|
||||
|
||||
fn zone_data(origin: &str, records: Vec<&str>, forwarders: Vec<&str>) -> ZoneData {
|
||||
zone_data_with_fallthrough(origin, records, forwarders, true)
|
||||
zone_data_with_fallthrough(origin, records, forwarders, hashset! {Fallthrough::Any})
|
||||
}
|
||||
|
||||
fn build_catalog(zones: ZoneGroup) -> Catalog {
|
||||
@@ -242,6 +232,13 @@ mod tests {
|
||||
.any(|record| matches!(record.data, RData::A(addr) if *addr == expected))
|
||||
}
|
||||
|
||||
fn has_aaaa_answer(message: &Message, expected: Ipv6Addr) -> bool {
|
||||
message
|
||||
.answers
|
||||
.iter()
|
||||
.any(|record| matches!(record.data, RData::AAAA(addr) if *addr == expected))
|
||||
}
|
||||
|
||||
async fn start_upstream_server() -> anyhow::Result<(SocketAddr, JoinHandle<()>)> {
|
||||
let upstream = Zone::try_from(&zone_data(
|
||||
"upstream.test",
|
||||
@@ -400,7 +397,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn catalog_lookup_returns_nodata_on_nameexists() -> anyhow::Result<()> {
|
||||
async fn catalog_lookup_forwards_on_nameexists() -> anyhow::Result<()> {
|
||||
let upstream = Zone::try_from(&zone_data(
|
||||
"forward-aaaa.test",
|
||||
vec!["host 60 IN AAAA 2001:db8::1"],
|
||||
@@ -435,10 +432,7 @@ mod tests {
|
||||
assert_eq!(rcode, ResponseCode::NoError);
|
||||
|
||||
let message = message.expect("response should exist");
|
||||
assert!(
|
||||
message.answers.is_empty(),
|
||||
"NameExists should return NODATA"
|
||||
);
|
||||
assert!(has_aaaa_answer(&message, "2001:db8::1".parse()?));
|
||||
|
||||
upstream_handle.abort();
|
||||
let _ = upstream_handle.await;
|
||||
@@ -528,13 +522,13 @@ mod tests {
|
||||
"fallback-disabled.test",
|
||||
vec!["first IN A 10.20.31.1"],
|
||||
vec![],
|
||||
false,
|
||||
hashset! {},
|
||||
))?,
|
||||
Zone::try_from(&zone_data_with_fallthrough(
|
||||
"fallback-disabled.test",
|
||||
vec!["target IN A 10.20.31.2"],
|
||||
vec![],
|
||||
false,
|
||||
hashset! {},
|
||||
))?,
|
||||
]
|
||||
.into();
|
||||
|
||||
@@ -7,7 +7,7 @@ package dns;
|
||||
message ZoneData {
|
||||
string content = 1;
|
||||
repeated common.Url forwarders = 2;
|
||||
bool fallthrough = 3;
|
||||
repeated int32 fallthrough = 3;
|
||||
}
|
||||
|
||||
message GetExportConfigRequest {}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::dns::config::zone::Fallthrough;
|
||||
use crate::proto::common::Url;
|
||||
use crate::proto::utils::TransientDigest;
|
||||
use hickory_proto::rr::LowerName;
|
||||
@@ -13,19 +14,13 @@ impl HeartbeatRequest {
|
||||
}
|
||||
|
||||
impl ZoneData {
|
||||
pub fn new<Records, R, Urls, U>(
|
||||
pub fn new<Record: AsRef<str>>(
|
||||
origin: &LowerName,
|
||||
ttl: u32,
|
||||
records: Records,
|
||||
forwarders: Urls,
|
||||
fallthrough: bool,
|
||||
) -> Self
|
||||
where
|
||||
Records: IntoIterator<Item = R>,
|
||||
R: AsRef<str>,
|
||||
Urls: IntoIterator<Item = U>,
|
||||
U: Into<Url>,
|
||||
{
|
||||
records: impl IntoIterator<Item = Record>,
|
||||
forwarders: impl IntoIterator<Item = Url>,
|
||||
fallthrough: impl IntoIterator<Item = Fallthrough>,
|
||||
) -> Self {
|
||||
let mut content = String::new();
|
||||
|
||||
content.push_str("; EasyTier Magic DNS zone data\n");
|
||||
@@ -44,7 +39,8 @@ impl ZoneData {
|
||||
content.push('\n');
|
||||
}
|
||||
|
||||
let forwarders = forwarders.into_iter().map(Into::into).collect();
|
||||
let forwarders = forwarders.into_iter().collect();
|
||||
let fallthrough = fallthrough.into_iter().map(Into::into).collect();
|
||||
|
||||
Self {
|
||||
content,
|
||||
|
||||
Reference in New Issue
Block a user