use core::fmt::{Debug, Display, Formatter};
use core::hash::Hash;
use crate::{Buffer, DnsError, DnsMessage, DnsMessageError, MutBuffer};
use crate::parse::ParseBytes;
use crate::write::WriteBytes;
const MAX_DOMAIN_NAME_DEPTH: usize = 128;
const MAX_DOMAIN_NAME_LABEL_LENGTH: usize = 63;
#[derive(Clone, Copy)]
pub struct DnsName<'a> {
bytes: &'a [u8],
offset: usize,
}
#[macro_export]
macro_rules! dns_name {
($value:expr $(,)?) => {
{
const NAME: [u8; $value.len() + 2] = {
let mut result = [0; $value.len() + 2];
let mut label_start = 0;
let mut index = 0;
loop {
if index == $value.len() {
if index - label_start > u8::MAX as usize {
panic!("Label too long, maximum length is 255.");
}
result[label_start] = (index - label_start) as u8;
break;
}
let byte = $value[index];
if byte == b'.' {
if index - label_start > u8::MAX as usize {
panic!("Label too long, maximum length is 255.");
}
result[label_start] = (index - label_start) as u8;
label_start = index + 1;
} else {
result[index + 1] = byte;
}
index += 1;
}
result
};
unsafe { flex_dns::name::DnsName::new_unchecked(&NAME) }
}
};
}
impl<'a> DnsName<'a> {
#[inline(always)]
pub fn new(bytes: &'a [u8]) -> Result<Self, DnsMessageError> {
for part in (NameIterator {
bytes,
offset: 0,
depth: 0,
}) {
part?;
}
Ok(Self { bytes, offset: 0 })
}
#[inline(always)]
pub const unsafe fn new_unchecked(bytes: &'a [u8]) -> Self {
Self { bytes, offset: 0 }
}
#[inline(always)]
pub fn iter(&self) -> NameIterator<'a> {
NameIterator {
bytes: self.bytes,
offset: self.offset,
depth: 0,
}
}
pub(crate) fn split_first(&self) -> Result<(&'a [u8], Option<Self>), DnsMessageError> {
let mut iter = self.iter();
let first = iter.next().unwrap()?;
if let Some(next) = iter.next() {
let next = next?;
let offset = next.as_ptr() as usize - self.bytes.as_ptr() as usize - 1;
Ok((first, Some(Self {
bytes: self.bytes,
offset,
})))
} else {
Ok((first, None))
}
}
}
impl<'a> ParseBytes<'a> for DnsName<'a> {
#[inline]
fn parse_bytes(bytes: &'a [u8], i: &mut usize) -> Result<Self, DnsMessageError> {
const MAX_LENGTH: usize = 255;
let mut j = *i;
loop {
if j - *i >= MAX_LENGTH {
return Err(DnsMessageError::DnsError(DnsError::NameTooLong));
}
match LabelType::from_bytes(bytes, &mut j)? {
LabelType::Pointer(_) => {
break;
}
LabelType::Part(len) => {
j += len as usize;
if len == 0 {
break;
}
if len > MAX_DOMAIN_NAME_LABEL_LENGTH as u8 {
return Err(DnsMessageError::DnsError(DnsError::LabelTooLong));
}
}
}
}
let offset = *i;
*i = j;
Ok(Self { bytes, offset })
}
}
impl<'a> WriteBytes for DnsName<'a> {
#[inline(always)]
fn write<
const PTR_STORAGE: usize,
const DNS_SECTION: usize,
B: MutBuffer + Buffer,
>(&self, message: &mut DnsMessage<PTR_STORAGE, DNS_SECTION, B>) -> Result<usize, DnsMessageError> {
message.write_name(*self)
}
}
pub struct NameIterator<'a> {
bytes: &'a [u8],
offset: usize,
depth: usize,
}
impl<'a> NameIterator<'a> {
pub fn cycle_safe(self) -> CycleSafeNameIterator<'a> {
CycleSafeNameIterator {
iter: self,
depth: [0; MAX_DOMAIN_NAME_DEPTH],
}
}
}
impl<'a> Iterator for NameIterator<'a> {
type Item = Result<&'a [u8], DnsMessageError>;
fn next(&mut self) -> Option<Self::Item> {
let mut i = self.offset;
loop {
self.depth += 1;
if self.depth > MAX_DOMAIN_NAME_DEPTH {
return Some(Err(DnsMessageError::DnsError(DnsError::NameTooLong)));
}
match LabelType::from_bytes(self.bytes, &mut i).unwrap() {
LabelType::Pointer(ptr) => {
if ptr < self.offset as u16 {
i = ptr as usize;
continue;
} else {
return Some(Err(DnsMessageError::DnsError(DnsError::PointerIntoTheFuture)));
}
}
LabelType::Part(len) => {
if len == 0 {
return None;
}
if len > MAX_DOMAIN_NAME_LABEL_LENGTH as u8 {
return Some(Err(DnsMessageError::DnsError(DnsError::LabelTooLong)));
}
if self.bytes.len() < i + len as usize {
return Some(Err(DnsMessageError::DnsError(DnsError::MessageTooShort)));
}
let part = &self.bytes[i..i + len as usize];
self.offset = i + len as usize;
return Some(Ok(part))
}
}
}
}
}
pub struct CycleSafeNameIterator<'a> {
iter: NameIterator<'a>,
depth: [usize; MAX_DOMAIN_NAME_DEPTH],
}
impl<'a> Iterator for CycleSafeNameIterator<'a> {
type Item = Result<&'a [u8], DnsMessageError>;
fn next(&mut self) -> Option<Self::Item> {
let next = self.iter.next();
if let Some(Ok(part)) = next {
let part = part.as_ptr() as usize;
for &known_part in &self.depth[..self.iter.depth - 1] {
if known_part == part {
return Some(Err(DnsMessageError::DnsError(DnsError::PointerCycle)));
}
}
self.depth[self.iter.depth - 1] = part;
}
next
}
}
impl PartialEq<DnsName<'_>> for DnsName<'_> {
fn eq(&self, other: &DnsName<'_>) -> bool {
for (a, b) in self.iter().zip(other.iter()) {
match (a, b) {
(Ok(a), Ok(b)) => {
if a != b {
return false;
}
}
_ => {
return false;
}
}
}
true
}
}
impl Hash for DnsName<'_> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
for part in self.iter() {
if let Err(_) = part {
return;
}
let part = part.unwrap();
state.write_u8(part.len() as u8);
state.write(part);
}
}
}
impl Display for DnsName<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
let mut first = true;
for part in self.iter() {
if first {
first = false;
} else {
f.write_str(".")?;
}
let part = part.map_err(|_| core::fmt::Error)?;
f.write_str(core::str::from_utf8(part).unwrap())?;
}
Ok(())
}
}
impl Debug for DnsName<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.write_str("DnsName(")?;
Display::fmt(self, f)?;
f.write_str(")")?;
Ok(())
}
}
#[derive(PartialEq)]
enum LabelType {
Pointer(u16),
Part(u8),
}
impl LabelType {
fn from_bytes(bytes: &[u8], i: &mut usize) -> Result<Self, DnsMessageError> {
const PTR_MASK: u8 = 0b11000000;
const LEN_MASK: u8 = !PTR_MASK;
let c = u8::parse_bytes(bytes, i)?;
if c & PTR_MASK == PTR_MASK {
let c = c & LEN_MASK;
let pointer = u16::from_be_bytes([c, u8::parse_bytes(bytes, i)?]);
if pointer >= *i as u16 {
return Err(DnsMessageError::DnsError(DnsError::PointerIntoTheFuture));
}
Ok(Self::Pointer(pointer))
} else {
let len = c & LEN_MASK;
Ok(Self::Part(len))
}
}
}