use {SerialNumber, Ttl, std};
pub trait Format<'a> {
type Name: Name<'a>;
type RawOctets: AsRef<[u8]> + Clone + std::fmt::Debug + Eq + PartialEq;
}
pub trait Name<'a>: std::fmt::Display {
type LabelIter: Iterator<Item = &'a str>;
fn labels(&'a self) -> Self::LabelIter;
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Question<'a, F: Format<'a>> {
qname: F::Name,
qtype: QType,
qclass: QClass,
}
impl<'a, F: Format<'a>> Question<'a, F> {
pub fn new<N: Into<F::Name>>(qname: N, qtype: QType, qclass: QClass) -> Self {
Question {
qname: qname.into(),
qtype: qtype,
qclass: qclass,
}
}
pub fn qname(&self) -> &F::Name {
&self.qname
}
pub fn qtype(&self) -> QType {
self.qtype
}
pub fn qclass(&self) -> QClass {
self.qclass
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ResourceRecord<'a, F: Format<'a>> {
name: F::Name,
type_: Type,
class: Class,
ttl: Ttl,
rdata: RData<'a, F>,
}
impl<'a, F: Format<'a>> ResourceRecord<'a, F> {
pub fn new<N: Into<F::Name>, IntoT: Into<Ttl>, R: Into<RData<'a, F>>>(name: N,
type_: Type,
class: Class,
ttl: IntoT,
rdata: R)
-> Self {
ResourceRecord {
name: name.into(),
type_: type_,
class: class,
ttl: ttl.into(),
rdata: rdata.into(),
}
}
pub fn name(&self) -> &F::Name {
&self.name
}
pub fn type_(&self) -> Type {
self.type_
}
pub fn class(&self) -> Class {
self.class
}
pub fn ttl(&self) -> Ttl {
self.ttl
}
pub fn rdata(&self) -> &RData<'a, F> {
&self.rdata
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum RData<'a, F: Format<'a>> {
A { address: std::net::Ipv4Addr },
CName { cname: F::Name },
NS { nsdname: F::Name },
SOA {
mname: F::Name,
rname: F::Name,
serial: SerialNumber,
refresh: Ttl,
retry: Ttl,
expire: Ttl,
minimum: Ttl,
},
Other { octets: F::RawOctets },
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Class(pub u16);
impl Class {
pub fn as_u16(&self) -> u16 {
self.0
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct QClass(pub u16);
impl QClass {
pub fn as_u16(&self) -> u16 {
self.0
}
}
impl From<QClass> for Class {
fn from(x: QClass) -> Self {
Class(x.0)
}
}
pub mod class {
use super::Class;
pub const IN: Class = Class(1);
}
pub mod qclass {
use super::QClass;
pub const IN: QClass = QClass(1);
pub const ANY: QClass = QClass(255);
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Type(pub u16);
impl Type {
pub fn as_u16(&self) -> u16 {
self.0
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct QType(pub u16);
impl QType {
pub fn as_u16(&self) -> u16 {
self.0
}
}
impl From<QType> for Type {
fn from(x: QType) -> Self {
Type(x.0)
}
}
pub mod type_ {
use super::Type;
pub const A: Type = Type(1);
pub const NS: Type = Type(2);
pub const CNAME: Type = Type(5);
pub const SOA: Type = Type(6);
}
pub mod qtype {
use super::QType;
pub const A: QType = QType(1);
pub const NS: QType = QType(2);
pub const CNAME: QType = QType(5);
pub const SOA: QType = QType(6);
pub const ANY: QType = QType(255);
}
pub fn is_label_valid(s: &[u8]) -> bool {
debug_assert!(!s.is_empty());
let c = *s.first().unwrap() as char;
if !c.is_alphabetic() {
return false;
}
let c = *s.last().unwrap() as char;
if !c.is_alphanumeric() {
return false;
}
s.iter().map(|&b| b as char).all(|c| c.is_alphanumeric() || c == '-')
}
#[cfg(test)]
mod tests {
#[test]
fn is_label_valid() {
let f = |s: &str| super::is_label_valid(s.as_bytes());
assert!(f("a"));
assert!(f("alpha"));
assert!(f("alpha17"));
assert!(f("alpha-bravo"));
assert!(f("alpha-bravo17"));
assert!(!f("-alpha-bravo17"));
assert!(!f("1alpha"));
assert!(!f("-alpha"));
assert!(!f("alpha-"));
assert!(!f("alpha.bravo"));
}
}