blob: 873b73e73eb4009ea30f73c632b50a429ff3f2fe [file] [log] [blame]
/*
* Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//! negative cache proof for non-existence
use super::nsec3;
use crate::error::*;
use crate::rr::dnssec::rdata::DNSSECRecordType;
use crate::rr::{Name, RecordType};
use crate::serialize::binary::*;
/// [RFC 4034, DNSSEC Resource Records, March 2005](https://tools.ietf.org/html/rfc4034#section-4)
///
/// ```text
/// 4.1. NSEC RDATA Wire Format
///
/// The RDATA of the NSEC RR is as shown below:
///
/// 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// / Next Domain Name /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// / Type Bit Maps /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
///
/// 4.1.3. Inclusion of Wildcard Names in NSEC RDATA
///
/// If a wildcard owner name appears in a zone, the wildcard label ("*")
/// is treated as a literal symbol and is treated the same as any other
/// owner name for the purposes of generating NSEC RRs. Wildcard owner
/// names appear in the Next Domain Name field without any wildcard
/// expansion. [RFC4035] describes the impact of wildcards on
/// authenticated denial of existence.
/// ```
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct NSEC {
next_domain_name: Name,
type_bit_maps: Vec<RecordType>,
}
impl NSEC {
/// Constructs a new NSEC RData, warning this won't guarantee that the NSEC covers itself
/// which it should at it's own name.
///
/// # Arguments
///
/// * `next_domain_name` - the name labels of the next ordered name in the zone
/// * `type_bit_maps` - a bit map of the types that exist at this name
///
/// # Returns
///
/// An NSEC RData for use in a Resource Record
pub fn new(next_domain_name: Name, type_bit_maps: Vec<RecordType>) -> NSEC {
NSEC {
next_domain_name,
type_bit_maps,
}
}
/// Constructs a new NSEC RData, this will add the NSEC itself as covered, generally
/// correct for NSEC records generated at their own name
///
/// # Arguments
///
/// * `next_domain_name` - the name labels of the next ordered name in the zone
/// * `type_bit_maps` - a bit map of the types that exist at this name
///
/// # Returns
///
/// An NSEC RData for use in a Resource Record
pub fn new_cover_self(next_domain_name: Name, mut type_bit_maps: Vec<RecordType>) -> NSEC {
type_bit_maps.push(RecordType::DNSSEC(DNSSECRecordType::NSEC));
Self::new(next_domain_name, type_bit_maps)
}
/// [RFC 4034, DNSSEC Resource Records, March 2005](https://tools.ietf.org/html/rfc4034#section-4.1.1)
///
/// ```text
/// 4.1.1. The Next Domain Name Field
///
/// The Next Domain field contains the next owner name (in the canonical
/// ordering of the zone) that has authoritative data or contains a
/// delegation point NS RRset; see Section 6.1 for an explanation of
/// canonical ordering. The value of the Next Domain Name field in the
/// last NSEC record in the zone is the name of the zone apex (the owner
/// name of the zone's SOA RR). This indicates that the owner name of
/// the NSEC RR is the last name in the canonical ordering of the zone.
///
/// A sender MUST NOT use DNS name compression on the Next Domain Name
/// field when transmitting an NSEC RR.
///
/// Owner names of RRsets for which the given zone is not authoritative
/// (such as glue records) MUST NOT be listed in the Next Domain Name
/// unless at least one authoritative RRset exists at the same owner
/// name.
/// ```
pub fn next_domain_name(&self) -> &Name {
&self.next_domain_name
}
/// [RFC 4034, DNSSEC Resource Records, March 2005](https://tools.ietf.org/html/rfc4034#section-4.1.2)
///
/// ```text
/// 4.1.2. The Type Bit Maps Field
///
/// The Type Bit Maps field identifies the RRset types that exist at the
/// NSEC RR's owner name.
///
/// A zone MUST NOT include an NSEC RR for any domain name that only
/// holds glue records.
/// ```
pub fn type_bit_maps(&self) -> &[RecordType] {
&self.type_bit_maps
}
}
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder, rdata_length: Restrict<u16>) -> ProtoResult<NSEC> {
let start_idx = decoder.index();
let next_domain_name = Name::read(decoder)?;
let bit_map_len = rdata_length
.map(|u| u as usize)
.checked_sub(decoder.index() - start_idx)
.map_err(|_| ProtoError::from("invalid rdata length in NSEC"))?;
let record_types = nsec3::decode_type_bit_maps(decoder, bit_map_len)?;
Ok(NSEC::new(next_domain_name, record_types))
}
/// [RFC 6840](https://tools.ietf.org/html/rfc6840#section-6)
///
/// ```text
/// 5.1. Errors in Canonical Form Type Code List
///
/// When canonicalizing DNS names (for both ordering and signing), DNS
/// names in the RDATA section of NSEC resource records are not converted
/// to lowercase. DNS names in the RDATA section of RRSIG resource
/// records are converted to lowercase.
/// ```
pub fn emit(encoder: &mut BinEncoder, rdata: &NSEC) -> ProtoResult<()> {
encoder.with_canonical_names(|encoder| {
rdata.next_domain_name().emit(encoder)?;
nsec3::encode_bit_maps(encoder, rdata.type_bit_maps())
})
}
#[cfg(test)]
mod tests {
#![allow(clippy::dbg_macro, clippy::print_stdout)]
use super::*;
#[test]
pub fn test() {
use crate::rr::dnssec::rdata::DNSSECRecordType;
use crate::rr::RecordType;
use std::str::FromStr;
let rdata = NSEC::new(
Name::from_str("www.example.com").unwrap(),
vec![
RecordType::A,
RecordType::AAAA,
RecordType::DNSSEC(DNSSECRecordType::DS),
RecordType::DNSSEC(DNSSECRecordType::RRSIG),
],
);
let mut bytes = Vec::new();
let mut encoder: BinEncoder = BinEncoder::new(&mut bytes);
assert!(emit(&mut encoder, &rdata).is_ok());
let bytes = encoder.into_bytes();
println!("bytes: {:?}", bytes);
let mut decoder: BinDecoder = BinDecoder::new(bytes);
let restrict = Restrict::new(bytes.len() as u16);
let read_rdata = read(&mut decoder, restrict).expect("Decoding error");
assert_eq!(rdata, read_rdata);
}
}