From 5012f15040eb0d9316613bd53616ff9520fe8ac4 Mon Sep 17 00:00:00 2001 From: nate Date: Sun, 25 Jan 2026 09:54:39 -0800 Subject: [PATCH 1/8] Small fix to ddns update and unit test to verify. --- libs/ddns/src/update.rs | 59 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/libs/ddns/src/update.rs b/libs/ddns/src/update.rs index 2939b3d..7b67fba 100644 --- a/libs/ddns/src/update.rs +++ b/libs/ddns/src/update.rs @@ -125,7 +125,7 @@ pub fn update( let mut prerequisite = Record::update0(name.clone(), 0, RecordType::ANY); prerequisite.set_dns_class(DNSClass::NONE); - message.add_update(prerequisite); + message.add_pre_requisite(prerequisite); let a_record = Record::from_rdata(name.clone(), ttl, A(leased).into_rdata()); let dhcid_record = Record::from_rdata( @@ -297,7 +297,12 @@ pub enum UpdateError { #[cfg(test)] mod test { use std::net::Ipv6Addr; - + use dora_core::hickory_proto::op::MessageType::Query; + use dora_core::hickory_proto::op::{OpCode, UpdateMessage}; + use dora_core::hickory_proto::rr::DNSClass::IN; + use dora_core::hickory_proto::rr::{RData, Record}; + use dora_core::hickory_proto::rr::rdata::NULL; + use crate::dhcid::IdType; use super::*; #[test] fn test_rev_ip() { @@ -317,4 +322,52 @@ mod test { "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.f.2.1.b.0.a.0.8.b.d.0.1.0.0.2.ip6.arpa." ) } -} + + #[test] + fn test_update_message() { + // Message captured from a running Kea/Bind9 DDNS update (for reference). + //let from_kea = BASE64_STANDARD.decode("wbYoAAABAAEAAgABA2xhYgAABgABCG91dHJpZGVywAwA/wD+AAAAAAAAwBUAAQABAAAEsAAECkVFNMAVADEAAQAABLAAIwABAasTowCr6hY874Nyfq0krHOxnvk5GwMgYIi6N1UY6lTRCGtlYS1iaW5kAAD6AP8AAAAAAD0LaG1hYy1zaGEyNTYAAABpbnyOASwAIB0XNv7B7IFpFMfsWXNH4jrSjqApS61geEUuVlin/bPBMsUAAAAA").unwrap(); + //let message = Message::from_vec(from_kea.as_slice()); + //println!("{:#?}", message); + let zone_origin = Name::from_ascii("lab.").unwrap(); + let name = Name::from_ascii("outrider").unwrap(); + + let dhcid = DhcId::new(IdType::ClientId, hex::decode("010708090a0b0c").unwrap()); + let address = Ipv4Addr::new(10,10,10,10); + + // Assert the shape and values of most of the request packet. + // TSIG is applied by Hickory if needed right before the packet is sent. + let update = update(zone_origin.clone(), name.clone(), dhcid.clone(), address, 1800, false).unwrap(); + assert_eq!(update.message_type(), Query); + assert_eq!(update.op_code(), OpCode::Update); + let queries = update.queries(); + assert_eq!(queries.len(), 1); + assert_eq!(queries[0].name(), &zone_origin); + let prerequisites = update.prerequisites(); + assert_eq!(prerequisites.len(), 1); + let answer_record = prerequisites[0].clone(); + assert_eq!(answer_record.name(), &name); + let name_servers = update.name_servers(); + assert_eq!(name_servers.len(), 2); + let name_server_1 = name_servers[0].clone(); + assert_eq!(name_server_1.name(), &name); + assert_eq!(name_server_1.dns_class(), IN); + assert_eq!(name_server_1.ttl(), 1800); + let name_server_1_rdata : Record = name_server_1.into_record_of_rdata(); + let should_be : Record = Record::from_rdata(name.clone(), 1800, A::new(10,10,10,10).into_rdata()); + assert_eq!(name_server_1_rdata, should_be); + let name_server_2 = name_servers[1].clone(); + assert_eq!(name_server_2.name(), &name); + assert_eq!(name_server_2.dns_class(), IN); + assert_eq!(name_server_2.ttl(), 1800); + let name_server_2_rdata : Record = name_server_2.into_record_of_rdata(); + let should_be_2 = Record::from_rdata( + name.clone(),1800, + RData::Unknown { + code: Unknown(49), + rdata: NULL::with(dhcid.clone().rdata(&name).unwrap()), + }); + assert_eq!(name_server_2_rdata, should_be_2); + } + +} \ No newline at end of file From 02b259001a68840f33ad0f2a6293f6de6f726737 Mon Sep 17 00:00:00 2001 From: nate Date: Sun, 25 Jan 2026 10:49:04 -0800 Subject: [PATCH 2/8] rustfmt --- libs/ddns/src/update.rs | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/libs/ddns/src/update.rs b/libs/ddns/src/update.rs index 7b67fba..e504c87 100644 --- a/libs/ddns/src/update.rs +++ b/libs/ddns/src/update.rs @@ -296,14 +296,14 @@ pub enum UpdateError { #[cfg(test)] mod test { - use std::net::Ipv6Addr; + use super::*; + use crate::dhcid::IdType; use dora_core::hickory_proto::op::MessageType::Query; use dora_core::hickory_proto::op::{OpCode, UpdateMessage}; use dora_core::hickory_proto::rr::DNSClass::IN; - use dora_core::hickory_proto::rr::{RData, Record}; use dora_core::hickory_proto::rr::rdata::NULL; - use crate::dhcid::IdType; - use super::*; + use dora_core::hickory_proto::rr::{RData, Record}; + use std::net::Ipv6Addr; #[test] fn test_rev_ip() { assert_eq!( @@ -333,11 +333,19 @@ mod test { let name = Name::from_ascii("outrider").unwrap(); let dhcid = DhcId::new(IdType::ClientId, hex::decode("010708090a0b0c").unwrap()); - let address = Ipv4Addr::new(10,10,10,10); + let address = Ipv4Addr::new(10, 10, 10, 10); // Assert the shape and values of most of the request packet. // TSIG is applied by Hickory if needed right before the packet is sent. - let update = update(zone_origin.clone(), name.clone(), dhcid.clone(), address, 1800, false).unwrap(); + let update = update( + zone_origin.clone(), + name.clone(), + dhcid.clone(), + address, + 1800, + false, + ) + .unwrap(); assert_eq!(update.message_type(), Query); assert_eq!(update.op_code(), OpCode::Update); let queries = update.queries(); @@ -353,21 +361,23 @@ mod test { assert_eq!(name_server_1.name(), &name); assert_eq!(name_server_1.dns_class(), IN); assert_eq!(name_server_1.ttl(), 1800); - let name_server_1_rdata : Record = name_server_1.into_record_of_rdata(); - let should_be : Record = Record::from_rdata(name.clone(), 1800, A::new(10,10,10,10).into_rdata()); + let name_server_1_rdata: Record = name_server_1.into_record_of_rdata(); + let should_be: Record = + Record::from_rdata(name.clone(), 1800, A::new(10, 10, 10, 10).into_rdata()); assert_eq!(name_server_1_rdata, should_be); let name_server_2 = name_servers[1].clone(); assert_eq!(name_server_2.name(), &name); assert_eq!(name_server_2.dns_class(), IN); assert_eq!(name_server_2.ttl(), 1800); - let name_server_2_rdata : Record = name_server_2.into_record_of_rdata(); + let name_server_2_rdata: Record = name_server_2.into_record_of_rdata(); let should_be_2 = Record::from_rdata( - name.clone(),1800, + name.clone(), + 1800, RData::Unknown { - code: Unknown(49), - rdata: NULL::with(dhcid.clone().rdata(&name).unwrap()), - }); + code: Unknown(49), + rdata: NULL::with(dhcid.clone().rdata(&name).unwrap()), + }, + ); assert_eq!(name_server_2_rdata, should_be_2); } - -} \ No newline at end of file +} From c4f2e8752cf41eda702ca6c16420d8c02fb4f646 Mon Sep 17 00:00:00 2001 From: Nate Putnam Date: Sun, 25 Jan 2026 16:49:15 -0800 Subject: [PATCH 3/8] Update libs/ddns/src/update.rs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- libs/ddns/src/update.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ddns/src/update.rs b/libs/ddns/src/update.rs index e504c87..98719ef 100644 --- a/libs/ddns/src/update.rs +++ b/libs/ddns/src/update.rs @@ -298,12 +298,12 @@ pub enum UpdateError { mod test { use super::*; use crate::dhcid::IdType; + use std::net::Ipv6Addr; use dora_core::hickory_proto::op::MessageType::Query; use dora_core::hickory_proto::op::{OpCode, UpdateMessage}; use dora_core::hickory_proto::rr::DNSClass::IN; use dora_core::hickory_proto::rr::rdata::NULL; use dora_core::hickory_proto::rr::{RData, Record}; - use std::net::Ipv6Addr; #[test] fn test_rev_ip() { assert_eq!( From 7771c29d8d629e452e21d85867c0704aaf1886d2 Mon Sep 17 00:00:00 2001 From: Evan Cameron Date: Sun, 25 Jan 2026 20:06:52 -0500 Subject: [PATCH 4/8] Update libs/ddns/src/update.rs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- libs/ddns/src/update.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ddns/src/update.rs b/libs/ddns/src/update.rs index 98719ef..143d709 100644 --- a/libs/ddns/src/update.rs +++ b/libs/ddns/src/update.rs @@ -375,7 +375,7 @@ mod test { 1800, RData::Unknown { code: Unknown(49), - rdata: NULL::with(dhcid.clone().rdata(&name).unwrap()), + rdata: NULL::with(dhcid.rdata(&name).unwrap()), }, ); assert_eq!(name_server_2_rdata, should_be_2); From ea6eea991468ba29af0b2cb701c07c000485e835 Mon Sep 17 00:00:00 2001 From: Evan Cameron Date: Sun, 25 Jan 2026 20:43:05 -0500 Subject: [PATCH 5/8] update_present should use add_pre_requisite --- libs/ddns/src/update.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ddns/src/update.rs b/libs/ddns/src/update.rs index 143d709..2c3e523 100644 --- a/libs/ddns/src/update.rs +++ b/libs/ddns/src/update.rs @@ -161,7 +161,7 @@ pub fn update_present( let mut prerequisite = Record::update0(name.clone(), 0, RecordType::ANY); // use ANY to check only update if this name is present prerequisite.set_dns_class(DNSClass::ANY); - message.add_update(prerequisite); + message.add_pre_requisite(prerequisite); // add dhcid to prereqs, will only update if dhcid is present let dhcid_record = Record::from_rdata( From 49cc18d38ed7b77bb50aba7a858f27b4afc8a4d4 Mon Sep 17 00:00:00 2001 From: Evan Cameron Date: Sun, 25 Jan 2026 20:44:56 -0500 Subject: [PATCH 6/8] Reorder imports in update.rs test module --- libs/ddns/src/update.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libs/ddns/src/update.rs b/libs/ddns/src/update.rs index 2c3e523..d69e7fb 100644 --- a/libs/ddns/src/update.rs +++ b/libs/ddns/src/update.rs @@ -297,13 +297,16 @@ pub enum UpdateError { #[cfg(test)] mod test { use super::*; - use crate::dhcid::IdType; + use std::net::Ipv6Addr; + + use crate::dhcid::IdType; use dora_core::hickory_proto::op::MessageType::Query; use dora_core::hickory_proto::op::{OpCode, UpdateMessage}; use dora_core::hickory_proto::rr::DNSClass::IN; use dora_core::hickory_proto::rr::rdata::NULL; use dora_core::hickory_proto::rr::{RData, Record}; + #[test] fn test_rev_ip() { assert_eq!( From 4970521a7c97e0ba9b7a3a762ffcef777cc911d7 Mon Sep 17 00:00:00 2001 From: Evan Cameron Date: Sun, 25 Jan 2026 20:47:44 -0500 Subject: [PATCH 7/8] Change update to prerequisite for dhcid_record --- libs/ddns/src/update.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libs/ddns/src/update.rs b/libs/ddns/src/update.rs index d69e7fb..cec2e80 100644 --- a/libs/ddns/src/update.rs +++ b/libs/ddns/src/update.rs @@ -172,7 +172,7 @@ pub fn update_present( rdata: NULL::with(duid.rdata(&name)?), }, ); - message.add_update(dhcid_record); + message.add_pre_requisite(dhcid_record); let a_record: Record = Record::from_rdata(name, ttl, A(leased).into_rdata()); message.add_update(a_record); @@ -297,15 +297,13 @@ pub enum UpdateError { #[cfg(test)] mod test { use super::*; - - use std::net::Ipv6Addr; - use crate::dhcid::IdType; use dora_core::hickory_proto::op::MessageType::Query; use dora_core::hickory_proto::op::{OpCode, UpdateMessage}; use dora_core::hickory_proto::rr::DNSClass::IN; use dora_core::hickory_proto::rr::rdata::NULL; use dora_core::hickory_proto::rr::{RData, Record}; + use std::net::Ipv6Addr; #[test] fn test_rev_ip() { From d54cecee6d51ae3c23151f2809796a35ae9f77aa Mon Sep 17 00:00:00 2001 From: Evan Cameron Date: Sun, 25 Jan 2026 20:50:55 -0500 Subject: [PATCH 8/8] cargo fmt --- libs/ddns/src/update.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/ddns/src/update.rs b/libs/ddns/src/update.rs index cec2e80..0d6d503 100644 --- a/libs/ddns/src/update.rs +++ b/libs/ddns/src/update.rs @@ -303,8 +303,8 @@ mod test { use dora_core::hickory_proto::rr::DNSClass::IN; use dora_core::hickory_proto::rr::rdata::NULL; use dora_core::hickory_proto::rr::{RData, Record}; - use std::net::Ipv6Addr; - + use std::net::Ipv6Addr; + #[test] fn test_rev_ip() { assert_eq!(