add dnssec lookup to Lookup
This commit is contained in:
@@ -339,7 +339,7 @@ impl fmt::Display for ProofError {
|
||||
}
|
||||
|
||||
/// A wrapper type to ensure that the state of a DNSSEC proof is evaluated before use
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Proven<T> {
|
||||
proof: Proof,
|
||||
value: T,
|
||||
@@ -393,4 +393,29 @@ impl<T> Proven<T> {
|
||||
Err(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Map the value with the associated function, carrying forward the proof
|
||||
pub fn map<U, F>(self, f: F) -> Proven<U>
|
||||
where
|
||||
F: FnOnce(T) -> U,
|
||||
{
|
||||
Proven {
|
||||
proof: self.proof,
|
||||
value: f(self.value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Proven<Option<T>> {
|
||||
/// If the inner type is an Option this will transpose them so that it's an option wrapped Proven
|
||||
pub fn transpose(self) -> Option<Proven<T>> {
|
||||
if let Some(value) = self.value {
|
||||
Some(Proven {
|
||||
proof: self.proof,
|
||||
value,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@ use crate::{
|
||||
};
|
||||
|
||||
#[cfg(feature = "dnssec")]
|
||||
use crate::rr::dnssec::Proof;
|
||||
use crate::rr::dnssec::{Proof, Proven};
|
||||
|
||||
#[allow(deprecated)]
|
||||
use crate::rr::IntoRecordSet;
|
||||
@@ -775,6 +775,22 @@ impl PartialOrd<Self> for Record {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "dnssec")]
|
||||
impl From<Record> for Proven<Record> {
|
||||
fn from(record: Record) -> Self {
|
||||
let proof = record.proof();
|
||||
Self::new(proof, record)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "dnssec")]
|
||||
impl<'a> From<&'a Record> for Proven<&'a Record> {
|
||||
fn from(record: &'a Record) -> Self {
|
||||
let proof = record.proof();
|
||||
Self::new(proof, record)
|
||||
}
|
||||
}
|
||||
|
||||
/// A Record where the RecordData type is already known
|
||||
pub struct RecordRef<'a, R: RecordData> {
|
||||
name_labels: &'a Name,
|
||||
|
@@ -41,7 +41,7 @@ use crate::{
|
||||
};
|
||||
|
||||
#[cfg(feature = "dnssec")]
|
||||
use proto::DnssecDnsHandle;
|
||||
use proto::{rr::dnssec::Proven, DnssecDnsHandle};
|
||||
|
||||
/// Result of a DNS query when querying for any record type supported by the Hickory DNS Proto library.
|
||||
///
|
||||
@@ -89,6 +89,12 @@ impl Lookup {
|
||||
LookupIter(self.records.iter())
|
||||
}
|
||||
|
||||
/// Returns a borrowed iterator of the returned data wrapped in a dnssec Proven type
|
||||
#[cfg(feature = "dnssec")]
|
||||
pub fn dnssec_iter(&self) -> DnssecIter<'_> {
|
||||
DnssecIter(self.dnssec_record_iter())
|
||||
}
|
||||
|
||||
/// Returns an iterator over all records returned during the query.
|
||||
///
|
||||
/// It may include additional record types beyond the queried type, e.g. CNAME.
|
||||
@@ -96,6 +102,12 @@ impl Lookup {
|
||||
LookupRecordIter(self.records.iter())
|
||||
}
|
||||
|
||||
/// Returns a borrowed iterator of the returned records wrapped in a dnssec Proven type
|
||||
#[cfg(feature = "dnssec")]
|
||||
pub fn dnssec_record_iter(&self) -> DnssecLookupRecordIter<'_> {
|
||||
DnssecLookupRecordIter(self.records.iter())
|
||||
}
|
||||
|
||||
/// Returns the `Instant` at which this `Lookup` is no longer valid.
|
||||
pub fn valid_until(&self) -> Instant {
|
||||
self.valid_until
|
||||
@@ -139,6 +151,20 @@ impl<'a> Iterator for LookupIter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over record data with all data wrapped in a Proven type for dnssec validation
|
||||
#[cfg(feature = "dnssec")]
|
||||
pub struct DnssecIter<'a>(DnssecLookupRecordIter<'a>);
|
||||
|
||||
#[cfg(feature = "dnssec")]
|
||||
|
||||
impl<'a> Iterator for DnssecIter<'a> {
|
||||
type Item = Proven<&'a RData>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.0.next().and_then(|r| r.map(Record::data).transpose())
|
||||
}
|
||||
}
|
||||
|
||||
/// Borrowed view of set of [`Record`]s returned from a Lookup
|
||||
pub struct LookupRecordIter<'a>(Iter<'a, Record>);
|
||||
|
||||
@@ -150,6 +176,20 @@ impl<'a> Iterator for LookupRecordIter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over record data with all data wrapped in a Proven type for dnssec validation
|
||||
#[cfg(feature = "dnssec")]
|
||||
pub struct DnssecLookupRecordIter<'a>(Iter<'a, Record>);
|
||||
|
||||
#[cfg(feature = "dnssec")]
|
||||
|
||||
impl<'a> Iterator for DnssecLookupRecordIter<'a> {
|
||||
type Item = Proven<&'a Record>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.0.next().map(Proven::from)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: consider removing this as it's not a zero-cost abstraction
|
||||
impl IntoIterator for Lookup {
|
||||
type Item = RData;
|
||||
@@ -699,4 +739,42 @@ pub mod tests {
|
||||
assert_eq!(lookup.next().unwrap(), RData::A(A::new(127, 0, 0, 2)));
|
||||
assert_eq!(lookup.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "dnssec")]
|
||||
fn test_dnssec_lookup() {
|
||||
use hickory_proto::rr::dnssec::Proof;
|
||||
|
||||
let mut a1 = Record::from_rdata(
|
||||
Name::from_str("www.example.com.").unwrap(),
|
||||
80,
|
||||
RData::A(A::new(127, 0, 0, 1)),
|
||||
);
|
||||
a1.set_proof(Proof::Secure);
|
||||
|
||||
let mut a2 = Record::from_rdata(
|
||||
Name::from_str("www.example.com.").unwrap(),
|
||||
80,
|
||||
RData::A(A::new(127, 0, 0, 2)),
|
||||
);
|
||||
a2.set_proof(Proof::Insecure);
|
||||
|
||||
let lookup = Lookup {
|
||||
query: Query::default(),
|
||||
records: Arc::from([a1.clone(), a2.clone()]),
|
||||
valid_until: Instant::now(),
|
||||
};
|
||||
|
||||
let mut lookup = lookup.dnssec_iter();
|
||||
|
||||
assert_eq!(
|
||||
*lookup.next().unwrap().try_take(Proof::Secure).unwrap(),
|
||||
*a1.data().unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
*lookup.next().unwrap().try_take(Proof::Insecure).unwrap(),
|
||||
*a2.data().unwrap()
|
||||
);
|
||||
assert_eq!(lookup.next(), None);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user