diff --git a/.unreleased/LLT-6364 b/.unreleased/LLT-6364 new file mode 100644 index 000000000..e1514a6ec --- /dev/null +++ b/.unreleased/LLT-6364 @@ -0,0 +1 @@ +Update trust-dns to v4.0.1 which bumps our fork from upstream v0.24.0 to v0.25.2 \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 1a19bd40e..ac4c0e611 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1025,6 +1025,12 @@ dependencies = [ "itertools 0.13.0", ] +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + [[package]] name = "crossbeam-channel" version = "0.5.15" @@ -1895,8 +1901,8 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hickory-proto" -version = "0.24.0" -source = "git+https://github.com/NordSecurity/trust-dns.git?tag=v3.0.1#88204024fd3ecdadccf4574eb7976167e7c52001" +version = "0.25.2" +source = "git+https://github.com/NordSecurity/trust-dns.git?tag=v4.0.1#a6791902c39d3945b48616dc5b51b19233a61046" dependencies = [ "async-trait", "cfg-if", @@ -1908,9 +1914,10 @@ dependencies = [ "idna", "ipnet", "once_cell", - "rand 0.8.5", + "rand 0.9.2", + "ring", "serde", - "thiserror 1.0.69", + "thiserror 2.0.17", "tinyvec", "tokio", "tracing", @@ -1919,39 +1926,42 @@ dependencies = [ [[package]] name = "hickory-resolver" -version = "0.24.0" -source = "git+https://github.com/NordSecurity/trust-dns.git?tag=v3.0.1#88204024fd3ecdadccf4574eb7976167e7c52001" +version = "0.25.2" +source = "git+https://github.com/NordSecurity/trust-dns.git?tag=v4.0.1#a6791902c39d3945b48616dc5b51b19233a61046" dependencies = [ "cfg-if", "futures-util", "hickory-proto", "ipconfig", - "lru-cache", + "moka", "once_cell", "parking_lot", - "rand 0.8.5", + "rand 0.9.2", "resolv-conf", "serde", "smallvec", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", "tracing", ] [[package]] name = "hickory-server" -version = "0.24.0" -source = "git+https://github.com/NordSecurity/trust-dns.git?tag=v3.0.1#88204024fd3ecdadccf4574eb7976167e7c52001" +version = "0.25.2" +source = "git+https://github.com/NordSecurity/trust-dns.git?tag=v4.0.1#a6791902c39d3945b48616dc5b51b19233a61046" dependencies = [ "async-trait", "bytes", "cfg-if", + "data-encoding", "enum-as-inner", "futures-util", "hickory-proto", "hickory-resolver", + "ipnet", + "prefix-trie", "serde", - "thiserror 1.0.69", + "thiserror 2.0.17", "time", "tokio", "tokio-util", @@ -2531,12 +2541,6 @@ dependencies = [ "libc", ] -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -2585,15 +2589,6 @@ dependencies = [ "value-bag", ] -[[package]] -name = "lru-cache" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" -dependencies = [ - "linked-hash-map", -] - [[package]] name = "lru-slab" version = "0.1.2" @@ -2752,6 +2747,24 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41f5c9112cb662acd3b204077e0de5bc66305fa8df65c8019d5adb10e9ab6e58" +[[package]] +name = "moka" +version = "0.12.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8261cd88c312e0004c1d51baad2980c66528dfdb2bee62003e643a4d8f86b077" +dependencies = [ + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "equivalent", + "parking_lot", + "portable-atomic", + "rustc_version", + "smallvec", + "tagptr", + "uuid", +] + [[package]] name = "multimap" version = "0.10.1" @@ -3061,6 +3074,10 @@ name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +dependencies = [ + "critical-section", + "portable-atomic", +] [[package]] name = "once_cell_polyfill" @@ -3441,6 +3458,16 @@ dependencies = [ "termtree", ] +[[package]] +name = "prefix-trie" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cf4c7c25f1dd66c76b451e9041a8cfce26e4ca754934fa7aed8d5a59a01d20" +dependencies = [ + "ipnet", + "num-traits", +] + [[package]] name = "pretty_assertions" version = "1.4.1" @@ -3550,7 +3577,7 @@ version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac6c3320f9abac597dcbc668774ef006702672474aad53c6d596b62e487b40b1" dependencies = [ - "heck 0.5.0", + "heck 0.4.1", "itertools 0.14.0", "log", "multimap", @@ -4725,6 +4752,12 @@ dependencies = [ "libc", ] +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + [[package]] name = "take-until" version = "0.1.0" diff --git a/crates/telio-dns/Cargo.toml b/crates/telio-dns/Cargo.toml index c3a3f6a17..c439c794e 100644 --- a/crates/telio-dns/Cargo.toml +++ b/crates/telio-dns/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] rand = { workspace = true, default-features = false } -hickory-server = { git = "https://github.com/NordSecurity/trust-dns.git", tag = "v3.0.1", features = ["hickory-resolver"], default-features = false } +hickory-server = { git = "https://github.com/NordSecurity/trust-dns.git", tag = "v4.0.1", features = ["resolver"], default-features = false } async-trait.workspace = true neptun.workspace = true x25519-dalek.workspace = true diff --git a/crates/telio-dns/src/forward.rs b/crates/telio-dns/src/forward.rs index bf80ed814..df75e057f 100644 --- a/crates/telio-dns/src/forward.rs +++ b/crates/telio-dns/src/forward.rs @@ -6,24 +6,25 @@ use std::{ io, net::{Ipv4Addr, Ipv6Addr, SocketAddr}, pin::Pin, + time::Duration, }; use async_trait::async_trait; use hickory_server::{ authority::{ - Authority, LookupError, LookupObject, LookupOptions, MessageRequest, UpdateResult, ZoneType, + Authority, LookupControlFlow, LookupError, LookupObject, LookupOptions, MessageRequest, + UpdateResult, ZoneType, }, proto::{ op::ResponseCode, rr::{LowerName, Name, Record, RecordType}, + runtime::{RuntimeProvider, TokioRuntimeProvider}, udp::{DnsUdpSocket, UdpSocket as ProtoUdpSocket}, + ProtoErrorKind, }, resolver::{ - config::ResolverConfig, - error::ResolveErrorKind, - lookup::Lookup as ResolverLookup, - name_server::{GenericConnector, RuntimeProvider, TokioRuntimeProvider}, - AsyncResolver, + config::ResolverConfig, lookup::Lookup as ResolverLookup, name_server::GenericConnector, + ResolveError, ResolveErrorKind, Resolver, }, server::RequestInfo, store::forwarder::ForwardConfig, @@ -49,8 +50,10 @@ impl RuntimeProvider for TelioRuntimeProvider { fn connect_tcp( &self, server_addr: SocketAddr, + bind_addr: Option, + timeout: Option, ) -> Pin>>> { - self.0.connect_tcp(server_addr) + self.0.connect_tcp(server_addr, bind_addr, timeout) } fn bind_udp( @@ -66,7 +69,7 @@ impl RuntimeProvider for TelioRuntimeProvider { } } -pub type TelioAsyncResolver = AsyncResolver>; +pub type TelioAsyncResolver = Resolver>; pub struct TelioUdpSocket(UdpSocket); @@ -168,7 +171,9 @@ impl ForwardAuthority { let config = ResolverConfig::from_parts(None, vec![], name_servers); - let resolver = TelioAsyncResolver::new(config, options, GenericConnector::default()); + let resolver = TelioAsyncResolver::builder_with_config(config, GenericConnector::default()) + .with_options(options) + .build(); telio_log_info!("forward resolver configured: {}: ", origin); @@ -178,6 +183,41 @@ impl ForwardAuthority { resolver, }) } + + fn transform_lookup_error(name: &LowerName, err: ResolveError) -> LookupError { + if let ResolveErrorKind::Proto(proto) = err.kind() { + if let ProtoErrorKind::NoRecordsFound { + query: _, + soa: _, + ns: _, + negative_ttl: _, + response_code, + trusted: _, + authorities: _, + } = proto.kind() + { + return if *response_code == ResponseCode::NoError { + telio_log_debug!("Got an error response with NoError code for {name}, this should not happen so converting to ServFail"); + // Failed query with no error - convert that to a real error, + // otherwise the LookupError::from will panic in debug builds. + // If we use a number from the 'private use' range: + // https://datatracker.ietf.org/doc/html/rfc2929#section-2.3 like + // LookupError::from(ResponseCode::Unknown(3841)) + // the trust-dns will end up looping until the requests with some other error + // is returned. This will make the original dns request (eg. by nslookup or dig or some app) + // never complete. To avoid that, lets return ServFail which will produce + // an empty respones. + LookupError::from(ResponseCode::ServFail) + } else { + LookupError::from(*response_code) + }; + } + } + + // NOTE: this is probably incorrect, and should be at least 24, most likely + // in range 3841-4095 ('private use' range), instead of '0'. + LookupError::from(ResponseCode::Unknown(0)) + } } #[async_trait::async_trait] @@ -186,7 +226,7 @@ impl Authority for ForwardAuthority { /// Always Forward fn zone_type(&self) -> ZoneType { - ZoneType::Forward + ZoneType::External } /// Always false for Forward zones @@ -213,7 +253,7 @@ impl Authority for ForwardAuthority { name: &LowerName, rtype: RecordType, _lookup_options: LookupOptions, - ) -> Result { + ) -> LookupControlFlow { // TODO: make this an error? debug_assert!(self.origin.zone_of(name)); @@ -227,7 +267,7 @@ impl Authority for ForwardAuthority { // // Log such errors with lower logging level Err(ref e) - if matches!(e.kind(), ResolveErrorKind::NoRecordsFound { .. }) + if e.is_no_records_found() && (rtype == RecordType::AAAA || rtype == RecordType::SOA) => { telio_log_debug!("DNS name resolution failed with {:?}", e); @@ -237,43 +277,17 @@ impl Authority for ForwardAuthority { Ok(_) => (), }; - resolve + let result = resolve .map(ForwardLookup) - .map_err(|code| match code.kind() { - ResolveErrorKind::NoRecordsFound { - query: _, - soa: _, - negative_ttl: _, - response_code, - trusted: _, - } => { - if *response_code == ResponseCode::NoError { - telio_log_debug!("Got an error response with NoError code for {name}, this should not happen so converting to ServFail"); - // Failed query with no error - convert that to a real error, - // otherwise the LookupError::from will panic in debug builds. - // If we use a number from the 'private use' range: - // https://datatracker.ietf.org/doc/html/rfc2929#section-2.3 like - // LookupError::from(ResponseCode::Unknown(3841)) - // the trust-dns will end up looping until the requests with some other error - // is returned. This will make the original dns request (eg. by nslookup or dig or some app) - // never complete. To avoid that, lets return ServFail which will produce - // an empty respones. - LookupError::from(ResponseCode::ServFail) - } else { - LookupError::from(*response_code) - } - } - // NOTE: this is probably incorrect, and should be at least 24, most likely - // in range 3841-4095 ('private use' range), instead of '0'. - _ => LookupError::from(ResponseCode::Unknown(0)), - }) + .map_err(|err| Self::transform_lookup_error(name, err)); + LookupControlFlow::Continue(result) } async fn search( &self, request_info: RequestInfo<'_>, lookup_options: LookupOptions, - ) -> Result { + ) -> LookupControlFlow { self.lookup( request_info.query.name(), request_info.query.query_type(), @@ -286,10 +300,10 @@ impl Authority for ForwardAuthority { &self, _name: &LowerName, _lookup_options: LookupOptions, - ) -> Result { - Err(LookupError::from(io::Error::other( + ) -> LookupControlFlow { + LookupControlFlow::Break(Err(LookupError::from(io::Error::other( "Getting NSEC records is unimplemented for the forwarder", - ))) + )))) } } diff --git a/crates/telio-dns/src/nameserver.rs b/crates/telio-dns/src/nameserver.rs index 6b7230db2..4db1dc28b 100644 --- a/crates/telio-dns/src/nameserver.rs +++ b/crates/telio-dns/src/nameserver.rs @@ -5,8 +5,8 @@ use crate::{ use async_trait::async_trait; use hickory_server::{ authority::MessageRequest, - proto::{rr::LowerName, serialize::binary::BinDecodable}, - server::{Protocol, Request}, + proto::{rr::LowerName, serialize::binary::BinDecodable, xfer::Protocol}, + server::Request, }; use neptun::noise::{Tunn, TunnResult}; use pnet_packet::{ @@ -697,14 +697,14 @@ impl NameServer for Arc> { self.zones_mut() .await - .upsert(LowerName::from_str(zone)?, Box::new(azone)); + .upsert(LowerName::from_str(zone)?, vec![azone]); Ok(()) } async fn forward(&self, to: &[IpAddr]) -> Result<(), String> { self.zones_mut().await.upsert( LowerName::from_str(".")?, - Box::new(Arc::new(ForwardZone::new(".", to).await?)), + vec![Arc::new(ForwardZone::new(".", to).await?)], ); Ok(()) } @@ -768,10 +768,10 @@ mod tests { .await .unwrap(); nameserver - .upsert("nord", &records, TtlValue(60)) + .upsert("nord.", &records, TtlValue(60)) .await .unwrap(); - let request = dns_request(entry_name.clone()); + let request = dns_request(String::from("pashka.nord")); let resolver = Resolver::new(); nameserver .zones() @@ -793,10 +793,9 @@ mod tests { #[tokio::test] async fn zones_are_lazily_copied_on_write_access() { - let name1 = "test.nord.".to_owned(); let mut records = Records::new(); records.insert( - name1.clone(), + "test.nord.".to_owned(), vec![IpAddr::V4(Ipv4Addr::new(100, 69, 69, 69))], ); let nameserver = LocalNameServer::new(&[IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8))]) @@ -804,38 +803,36 @@ mod tests { .unwrap(); let raw_read_ptr1 = Arc::as_ptr(&nameserver.zones().await); nameserver - .upsert("nord", &records, TtlValue(60)) + .upsert("nord.", &records, TtlValue(60)) .await .unwrap(); let raw_read_ptr2 = Arc::as_ptr(&nameserver.zones().await); assert_eq!(raw_read_ptr1, raw_read_ptr2); - let name2 = "test.nord2.".to_owned(); let mut records = Records::new(); records.insert( - name2.clone(), + "test.nord2.".to_owned(), vec![IpAddr::V4(Ipv4Addr::new(100, 69, 69, 69))], ); let read_ptr3 = nameserver.zones().await; nameserver - .upsert("nord2", &records, TtlValue(60)) + .upsert("nord2.", &records, TtlValue(60)) .await .unwrap(); let raw_read_ptr4 = Arc::as_ptr(&nameserver.zones().await); assert_ne!(Arc::as_ptr(&read_ptr3), raw_read_ptr4); let zones = nameserver.zones().await; - assert!(zones.contains(&LowerName::from_str("nord").unwrap())); - assert!(zones.contains(&LowerName::from_str("nord2").unwrap())); + assert!(zones.contains(&LowerName::from_str("nord.").unwrap())); + assert!(zones.contains(&LowerName::from_str("nord2.").unwrap())); } #[tokio::test] async fn forward_zones_are_cloned_too() { - let name1 = "test.nord.".to_owned(); let mut records = Records::new(); records.insert( - name1.clone(), + "test.nord.".to_owned(), vec![IpAddr::V4(Ipv4Addr::new(100, 69, 69, 69))], ); let nameserver = LocalNameServer::new(&[IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8))]) @@ -848,6 +845,6 @@ mod tests { let zones = nameserver.zones().await; assert!(zones.contains(&LowerName::from_str(".").unwrap())); - assert!(zones.contains(&LowerName::from_str("nord").unwrap())); + assert!(zones.contains(&LowerName::from_str("nord.").unwrap())); } } diff --git a/crates/telio-dns/src/zone.rs b/crates/telio-dns/src/zone.rs index 7a666bbe7..82b3444ed 100644 --- a/crates/telio-dns/src/zone.rs +++ b/crates/telio-dns/src/zone.rs @@ -1,11 +1,14 @@ use async_trait::async_trait; use hickory_server::{ authority::{ - Authority, AuthorityObject, Catalog, LookupError, LookupOptions, MessageRequest, - UpdateResult, ZoneType, + Authority, AuthorityObject, Catalog, LookupControlFlow, LookupError, LookupOptions, + MessageRequest, UpdateResult, ZoneType, }, - proto::rr::{rdata, rdata::SOA, DNSClass, LowerName, Name, RData, Record, RecordType}, - resolver::config::{NameServerConfigGroup, ResolverOpts}, + proto::rr::{ + rdata::{self, SOA}, + DNSClass, LowerName, Name, RData, Record, RecordType, + }, + resolver::config::{NameServerConfigGroup, ResolveHosts, ResolverOpts}, server::{Request, RequestInfo, ResponseHandler, ResponseInfo}, store::{forwarder::ForwardConfig, in_memory::InMemoryAuthority}, }; @@ -14,6 +17,7 @@ use std::{ convert::TryInto, net::IpAddr, str::FromStr, + sync::Arc, }; use telio_model::features::TtlValue; use telio_utils::telio_log_warn; @@ -58,33 +62,26 @@ impl AuthoritativeZone { default } }; + let rdata = RData::SOA(SOA::new( + Name::parse("mesh.nordsec.com.", None)?, + Name::parse("support.nordsec.com.", None)?, + 2015082403, + 7200, + ttl_value_signed, + 1209600, + ttl_value.0, + )); zone.upsert( - Record::new() - .set_name(zone_name) - .set_ttl(ttl_value.0) - .set_rr_type(RecordType::SOA) + Record::from_rdata(zone_name, ttl_value.0, rdata) .set_dns_class(DNSClass::IN) - .set_data(Some(RData::SOA(SOA::new( - Name::parse("mesh.nordsec.com.", None)?, - Name::parse("support.nordsec.com.", None)?, - 2015082403, - 7200, - ttl_value_signed, - 1209600, - ttl_value.0, - )))) .clone(), 0, ) .await; - let build_record = |name: Name, ty: RecordType, data: RData| -> Record { - Record::new() - .set_name(name) - .set_ttl(ttl_value.0) - .set_rr_type(ty) + let build_record = |name: Name, data: RData| -> Record { + Record::from_rdata(name, ttl_value.0, data) .set_dns_class(DNSClass::IN) - .set_data(Some(data)) .clone() }; @@ -94,20 +91,13 @@ impl AuthoritativeZone { match *ip { IpAddr::V4(ipv4) => { let _ = zone - .upsert( - build_record(name.clone(), RecordType::A, RData::A(rdata::A(ipv4))), - 0, - ) + .upsert(build_record(name.clone(), RData::A(rdata::A(ipv4))), 0) .await; } IpAddr::V6(ipv6) => { let _ = zone .upsert( - build_record( - name.clone(), - RecordType::AAAA, - RData::AAAA(rdata::AAAA(ipv6)), - ), + build_record(name.clone(), RData::AAAA(rdata::AAAA(ipv6))), 0, ) .await; @@ -125,19 +115,19 @@ impl Authority for AuthoritativeZone { type Lookup = ::Lookup; fn zone_type(&self) -> ZoneType { - self.zone.zone_type() + Authority::zone_type(&self.zone) } fn is_axfr_allowed(&self) -> bool { - self.zone.is_axfr_allowed() + Authority::is_axfr_allowed(&self.zone) } async fn update(&self, update: &MessageRequest) -> UpdateResult { - self.zone.update(update).await + Authority::update(&self.zone, update).await } fn origin(&self) -> &LowerName { - self.zone.origin() + Authority::origin(&self.zone) } async fn lookup( @@ -145,24 +135,24 @@ impl Authority for AuthoritativeZone { name: &LowerName, rtype: RecordType, lookup_options: LookupOptions, - ) -> Result { - self.zone.lookup(name, rtype, lookup_options).await + ) -> LookupControlFlow { + Authority::lookup(&self.zone, name, rtype, lookup_options).await } async fn search( &self, request_info: RequestInfo<'_>, lookup_options: LookupOptions, - ) -> Result { - self.zone.search(request_info, lookup_options).await + ) -> LookupControlFlow { + Authority::search(&self.zone, request_info, lookup_options).await } async fn get_nsec_records( &self, name: &LowerName, lookup_options: LookupOptions, - ) -> Result { - self.zone.get_nsec_records(name, lookup_options).await + ) -> LookupControlFlow { + Authority::get_nsec_records(&self.zone, name, lookup_options).await } } @@ -179,7 +169,7 @@ impl ForwardZone { // Some tools and browsers do not accept responses without intermediates preserved options.preserve_intermediates = true; // We provide our own forward servers, so we don't need to look at the hosts file - options.use_hosts_file = false; + options.use_hosts_file = ResolveHosts::Never; options.num_concurrent_reqs = 1; @@ -188,7 +178,7 @@ impl ForwardZone { let zone = ForwardAuthority::try_from_config( Name::from_str(name)?, - ZoneType::Forward, + ZoneType::External, ForwardConfig { options: Some(options), name_servers: NameServerConfigGroup::from_ips_clear(ips, 53, true), @@ -204,19 +194,19 @@ impl Authority for ForwardZone { type Lookup = ::Lookup; fn zone_type(&self) -> ZoneType { - self.zone.zone_type() + Authority::zone_type(&self.zone) } fn is_axfr_allowed(&self) -> bool { - self.zone.is_axfr_allowed() + Authority::is_axfr_allowed(&self.zone) } async fn update(&self, update: &MessageRequest) -> UpdateResult { - self.zone.update(update).await + Authority::update(&self.zone, update).await } fn origin(&self) -> &LowerName { - self.zone.origin() + Authority::origin(&self.zone) } async fn lookup( @@ -224,24 +214,24 @@ impl Authority for ForwardZone { name: &LowerName, rtype: RecordType, lookup_options: LookupOptions, - ) -> Result { - self.zone.lookup(name, rtype, lookup_options).await + ) -> LookupControlFlow { + Authority::lookup(&self.zone, name, rtype, lookup_options).await } async fn search( &self, request_info: RequestInfo<'_>, lookup_options: LookupOptions, - ) -> Result { - self.zone.search(request_info, lookup_options).await + ) -> LookupControlFlow { + Authority::search(&self.zone, request_info, lookup_options).await } async fn get_nsec_records( &self, name: &LowerName, lookup_options: LookupOptions, - ) -> Result { - self.zone.get_nsec_records(name, lookup_options).await + ) -> LookupControlFlow { + Authority::get_nsec_records(&self.zone, name, lookup_options).await } } @@ -256,8 +246,8 @@ impl ClonableZones { Self::default() } - pub fn upsert(&mut self, name: LowerName, authority: Box) { - self.zones.upsert(name.clone(), authority); + pub fn upsert(&mut self, name: LowerName, authorities: Vec>) { + self.zones.upsert(name.clone(), authorities); self.names.insert(name); } @@ -283,7 +273,7 @@ impl Clone for ClonableZones { .iter() .flat_map(|name| self.zones.find(name).map(|auth| (name, auth))) .fold(Zones::new(), |mut zone, (name, auth)| { - zone.upsert(name.clone(), auth.box_clone()); + zone.upsert(name.clone(), auth.clone()); zone }), names: self.names.clone(), @@ -302,13 +292,13 @@ mod tests { expected_ipv4: Option, expected_ipv6: Option, ) { - let lookup = zone - .lookup( - &Name::from_str(name).unwrap().into(), - RecordType::A, - Default::default(), - ) - .await; + let lookup = Authority::lookup( + zone, + &Name::from_str(name).unwrap().into(), + RecordType::A, + Default::default(), + ) + .await; if let Some(expected_ipv4) = expected_ipv4 { let lookup = lookup.unwrap(); @@ -316,18 +306,21 @@ mod tests { assert_eq!(records.len(), 1); let record = records[0]; assert_eq!(record.name(), &Name::from_str(name).unwrap()); - assert_eq!(record.data(), Some(&RData::A(rdata::A(expected_ipv4)))); + assert_eq!(record.data(), &RData::A(rdata::A(expected_ipv4))); } else { - assert!(matches!(lookup, Err(LookupError::NameExists))); + assert!(matches!( + lookup, + LookupControlFlow::Continue(Err(LookupError::NameExists)) + )); } - let lookup = zone - .lookup( - &Name::from_str(name).unwrap().into(), - RecordType::AAAA, - Default::default(), - ) - .await; + let lookup = Authority::lookup( + zone, + &Name::from_str(name).unwrap().into(), + RecordType::AAAA, + Default::default(), + ) + .await; if let Some(expected_ipv6) = expected_ipv6 { let lookup = lookup.unwrap(); @@ -335,12 +328,12 @@ mod tests { assert_eq!(records.len(), 1); let record = records[0]; assert_eq!(record.name(), &Name::from_str(name).unwrap()); - assert_eq!( - record.data(), - Some(&RData::AAAA(rdata::AAAA(expected_ipv6))) - ); + assert_eq!(record.data(), &RData::AAAA(rdata::AAAA(expected_ipv6))); } else { - assert!(matches!(lookup, Err(LookupError::NameExists))); + assert!(matches!( + lookup, + LookupControlFlow::Continue(Err(LookupError::NameExists)) + )); } } diff --git a/src/device.rs b/src/device.rs index 68133b72d..7a2cdce99 100644 --- a/src/device.rs +++ b/src/device.rs @@ -946,7 +946,7 @@ impl RequestedState { .filter_map(|v| { v.ip_addresses .as_ref() - .map(|ips| (v.hostname.0.to_owned().to_string(), ips.clone())) + .map(|ips| (format!("{}.", v.hostname.0), ips.clone())) }) .collect() } @@ -972,7 +972,7 @@ impl RequestedState { }) .filter(|(nick, _)| validate_nickname(nick)) .fold(Records::new(), |mut records, (mut nick, ip)| { - nick.0 += ".nord"; + nick.0 += ".nord."; if let Entry::Vacant(e) = records.entry(nick.0.to_owned()) { e.insert(ip); @@ -1621,7 +1621,7 @@ impl Runtime { .collect(); peers.extend(wildcarded_peers); - dns.upsert("nord", &peers, self.features.dns.ttl_value) + dns.upsert("nord.", &peers, self.features.dns.ttl_value) .await .map_err(Error::DnsResolverError)?; } @@ -2839,11 +2839,11 @@ mod tests { let records = requested_state.collect_dns_records(); - assert!(records["alpha.nord"].contains(&IpAddr::V4(alpha_ipv4))); - assert!(records["alpha.nord"].contains(&IpAddr::V6(alpha_ipv6))); + assert!(records["alpha.nord."].contains(&IpAddr::V4(alpha_ipv4))); + assert!(records["alpha.nord."].contains(&IpAddr::V6(alpha_ipv6))); - assert_eq!(records["beta.nord"].clone(), vec![IpAddr::V4(beta_ipv4)]); - assert_eq!(records["gamma.nord"].clone(), vec![IpAddr::V6(gamma_ipv6)]); + assert_eq!(records["beta.nord."].clone(), vec![IpAddr::V4(beta_ipv4)]); + assert_eq!(records["gamma.nord."].clone(), vec![IpAddr::V6(gamma_ipv6)]); assert_eq!(records.len(), 3); } @@ -2882,20 +2882,20 @@ mod tests { let mut records = requested_state.collect_dns_nickname_records(); records.extend(requested_state.collect_dns_records()); - assert!(records["alpha.nord"].contains(&IpAddr::V4(alpha_ipv4))); - assert!(records["alpha.nord"].contains(&IpAddr::V6(alpha_ipv6))); - assert!(records["johnnyrotten.nord"].contains(&IpAddr::V4(alpha_ipv4))); - assert!(records["johnnyrotten.nord"].contains(&IpAddr::V6(alpha_ipv6))); + assert!(records["alpha.nord."].contains(&IpAddr::V4(alpha_ipv4))); + assert!(records["alpha.nord."].contains(&IpAddr::V6(alpha_ipv6))); + assert!(records["johnnyrotten.nord."].contains(&IpAddr::V4(alpha_ipv4))); + assert!(records["johnnyrotten.nord."].contains(&IpAddr::V6(alpha_ipv6))); - assert_eq!(records["beta.nord"].clone(), vec![IpAddr::V4(beta_ipv4)]); + assert_eq!(records["beta.nord."].clone(), vec![IpAddr::V4(beta_ipv4)]); assert_eq!( - records["bond-jamesbond.nord"].clone(), + records["bond-jamesbond.nord."].clone(), vec![IpAddr::V4(beta_ipv4)] ); - assert_eq!(records["gaMMa.nord"].clone(), vec![IpAddr::V6(gamma_ipv6)]); + assert_eq!(records["gaMMa.nord."].clone(), vec![IpAddr::V6(gamma_ipv6)]); - assert!(!records.contains_key("theta.nord")); + assert!(!records.contains_key("theta.nord.")); assert_eq!(records.len(), 5); } @@ -2962,9 +2962,9 @@ mod tests { let mut records = requested_state.collect_dns_nickname_records(); records.extend(requested_state.collect_dns_records()); - assert!(records[valid_hostname].contains(&valid_ipv4.clone().unwrap()[0])); + assert!(records[&format!("{valid_hostname}.")].contains(&valid_ipv4.clone().unwrap()[0])); assert!( - records[format!("{}.nord", valid_nickname.clone().unwrap()).as_str()] + records[format!("{}.nord.", valid_nickname.clone().unwrap()).as_str()] .contains(&valid_ipv4.clone().unwrap()[0]) ); @@ -3003,13 +3003,13 @@ mod tests { let mut records = requested_state.collect_dns_nickname_records(); records.extend(requested_state.collect_dns_records()); - assert_eq!(records["alpha.nord"].clone(), vec![IpAddr::V4(alpha_ipv4)]); + assert_eq!(records["alpha.nord."].clone(), vec![IpAddr::V4(alpha_ipv4)]); assert_eq!( - records["johnnyrotten.nord"].clone(), + records["johnnyrotten.nord."].clone(), vec![IpAddr::V4(alpha_ipv4)] ); - assert_eq!(records["beta.nord"].clone(), vec![IpAddr::V4(beta_ipv4)]); - assert_eq!(records["gamma.nord"].clone(), vec![IpAddr::V4(gamma_ipv4)]); + assert_eq!(records["beta.nord."].clone(), vec![IpAddr::V4(beta_ipv4)]); + assert_eq!(records["gamma.nord."].clone(), vec![IpAddr::V4(gamma_ipv4)]); assert_eq!(records.len(), 4); }