Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rdata/rfc6672: added Dname type support #58

Merged
merged 1 commit into from
Apr 17, 2020
Merged
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
149 changes: 149 additions & 0 deletions domain/src/rdata/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -703,3 +703,152 @@ macro_rules! rdata_types {
}
}


//------------ dname_type! --------------------------------------------------

/// A macro for implementing a record data type with a single domain name.
///
/// Implements some basic methods plus the `RecordData`, `FlatRecordData`,
/// and `Display` traits.
macro_rules! dname_type {
($(#[$attr:meta])* ( $target:ident, $rtype:ident, $field:ident ) ) => {
$(#[$attr])*
#[derive(Clone, Debug)]
pub struct $target<N> {
$field: N
}

impl<N> $target<N> {
pub fn new($field: N) -> Self {
$target { $field: $field }
}

pub fn $field(&self) -> &N {
&self.$field
}
}

//--- From and FromStr

impl<N> From<N> for $target<N> {
fn from(name: N) -> Self {
Self::new(name)
}
}

impl<N: FromStr> FromStr for $target<N> {
type Err = N::Err;

fn from_str(s: &str) -> Result<Self, Self::Err> {
N::from_str(s).map(Self::new)
}
}


//--- PartialEq and Eq

impl<N, NN> PartialEq<$target<NN>> for $target<N>
where N: ToDname, NN: ToDname {
fn eq(&self, other: &$target<NN>) -> bool {
self.$field.name_eq(&other.$field)
}
}

impl<N: ToDname> Eq for $target<N> { }


//--- PartialOrd, Ord, and CanonicalOrd

impl<N, NN> PartialOrd<$target<NN>> for $target<N>
where N: ToDname, NN: ToDname {
fn partial_cmp(&self, other: &$target<NN>) -> Option<Ordering> {
Some(self.$field.name_cmp(&other.$field))
}
}

impl<N: ToDname> Ord for $target<N> {
fn cmp(&self, other: &Self) -> Ordering {
self.$field.name_cmp(&other.$field)
}
}

impl<N: ToDname, NN: ToDname> CanonicalOrd<$target<NN>> for $target<N> {
fn canonical_cmp(&self, other: &$target<NN>) -> Ordering {
self.$field.lowercase_composed_cmp(&other.$field)
}
}


//--- Hash

impl<N: hash::Hash> hash::Hash for $target<N> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.$field.hash(state)
}
}


//--- Parse and Compose

impl<Ref: OctetsRef> Parse<Ref> for $target<ParsedDname<Ref>> {
fn parse(parser: &mut Parser<Ref>) -> Result<Self, ParseError> {
ParsedDname::parse(parser).map(Self::new)
}

fn skip(parser: &mut Parser<Ref>) -> Result<(), ParseError> {
ParsedDname::skip(parser).map_err(Into::into)
}
}

impl<N: ToDname> Compose for $target<N> {
fn compose<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
target.append_compressed_dname(&self.$field)
}

fn compose_canonical<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
self.$field.compose_canonical(target)
}
}


//--- Scan and Display

#[cfg(feature="master")]
impl<N: Scan> Scan for $target<N> {
fn scan<C: CharSource>(scanner: &mut Scanner<C>)
-> Result<Self, ScanError> {
N::scan(scanner).map(Self::new)
}
}

impl<N: fmt::Display> fmt::Display for $target<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}.", self.$field)
}
}


//--- RtypeRecordData

impl<N> RtypeRecordData for $target<N> {
const RTYPE: Rtype = Rtype::$rtype;
}


//--- Deref

impl<N> ops::Deref for $target<N> {
type Target = N;

fn deref(&self) -> &Self::Target {
&self.$field
}
}
}
}
12 changes: 9 additions & 3 deletions domain/src/rdata/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,18 @@
//! [`MasterRecordData`]: enum.MasterRecordData.html
//! [`base::iana::Rtype`]: ../base/iana/enum.Rtype.html

#[macro_use]
mod macros;

pub mod rfc1035;
pub mod rfc2782;
pub mod rfc2845;
pub mod rfc3596;
pub mod rfc4034;
pub mod rfc6672;
pub mod rfc5155;
pub mod rfc7344;

#[macro_use]
mod macros;

// The rdata_types! macro (defined in self::macros) reexports the record data
// types here and creates the MasterRecordData and AllRecordData enums
// containing all record types that can appear in master files or all record
Expand Down Expand Up @@ -95,6 +96,11 @@ rdata_types! {
Ds<O>,
}
}
rfc6672::{
master {
Dname<N>,
}
}
rfc5155::{
master {
Nsec3<O>,
Expand Down
151 changes: 0 additions & 151 deletions domain/src/rdata/rfc1035.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,157 +25,6 @@ use crate::base::serial::Serial;
CharSource, ScanError, Scan, Scanner, SyntaxError
};


//------------ dname_type! --------------------------------------------------

/// A macro for implementing a record data type with a single domain name.
///
/// Implements some basic methods plus the `RecordData`, `FlatRecordData`,
/// and `Display` traits.
macro_rules! dname_type {
($(#[$attr:meta])* ( $target:ident, $rtype:ident, $field:ident ) ) => {
$(#[$attr])*
#[derive(Clone, Debug)]
pub struct $target<N> {
$field: N
}

impl<N> $target<N> {
pub fn new($field: N) -> Self {
$target { $field: $field }
}

pub fn $field(&self) -> &N {
&self.$field
}
}

//--- From and FromStr

impl<N> From<N> for $target<N> {
fn from(name: N) -> Self {
Self::new(name)
}
}

impl<N: FromStr> FromStr for $target<N> {
type Err = N::Err;

fn from_str(s: &str) -> Result<Self, Self::Err> {
N::from_str(s).map(Self::new)
}
}


//--- PartialEq and Eq

impl<N, NN> PartialEq<$target<NN>> for $target<N>
where N: ToDname, NN: ToDname {
fn eq(&self, other: &$target<NN>) -> bool {
self.$field.name_eq(&other.$field)
}
}

impl<N: ToDname> Eq for $target<N> { }


//--- PartialOrd, Ord, and CanonicalOrd

impl<N, NN> PartialOrd<$target<NN>> for $target<N>
where N: ToDname, NN: ToDname {
fn partial_cmp(&self, other: &$target<NN>) -> Option<Ordering> {
Some(self.$field.name_cmp(&other.$field))
}
}

impl<N: ToDname> Ord for $target<N> {
fn cmp(&self, other: &Self) -> Ordering {
self.$field.name_cmp(&other.$field)
}
}

impl<N: ToDname, NN: ToDname> CanonicalOrd<$target<NN>> for $target<N> {
fn canonical_cmp(&self, other: &$target<NN>) -> Ordering {
self.$field.lowercase_composed_cmp(&other.$field)
}
}


//--- Hash

impl<N: hash::Hash> hash::Hash for $target<N> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.$field.hash(state)
}
}


//--- Parse and Compose

impl<Ref: OctetsRef> Parse<Ref> for $target<ParsedDname<Ref>> {
fn parse(parser: &mut Parser<Ref>) -> Result<Self, ParseError> {
ParsedDname::parse(parser).map(Self::new)
}

fn skip(parser: &mut Parser<Ref>) -> Result<(), ParseError> {
ParsedDname::skip(parser).map_err(Into::into)
}
}

impl<N: ToDname> Compose for $target<N> {
fn compose<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
target.append_compressed_dname(&self.$field)
}

fn compose_canonical<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
self.$field.compose_canonical(target)
}
}


//--- Scan and Display

#[cfg(feature="master")]
impl<N: Scan> Scan for $target<N> {
fn scan<C: CharSource>(scanner: &mut Scanner<C>)
-> Result<Self, ScanError> {
N::scan(scanner).map(Self::new)
}
}

impl<N: fmt::Display> fmt::Display for $target<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}.", self.$field)
}
}


//--- RtypeRecordData

impl<N> RtypeRecordData for $target<N> {
const RTYPE: Rtype = Rtype::$rtype;
}


//--- Deref

impl<N> ops::Deref for $target<N> {
type Target = N;

fn deref(&self) -> &Self::Target {
&self.$field
}
}
}
}


//------------ A ------------------------------------------------------------

/// A record data.
Expand Down
37 changes: 37 additions & 0 deletions domain/src/rdata/rfc6672.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use crate::base::cmp::CanonicalOrd;
use crate::base::iana::Rtype;
use crate::base::name::{ParsedDname, ToDname};
use crate::base::octets::{Compose, OctetsBuilder, OctetsRef, Parse, ParseError, Parser, ShortBuf};
use crate::base::rdata::RtypeRecordData;
#[cfg(feature = "master")]
use crate::master::scan::{CharSource, Scan, ScanError, Scanner};
use core::cmp::Ordering;
use core::str::FromStr;
use core::{fmt, hash, ops};

//------------ Dname --------------------------------------------------------

dname_type! {
/// DNAME record data.
///
/// The DNAME record provides redirection for a subtree of the domain
/// name tree in the DNS.
///
/// The DNAME type is defined in RFC 6672.
(Dname, Dname, dname)
}

#[cfg(test)]
mod test {
use crate::base::name::Dname;
use crate::rdata::rfc6672;
use core::str::FromStr;
use std::vec::Vec;

#[test]
fn create_dname() {
let name = Dname::<Vec<u8>>::from_str("bar.example.com").unwrap();
let rdata = rfc6672::Dname::new(name.clone());
assert_eq!(rdata.dname(), &name);
}
}