diff --git a/Cargo.lock b/Cargo.lock index 5a468f7..63b8f70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -253,6 +253,26 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "const_format" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c655d81ff1114fb0dcdea9225ea9f0cc712a6f8d189378e82bdf62a473a64b" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff1a44b93f47b1bac19a27932f5c591e43d1ba357ee4f61526c8a25603f0eb1" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -299,6 +319,7 @@ dependencies = [ "bytes", "chrono", "clap", + "const_format", "domain", "lazy_static", "lexopt", @@ -313,7 +334,7 @@ dependencies = [ [[package]] name = "domain" version = "0.10.3" -source = "git+https://github.com/NLnetLabs/domain?branch=sortedrecords-zonemd-remove-replace-plus-pr444#7aac5ed30141a9fb53c63a27a148104d2821d5ae" +source = "git+https://github.com/NLnetLabs/domain?branch=sortedrecords-zonemd-remove-replace-plus-pr444#93259567c56c88b4690a0bbfb07595cb1961af25" dependencies = [ "arc-swap", "bytes", @@ -1224,6 +1245,12 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "untrusted" version = "0.9.0" diff --git a/Cargo.toml b/Cargo.toml index 9cfc98c..3e59e06 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ lexopt = "0.3.0" octseq = "0.5.2" ring = "0.17.8" tokio = "1.40.0" +#tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } # This is a workaround. lazy_static 1.0.0 fails to compile, but sharded-slab # still uses it. And sharded-slab is used by tracing-subscriber, which is @@ -46,6 +47,7 @@ tokio = "1.40.0" _unused_lazy_static = { package = "lazy_static", version = "1.0.2" } [dev-dependencies] +const_format = " 0.2.33" test_bin = "0.4.0" tempfile = "3.14.0" regex = "1.11.1" diff --git a/test-data/Kjelte.nlnetlabs.nl.+008+19779.key b/test-data/Kjelte.nlnetlabs.nl.+008+19779.key new file mode 100644 index 0000000..7e120cf --- /dev/null +++ b/test-data/Kjelte.nlnetlabs.nl.+008+19779.key @@ -0,0 +1 @@ +jelte.nlnetlabs.nl. IN DNSKEY 256 3 8 AwEAAbmZNEjurnAH9aav6UEJsoMWoTx/gGRd92xGrrVPC/JzDxL3Ksw8MkReNZGke1ChRnbIQ2f04yj8K5G9OjK/fxBh3J32G7IXdQHWQReBf4oxT1ReQXnZZ3FkiCqgkq5fsAlhO7KQBVSKAVCF17Cso8HAoyQSU6dwKbG27472OhOygEf/knw4nKo+VQpnK90dhs4NikHCI1veo+qd5Q3bFxWIJTWc0LwcWOGYcKZVzkZPCANqFCKANPXGdcqH+bTeAeVHzvM9oaXvseL9TjY5LBg+CMDRSfQv8tpIBk/iBoagDKJ3R8LdUF6SjH3ICVIprbXep98FaB1ZStowgOKPbCc= diff --git a/test-data/Kjelte.nlnetlabs.nl.+008+19779.private b/test-data/Kjelte.nlnetlabs.nl.+008+19779.private new file mode 100644 index 0000000..e038d3d --- /dev/null +++ b/test-data/Kjelte.nlnetlabs.nl.+008+19779.private @@ -0,0 +1,10 @@ +Private-key-format: v1.2 +Algorithm: 8 (RSASHA256) +Modulus: uZk0SO6ucAf1pq/pQQmygxahPH+AZF33bEautU8L8nMPEvcqzDwyRF41kaR7UKFGdshDZ/TjKPwrkb06Mr9/EGHcnfYbshd1AdZBF4F/ijFPVF5BedlncWSIKqCSrl+wCWE7spAFVIoBUIXXsKyjwcCjJBJTp3ApsbbvjvY6E7KAR/+SfDicqj5VCmcr3R2Gzg2KQcIjW96j6p3lDdsXFYglNZzQvBxY4ZhwplXORk8IA2oUIoA09cZ1yof5tN4B5UfO8z2hpe+x4v1ONjksGD4IwNFJ9C/y2kgGT+IGhqAMondHwt1QXpKMfcgJUimttd6n3wVoHVlK2jCA4o9sJw== +PublicExponent: AQAB +PrivateExponent: Cr+NQEQCT3PxN/asAsY1qP3LLJ5oUxJWB9aNZkFDpzDJSLHjr/GJ1QfCVm2OGVHzALdW9VLrQi5dtOeefTM11T8K8GLroQQBagUnE94TWBoZnACGuNsW8IF/7pK0q+stXf2xiq+91J2BYfu+TU781Mr70lT1X0Gm8ycYTHvZ9StMZWEcsT1dOJ00axMXyDtwvAleoBbdPWgEp1Q8HWTEPL8ve6bEPUeINvhovuq+bqL1L0wFL7kwSOez6HTrUEv7WqYmC9eE0MIWAVRfLEQHkgTMnnc6yNP7soPLIhXp1+r8B6innOTx2ZRrza+PjZaf7aDfPsBAbNmxg6ru9OCyIQ== +Prime1: +TBbSkr5BDS88V+XI/metoiZca8Y+E4JfoLeNtVgTcFa72Fp/jNvUTi5/eKb9cjf5bYyZvUI6NefkwOLtWx1PnwH2s9d/LcdOM5OSTOlco/um+t7rM9opgp4w5ZpWd8JMA1YjSOod38ngM47B9myjTuDn/h/Xv/+PV35XUx4bO8= +Prime2: vqvjRtHS1UGslBQRzjImqDIQw1nbN6BuhrbJYtXOc23Bz/dNIsC4h9+B4R2D+Tkf6c4l4beJMaAnXuB4ngvAKKKpcgy+o4Utew3HOSEeamLq1bPBAHkV9S50oUEc2wcLYD+5vHN13WyNiEiSuRXW8LSUWbjH1Wrqp38+M6cFZEk= +Exponent1: DqhghlM4qJ2ti4ky68PQKS6J0B0bm+eDOXTbO2B7xLcd8TzKrlA6OQ3cKun8gI2rVejMuC+rsX6VfWFVA3v4vY8wKxfNkIL47hF8m2O1VLLQt003vieJIVM2XVLoqYesE66FSfASBc1t9m6rHEAa96HLkUpdu6nVO6jedTV9U/M= +Exponent2: nWoXVy5/W2S+7/mpwYwR8iZzRHR40XH4Dev2U0ylBxMEQYev/RMSxco21f2iKS2KNWLmT3VRJNFN77xumDynRmUUc34mHaYjqEX1xiqbi8Vij0+59YQCJstVqpOxGPq135583yKLmmS2bF9OEtP/AfZzy6cMBBwi4mnglpA7mVE= +Coefficient: vO61lIEOgDwn5xR/OOrxt3N0fbGPHNB+DcW5p58tgkyeVLKHk12Lzs2pSzJ2hLuw1u9FMkDb/2fahMJY0BHHi6AphEA+CVPDAwEBsnSeQvQlkaSrCyRoimVrxT8Cdie1DOncC3h3jzfvGkY5ppBMNks1FjErIJZCN+g70CiKQw== diff --git a/test-data/jelte.nlnetlabs.nl b/test-data/jelte.nlnetlabs.nl new file mode 100644 index 0000000..aaaf45e --- /dev/null +++ b/test-data/jelte.nlnetlabs.nl @@ -0,0 +1,34 @@ +; loosely based on jelte.nlnetlabs.nl. + +jelte.nlnetlabs.nl. 3600 IN SOA ns.jelte.nlnetlabs.nl. jelte.jelte.nlnetlabs.nl. 808 28800 7200 604800 3600 +jelte.nlnetlabs.nl. 3600 IN NS ns.jelte.nlnetlabs.nl. +jelte.nlnetlabs.nl. 3600 IN NS ext.ns.whyscream.net. +jelte.nlnetlabs.nl. 3600 IN NS ns-ext.nlnetlabs.nl. +jelte.nlnetlabs.nl. 3600 IN A 178.18.82.80 +jelte.nlnetlabs.nl. 60 IN MX 10 smtp.jelte.nlnetlabs.nl. +jelte.nlnetlabs.nl. 3600 IN AAAA 2a02:348:55:5250::80 +jelte.nlnetlabs.nl. 0 IN TYPE65534 \# 5 0846480001 +dnssec.jelte.nlnetlabs.nl. 3600 IN NS ns2.jelte.nlnetlabs.nl. +dnssec.jelte.nlnetlabs.nl. 3600 IN DS 8340 5 1 5733A59841EA708AE9223822124B07B555E17332 +dragon.jelte.nlnetlabs.nl. 1234 IN AAAA 2002:c3a9:dd9d:8:219:d1ff:fe81:5c10 +git.jelte.nlnetlabs.nl. 3600 IN AAAA 2a02:348:55:5250::80 +git.jelte.nlnetlabs.nl. 3600 IN A 178.18.82.80 +imap.jelte.nlnetlabs.nl. 3600 IN A 178.18.82.80 +nepmail.jelte.nlnetlabs.nl. 3600 IN MX 10 mirre.nlnetlabs.nl. +ns.jelte.nlnetlabs.nl. 3600 IN A 178.18.82.80 +ns.jelte.nlnetlabs.nl. 3600 IN AAAA 2a02:348:55:5250::53 +ns-ext.jelte.nlnetlabs.nl. 3600 IN A 178.18.82.80 +ns2.jelte.nlnetlabs.nl. 3600 IN A 195.169.221.157 +ns2.jelte.nlnetlabs.nl. 3600 IN AAAA 2002:c3a9:dd9d:1::1 +nsec3.jelte.nlnetlabs.nl. 3600 IN NS ns2.jelte.nlnetlabs.nl. +nsec3.jelte.nlnetlabs.nl. 3600 IN DS 21665 7 1 8D5E7DEDC1501A38009882DD1508246EB4A2251C +smtp.jelte.nlnetlabs.nl. 3600 IN A 178.18.82.80 +svn.jelte.nlnetlabs.nl. 3600 IN A 178.18.82.80 +talon.jelte.nlnetlabs.nl. 3600 IN A 195.169.221.157 +v6.jelte.nlnetlabs.nl. 3600 IN AAAA 2002:c3a9:dd9d:1::1 +vps.jelte.nlnetlabs.nl. 3600 IN A 178.18.82.80 +vpsv6.jelte.nlnetlabs.nl. 3600 IN AAAA 2a02:348:55:5250::1 +www.jelte.nlnetlabs.nl. 3600 IN A 178.18.82.80 +www.jelte.nlnetlabs.nl. 3600 IN AAAA 2a02:348:55:5250::80 +wwwv6.jelte.nlnetlabs.nl. 3600 IN AAAA 2a02:348:55:5250::80 + diff --git a/tests/common.rs b/tests/common.rs new file mode 100644 index 0000000..b044d3d --- /dev/null +++ b/tests/common.rs @@ -0,0 +1,62 @@ +use std::process::Command; + +pub fn assert_org_ldns_cmd_eq_new_ldns_cmd( + org_ldns_cmd: &[&str], + new_ldns_cmd: &[&str], + expect_stdout_content: bool, +) { + let org_ldns_cmd_out = Command::new(org_ldns_cmd[0]) + .args(&org_ldns_cmd[1..]) + .output() + .unwrap(); + + let new_ldns_cmd_out = test_bin::get_test_bin("ldns") + .args(new_ldns_cmd) + .output() + .unwrap(); + + assert_eq!( + std::str::from_utf8(&org_ldns_cmd_out.stderr), + Ok(""), + "Unexpected stderr content for original ldns command: {}", + org_ldns_cmd.join(" ") + ); + assert_eq!( + std::str::from_utf8(&new_ldns_cmd_out.stderr), + Ok(""), + "Unexpected stderr content for reimplemented ldns command: {}", + new_ldns_cmd.join(" ") + ); + if expect_stdout_content { + assert!( + !org_ldns_cmd_out.stdout.is_empty(), + "Expected stdout content for original ldns command: {}: {:?}", + org_ldns_cmd.join(" "), + std::str::from_utf8(&org_ldns_cmd_out.stdout) + ); + assert!( + !new_ldns_cmd_out.stdout.is_empty(), + "Expected stdout content for reimplemented ldns command: {}: {:?}", + new_ldns_cmd.join(" "), + std::str::from_utf8(&new_ldns_cmd_out.stdout) + ); + } + assert_eq!( + org_ldns_cmd_out.status.code(), + new_ldns_cmd_out.status.code(), + "Exit code mismatch for original ldns command: {}", + org_ldns_cmd.join(" ") + ); + + // This will only work for LDNS commands whose output we are able to + // replicate exactly. + assert_eq!( + std::str::from_utf8(&org_ldns_cmd_out.stdout), + std::str::from_utf8(&new_ldns_cmd_out.stdout), + "Stdout content mismatch for original ldns command: {}", + { + eprintln!("{}", std::str::from_utf8(&new_ldns_cmd_out.stdout).unwrap()); + org_ldns_cmd.join(" ") + } + ); +} diff --git a/tests/vs-ldns.rs b/tests/nsec3hash.rs similarity index 51% rename from tests/vs-ldns.rs rename to tests/nsec3hash.rs index f34b41e..9dbc52e 100644 --- a/tests/vs-ldns.rs +++ b/tests/nsec3hash.rs @@ -1,23 +1,27 @@ -use std::process::Command; +mod common; + +use common::assert_org_ldns_cmd_eq_new_ldns_cmd; -const TEST_ZONE_NAME: &str = "nlnetlabs.nl"; const LDNS_NSEC3_CMD: &str = "ldns-nsec3-hash"; const DNST_NSEC3_SUBCMD: &str = "nsec3-hash"; +const TEST_ZONE_NAME: &str = "nlnetlabs.nl"; #[ignore = "should only be run if ldns command line tools are installed"] #[test] fn nsec3_hash() { // Note: ldns-nsec3-hash defaults NSEC3 iterations to 1, while dnst // nsec-hash defaults NSEC3 iterations to 0. - assert_cmds_eq( + assert_org_ldns_cmd_eq_new_ldns_cmd( &[LDNS_NSEC3_CMD, TEST_ZONE_NAME], &[DNST_NSEC3_SUBCMD, "--iterations", "1", TEST_ZONE_NAME], + true, ); - assert_cmds_eq( + assert_org_ldns_cmd_eq_new_ldns_cmd( &[LDNS_NSEC3_CMD, TEST_ZONE_NAME, "-t", "0"], &[DNST_NSEC3_SUBCMD, TEST_ZONE_NAME], + true, ); - assert_cmds_eq( + assert_org_ldns_cmd_eq_new_ldns_cmd( &[LDNS_NSEC3_CMD, "-a", "1", TEST_ZONE_NAME], &[ DNST_NSEC3_SUBCMD, @@ -27,8 +31,9 @@ fn nsec3_hash() { "1", TEST_ZONE_NAME, ], + true, ); - assert_cmds_eq( + assert_org_ldns_cmd_eq_new_ldns_cmd( &[LDNS_NSEC3_CMD, "-s", "", TEST_ZONE_NAME], &[ DNST_NSEC3_SUBCMD, @@ -38,8 +43,9 @@ fn nsec3_hash() { "", TEST_ZONE_NAME, ], + true, ); - assert_cmds_eq( + assert_org_ldns_cmd_eq_new_ldns_cmd( &[LDNS_NSEC3_CMD, "-s", "DEADBEEF", TEST_ZONE_NAME], &[ DNST_NSEC3_SUBCMD, @@ -49,10 +55,11 @@ fn nsec3_hash() { "DEADBEEF", TEST_ZONE_NAME, ], + true, ); for iterations in 0..10 { - assert_cmds_eq( + assert_org_ldns_cmd_eq_new_ldns_cmd( &[ LDNS_NSEC3_CMD, "-t", @@ -65,52 +72,7 @@ fn nsec3_hash() { &iterations.to_string(), TEST_ZONE_NAME, ], + true, ); } } - -fn assert_cmds_eq(cmd1: &[&str], cmd2: &[&str]) { - let cmd1_output = Command::new(cmd1[0]).args(&cmd1[1..]).output().unwrap(); - - let cmd2_output = test_bin::get_test_bin("dnst").args(cmd2).output().unwrap(); - - assert_eq!( - std::str::from_utf8(&cmd1_output.stderr), - Ok(""), - "Unexpected stderr content for command: {}", - cmd1.join(" ") - ); - assert_eq!( - std::str::from_utf8(&cmd2_output.stderr), - Ok(""), - "Unexpected stderr content for command: {}", - cmd2.join(" ") - ); - assert!( - !cmd1_output.stdout.is_empty(), - "Expected stdout content for command: {}: {:?}", - cmd1.join(" "), - std::str::from_utf8(&cmd1_output.stdout) - ); - assert!( - !cmd2_output.stdout.is_empty(), - "Expected stdout content for command: {}: {:?}", - cmd2.join(" "), - std::str::from_utf8(&cmd2_output.stdout) - ); - assert_eq!( - cmd1_output.status.code(), - cmd2_output.status.code(), - "Exit code mismatch for command: {}", - cmd1.join(" ") - ); - - // This will only work for LDNS commands whose output we are able to - // replicate exactly. - assert_eq!( - std::str::from_utf8(&cmd1_output.stdout), - std::str::from_utf8(&cmd2_output.stdout), - "Stdout content mismatch for command: {}", - cmd1.join(" ") - ); -} diff --git a/tests/signzone.rs b/tests/signzone.rs new file mode 100644 index 0000000..8ac72ba --- /dev/null +++ b/tests/signzone.rs @@ -0,0 +1,60 @@ +// Based on: https://github.com/NLnetLabs/ldns/tree/1.8.4/test/20-sign-zone.tpkg +// But uses a newer algorithm as algorithm 5 is not supported by DNST. + +mod common; + +use common::assert_org_ldns_cmd_eq_new_ldns_cmd; +use const_format::concatcp; +use std::process::Command; +use tempfile::tempdir; + +const LDNS_CMD: &str = "ldns-signzone"; +const TEST_DATA_DIR: &str = "test-data/"; +const TEST_ZONE_PATH: &str = concatcp!(TEST_DATA_DIR, "jelte.nlnetlabs.nl"); +const KEY_FILE_BASE_PATH: &str = concatcp!(TEST_DATA_DIR, "Kjelte.nlnetlabs.nl.+008+19779"); + +#[ignore = "should only be run if ldns command line tools are installed"] +#[test] +fn signzone() { + let temp_dir = tempdir().unwrap().into_path(); + let ldns_out_path = format!("{}/ldns.signed", temp_dir.display()); + let dnst_out_path = format!("{}/dnst.signed", temp_dir.display()); + + assert_org_ldns_cmd_eq_new_ldns_cmd( + &[ + LDNS_CMD, + "-b", + "-f", + &ldns_out_path, + TEST_ZONE_PATH, + KEY_FILE_BASE_PATH, + ], + &[ + LDNS_CMD, + "-b", + "-f", + &dnst_out_path, + TEST_ZONE_PATH, + KEY_FILE_BASE_PATH, + ], + false, + ); + + let verify_output = Command::new("ldns-verify-zone") + .args(&[&dnst_out_path]) + .output() + .unwrap(); + + if !verify_output.status.success() { + eprintln!( + "ldns-verify-zone failed with exit code {:?} and stderr output:\n{}", + verify_output.status.code(), + std::str::from_utf8(&verify_output.stderr).unwrap() + ); + } + + assert!( + verify_output.status.success(), + "Expected zone verification to succeed" + ); +}