pub mod name;
use crate::binutils::*;
use crate::body::name::Name;
use crate::ParseError;
use std::borrow::Cow;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::str;
const INIT_RR_SIZE: usize = 64;
macro_rules! types {
(
$(
#[$inner:meta]
$variant:tt = $value:literal
)+
) => {
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd)]
pub enum Type {
$(
#[$inner]
$variant,
)*
Unknown(u16),
}
impl TryFrom<QType> for Type {
type Error = &'static str;
#[inline]
fn try_from(value: QType) -> Result<Self, Self::Error> {
match value {
$(QType::$variant => Ok(Self::$variant),)*
QType::Unknown(n) => Ok(Self::Unknown(n)),
_ => Err("QType is not a valid Type")
}
}
}
impl From<u16> for Type {
#[inline]
fn from(value: u16) -> Self {
match value {
$($value => Self::$variant,)*
_ => Self::Unknown(value),
}
}
}
impl From<Type> for u16 {
#[inline]
fn from(value: Type) -> Self {
match value {
$(Type::$variant => $value,)*
Type::Unknown(n) => n,
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd)]
pub enum QType {
$(
#[$inner]
$variant,
)*
All,
Unknown(u16),
}
impl From<Type> for QType {
#[inline]
fn from(value: Type) -> Self {
match value {
$(Type::$variant => Self::$variant,)*
Type::Unknown(n) => Self::Unknown(n),
}
}
}
impl From<u16> for QType {
#[inline]
fn from(value: u16) -> Self {
match value {
$($value => Self::$variant,)*
255 => Self::All,
_ => Self::Unknown(value),
}
}
}
impl From<QType> for u16 {
#[inline]
fn from(value: QType) -> Self {
match value {
$(QType::$variant => $value,)*
QType::All => 255,
QType::Unknown(n) => n,
}
}
}
};
}
#[derive(Clone, Debug)]
pub struct Question<'a> {
pub name: Name<'a>,
pub qtype: QType,
pub class: Class,
}
impl From<Question<'_>> for Vec<u8> {
#[inline]
fn from(question: Question<'_>) -> Self {
let mut out = question.name.into();
push_u16(&mut out, question.qtype.into());
push_u16(&mut out, question.class.into());
out
}
}
impl<'a> Question<'a> {
#[inline]
pub fn parse(buff: &'a [u8], start: usize) -> Result<(Self, usize), crate::ParseError> {
let (name, size) = Name::parse(buff, start)?;
let n = start + size;
Ok((
Question {
name,
qtype: safe_u16_read(buff, n)?.into(),
class: safe_u16_read(buff, n + 2)?.into(),
},
size + 4,
))
}
#[inline]
pub fn serialize(&self, packet: &mut Vec<u8>) {
self.name.serialize(packet);
push_u16(packet, self.qtype.into());
push_u16(packet, self.class.into());
}
}
#[derive(Debug, Clone)]
pub struct ResourceRecord<'a> {
pub preamble: RecordPreamble<'a>,
pub data: RecordData<'a>,
}
impl From<ResourceRecord<'_>> for Vec<u8> {
#[inline]
fn from(rr: ResourceRecord<'_>) -> Self {
let mut out = Vec::with_capacity(INIT_RR_SIZE);
rr.serialize(&mut out);
out
}
}
impl<'a> ResourceRecord<'a> {
#[inline]
pub fn parse(buff: &'a [u8], pos: usize) -> Result<(Self, usize), ParseError> {
let (preamble, size) = RecordPreamble::parse(buff, pos)?;
let (data, len) = RecordData::parse(buff, pos + size, &preamble)?;
Ok((Self { preamble, data }, size + len))
}
#[inline]
pub fn serialize(&self, packet: &mut Vec<u8>) {
self.preamble.serialize(packet);
self.data.serialize(packet);
}
}
#[derive(Debug, Clone)]
pub struct RecordPreamble<'a> {
pub name: Name<'a>,
pub rrtype: Type,
pub class: Class,
pub ttl: i32,
pub rdlen: u16,
}
impl<'a> RecordPreamble<'a> {
#[inline]
fn parse(buff: &'a [u8], pos: usize) -> Result<(Self, usize), ParseError> {
let (name, size) = Name::parse(buff, pos)?;
let n = size + pos;
Ok((
RecordPreamble {
name,
rrtype: safe_u16_read(buff, n)?.into(),
class: safe_u16_read(buff, n + 2)?.into(),
ttl: safe_i32_read(buff, n + 4)?,
rdlen: safe_u16_read(buff, n + 8)?,
},
size + 10,
))
}
#[inline]
fn serialize(&self, packet: &mut Vec<u8>) {
self.name.serialize(packet);
push_u16(packet, self.rrtype.into());
push_u16(packet, self.class.into());
push_i32(packet, self.ttl);
push_u16(packet, self.rdlen);
}
}
#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum RecordData<'a> {
A(Ipv4Addr),
Ns(Name<'a>),
Cname(Name<'a>),
Mx {
preference: u16,
exchange: Name<'a>,
},
Txt(Cow<'a, str>),
Aaaa(Ipv6Addr),
Unknown(Cow<'a, [u8]>),
}
impl<'a> RecordData<'a> {
#[inline]
fn parse(
buff: &'a [u8],
pos: usize,
rrpreamble: &RecordPreamble<'_>,
) -> Result<(Self, usize), ParseError> {
match rrpreamble.rrtype {
Type::A => Ok((Self::A(safe_ipv4_read(buff, pos)?), 4)),
Type::Ns => {
let (name, n) = Name::parse(buff, pos)?;
Ok((Self::Ns(name), n))
}
Type::Cname => {
let (name, n) = Name::parse(buff, pos)?;
Ok((Self::Cname(name), n))
}
Type::Mx => {
let (exchange, n) = Name::parse(buff, pos + 2)?;
Ok((
Self::Mx {
preference: safe_u16_read(buff, pos)?,
exchange,
},
n + 2,
))
}
Type::Txt => {
let len = safe_u8_read(buff, pos)?;
let str_bytes = str::from_utf8(&buff[pos..pos + len as usize])?;
Ok((Self::Txt(Cow::from(str_bytes)), len as _))
}
Type::Aaaa => Ok((Self::Aaaa(safe_ipv6_read(buff, pos)?), 16)),
Type::Unknown(_) => {
let len = rrpreamble.rdlen as _;
let end = pos + len;
if buff.len() < end {
Err(ParseError::OobRead(end))?
}
let cow_bytes = Cow::from(&buff[pos..end]);
Ok((Self::Unknown(cow_bytes), len))
}
}
}
#[inline]
fn serialize(&self, packet: &mut Vec<u8>) {
use std::ops::Deref;
match self {
Self::A(ip) => packet.extend(ip.octets()),
Self::Ns(name) => name.serialize(packet),
Self::Cname(name) => name.serialize(packet),
Self::Mx {
preference,
exchange,
} => {
push_u16(packet, *preference);
exchange.serialize(packet);
}
Self::Txt(txt) => {
packet.push(txt.len() as _);
packet.extend(txt.as_bytes());
}
Self::Aaaa(ip) => packet.extend(ip.octets()),
Self::Unknown(buff) => packet.extend(buff.deref()),
}
}
}
types! {
A = 1
Ns = 2
Cname = 5
Mx = 15
Txt = 16
Aaaa = 28
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd)]
pub enum Class {
IN,
CS,
CH,
HS,
Any,
Unknown(u16),
}
impl From<u16> for Class {
#[inline]
fn from(value: u16) -> Self {
match value {
1 => Self::IN,
2 => Self::CS,
3 => Self::CH,
4 => Self::HS,
255 => Self::Any,
_ => Self::Unknown(value),
}
}
}
impl From<Class> for u16 {
#[inline]
fn from(value: Class) -> Self {
match value {
Class::IN => 1,
Class::CS => 2,
Class::CH => 3,
Class::HS => 4,
Class::Any => 255,
Class::Unknown(n) => n,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn class_transformations() {
assert_eq!(Class::IN, From::from(1u16));
assert_eq!(Class::CS, From::from(2u16));
assert_eq!(Class::CH, From::from(3u16));
assert_eq!(Class::HS, From::from(4u16));
assert_eq!(Class::Any, From::from(255u16));
assert_eq!(Class::Unknown(225u16), From::from(225u16));
assert_eq!(1u16, From::from(Class::IN));
assert_eq!(2u16, From::from(Class::CS));
assert_eq!(3u16, From::from(Class::CH));
assert_eq!(4u16, From::from(Class::HS));
assert_eq!(255u16, From::from(Class::Any));
assert_eq!(225u16, From::from(Class::Unknown(225u16)));
}
#[test]
fn qtype_transformations() {
assert_eq!(QType::A, From::from(1u16));
assert_eq!(QType::Ns, From::from(2u16));
assert_eq!(QType::Cname, From::from(5u16));
assert_eq!(QType::Mx, From::from(15u16));
assert_eq!(QType::All, From::from(255u16));
assert_eq!(QType::Unknown(225u16), From::from(225u16));
assert_eq!(1u16, From::from(QType::A));
assert_eq!(2u16, From::from(QType::Ns));
assert_eq!(5u16, From::from(QType::Cname));
assert_eq!(15u16, From::from(QType::Mx));
assert_eq!(255u16, From::from(QType::All));
assert_eq!(225u16, From::from(QType::Unknown(225u16)));
}
}