use crate::{Buffer, DnsMessage, DnsMessageError};
use crate::name::DnsName;
use crate::parse::{Parse, ParseBytes};
use crate::write::WriteBytes;
pub struct DnsQuestions<
const PTR_STORAGE: usize,
B: Buffer,
> {
message: DnsMessage<PTR_STORAGE, 0, B>,
remaining: usize,
}
impl<
const PTR_STORAGE: usize,
B: Buffer,
> DnsQuestions<PTR_STORAGE, B> {
#[inline(always)]
pub(crate) fn new(message: DnsMessage<PTR_STORAGE, 0, B>) -> Self {
let remaining = message.header().unwrap().question_count() as usize;
Self {
message,
remaining,
}
}
pub fn append(&mut self, question: DnsQuestion) -> Result<(), DnsMessageError> {
let (buffer, position) = self.message.buffer_and_position();
buffer.truncate(*position)?;
question.write(&mut self.message)?;
let question_count = self.message.header().unwrap().question_count();
let question_count = question_count + 1 - self.remaining as u16;
self.message.header_mut()?.set_question_count(question_count);
self.message.header_mut()?.set_answer_count(0);
self.message.header_mut()?.set_name_server_count(0);
self.message.header_mut()?.set_additional_records_count(0);
self.remaining = 0;
Ok(())
}
#[inline(always)]
pub fn iter(&mut self) -> Result<DnsQuestionIterator, DnsMessageError> {
let (buffer, position) = self.message.buffer_and_position();
let buffer = buffer.bytes();
Ok(DnsQuestionIterator {
buffer,
current_position: position,
remaining: &mut self.remaining,
})
}
#[inline(always)]
pub fn complete(mut self) -> Result<DnsMessage<PTR_STORAGE, 1, B>, DnsMessageError> {
if self.remaining != 0 {
for x in self.iter()? { x?; }
}
Ok(DnsMessage {
buffer: self.message.buffer,
position: self.message.position,
ptr_storage: self.message.ptr_storage,
ptr_len: self.message.ptr_len,
})
}
}
pub struct DnsQuestionIterator<'a> {
buffer: &'a [u8],
current_position: &'a mut usize,
remaining: &'a mut usize,
}
impl<'a> Iterator for DnsQuestionIterator<'a> {
type Item = Result<DnsQuestion<'a>, DnsMessageError>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if *self.remaining == 0 {
return None;
}
let question = DnsQuestion::parse(
self.buffer, self.current_position
);
*self.remaining -= 1;
Some(question)
}
}
#[derive(Debug, PartialEq)]
pub struct DnsQuestion<'a> {
pub name: DnsName<'a>,
pub qtype: DnsQType,
pub qclass: DnsQClass,
}
impl<'a> ParseBytes<'a> for DnsQuestion<'a> {
fn parse_bytes(bytes: &'a [u8], i: &mut usize) -> Result<Self, DnsMessageError> {
let name = DnsName::parse(bytes, i)?;
let qtype = u16::parse(bytes, i)?.into();
let qclass = u16::parse(bytes, i)?.into();
Ok(Self {
name,
qtype,
qclass,
})
}
}
impl<'a> WriteBytes for DnsQuestion<'a> {
fn write<
const PTR_STORAGE: usize,
const DNS_SECTION: usize,
B: Buffer,
>(&self, message: &mut DnsMessage<PTR_STORAGE, DNS_SECTION, B>) -> Result<usize, DnsMessageError> {
let mut bytes = 0;
bytes += self.name.write(message)?;
bytes += self.qtype.id().write(message)?;
bytes += self.qclass.id().write(message)?;
Ok(bytes)
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(u16)]
pub enum DnsQType {
A = 1,
NS = 2,
CNAME = 5,
SOA = 6,
PTR = 12,
HINFO = 13,
MX = 15,
TXT = 16,
RP = 17,
AFSDB = 18,
SIG = 24,
KEY = 25,
AAAA = 28,
LOC = 29,
SRV = 33,
NAPTR = 35,
KX = 36,
CERT = 37,
DNAME = 39,
OPT = 41,
APL = 42,
DS = 43,
SSHFP = 44,
IPSECKEY = 45,
RRSIG = 46,
NSEC = 47,
DNSKEY = 48,
DHCID = 49,
NSEC3 = 50,
NSEC3PARAM = 51,
TLSA = 52,
SMIMEA = 53,
HIP = 55,
CDS = 59,
CDNSKEY = 60,
OPENPGPKEY = 61,
CSYNC = 62,
ZONEMD = 63,
SVCB = 64,
HTTPS = 65,
EUI48 = 108,
EUI64 = 109,
TKEY = 249,
TSIG = 250,
IXFR = 251,
AXFR = 252,
ALL = 255,
URI = 256,
CAA = 257,
TA = 32768,
DLV = 32769,
Reserved,
}
impl DnsQType {
#[inline(always)]
pub fn from_id(id: u16) -> Self {
match id {
1..=2 | 5..=6 | 12..=13 | 15..=18 | 24..=25 | 28..=29
| 33 | 35..=37 | 39 | 41..=53 | 55 | 59..=65
| 108..=109 | 249..=252 | 255 | 256 | 257
| 32768..=32769 => unsafe {
core::mem::transmute(id)
},
_ => DnsQType::Reserved,
}
}
#[inline(always)]
pub fn id(&self) -> u16 {
match self {
DnsQType::Reserved => panic!("Reserved QType"),
_ => *self as u16,
}
}
}
impl From<DnsQType> for u16 {
#[inline(always)]
fn from(q: DnsQType) -> Self {
DnsQType::id(&q)
}
}
impl From<u16> for DnsQType {
#[inline(always)]
fn from(n: u16) -> Self {
DnsQType::from_id(n)
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(u16)]
pub enum DnsQClass {
IN = 1,
CS = 2,
CH = 3,
HS = 4,
ANY = 255,
Reserved,
}
impl DnsQClass {
#[inline(always)]
pub fn from_id(id: u16) -> Self {
match id {
1..=4 | 255 => unsafe { core::mem::transmute(id) },
_ => DnsQClass::Reserved,
}
}
#[inline(always)]
pub fn id(&self) -> u16 {
match self {
DnsQClass::Reserved => panic!("Reserved QClass"),
_ => *self as u16,
}
}
}
impl From<DnsQClass> for u16 {
#[inline(always)]
fn from(q: DnsQClass) -> Self {
DnsQClass::id(&q)
}
}
impl From<u16> for DnsQClass {
#[inline(always)]
fn from(n: u16) -> Self {
DnsQClass::from_id(n)
}
}