use core::{fmt, hash, ptr};
use core::cmp::Ordering;
use core::convert::TryInto;
#[cfg(feature = "std")] use std::vec::Vec;
#[cfg(feature="master")] use bytes::{Bytes, BytesMut};
use crate::base::cmp::CanonicalOrd;
use crate::base::iana::{DigestAlg, Rtype, SecAlg};
use crate::base::name::{ParsedDname, ToDname};
use crate::base::octets::{
Compose, EmptyBuilder, FormError, FromBuilder, IntoOctets, OctetsBuilder,
OctetsRef, Parse, ParseError, Parser, ShortBuf
};
use crate::base::rdata::{RtypeRecordData};
use crate::base::serial::Serial;
#[cfg(feature="master")] use crate::base::name::Dname;
#[cfg(feature="master")] use crate::master::scan::{
CharSource, ScanError, Scan, Scanner
};
use crate::utils::base64;
#[derive(Clone)]
pub struct Dnskey<Octets> {
flags: u16,
protocol: u8,
algorithm: SecAlg,
public_key: Octets,
}
impl<Octets> Dnskey<Octets> {
pub fn new(
flags: u16,
protocol: u8,
algorithm: SecAlg,
public_key: Octets)
-> Self {
Dnskey {
flags,
protocol,
algorithm,
public_key,
}
}
pub fn flags(&self) -> u16 {
self.flags
}
pub fn protocol(&self) -> u8 {
self.protocol
}
pub fn algorithm(&self) -> SecAlg {
self.algorithm
}
pub fn public_key(&self) -> &Octets {
&self.public_key
}
pub fn into_public_key(self) -> Octets {
self.public_key
}
pub fn convert<Other: From<Octets>>(
self
) -> Dnskey<Other> {
Dnskey {
flags: self.flags,
protocol: self.protocol,
algorithm: self.algorithm,
public_key: self.public_key.into()
}
}
pub fn is_revoked(&self) -> bool {
self.flags() & 0b0000_0000_1000_0000 != 0
}
pub fn is_secure_entry_point(&self) -> bool {
self.flags() & 0b0000_0000_0000_0001 != 0
}
pub fn is_zsk(&self) -> bool {
self.flags() & 0b0000_0001_0000_0000 != 0
}
pub fn key_tag(&self) -> u16
where Octets: AsRef<[u8]> {
if self.algorithm == SecAlg::RsaMd5 {
let len = self.public_key.as_ref().len();
if len > 2 {
u16::from_be_bytes(
self.public_key.as_ref()[len - 3..len - 1]
.try_into().unwrap()
)
}
else {
0
}
}
else {
let mut res = u32::from(self.flags);
res += u32::from(self.protocol) << 8;
res += u32::from(self.algorithm.to_int());
let mut iter = self.public_key().as_ref().iter();
loop {
match iter.next() {
Some(&x) => res += u32::from(x) << 8,
None => break
}
match iter.next() {
Some(&x) => res += u32::from(x),
None => break
}
}
res += (res >> 16) & 0xFFFF;
(res & 0xFFFF) as u16
}
}
}
impl<Octets, Other> PartialEq<Dnskey<Other>> for Dnskey<Octets>
where Octets: AsRef<[u8]>, Other: AsRef<[u8]> {
fn eq(&self, other: &Dnskey<Other>) -> bool {
self.flags == other.flags
&& self.protocol == other.protocol
&& self.algorithm == other.algorithm
&& self.public_key.as_ref() == other.public_key.as_ref()
}
}
impl<Octets: AsRef<[u8]>> Eq for Dnskey<Octets> { }
impl<Octets, Other> PartialOrd<Dnskey<Other>> for Dnskey<Octets>
where Octets: AsRef<[u8]>, Other: AsRef<[u8]> {
fn partial_cmp(&self, other: &Dnskey<Other>) -> Option<Ordering> {
Some(self.canonical_cmp(other))
}
}
impl<Octets, Other> CanonicalOrd<Dnskey<Other>> for Dnskey<Octets>
where Octets: AsRef<[u8]>, Other: AsRef<[u8]> {
fn canonical_cmp(&self, other: &Dnskey<Other>) -> Ordering {
match self.flags.cmp(&other.flags) {
Ordering::Equal => { }
other => return other
}
match self.protocol.cmp(&other.protocol) {
Ordering::Equal => { }
other => return other
}
match self.algorithm.cmp(&other.algorithm) {
Ordering::Equal => { }
other => return other
}
self.public_key.as_ref().cmp(other.public_key.as_ref())
}
}
impl<Octets: AsRef<[u8]>> Ord for Dnskey<Octets> {
fn cmp(&self, other: &Self) -> Ordering {
self.canonical_cmp(other)
}
}
impl<Octets: AsRef<[u8]>> hash::Hash for Dnskey<Octets> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.flags.hash(state);
self.protocol.hash(state);
self.algorithm.hash(state);
self.public_key.as_ref().hash(state);
}
}
impl<Ref: OctetsRef> Parse<Ref> for Dnskey<Ref::Range> {
fn parse(parser: &mut Parser<Ref>) -> Result<Self, ParseError> {
let len = match parser.remaining().checked_sub(4) {
Some(len) => len,
None => return Err(ParseError::ShortInput)
};
Ok(Self::new(
u16::parse(parser)?,
u8::parse(parser)?,
SecAlg::parse(parser)?,
parser.parse_octets(len)?
))
}
fn skip(parser: &mut Parser<Ref>) -> Result<(), ParseError> {
if parser.remaining() < 4 {
return Err(ParseError::ShortInput)
}
parser.advance_to_end();
Ok(())
}
}
impl<Octets: AsRef<[u8]>> Compose for Dnskey<Octets> {
fn compose<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
target.append_all(|buf| {
self.flags.compose(buf)?;
self.protocol.compose(buf)?;
self.algorithm.compose(buf)?;
buf.append_slice(self.public_key.as_ref())
})
}
}
#[cfg(feature="master")]
impl Scan for Dnskey<Bytes> {
fn scan<C: CharSource>(
scanner: &mut Scanner<C>
) -> Result<Self, ScanError> {
Ok(Self::new(
u16::scan(scanner)?,
u8::scan(scanner)?,
SecAlg::scan(scanner)?,
scanner.scan_base64_phrases(Ok)?
))
}
}
impl<Octets: AsRef<[u8]>> fmt::Display for Dnskey<Octets> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {} {} ", self.flags, self.protocol, self.algorithm)?;
base64::display(&self.public_key, f)
}
}
impl<Octets: AsRef<[u8]>> fmt::Debug for Dnskey<Octets> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Dnskey")
.field("flags", &self.flags)
.field("protocol", &self.protocol)
.field("algorithm", &self.algorithm)
.field("public_key", &self.public_key.as_ref())
.finish()
}
}
impl<Octets> RtypeRecordData for Dnskey<Octets> {
const RTYPE: Rtype = Rtype::Dnskey;
}
#[derive(Clone)]
pub struct ProtoRrsig<Name> {
type_covered: Rtype,
algorithm: SecAlg,
labels: u8,
original_ttl: u32,
expiration: Serial,
inception: Serial,
key_tag: u16,
signer_name: Name,
}
impl<Name> ProtoRrsig<Name> {
#[allow(clippy::too_many_arguments)]
pub fn new(
type_covered: Rtype,
algorithm: SecAlg,
labels: u8,
original_ttl: u32,
expiration: Serial,
inception: Serial,
key_tag: u16,
signer_name: Name,
) -> Self {
ProtoRrsig {
type_covered,
algorithm,
labels,
original_ttl,
expiration,
inception,
key_tag,
signer_name,
}
}
pub fn into_rrsig<Octets>(
self,
signature: Octets
) -> Rrsig<Octets, Name> {
Rrsig::new(
self.type_covered, self.algorithm, self.labels,
self.original_ttl, self.expiration, self.inception,
self.key_tag, self.signer_name, signature
)
}
}
impl<Name: Compose> Compose for ProtoRrsig<Name> {
fn compose<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
target.append_all(|buf| {
self.type_covered.compose(buf)?;
self.algorithm.compose(buf)?;
self.labels.compose(buf)?;
self.original_ttl.compose(buf)?;
self.expiration.compose(buf)?;
self.inception.compose(buf)?;
self.key_tag.compose(buf)?;
self.signer_name.compose(buf)
})
}
fn compose_canonical<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
target.append_all(|buf| {
self.type_covered.compose(buf)?;
self.algorithm.compose(buf)?;
self.labels.compose(buf)?;
self.original_ttl.compose(buf)?;
self.expiration.compose(buf)?;
self.inception.compose(buf)?;
self.key_tag.compose(buf)?;
self.signer_name.compose_canonical(buf)
})
}
}
#[derive(Clone)]
pub struct Rrsig<Octets, Name> {
type_covered: Rtype,
algorithm: SecAlg,
labels: u8,
original_ttl: u32,
expiration: Serial,
inception: Serial,
key_tag: u16,
signer_name: Name,
signature: Octets,
}
impl<Octets, Name> Rrsig<Octets, Name> {
#[allow(clippy::too_many_arguments)]
pub fn new(
type_covered: Rtype,
algorithm: SecAlg,
labels: u8,
original_ttl: u32,
expiration: Serial,
inception: Serial,
key_tag: u16,
signer_name: Name,
signature: Octets
) -> Self {
Rrsig {
type_covered,
algorithm,
labels,
original_ttl,
expiration,
inception,
key_tag,
signer_name,
signature
}
}
pub fn type_covered(&self) -> Rtype {
self.type_covered
}
pub fn algorithm(&self) -> SecAlg {
self.algorithm
}
pub fn labels(&self) -> u8 {
self.labels
}
pub fn original_ttl(&self) -> u32 {
self.original_ttl
}
pub fn expiration(&self) -> Serial {
self.expiration
}
pub fn inception(&self) -> Serial {
self.inception
}
pub fn key_tag(&self) -> u16 {
self.key_tag
}
pub fn signer_name(&self) -> &Name {
&self.signer_name
}
pub fn signature(&self) -> &Octets {
&self.signature
}
pub fn set_signature(&mut self, signature: Octets) {
self.signature = signature
}
}
impl<N, NN, O, OO> PartialEq<Rrsig<OO, NN>> for Rrsig<O, N>
where N: ToDname, NN: ToDname, O: AsRef<[u8]>, OO: AsRef<[u8]> {
fn eq(&self, other: &Rrsig<OO, NN>) -> bool {
self.type_covered == other.type_covered
&& self.algorithm == other.algorithm
&& self.labels == other.labels
&& self.original_ttl == other.original_ttl
&& self.expiration.into_int() == other.expiration.into_int()
&& self.inception.into_int() == other.inception.into_int()
&& self.key_tag == other.key_tag
&& self.signer_name.name_eq(&other.signer_name)
&& self.signature.as_ref() == other.signature.as_ref()
}
}
impl<Octets, Name> Eq for Rrsig<Octets, Name>
where Octets: AsRef<[u8]>, Name: ToDname { }
impl<N, NN, O, OO> PartialOrd<Rrsig<OO, NN>> for Rrsig<O, N>
where N: ToDname, NN: ToDname, O: AsRef<[u8]>, OO: AsRef<[u8]> {
fn partial_cmp(&self, other: &Rrsig<OO, NN>) -> Option<Ordering> {
match self.type_covered.partial_cmp(&other.type_covered) {
Some(Ordering::Equal) => { }
other => return other
}
match self.algorithm.partial_cmp(&other.algorithm) {
Some(Ordering::Equal) => { }
other => return other
}
match self.labels.partial_cmp(&other.labels) {
Some(Ordering::Equal) => { }
other => return other
}
match self.original_ttl.partial_cmp(&other.original_ttl) {
Some(Ordering::Equal) => { }
other => return other
}
match self.expiration.partial_cmp(&other.expiration) {
Some(Ordering::Equal) => { }
other => return other
}
match self.inception.partial_cmp(&other.inception) {
Some(Ordering::Equal) => { }
other => return other
}
match self.key_tag.partial_cmp(&other.key_tag) {
Some(Ordering::Equal) => { }
other => return other
}
match self.signer_name.name_cmp(&other.signer_name) {
Ordering::Equal => { }
other => return Some(other)
}
self.signature.as_ref().partial_cmp(other.signature.as_ref())
}
}
impl<N, NN, O, OO> CanonicalOrd<Rrsig<OO, NN>> for Rrsig<O, N>
where N: ToDname, NN: ToDname, O: AsRef<[u8]>, OO: AsRef<[u8]> {
fn canonical_cmp(&self, other: &Rrsig<OO, NN>) -> Ordering {
match self.type_covered.cmp(&other.type_covered) {
Ordering::Equal => { }
other => return other
}
match self.algorithm.cmp(&other.algorithm) {
Ordering::Equal => { }
other => return other
}
match self.labels.cmp(&other.labels) {
Ordering::Equal => { }
other => return other
}
match self.original_ttl.cmp(&other.original_ttl) {
Ordering::Equal => { }
other => return other
}
match self.expiration.canonical_cmp(&other.expiration) {
Ordering::Equal => { }
other => return other
}
match self.inception.canonical_cmp(&other.inception) {
Ordering::Equal => { }
other => return other
}
match self.key_tag.cmp(&other.key_tag) {
Ordering::Equal => { }
other => return other
}
match self.signer_name.lowercase_composed_cmp(&other.signer_name) {
Ordering::Equal => { }
other => return other
}
self.signature.as_ref().cmp(other.signature.as_ref())
}
}
impl<O: AsRef<[u8]>, N: ToDname> Ord for Rrsig<O, N> {
fn cmp(&self, other: &Self) -> Ordering {
self.canonical_cmp(other)
}
}
impl<O: AsRef<[u8]>, N: hash::Hash> hash::Hash for Rrsig<O, N> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.type_covered.hash(state);
self.algorithm.hash(state);
self.labels.hash(state);
self.original_ttl.hash(state);
self.expiration.into_int().hash(state);
self.inception.into_int().hash(state);
self.key_tag.hash(state);
self.signer_name.hash(state);
self.signature.as_ref().hash(state);
}
}
impl<Ref: OctetsRef> Parse<Ref> for Rrsig<Ref::Range, ParsedDname<Ref>> {
fn parse(parser: &mut Parser<Ref>) -> Result<Self, ParseError> {
let type_covered = Rtype::parse(parser)?;
let algorithm = SecAlg::parse(parser)?;
let labels = u8::parse(parser)?;
let original_ttl = u32::parse(parser)?;
let expiration = Serial::parse(parser)?;
let inception = Serial::parse(parser)?;
let key_tag = u16::parse(parser)?;
let signer_name = ParsedDname::parse(parser)?;
let len = parser.remaining();
let signature = parser.parse_octets(len)?;
Ok(Self::new(
type_covered, algorithm, labels, original_ttl, expiration,
inception, key_tag, signer_name, signature
))
}
fn skip(parser: &mut Parser<Ref>) -> Result<(), ParseError> {
Rtype::skip(parser)?;
SecAlg::skip(parser)?;
u8::skip(parser)?;
u32::skip(parser)?;
Serial::skip(parser)?;
Serial::skip(parser)?;
u16::skip(parser)?;
ParsedDname::skip(parser)?;
parser.advance_to_end();
Ok(())
}
}
impl<Octets: AsRef<[u8]>, Name: Compose> Compose for Rrsig<Octets, Name> {
fn compose<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
target.append_all(|buf| {
self.type_covered.compose(buf)?;
self.algorithm.compose(buf)?;
self.labels.compose(buf)?;
self.original_ttl.compose(buf)?;
self.expiration.compose(buf)?;
self.inception.compose(buf)?;
self.key_tag.compose(buf)?;
self.signer_name.compose(buf)?;
buf.append_slice(self.signature.as_ref())
})
}
fn compose_canonical<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
target.append_all(|buf| {
self.type_covered.compose(buf)?;
self.algorithm.compose(buf)?;
self.labels.compose(buf)?;
self.original_ttl.compose(buf)?;
self.expiration.compose(buf)?;
self.inception.compose(buf)?;
self.key_tag.compose(buf)?;
self.signer_name.compose_canonical(buf)?;
buf.append_slice(self.signature.as_ref())
})
}
}
#[cfg(feature="master")]
impl Scan for Rrsig<Bytes, Dname<Bytes>> {
fn scan<C: CharSource>(
scanner: &mut Scanner<C>
) -> Result<Self, ScanError> {
Ok(Self::new(
Rtype::scan(scanner)?,
SecAlg::scan(scanner)?,
u8::scan(scanner)?,
u32::scan(scanner)?,
Serial::scan_rrsig(scanner)?,
Serial::scan_rrsig(scanner)?,
u16::scan(scanner)?,
Dname::scan(scanner)?,
scanner.scan_base64_phrases(Ok)?
))
}
}
impl<Octets, Name> fmt::Display for Rrsig<Octets, Name>
where Octets: AsRef<[u8]>, Name: fmt::Display {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {} {} {} {} {} {} {}. ",
self.type_covered, self.algorithm, self.labels,
self.original_ttl, self.expiration, self.inception,
self.key_tag, self.signer_name)?;
base64::display(&self.signature, f)
}
}
impl<Octets, Name> fmt::Debug for Rrsig<Octets, Name>
where Octets: AsRef<[u8]>, Name: fmt::Debug {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Rrsig")
.field("type_covered", &self.type_covered)
.field("algorithm", &self.algorithm)
.field("labels", &self.labels)
.field("original_ttl", &self.original_ttl)
.field("expiration", &self.expiration)
.field("inception", &self.inception)
.field("key_tag", &self.key_tag)
.field("signer_name", &self.signer_name)
.field("signature", &self.signature.as_ref())
.finish()
}
}
impl<Octets, Name> RtypeRecordData for Rrsig<Octets, Name> {
const RTYPE: Rtype = Rtype::Rrsig;
}
#[derive(Clone)]
pub struct Nsec<Octets, Name> {
next_name: Name,
types: RtypeBitmap<Octets>,
}
impl<Octets, Name> Nsec<Octets, Name> {
pub fn new(next_name: Name, types: RtypeBitmap<Octets>) -> Self {
Nsec { next_name, types }
}
pub fn next_name(&self) -> &Name {
&self.next_name
}
pub fn set_next_name(&mut self, next_name: Name) {
self.next_name = next_name
}
pub fn types(&self) -> &RtypeBitmap<Octets> {
&self.types
}
}
impl<O, OO, N, NN> PartialEq<Nsec<OO, NN>> for Nsec<O, N>
where
O: AsRef<[u8]>, OO: AsRef<[u8]>,
N: ToDname, NN: ToDname,
{
fn eq(&self, other: &Nsec<OO, NN>) -> bool {
self.next_name.name_eq(&other.next_name)
&& self.types == other.types
}
}
impl<O: AsRef<[u8]>, N: ToDname> Eq for Nsec<O, N> { }
impl<O, OO, N, NN> PartialOrd<Nsec<OO, NN>> for Nsec<O, N>
where
O: AsRef<[u8]>, OO: AsRef<[u8]>,
N: ToDname, NN: ToDname,
{
fn partial_cmp(&self, other: &Nsec<OO, NN>) -> Option<Ordering> {
match self.next_name.name_cmp(&other.next_name) {
Ordering::Equal => { }
other => return Some(other)
}
self.types.partial_cmp(&self.types)
}
}
impl<O, OO, N, NN> CanonicalOrd<Nsec<OO, NN>> for Nsec<O, N>
where
O: AsRef<[u8]>, OO: AsRef<[u8]>,
N: ToDname, NN: ToDname,
{
fn canonical_cmp(&self, other: &Nsec<OO, NN>) -> Ordering {
match self.next_name.composed_cmp(&other.next_name) {
Ordering::Equal => { }
other => return other
}
self.types.cmp(&self.types)
}
}
impl<O, N> Ord for Nsec<O, N>
where O: AsRef<[u8]>, N: ToDname {
fn cmp(&self, other: &Self) -> Ordering {
match self.next_name.name_cmp(&other.next_name) {
Ordering::Equal => { }
other => return other
}
self.types.cmp(&self.types)
}
}
impl<Octets: AsRef<[u8]>, Name: hash::Hash> hash::Hash for Nsec<Octets, Name> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.next_name.hash(state);
self.types.hash(state);
}
}
impl<Ref: OctetsRef> Parse<Ref> for Nsec<Ref::Range, ParsedDname<Ref>> {
fn parse(parser: &mut Parser<Ref>) -> Result<Self, ParseError> {
Ok(Nsec::new(
ParsedDname::parse(parser)?,
RtypeBitmap::parse(parser)?
))
}
fn skip(parser: &mut Parser<Ref>) -> Result<(), ParseError> {
ParsedDname::skip(parser)?;
RtypeBitmap::skip(parser)
}
}
impl<Octets: AsRef<[u8]>, Name: Compose> Compose for Nsec<Octets, Name> {
fn compose<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
target.append_all(|target| {
self.next_name.compose(target)?;
self.types.compose(target)
})
}
}
#[cfg(feature="master")]
impl<N: Scan> Scan for Nsec<Bytes, N> {
fn scan<C: CharSource>(
scanner: &mut Scanner<C>
) -> Result<Self, ScanError> {
Ok(Self::new(
N::scan(scanner)?,
RtypeBitmap::scan(scanner)?,
))
}
}
impl<Octets, Name> fmt::Display for Nsec<Octets, Name>
where Octets: AsRef<[u8]>, Name: fmt::Display {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}. {}", self.next_name, self.types)
}
}
impl<Octets, Name> fmt::Debug for Nsec<Octets, Name>
where Octets: AsRef<[u8]>, Name: fmt::Debug {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Nsec")
.field("next_name", &self.next_name)
.field("types", &self.types)
.finish()
}
}
impl<Octets, Name> RtypeRecordData for Nsec<Octets, Name> {
const RTYPE: Rtype = Rtype::Nsec;
}
#[derive(Clone)]
pub struct Ds<Octets> {
key_tag: u16,
algorithm: SecAlg,
digest_type: DigestAlg,
digest: Octets,
}
impl<Octets> Ds<Octets> {
pub fn new(
key_tag: u16,
algorithm: SecAlg,
digest_type: DigestAlg,
digest: Octets
) -> Self {
Ds { key_tag, algorithm, digest_type, digest }
}
pub fn key_tag(&self) -> u16 {
self.key_tag
}
pub fn algorithm(&self) -> SecAlg {
self.algorithm
}
pub fn digest_type(&self) -> DigestAlg {
self.digest_type
}
pub fn digest(&self) -> &Octets {
&self.digest
}
pub fn into_digest(self) -> Octets {
self.digest
}
}
impl<Octets, Other> PartialEq<Ds<Other>> for Ds<Octets>
where Octets: AsRef<[u8]>, Other: AsRef<[u8]> {
fn eq(&self, other: &Ds<Other>) -> bool {
self.key_tag == other.key_tag
&& self.algorithm == other.algorithm
&& self.digest_type == other.digest_type
&& self.digest.as_ref().eq(other.digest.as_ref())
}
}
impl<Octets: AsRef<[u8]>> Eq for Ds<Octets> { }
impl<Octets, Other> PartialOrd<Ds<Other>> for Ds<Octets>
where Octets: AsRef<[u8]>, Other: AsRef<[u8]> {
fn partial_cmp(&self, other: &Ds<Other>) -> Option<Ordering> {
match self.key_tag.partial_cmp(&other.key_tag) {
Some(Ordering::Equal) => { }
other => return other
}
match self.algorithm.partial_cmp(&other.algorithm) {
Some(Ordering::Equal) => { }
other => return other
}
match self.digest_type.partial_cmp(&other.digest_type) {
Some(Ordering::Equal) => { }
other => return other
}
self.digest.as_ref().partial_cmp(other.digest.as_ref())
}
}
impl<Octets, Other> CanonicalOrd<Ds<Other>> for Ds<Octets>
where Octets: AsRef<[u8]>, Other: AsRef<[u8]> {
fn canonical_cmp(&self, other: &Ds<Other>) -> Ordering {
match self.key_tag.cmp(&other.key_tag) {
Ordering::Equal => { }
other => return other
}
match self.algorithm.cmp(&other.algorithm) {
Ordering::Equal => { }
other => return other
}
match self.digest_type.cmp(&other.digest_type) {
Ordering::Equal => { }
other => return other
}
self.digest.as_ref().cmp(other.digest.as_ref())
}
}
impl<Octets: AsRef<[u8]>> Ord for Ds<Octets> {
fn cmp(&self, other: &Self) -> Ordering {
self.canonical_cmp(other)
}
}
impl<Octets: AsRef<[u8]>> hash::Hash for Ds<Octets> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.key_tag.hash(state);
self.algorithm.hash(state);
self.digest_type.hash(state);
self.digest.as_ref().hash(state);
}
}
impl<Ref: OctetsRef> Parse<Ref> for Ds<Ref::Range> {
fn parse(parser: &mut Parser<Ref>) -> Result<Self, ParseError> {
let len = match parser.remaining().checked_sub(4) {
Some(len) => len,
None => return Err(ParseError::ShortInput)
};
Ok(Self::new(
u16::parse(parser)?,
SecAlg::parse(parser)?,
DigestAlg::parse(parser)?,
parser.parse_octets(len)?
))
}
fn skip(parser: &mut Parser<Ref>) -> Result<(), ParseError> {
if parser.remaining() < 4 {
return Err(ParseError::ShortInput);
}
parser.advance_to_end();
Ok(())
}
}
impl<Octets: AsRef<[u8]>> Compose for Ds<Octets> {
fn compose<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
target.append_all(|buf| {
self.key_tag.compose(buf)?;
self.algorithm.compose(buf)?;
self.digest_type.compose(buf)?;
buf.append_slice(self.digest.as_ref())
})
}
}
#[cfg(feature="master")]
impl Scan for Ds<Bytes> {
fn scan<C: CharSource>(
scanner: &mut Scanner<C>
) -> Result<Self, ScanError> {
Ok(Self::new(
u16::scan(scanner)?,
SecAlg::scan(scanner)?,
DigestAlg::scan(scanner)?,
scanner.scan_hex_words(Ok)?,
))
}
}
impl<Octets: AsRef<[u8]>> fmt::Display for Ds<Octets> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {} {} ", self.key_tag, self.algorithm,
self.digest_type)?;
for ch in self.digest.as_ref() {
write!(f, "{:02x}", ch)?
}
Ok(())
}
}
impl<Octets: AsRef<[u8]>> fmt::Debug for Ds<Octets> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Ds")
.field("key_tag", &self.key_tag)
.field("algorithm", &self.algorithm)
.field("digest_type", &self.digest_type)
.field("digest", &self.digest.as_ref())
.finish()
}
}
impl<Octets> RtypeRecordData for Ds<Octets> {
const RTYPE: Rtype = Rtype::Ds;
}
#[derive(Clone)]
pub struct RtypeBitmap<Octets>(Octets);
impl<Octets> RtypeBitmap<Octets> {
pub fn from_octets(octets: Octets) -> Result<Self, RtypeBitmapError>
where Octets: AsRef<[u8]> {
{
let mut data = octets.as_ref();
while !data.is_empty() {
if data.len() < 2 {
return Err(RtypeBitmapError::ShortInput)
}
let len = (data[1] as usize) + 2;
if len == 2 {
return Err(RtypeBitmapError::BadRtypeBitmap);
}
if len > 34 {
return Err(RtypeBitmapError::BadRtypeBitmap)
}
if data.len() < len {
return Err(RtypeBitmapError::ShortInput)
}
data = &data[len..];
}
}
Ok(RtypeBitmap(octets))
}
pub fn builder() -> RtypeBitmapBuilder<Octets::Builder>
where
Octets: FromBuilder,
<Octets as FromBuilder>::Builder: EmptyBuilder
{
RtypeBitmapBuilder::new()
}
pub fn as_octets(&self) -> &Octets {
&self.0
}
}
impl<Octets: AsRef<[u8]>> RtypeBitmap<Octets> {
pub fn as_slice(&self) -> &[u8]
where Octets: AsRef<[u8]> {
self.0.as_ref()
}
pub fn iter(&self) -> RtypeBitmapIter {
RtypeBitmapIter::new(self.0.as_ref())
}
pub fn contains(&self, rtype: Rtype) -> bool
where Octets: AsRef<[u8]> {
let (block, octet, mask) = split_rtype(rtype);
let mut data = self.0.as_ref();
while !data.is_empty() {
let ((window_num, window), next_data) = read_window(data).unwrap();
if window_num == block {
return !(window.len() <= octet || window[octet] & mask == 0);
}
data = next_data;
}
false
}
}
impl<T, Octets: AsRef<T>> AsRef<T> for RtypeBitmap<Octets> {
fn as_ref(&self) -> &T {
self.0.as_ref()
}
}
impl<O, OO> PartialEq<RtypeBitmap<OO>> for RtypeBitmap<O>
where O: AsRef<[u8]>, OO: AsRef<[u8]> {
fn eq(&self, other: &RtypeBitmap<OO>) -> bool {
self.0.as_ref().eq(other.0.as_ref())
}
}
impl<O: AsRef<[u8]>> Eq for RtypeBitmap<O> { }
impl<O, OO> PartialOrd<RtypeBitmap<OO>> for RtypeBitmap<O>
where O: AsRef<[u8]>, OO: AsRef<[u8]> {
fn partial_cmp(&self, other: &RtypeBitmap<OO>) -> Option<Ordering> {
self.0.as_ref().partial_cmp(other.0.as_ref())
}
}
impl<O, OO> CanonicalOrd<RtypeBitmap<OO>> for RtypeBitmap<O>
where O: AsRef<[u8]>, OO: AsRef<[u8]> {
fn canonical_cmp(&self, other: &RtypeBitmap<OO>) -> Ordering {
self.0.as_ref().cmp(other.0.as_ref())
}
}
impl<O: AsRef<[u8]>> Ord for RtypeBitmap<O> {
fn cmp(&self, other: &Self) -> Ordering {
self.0.as_ref().cmp(other.0.as_ref())
}
}
impl<O: AsRef<[u8]>> hash::Hash for RtypeBitmap<O> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.0.as_ref().hash(state)
}
}
impl<'a, Octets: AsRef<[u8]>> IntoIterator for &'a RtypeBitmap<Octets> {
type Item = Rtype;
type IntoIter = RtypeBitmapIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<Ref: OctetsRef> Parse<Ref> for RtypeBitmap<Ref::Range> {
fn parse(parser: &mut Parser<Ref>) -> Result<Self, ParseError> {
let len = parser.remaining();
RtypeBitmap::from_octets(parser.parse_octets(len)?).map_err(Into::into)
}
fn skip(parser: &mut Parser<Ref>) -> Result<(), ParseError> {
parser.advance_to_end();
Ok(())
}
}
impl<Octets: AsRef<[u8]>> Compose for RtypeBitmap<Octets> {
fn compose<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
target.append_slice(self.0.as_ref())
}
}
#[cfg(feature="master")]
impl Scan for RtypeBitmap<Bytes> {
fn scan<C: CharSource>(
scanner: &mut Scanner<C>
) -> Result<Self, ScanError> {
let mut builder = RtypeBitmapBuilder::<BytesMut>::new();
while let Ok(rtype) = Rtype::scan(scanner) {
builder.add(rtype).unwrap()
}
Ok(builder.finalize())
}
}
impl<Octets: AsRef<[u8]>> fmt::Display for RtypeBitmap<Octets> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut iter = self.iter();
if let Some(rtype) = iter.next() {
rtype.fmt(f)?;
}
for rtype in iter {
write!(f, " {}", rtype)?
}
Ok(())
}
}
impl<Octets: AsRef<[u8]>> fmt::Debug for RtypeBitmap<Octets> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("RtypeBitmap(")?;
fmt::Display::fmt(self, f)?;
f.write_str(")")
}
}
#[derive(Clone, Debug)]
pub struct RtypeBitmapBuilder<Builder> {
buf: Builder,
}
impl<Builder: OctetsBuilder> RtypeBitmapBuilder<Builder> {
pub fn new() -> Self
where Builder: EmptyBuilder {
RtypeBitmapBuilder {
buf: Builder::with_capacity(34)
}
}
}
#[cfg(feature = "std")]
impl RtypeBitmapBuilder<Vec<u8>> {
pub fn new_vec() -> Self {
Self::new()
}
}
impl<Builder: OctetsBuilder> RtypeBitmapBuilder<Builder> {
pub fn add(&mut self, rtype: Rtype) -> Result<(), ShortBuf> {
let (block, octet, bit) = split_rtype(rtype);
let block = self.get_block(block)?;
if (block[1] as usize) < (octet + 1) {
block[1] = (octet + 1) as u8
}
block[octet + 2] |= bit;
Ok(())
}
fn get_block(&mut self, block: u8) -> Result<&mut [u8], ShortBuf> {
let mut pos = 0;
while pos < self.buf.as_ref().len() {
match self.buf.as_ref()[pos].cmp(&block) {
Ordering::Equal => {
return Ok(&mut self.buf.as_mut()[pos..pos + 34])
}
Ordering::Greater => {
let len = self.buf.as_ref().len() - pos;
self.buf.append_slice(&[0; 34])?;
let buf = self.buf.as_mut();
unsafe {
ptr::copy(
buf.as_ptr().add(pos),
buf.as_mut_ptr().add(pos + 34),
len
);
ptr::write_bytes(
buf.as_mut_ptr().add(pos),
0,
34
);
}
buf[pos] = block;
return Ok(&mut buf[pos..pos + 34])
}
Ordering::Less => {
pos += 34
}
}
}
self.buf.append_slice(&[0; 34])?;
self.buf.as_mut()[pos] = block;
Ok(&mut self.buf.as_mut()[pos..pos + 34])
}
pub fn finalize(mut self) -> RtypeBitmap<Builder::Octets>
where Builder: IntoOctets {
let mut src_pos = 0;
let mut dst_pos = 0;
while src_pos < self.buf.as_ref().len() {
let len = (self.buf.as_ref()[src_pos + 1] as usize) + 2;
if src_pos != dst_pos {
let buf = self.buf.as_mut();
unsafe {
ptr::copy(
buf.as_ptr().add(src_pos),
buf.as_mut_ptr().add(dst_pos),
len
)
}
}
dst_pos += len;
src_pos += 34;
}
self.buf.truncate(dst_pos);
RtypeBitmap(self.buf.into_octets())
}
}
impl<Builder> Default for RtypeBitmapBuilder<Builder>
where Builder: OctetsBuilder + EmptyBuilder {
fn default() -> Self {
Self::new()
}
}
pub struct RtypeBitmapIter<'a> {
data: &'a [u8],
block: u16,
len: usize,
octet: usize,
bit: u16
}
impl<'a> RtypeBitmapIter<'a> {
fn new(data: &'a [u8]) -> Self {
if data.is_empty() {
RtypeBitmapIter {
data,
block: 0, len: 0, octet: 0, bit: 0
}
}
else {
let mut res = RtypeBitmapIter {
data: &data[2..],
block: u16::from(data[0]) << 8,
len: usize::from(data[1]),
octet: 0,
bit: 0
};
if res.data[0] & 0x80 == 0 {
res.advance()
}
res
}
}
fn advance(&mut self) {
loop {
self.bit += 1;
if self.bit == 8 {
self.bit = 0;
self.octet += 1;
if self.octet == self.len {
self.data = &self.data[self.len..];
if self.data.is_empty() {
return;
}
self.block = u16::from(self.data[0]) << 8;
self.len = usize::from(self.data[1]);
self.data = &self.data[2..];
self.octet = 0;
}
}
if self.data[self.octet] & (0x80 >> self.bit) != 0 {
return
}
}
}
}
impl<'a> Iterator for RtypeBitmapIter<'a> {
type Item = Rtype;
fn next(&mut self) -> Option<Self::Item> {
if self.data.is_empty() {
return None
}
let res = Rtype::from_int(
self.block | (self.octet as u16) << 3 | self.bit
);
self.advance();
Some(res)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RtypeBitmapError {
ShortInput,
BadRtypeBitmap,
}
impl From<RtypeBitmapError> for ParseError {
fn from(err: RtypeBitmapError) -> ParseError {
match err {
RtypeBitmapError::ShortInput => ParseError::ShortInput,
RtypeBitmapError::BadRtypeBitmap => {
FormError::new("invalid NSEC bitmap").into()
}
}
}
}
impl fmt::Display for RtypeBitmapError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
RtypeBitmapError::ShortInput
=> ParseError::ShortInput.fmt(f),
RtypeBitmapError::BadRtypeBitmap
=> f.write_str("invalid record type bitmap")
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for RtypeBitmapError { }
fn split_rtype(rtype: Rtype) -> (u8, usize, u8) {
let rtype = rtype.to_int();
(
(rtype >> 8) as u8,
((rtype & 0xFF) >> 3) as usize,
0b1000_0000 >> (rtype & 0x07)
)
}
#[allow(clippy::type_complexity)]
fn read_window(data: &[u8]) -> Option<((u8, &[u8]), &[u8])> {
data.split_first()
.and_then(|(n, data)| {
data.split_first()
.and_then(|(l, data)| if data.len() >= usize::from(*l) {
let (window, data) = data.split_at(usize::from(*l));
Some(((*n, window), data))
} else {
None
})
})
}
#[cfg(test)]
mod test {
use std::vec::Vec;
use crate::base::iana::Rtype;
use super::*;
#[test]
fn rtype_split() {
assert_eq!(split_rtype(Rtype::A), (0, 0, 0b01000000));
assert_eq!(split_rtype(Rtype::Ns), (0, 0, 0b00100000));
assert_eq!(split_rtype(Rtype::Caa), (1, 0, 0b01000000));
}
#[test]
fn rtype_bitmap_read_window() {
let mut builder = RtypeBitmapBuilder::new_vec();
builder.add(Rtype::A).unwrap();
builder.add(Rtype::Caa).unwrap();
let bitmap = builder.finalize();
let ((n, window), data) = read_window(bitmap.as_slice()).unwrap();
assert_eq!((n, window), (0u8, b"\x40".as_ref()));
let ((n, window), data) = read_window(data).unwrap();
assert_eq!((n, window), (1u8, b"\x40".as_ref()));
assert!(data.is_empty());
assert!(read_window(data).is_none());
}
#[test]
fn rtype_bitmap_builder() {
let mut builder = RtypeBitmapBuilder::new_vec();
builder.add(Rtype::Int(1234)).unwrap();
builder.add(Rtype::A).unwrap();
builder.add(Rtype::Mx).unwrap();
builder.add(Rtype::Rrsig).unwrap();
builder.add(Rtype::Nsec).unwrap();
let bitmap = builder.finalize();
assert_eq!(
bitmap.as_slice(),
&b"\x00\x06\x40\x01\x00\x00\x00\x03\
\x04\x1b\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x20"[..]
);
assert!(bitmap.contains(Rtype::A));
assert!(bitmap.contains(Rtype::Mx));
assert!(bitmap.contains(Rtype::Rrsig));
assert!(bitmap.contains(Rtype::Nsec));
assert!(bitmap.contains(Rtype::Int(1234)));
assert!(!bitmap.contains(Rtype::Int(1235)));
assert!(!bitmap.contains(Rtype::Ns));
}
#[test]
fn rtype_bitmap_iter() {
let mut builder = RtypeBitmapBuilder::new_vec();
let types = vec![
Rtype::Ns, Rtype::Soa, Rtype::Mx, Rtype::Txt, Rtype::Rrsig,
Rtype::Dnskey, Rtype::Nsec3param, Rtype::Spf, Rtype::Caa
];
for t in types.iter() {
builder.add(*t).unwrap();
}
let bitmap = builder.finalize();
let bitmap_types: Vec<_> = bitmap.iter().collect();
assert_eq!(types, bitmap_types);
}
#[test]
#[cfg(feature = "bytes")]
fn dnskey_key_tag() {
assert_eq!(
Dnskey::new(
256, 3, SecAlg::RsaSha256,
base64::decode(
"AwEAAcTQyaIe6nt3xSPOG2L/YfwBkOVTJN6mlnZ249O5Rtt3ZSRQHxQS\
W61AODYw6bvgxrrGq8eeOuenFjcSYgNAMcBYoEYYmKDW6e9EryW4ZaT/\
MCq+8Am06oR40xAA3fClOM6QjRcT85tP41Go946AicBGP8XOP/Aj1aI/\
oPRGzRnboUPUok/AzTNnW5npBU69+BuiIwYE7mQOiNBFePyvjQBdoiuY\
bmuD3Py0IyjlBxzZUXbqLsRL9gYFkCqeTY29Ik7usuzMTa+JRSLz6KGS\
5RSJ7CTSMjZg8aNaUbN2dvGhakJPh92HnLvMA3TefFgbKJphFNPA3BWS\
KLZ02cRWXqM="
).unwrap()
).key_tag(),
59944
);
assert_eq!(
Dnskey::new(
257, 3, SecAlg::RsaSha256,
base64::decode(
"AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTO\
iW1vkIbzxeF3+/4RgWOq7HrxRixHlFlExOLAJr5emLvN\
7SWXgnLh4+B5xQlNVz8Og8kvArMtNROxVQuCaSnIDdD5\
LKyWbRd2n9WGe2R8PzgCmr3EgVLrjyBxWezF0jLHwVN8\
efS3rCj/EWgvIWgb9tarpVUDK/b58Da+sqqls3eNbuv7\
pr+eoZG+SrDK6nWeL3c6H5Apxz7LjVc1uTIdsIXxuOLY\
A4/ilBmSVIzuDWfdRUfhHdY6+cn8HFRm+2hM8AnXGXws\
9555KrUB5qihylGa8subX2Nn6UwNR1AkUTV74bU="
).unwrap()
).key_tag(),
20326
);
assert_eq!(
Dnskey::new(
257, 3, SecAlg::RsaMd5,
base64::decode(
"AwEAAcVaA4jSBIGRrSzpecoJELvKE9+OMuFnL8mmUBsY\
lB6epN1CqX7NzwjDpi6VySiEXr0C4uTYkU/L1uMv2mHE\
AljThFDJ1GuozJ6gA7jf3lnaGppRg2IoVQ9IVmLORmjw\
C+7Eoi12SqybMTicD3Ezwa9XbG1iPjmjhbMrLh7MSQpX"
).unwrap()
).key_tag(),
18698
);
}
#[test]
#[cfg(feature = "bytes")]
fn dnskey_flags() {
let dnskey = Dnskey::new(
257, 3, SecAlg::RsaSha256, bytes::Bytes::new()
);
assert_eq!(dnskey.is_zsk(), true);
assert_eq!(dnskey.is_secure_entry_point(), true);
assert_eq!(dnskey.is_revoked(), false);
}
}