Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/decode/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ pub enum DecodeError {
SSHFPAlgorithm(u8),
#[error("Could not decode SSHFPType: {0}")]
SSHFPType(u8),
#[error("The bitmap length must be between 1 and 32 bytes: {0}")]
NSECBitmapLength(u8),
#[error("Could not decode AlgorithmType: {0}")]
AlgorithmType(u8),
#[error("Could not decode DigestType: {0}")]
Expand Down
1 change: 1 addition & 0 deletions src/decode/rr/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ impl<'a, 'b: 'a> Decoder<'b, 'b> {
Type::URI => RR::URI(r_data.rr_uri(header)?),
Type::EID => RR::EID(r_data.rr_eid(header)?),
Type::NIMLOC => RR::NIMLOC(r_data.rr_nimloc(header)?),
Type::NSEC => RR::NSEC(r_data.rr_nsec(header)?),
Type::DNSKEY => RR::DNSKEY(r_data.rr_dnskey(header)?),
Type::DS => RR::DS(r_data.rr_ds(header)?),
Type::CAA => RR::CAA(r_data.rr_caa(header)?),
Expand Down
35 changes: 34 additions & 1 deletion src/decode/rr/rfc_4034.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use super::Header;
use crate::rr::{
AlgorithmType, DigestType, DNSKEY, DNSKEY_ZERO_MASK, DS, SECURE_ENTRY_POINT_FLAG, ZONE_KEY_FLAG,
AlgorithmType, DigestType, Type, DNSKEY, DNSKEY_ZERO_MASK, DS, NSEC, SECURE_ENTRY_POINT_FLAG,
ZONE_KEY_FLAG,
};
use crate::DecodeResult;
use crate::{decode::Decoder, DecodeError};
use std::collections::BTreeSet;
use std::convert::TryFrom;

impl<'a, 'b: 'a> Decoder<'a, 'b> {
Expand Down Expand Up @@ -66,4 +68,35 @@ impl<'a, 'b: 'a> Decoder<'a, 'b> {
};
Ok(ds)
}

pub(super) fn rr_nsec(&mut self, header: Header) -> DecodeResult<NSEC> {
let class = header.get_class()?;
let next_domain_name = self.domain_name()?;
let mut type_bit_maps = BTreeSet::new();
while self.remaining()? > 0 {
let window = self.u8()?;
let bitmap_length = self.u8()?;
if bitmap_length == 0 || bitmap_length > 32 {
return Err(DecodeError::NSECBitmapLength(bitmap_length));
}
let bitmap = self.read(bitmap_length as usize)?;
for (index, byte) in bitmap.iter().enumerate() {
for bit in 0..8 {
if byte & (0x80 >> bit) != 0 {
let type_number = u16::from(window) * 256 + (index as u16 * 8 + bit);
let type_ = Type::try_from(type_number).map_err(DecodeError::Type)?;
type_bit_maps.insert(type_);
}
}
}
}
let nsec = NSEC {
domain_name: header.domain_name,
ttl: header.ttl,
class,
next_domain_name,
type_bit_maps,
};
Ok(nsec)
}
}
16 changes: 16 additions & 0 deletions src/encode/domain_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,22 @@ impl Encoder {
self.merge_domain_name_index(domain_name_index, 0)?;
Ok(())
}

pub(super) fn domain_name_without_compression(
&mut self,
domain_name: &DomainName,
) -> EncodeResult<()> {
let mut domain_name_index = HashMap::new();
for (label, domain_name) in domain_name.iter() {
let index = self.label(&label)?;
if index <= MAX_OFFSET {
domain_name_index.insert(domain_name, index);
}
}
self.string_with_len("")?;
self.merge_domain_name_index(domain_name_index, 0)?;
Ok(())
}
}

impl DomainName {
Expand Down
1 change: 1 addition & 0 deletions src/encode/rr/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ impl Encoder {
RR::URI(uri) => self.rr_uri(uri),
RR::EID(eid) => self.rr_eid(eid),
RR::NIMLOC(nimloc) => self.rr_nimloc(nimloc),
RR::NSEC(nsec) => self.rr_nsec(nsec),
RR::DNSKEY(dnskey) => self.rr_dnskey(dnskey),
RR::DS(ds) => self.rr_ds(ds),
RR::CAA(caa) => self.rr_caa(caa),
Expand Down
38 changes: 37 additions & 1 deletion src/encode/rr/rfc_4034.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::encode::Encoder;
use crate::rr::{AlgorithmType, DigestType, Type, DNSKEY, DS};
use crate::rr::{AlgorithmType, DigestType, Type, DNSKEY, DS, NSEC};
use crate::EncodeResult;
use std::collections::BTreeMap;

impl Encoder {
fn rr_algorithm_type(&mut self, algorithm_type: AlgorithmType) {
Expand Down Expand Up @@ -36,4 +37,39 @@ impl Encoder {
self.vec(&ds.digest);
self.set_length_index(length_index)
}

pub(super) fn rr_nsec(&mut self, nsec: &NSEC) -> EncodeResult<()> {
self.domain_name(&nsec.domain_name)?;
self.rr_type(&Type::NSEC);
self.rr_class(&nsec.class);
self.u32(nsec.ttl);
let length_index = self.create_length_index();
self.domain_name_without_compression(&nsec.next_domain_name)?;

let mut windows: BTreeMap<u8, [u8; 32]> = BTreeMap::new();
for type_ in &nsec.type_bit_maps {
let type_value = *type_ as u16;
let window = (type_value / 256) as u8;
let offset = (type_value % 256) as u8;
let bitmap = windows.entry(window).or_insert([0u8; 32]);
let byte_index = (offset / 8) as usize;
let bit_index = offset % 8;
bitmap[byte_index] |= 0x80 >> bit_index;
}

for (window, bitmap) in windows {
let mut length = bitmap.len();
while length > 0 && bitmap[length - 1] == 0 {
length -= 1;
}
if length == 0 {
continue;
}
self.u8(window);
self.u8(length as u8);
self.vec(&bitmap[..length]);
}

self.set_length_index(length_index)
}
}
18 changes: 11 additions & 7 deletions src/rr/enums.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pub use super::{
A, AAAA, AFSDB, APL, CAA, CNAME, DNAME, DNSKEY, DS, EID, EUI48, EUI64, GPOS, HINFO, ISDN, KX,
L32, L64, LOC, LP, MB, MD, MF, MG, MINFO, MR, MX, NID, NIMLOC, NS, NSAP, NULL, OPT, PTR, PX,
RP, RT, SOA, SRV, SSHFP, TXT, URI, WKS, X25,
L32, L64, LOC, LP, MB, MD, MF, MG, MINFO, MR, MX, NID, NIMLOC, NS, NSAP, NSEC, NULL, OPT, PTR,
PX, RP, RT, SOA, SRV, SSHFP, TXT, URI, WKS, X25,
};
use crate::rr::draft_ietf_dnsop_svcb_https::ServiceBinding;
use std::fmt::{Display, Formatter, Result as FmtResult};
Expand Down Expand Up @@ -31,7 +31,7 @@ try_from_enum_to_integer! {
///
/// [type]: https://tools.ietf.org/html/rfc1035#section-3.2.2
/// [resource records]: crate::rr::RR
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum Type {
/// The [IPv4] [host address] type.
///
Expand Down Expand Up @@ -176,10 +176,10 @@ try_from_enum_to_integer! {
/// The [DNSKEY] type.
///
/// [DNSKEY]: https://tools.ietf.org/html/rfc4034#section-2
DNSKEY = 48,
DHCID = 49,
NSEC3 = 50,
NSEC3PARAM = 51,
DNSKEY = 48,
DHCID = 49,
NSEC3 = 50,
NSEC3PARAM = 51,
TLSA = 52,
SMIMEA = 53,

Expand Down Expand Up @@ -280,6 +280,7 @@ pub enum RR {
EUI48(EUI48),
EUI64(EUI64),
DS(DS),
NSEC(NSEC),
DNSKEY(DNSKEY),
CAA(CAA),
SVCB(ServiceBinding),
Expand Down Expand Up @@ -331,6 +332,7 @@ impl RR {
RR::URI(uri) => Some(uri.ttl),
RR::EID(eid) => Some(eid.ttl),
RR::DS(ds) => Some(ds.ttl),
RR::NSEC(nsec) => Some(nsec.ttl),
RR::DNSKEY(dnskey) => Some(dnskey.ttl),
RR::CAA(caa) => Some(caa.ttl),
RR::SVCB(svcb) => Some(svcb.ttl),
Expand Down Expand Up @@ -382,6 +384,7 @@ impl RR {
RR::URI(uri) => Some(uri.class),
RR::EID(eid) => Some(eid.class),
RR::DS(ds) => Some(ds.class),
RR::NSEC(nsec) => Some(nsec.class),
RR::DNSKEY(dnskey) => Some(dnskey.class),
RR::CAA(caa) => Some(caa.class),
RR::SVCB(_) => Some(Class::IN),
Expand Down Expand Up @@ -435,6 +438,7 @@ impl Display for RR {
RR::URI(uri) => uri.fmt(f),
RR::EID(eid) => eid.fmt(f),
RR::DS(ds) => ds.fmt(f),
RR::NSEC(nsec) => nsec.fmt(f),
RR::DNSKEY(dnskey) => dnskey.fmt(f),
RR::CAA(caa) => caa.fmt(f),
RR::SVCB(svcb) => svcb.fmt(f),
Expand Down
3 changes: 2 additions & 1 deletion src/rr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ pub use rfc_3123::{APItem, APL, APL_NEGATION_MASK};
pub use rfc_3596::AAAA;
pub use rfc_3658::{SSHFPAlgorithm, SSHFPType, SSHFP};
pub use rfc_4034::{
AlgorithmType, DigestType, DNSKEY, DNSKEY_ZERO_MASK, DS, SECURE_ENTRY_POINT_FLAG, ZONE_KEY_FLAG,
AlgorithmType, DigestType, DNSKEY, DNSKEY_ZERO_MASK, DS, NSEC, SECURE_ENTRY_POINT_FLAG,
ZONE_KEY_FLAG,
};
pub use rfc_6672::DNAME;
pub use rfc_6742::{L32, L64, LP, NID};
Expand Down
29 changes: 29 additions & 0 deletions src/rr/rfc_4034.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::rr::Class;
use crate::rr::Type;
use crate::DomainName;
use hex::encode;
use std::collections::BTreeSet;
use std::fmt::{Display, Formatter, Result as FmtResult};

/// The bit at offset 7 of the DNSKEY flags field is the [Zone Key flag].
Expand Down Expand Up @@ -116,3 +118,30 @@ impl Display for DS {
)
}
}

#[derive(Debug, PartialEq, Clone, Eq, Hash)]
pub struct NSEC {
pub domain_name: DomainName,
pub ttl: u32,
pub class: Class,
pub next_domain_name: DomainName,
pub type_bit_maps: BTreeSet<Type>,
}

impl Display for NSEC {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(
f,
"{} {} {} NSEC {} {}",
self.domain_name,
self.ttl,
self.class,
self.next_domain_name,
self.type_bit_maps
.iter()
.map(|type_| format!("{:?}", type_))
.collect::<Vec<_>>()
.join(" ")
)
}
}
Loading