diff --git a/Cargo.lock b/Cargo.lock index ff35eeb86edca..556fb68cbd998 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "Inflector" @@ -4397,11 +4397,13 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hickory-proto" -version = "0.24.4" +version = "0.25.0-alpha.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92652067c9ce6f66ce53cc38d1169daa36e6e7eb7dd3b63b5103bd9d97117248" +checksum = "1d00147af6310f4392a31680db52a3ed45a2e0f68eb18e8c3fe5537ecc96d9e2" dependencies = [ + "async-recursion", "async-trait", + "bitflags 2.8.0", "cfg-if", "data-encoding", "enum-as-inner 0.6.0", @@ -4411,8 +4413,11 @@ dependencies = [ "idna 1.0.3", "ipnet", "once_cell", - "rand 0.8.5", - "thiserror 1.0.68", + "rand 0.9.0", + "ring", + "rustls-pki-types", + "thiserror 2.0.3", + "time", "tinyvec", "tracing 0.1.41", "url", @@ -4594,7 +4599,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.10", + "socket2 0.5.8", "tokio", "tower-service", "tracing 0.1.41", @@ -6237,7 +6242,7 @@ dependencies = [ [[package]] name = "nix" version = "0.26.2" -source = "git+https://github.com/vectordotdev/nix.git?branch=memfd/gnu/musl#6c53a918d2d5bf4307fd60a19d9e10913ae71eeb" +source = "git+https://github.com/vectordotdev/nix.git?branch=memfd%2Fgnu%2Fmusl#6c53a918d2d5bf4307fd60a19d9e10913ae71eeb" dependencies = [ "bitflags 1.3.2", "cfg-if", @@ -7642,7 +7647,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.13.0", "proc-macro2 1.0.93", "quote 1.0.38", "syn 2.0.98", diff --git a/Cargo.toml b/Cargo.toml index e40f5bb0baaad..6ad91c495c87e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -142,7 +142,7 @@ clap = { version = "4.5.30", default-features = false, features = ["derive", "er flate2 = { version = "1.0.35", default-features = false, features = ["default"] } futures = { version = "0.3.31", default-features = false, features = ["compat", "io-compat", "std"], package = "futures" } glob = { version = "0.3.2", default-features = false } -hickory-proto = { version = "0.24.4", default-features = false, features = ["dnssec"] } +hickory-proto = { version = "0.25.0-alpha.5", default-features = false, features = ["dnssec-ring"] } indexmap = { version = "2.7.1", default-features = false, features = ["serde", "std"] } inventory = { version = "0.3" } metrics = "0.24.1" @@ -377,8 +377,8 @@ tikv-jemallocator = { version = "0.6.0", default-features = false, features = [" tokio-postgres = { version = "0.7.13", default-features = false, features = ["runtime", "with-chrono-0_4"], optional = true } tokio-tungstenite = { version = "0.20.1", default-features = false, features = ["connect"], optional = true } toml.workspace = true -tonic = { workspace = true, optional = true } hickory-proto = { workspace = true, optional = true } +tonic = { workspace = true, optional = true } thread_local = { version = "1.1.8", default-features = false, optional = true } typetag = { version = "0.2.19", default-features = false } url = { version = "2.5.4", default-features = false, features = ["serde"] } diff --git a/lib/dnsmsg-parser/src/dns_message.rs b/lib/dnsmsg-parser/src/dns_message.rs index d22bff280631d..fd0cc8f613dcf 100644 --- a/lib/dnsmsg-parser/src/dns_message.rs +++ b/lib/dnsmsg-parser/src/dns_message.rs @@ -16,7 +16,6 @@ pub(super) const RTYPE_NSAP: u16 = 22; pub(super) const RTYPE_PX: u16 = 26; pub(super) const RTYPE_LOC: u16 = 29; pub(super) const RTYPE_KX: u16 = 36; -pub(super) const RTYPE_CERT: u16 = 37; pub(super) const RTYPE_A6: u16 = 38; pub(super) const RTYPE_SINK: u16 = 40; pub(super) const RTYPE_APL: u16 = 42; diff --git a/lib/dnsmsg-parser/src/dns_message_parser.rs b/lib/dnsmsg-parser/src/dns_message_parser.rs index efa54c372ebbc..f3d552acc1b05 100644 --- a/lib/dnsmsg-parser/src/dns_message_parser.rs +++ b/lib/dnsmsg-parser/src/dns_message_parser.rs @@ -2,14 +2,11 @@ use std::str::Utf8Error; use std::{fmt::Write as _, ops::Deref}; use data_encoding::{BASE32HEX_NOPAD, BASE64, HEXUPPER}; +use hickory_proto::dnssec::rdata::{DNSSECRData, DNSKEY, DS}; +use hickory_proto::dnssec::SupportedAlgorithms; use hickory_proto::{ - error::ProtoError, op::{message::Message as TrustDnsMessage, Query}, rr::{ - dnssec::{ - rdata::{DNSSECRData, DNSKEY, DS}, - Algorithm, SupportedAlgorithms, - }, rdata::{ caa::Value, opt::{EdnsCode, EdnsOption}, @@ -20,6 +17,7 @@ use hickory_proto::{ Name, RecordType, }, serialize::binary::{BinDecodable, BinDecoder}, + ProtoError, }; use snafu::Snafu; @@ -188,11 +186,9 @@ impl DnsMessageParser { pub(crate) fn parse_dns_record(&mut self, record: &Record) -> DnsParserResult { let record_data = match record.data() { - Some(RData::Unknown { code, rdata }) => { - self.format_unknown_rdata((*code).into(), rdata) - } - Some(rdata) => self.format_rdata(rdata), - None => Ok((Some(String::from("")), None)), // NULL record + RData::Unknown { code, rdata } => self.format_unknown_rdata((*code).into(), rdata), + RData::Update0(_) => Ok((Some(String::from("")), None)), // Previously none value + rdata => self.format_rdata(rdata), }?; Ok(DnsRecord { @@ -500,20 +496,6 @@ impl DnsMessageParser { Ok((Some(format!("{} {}", preference, exchanger)), None)) } - dns_message::RTYPE_CERT => { - let raw_rdata = rdata.anything(); - let mut decoder = BinDecoder::new(raw_rdata); - let cert_type = parse_u16(&mut decoder)?; - let key_tag = parse_u16(&mut decoder)?; - let algorithm = Algorithm::from_u8(parse_u8(&mut decoder)?).as_str(); - let crl_len = raw_rdata.len() as u16 - 5; - let crl = BASE64.encode(&parse_vec_with_u16_len(&mut decoder, crl_len)?); - Ok(( - Some(format!("{} {} {} {}", cert_type, key_tag, algorithm, crl)), - None, - )) - } - dns_message::RTYPE_A6 => self.parse_a6_rdata(rdata.anything()), dns_message::RTYPE_SINK => { @@ -562,6 +544,20 @@ impl DnsMessageParser { RData::AAAA(ip) => Ok((Some(ip.to_string()), None)), RData::ANAME(name) => Ok((Some(name.to_string_with_options(&self.options)), None)), RData::CNAME(name) => Ok((Some(name.to_string_with_options(&self.options)), None)), + RData::CERT(cert) => { + let crl = BASE64.encode(&cert.cert_data()); + Ok(( + Some(format!( + "{} {} {} {}", + u16::from(cert.cert_type()), + cert.key_tag(), + cert.algorithm(), + crl + )), + None, + )) + } + RData::CSYNC(csync) => { // Using CSYNC's formatter since not all data is exposed otherwise let csync_rdata = format!("{}", csync); @@ -798,8 +794,8 @@ impl DnsMessageParser { u8::from(sig.algorithm()), sig.num_labels(), sig.original_ttl(), - sig.sig_expiration(), // currently in epoch convert to human readable ? - sig.sig_inception(), // currently in epoch convert to human readable ? + sig.sig_expiration().get(), // currently in epoch convert to human readable ? + sig.sig_inception().get(), // currently in epoch convert to human readable ? sig.key_tag(), sig.signer_name().to_string_with_options(&self.options), BASE64.encode(sig.sig()) @@ -818,8 +814,8 @@ impl DnsMessageParser { u8::from(sig.algorithm()), sig.num_labels(), sig.original_ttl(), - sig.sig_expiration(), // currently in epoch convert to human readable ? - sig.sig_inception(), // currently in epoch convert to human readable ? + sig.sig_expiration().get(), // currently in epoch convert to human readable ? + sig.sig_inception().get(), // currently in epoch convert to human readable ? sig.key_tag(), sig.signer_name().to_string_with_options(&self.options), BASE64.encode(sig.sig()) @@ -968,7 +964,7 @@ fn parse_edns(dns_message: &TrustDnsMessage) -> Option DnsParserResult<(Vec, Vec = edns .as_ref() .iter() - .filter(|(&code, _)| u16::from(code) != EDE_OPTION_CODE) + .filter(|(code, _)| u16::from(*code) != EDE_OPTION_CODE) .map(|(code, option)| match option { EdnsOption::DAU(algorithms) | EdnsOption::DHU(algorithms) @@ -1270,26 +1266,13 @@ fn format_bytes_as_hex_string(bytes: &[u8]) -> String { #[cfg(test)] mod tests { use std::{ - collections::HashMap, net::{Ipv4Addr, Ipv6Addr}, str::FromStr, }; #[allow(deprecated)] + use hickory_proto::dnssec::rdata::key::UpdateScope; use hickory_proto::rr::{ - dnssec::{ - rdata::{ - dnskey::DNSKEY, - ds::DS, - key::{KeyTrust, KeyUsage, Protocol, UpdateScope}, - nsec::NSEC, - nsec3::NSEC3, - nsec3param::NSEC3PARAM, - sig::SIG, - DNSSECRData, KEY, RRSIG, - }, - Algorithm as DNSSEC_Algorithm, DigestType, Nsec3HashAlgorithm, - }, domain::Name, rdata::{ caa::KeyValue, @@ -1299,7 +1282,20 @@ mod tests { CAA, CSYNC, HINFO, HTTPS, NAPTR, OPT, SSHFP, TLSA, TXT, }, }; - use hickory_proto::serialize::binary::Restrict; + use hickory_proto::{ + dnssec::{ + rdata::{ + key::{KeyTrust, KeyUsage, Protocol}, + KEY, NSEC, NSEC3, NSEC3PARAM, RRSIG, SIG, + }, + Algorithm as DNSSEC_Algorithm, DigestType, Nsec3HashAlgorithm, + }, + rr::rdata::{ + cert::{Algorithm as CertAlgorithm, CertType}, + CERT, + }, + serialize::binary::Restrict, + }; use super::*; @@ -1384,6 +1380,29 @@ mod tests { ); } + #[test] + fn test_parse_as_query_message_with_multiple_ede() { + let raw_dns_message = + "szgAAAABAAAAAAABAmg1B2V4YW1wbGUDY29tAAAGAAEAACkAAAEBQAAADAAPAAIAFQAPAAIAFA=="; + let raw_query_message = BASE64 + .decode(raw_dns_message.as_bytes()) + .expect("Invalid base64 encoded data."); + let parse_result = DnsMessageParser::new(raw_query_message).parse_as_query_message(); + assert!(parse_result.is_ok()); + let message = parse_result.expect("Message is not parsed."); + let opt_pseudo_section = message.opt_pseudo_section.expect("OPT section was missing"); + assert_eq!(opt_pseudo_section.ede.len(), 2); + assert_eq!(opt_pseudo_section.ede[0].info_code(), 21u16); + assert_eq!(opt_pseudo_section.ede[0].purpose(), Some("Not Supported")); + assert_eq!(opt_pseudo_section.ede[0].extra_text(), None); + assert_eq!(opt_pseudo_section.ede[1].info_code(), 20u16); + assert_eq!( + opt_pseudo_section.ede[1].purpose(), + Some("Not Authoritative") + ); + assert_eq!(opt_pseudo_section.ede[1].extra_text(), None); + } + #[test] fn test_parse_as_query_message_with_invalid_data() { let err = DnsMessageParser::new(vec![1, 2, 3]) @@ -1987,11 +2006,10 @@ mod tests { #[test] fn test_format_rdata_for_opt_type() { - let mut options = HashMap::new(); - options.insert( + let options = vec![( EdnsCode::LLQ, EdnsOption::Unknown(u16::from(EdnsCode::LLQ), vec![0x01; 18]), - ); + )]; let rdata = RData::OPT(OPT::new(options)); let rdata_text = format_rdata(&rdata); assert!(rdata_text.is_ok()); @@ -2001,6 +2019,31 @@ mod tests { } } + #[test] + fn test_format_rdata_for_cert_type() { + let rdata = RData::CERT(CERT::new( + CertType::Experimental(65534), + 65535, + CertAlgorithm::RSASHA1, + BASE64 + .decode( + b"MxFcby9k/yvedMfQgKzhH5er0Mu/vILz4\ + 5IkskceFGgiWCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nld80jEeC8aTrO+KKmCaY=", + ) + .unwrap(), + )); + let rdata_text = format_rdata(&rdata); + assert!(rdata_text.is_ok()); + if let Ok((parsed, raw_rdata)) = rdata_text { + assert!(raw_rdata.is_none()); + assert_eq!( + "65534 65535 RSASHA1 MxFcby9k/yvedMfQgKzhH5er0Mu/vILz4\ + 5IkskceFGgiWCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nld80jEeC8aTrO+KKmCaY=", + parsed.unwrap() + ); + } + } + #[test] fn test_format_rdata_for_minfo_type() { test_format_rdata_with_compressed_domain_names( @@ -2132,17 +2175,6 @@ mod tests { ); } - #[test] - fn test_format_rdata_for_cert_type() { - test_format_rdata( - "//7//wUzEVxvL2T/K950x9CArOEfl6vQy7+8gvPjkiSyRx4UaCJYKf8bEeFq\ - LpUC4cCg1TPhihTW1V9IJKpBifr//XVTo2V3zSMR4LxpOs74oqYJpg==", - 37, - "65534 65535 RSASHA1 MxFcby9k/yvedMfQgKzhH5er0Mu/vILz4\ - 5IkskceFGgiWCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nld80jEeC8aTrO+KKmCaY=", - ); - } - #[test] fn test_format_rdata_for_a6_type() { test_format_rdata( diff --git a/lib/dnsmsg-parser/src/ede.rs b/lib/dnsmsg-parser/src/ede.rs index a6c30f5f1348f..32d6a91708438 100644 --- a/lib/dnsmsg-parser/src/ede.rs +++ b/lib/dnsmsg-parser/src/ede.rs @@ -1,6 +1,6 @@ use hickory_proto::{ - error::ProtoResult, serialize::binary::{BinDecodable, BinDecoder, BinEncodable, BinEncoder}, + ProtoError, }; pub const EDE_OPTION_CODE: u16 = 15u16; @@ -67,7 +67,7 @@ impl EDE { } impl BinEncodable for EDE { - fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> { + fn emit(&self, encoder: &mut BinEncoder<'_>) -> Result<(), ProtoError> { encoder.emit_u16(self.info_code)?; if let Some(extra_text) = &self.extra_text { encoder.emit_vec(extra_text.as_bytes())?; @@ -77,7 +77,7 @@ impl BinEncodable for EDE { } impl<'a> BinDecodable<'a> for EDE { - fn read(decoder: &mut BinDecoder<'a>) -> ProtoResult { + fn read(decoder: &mut BinDecoder<'a>) -> Result { let info_code = decoder.read_u16()?.unverified(); let extra_text = if decoder.is_empty() { None