use super::dig_printer::DigPrinter;
use super::header::{Header, HeaderCounts, HeaderSection};
use super::iana::{Class, OptRcode, Rcode, Rtype};
use super::message_builder::{AdditionalBuilder, AnswerBuilder, PushError};
use super::name::ParsedName;
use super::opt::{Opt, OptRecord};
use super::question::Question;
use super::rdata::{ParseAnyRecordData, ParseRecordData};
use super::record::{ComposeRecord, ParsedRecord, Record};
use super::wire::{Composer, ParseError};
use crate::rdata::rfc1035::Cname;
use core::marker::PhantomData;
use core::{fmt, mem};
use octseq::{Octets, OctetsFrom, Parser};
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Message<Octs: ?Sized> {
octets: Octs,
}
impl<Octs> Message<Octs> {
pub fn from_octets(octets: Octs) -> Result<Self, ShortMessage>
where
Octs: AsRef<[u8]>,
{
Message::check_slice(octets.as_ref())?;
Ok(unsafe { Self::from_octets_unchecked(octets) })
}
pub fn try_from_octets(octets: Octs) -> Result<Self, Octs>
where
Octs: AsRef<[u8]>,
{
if Message::check_slice(octets.as_ref()).is_err() {
Err(octets)
} else {
Ok(unsafe { Self::from_octets_unchecked(octets) })
}
}
pub(super) unsafe fn from_octets_unchecked(octets: Octs) -> Self {
Message { octets }
}
}
impl Message<[u8]> {
pub fn from_slice(slice: &[u8]) -> Result<&Self, ShortMessage> {
Message::check_slice(slice)?;
Ok(unsafe { Self::from_slice_unchecked(slice) })
}
unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self {
mem::transmute(slice)
}
fn check_slice(slice: &[u8]) -> Result<(), ShortMessage> {
if slice.len() < mem::size_of::<HeaderSection>() {
Err(ShortMessage(()))
} else {
Ok(())
}
}
}
impl<Octs: ?Sized> Message<Octs> {
pub fn as_octets(&self) -> &Octs {
&self.octets
}
pub fn into_octets(self) -> Octs
where
Octs: Sized,
{
self.octets
}
pub fn as_slice(&self) -> &[u8]
where
Octs: AsRef<[u8]>,
{
self.octets.as_ref()
}
fn as_slice_mut(&mut self) -> &mut [u8]
where
Octs: AsMut<[u8]>,
{
self.octets.as_mut()
}
pub fn for_slice(&self) -> &Message<[u8]>
where
Octs: AsRef<[u8]>,
{
unsafe { Message::from_slice_unchecked(self.octets.as_ref()) }
}
pub fn for_slice_ref(&self) -> Message<&[u8]>
where
Octs: AsRef<[u8]>,
{
unsafe { Message::from_octets_unchecked(self.octets.as_ref()) }
}
}
impl<Octs: AsRef<[u8]> + ?Sized> Message<Octs> {
pub fn header(&self) -> Header {
*Header::for_message_slice(self.as_slice())
}
pub fn header_mut(&mut self) -> &mut Header
where
Octs: AsMut<[u8]>,
{
Header::for_message_slice_mut(self.as_slice_mut())
}
pub fn header_counts(&self) -> HeaderCounts {
*HeaderCounts::for_message_slice(self.as_slice())
}
pub fn header_section(&self) -> HeaderSection {
*HeaderSection::for_message_slice(self.as_slice())
}
pub fn no_error(&self) -> bool {
self.header().rcode() == Rcode::NOERROR
}
pub fn is_error(&self) -> bool {
self.header().rcode() != Rcode::NOERROR
}
}
impl<Octs: Octets + ?Sized> Message<Octs> {
pub fn question(&self) -> QuestionSection<'_, Octs> {
QuestionSection::new(&self.octets)
}
pub fn zone(&self) -> QuestionSection<'_, Octs> {
self.question()
}
pub fn answer(&self) -> Result<RecordSection<'_, Octs>, ParseError> {
self.question().next_section()
}
pub fn prerequisite(
&self,
) -> Result<RecordSection<'_, Octs>, ParseError> {
self.answer()
}
pub fn authority(&self) -> Result<RecordSection<'_, Octs>, ParseError> {
Ok(self.answer()?.next_section()?.unwrap())
}
pub fn update(&self) -> Result<RecordSection<'_, Octs>, ParseError> {
self.authority()
}
pub fn additional(&self) -> Result<RecordSection<'_, Octs>, ParseError> {
Ok(self.authority()?.next_section()?.unwrap())
}
#[allow(clippy::type_complexity)]
pub fn sections(
&self,
) -> Result<
(
QuestionSection<'_, Octs>,
RecordSection<'_, Octs>,
RecordSection<'_, Octs>,
RecordSection<'_, Octs>,
),
ParseError,
> {
let question = self.question();
let answer = question.next_section()?;
let authority = answer.next_section()?.unwrap();
let additional = authority.next_section()?.unwrap();
Ok((question, answer, authority, additional))
}
pub fn iter(&self) -> MessageIter<'_, Octs> {
self.into_iter()
}
}
impl<Octs: Octets + ?Sized> Message<Octs> {
pub fn is_answer<Other: Octets + ?Sized>(
&self,
query: &Message<Other>,
) -> bool {
if !self.header().qr()
|| self.header().id() != query.header().id()
|| self.header_counts().qdcount()
!= query.header_counts().qdcount()
{
false
} else {
self.question() == query.question()
}
}
pub fn is_xfr(&self) -> bool {
self.first_question()
.map(|q| matches!(q.qtype(), Rtype::AXFR | Rtype::IXFR))
.unwrap_or_default()
}
pub fn first_question(
&self,
) -> Option<Question<ParsedName<Octs::Range<'_>>>> {
match self.question().next() {
None | Some(Err(..)) => None,
Some(Ok(question)) => Some(question),
}
}
pub fn sole_question(
&self,
) -> Result<Question<ParsedName<Octs::Range<'_>>>, ParseError> {
match self.header_counts().qdcount() {
0 => return Err(ParseError::form_error("no question")),
1 => {}
_ => return Err(ParseError::form_error("multiple questions")),
}
self.question().next().unwrap()
}
pub fn qtype(&self) -> Option<Rtype> {
self.first_question().map(|x| x.qtype())
}
pub fn contains_answer<'s, Data>(&'s self) -> bool
where
Data: ParseRecordData<'s, Octs>,
{
let answer = match self.answer() {
Ok(answer) => answer,
Err(..) => return false,
};
answer.limit_to::<Data>().next().is_some()
}
pub fn canonical_name(&self) -> Option<ParsedName<Octs::Range<'_>>> {
let question = self.first_question()?;
let mut name = question.into_qname();
let answer = match self.answer() {
Ok(answer) => answer.limit_to::<Cname<_>>(),
Err(_) => return None,
};
for _ in 0..self.header_counts().ancount() + 1 {
let mut found = false;
for record in answer.clone() {
let record = match record {
Ok(record) => record,
Err(_) => continue,
};
if *record.owner() == name {
name = record.into_data().into_cname();
found = true;
break;
}
}
if !found {
return Some(name);
}
}
None
}
pub fn opt(&self) -> Option<OptRecord<Octs::Range<'_>>> {
match self.additional() {
Ok(section) => match section.limit_to::<Opt<_>>().next() {
Some(Ok(rr)) => Some(OptRecord::from(rr)),
_ => None,
},
Err(_) => None,
}
}
pub fn get_last_additional<'s, Data: ParseRecordData<'s, Octs>>(
&'s self,
) -> Option<Record<ParsedName<Octs::Range<'s>>, Data>> {
let mut section = match self.additional() {
Ok(section) => section,
Err(_) => return None,
};
loop {
match section.count {
Err(_) => return None,
Ok(0) => return None,
Ok(1) => break,
_ => {}
}
let _ = section.next();
}
let record = match ParsedRecord::parse(&mut section.parser) {
Ok(record) => record,
Err(_) => return None,
};
let record = match record.into_record() {
Ok(Some(record)) => record,
_ => return None,
};
Some(record)
}
pub fn remove_last_additional(&mut self)
where
Octs: AsMut<[u8]>,
{
HeaderCounts::for_message_slice_mut(self.octets.as_mut())
.dec_arcount();
}
pub fn copy_records<'s, R, F, T, O>(
&'s self,
target: T,
mut op: F,
) -> Result<AdditionalBuilder<O>, CopyRecordsError>
where
Octs: Octets,
R: ComposeRecord + 's,
F: FnMut(ParsedRecord<'s, Octs>) -> Option<R>,
T: Into<AnswerBuilder<O>>,
O: Composer,
{
let mut source = self.answer()?;
let mut target = target.into();
for rr in &mut source {
let rr = rr?;
if let Some(rr) = op(rr) {
target.push(rr).map_err(CopyRecordsError::Push)?;
}
}
let mut source = source.next_section()?.unwrap();
let mut target = target.authority();
for rr in &mut source {
let rr = rr?;
if let Some(rr) = op(rr) {
target.push(rr).map_err(CopyRecordsError::Push)?;
}
}
let source = source.next_section()?.unwrap();
let mut target = target.additional();
for rr in source {
let rr = rr?;
if let Some(rr) = op(rr) {
target.push(rr).map_err(CopyRecordsError::Push)?;
}
}
Ok(target)
}
pub fn opt_rcode(&self) -> OptRcode {
self.opt()
.map(|opt| opt.rcode(self.header()))
.unwrap_or_else(|| self.header().rcode().into())
}
}
impl<Octs: AsRef<[u8]>> Message<Octs> {
pub fn display_dig_style(&self) -> impl core::fmt::Display + '_ {
DigPrinter { msg: self }
}
}
impl<Octs> AsRef<Octs> for Message<Octs> {
fn as_ref(&self) -> &Octs {
&self.octets
}
}
impl<Octs: AsRef<[u8]> + ?Sized> AsRef<[u8]> for Message<Octs> {
fn as_ref(&self) -> &[u8] {
self.octets.as_ref()
}
}
impl<Octs: AsRef<[u8]> + ?Sized> AsRef<Message<[u8]>> for Message<Octs> {
fn as_ref(&self) -> &Message<[u8]> {
unsafe { Message::from_slice_unchecked(self.octets.as_ref()) }
}
}
impl<Octs, SrcOcts> OctetsFrom<Message<SrcOcts>> for Message<Octs>
where
Octs: OctetsFrom<SrcOcts>,
{
type Error = Octs::Error;
fn try_octets_from(
source: Message<SrcOcts>,
) -> Result<Self, Self::Error> {
Octs::try_octets_from(source.octets)
.map(|octets| unsafe { Self::from_octets_unchecked(octets) })
}
}
impl<'a, Octs: Octets + ?Sized> IntoIterator for &'a Message<Octs> {
type Item = Result<(ParsedRecord<'a, Octs>, Section), ParseError>;
type IntoIter = MessageIter<'a, Octs>;
fn into_iter(self) -> Self::IntoIter {
MessageIter {
inner: self.answer().ok(),
}
}
}
impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for Message<Octs> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Message")
.field("id", &self.header().id())
.field("qr", &self.header().qr())
.field("opcode", &self.header().opcode())
.field("flags", &self.header().flags())
.field("rcode", &self.header().rcode())
.field("qdcount", &self.header_counts().qdcount())
.field("ancount", &self.header_counts().ancount())
.field("nscount", &self.header_counts().nscount())
.field("arcount", &self.header_counts().arcount())
.finish()
}
}
#[derive(Debug)]
pub struct QuestionSection<'a, Octs: ?Sized> {
parser: Parser<'a, Octs>,
count: Result<u16, ParseError>,
}
impl<'a, Octs: Octets + ?Sized> QuestionSection<'a, Octs> {
fn new(octets: &'a Octs) -> Self {
let mut parser = Parser::from_ref(octets);
parser.advance(mem::size_of::<HeaderSection>()).unwrap();
QuestionSection {
count: Ok(
HeaderCounts::for_message_slice(parser.as_slice()).qdcount()
),
parser,
}
}
#[must_use]
pub fn pos(&self) -> usize {
self.parser.pos()
}
pub fn answer(mut self) -> Result<RecordSection<'a, Octs>, ParseError> {
while self.next().is_some() {}
let _ = self.count?;
Ok(RecordSection::new(self.parser, Section::first()))
}
pub fn next_section(self) -> Result<RecordSection<'a, Octs>, ParseError> {
self.answer()
}
}
impl<Octs: ?Sized> Clone for QuestionSection<'_, Octs> {
fn clone(&self) -> Self {
*self
}
}
impl<Octs: ?Sized> Copy for QuestionSection<'_, Octs> {}
impl<'a, Octs: Octets + ?Sized> Iterator for QuestionSection<'a, Octs> {
type Item = Result<Question<ParsedName<Octs::Range<'a>>>, ParseError>;
fn next(&mut self) -> Option<Self::Item> {
match self.count {
Ok(count) if count > 0 => match Question::parse(&mut self.parser)
{
Ok(question) => {
self.count = Ok(count - 1);
Some(Ok(question))
}
Err(err) => {
self.count = Err(err);
Some(Err(err))
}
},
_ => None,
}
}
}
impl<'o, Octs, Other> PartialEq<QuestionSection<'o, Other>>
for QuestionSection<'_, Octs>
where
Octs: Octets + ?Sized,
Other: Octets + ?Sized,
{
fn eq(&self, other: &QuestionSection<'o, Other>) -> bool {
let mut me = *self;
let mut other = *other;
loop {
match (me.next(), other.next()) {
(Some(Ok(left)), Some(Ok(right))) => {
if left != right {
return false;
}
}
(None, None) => return true,
_ => return false,
}
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd)]
pub enum Section {
Answer,
Authority,
Additional,
}
impl Section {
#[must_use]
pub fn first() -> Self {
Section::Answer
}
fn count(self, counts: HeaderCounts) -> u16 {
match self {
Section::Answer => counts.ancount(),
Section::Authority => counts.nscount(),
Section::Additional => counts.arcount(),
}
}
pub(crate) fn next_section(self) -> Option<Self> {
match self {
Section::Answer => Some(Section::Authority),
Section::Authority => Some(Section::Additional),
Section::Additional => None,
}
}
}
#[derive(Debug)]
pub struct RecordSection<'a, Octs: ?Sized> {
parser: Parser<'a, Octs>,
section: Section,
count: Result<u16, ParseError>,
}
impl<'a, Octs: Octets + ?Sized> RecordSection<'a, Octs> {
fn new(parser: Parser<'a, Octs>, section: Section) -> Self {
RecordSection {
count: Ok(section
.count(*HeaderCounts::for_message_slice(parser.as_slice()))),
section,
parser,
}
}
#[must_use]
pub fn pos(&self) -> usize {
self.parser.pos()
}
#[must_use]
pub fn limit_to<Data: ParseRecordData<'a, Octs>>(
self,
) -> RecordIter<'a, Octs, Data> {
RecordIter::new(self, false)
}
#[must_use]
pub fn limit_to_in<Data: ParseRecordData<'a, Octs>>(
self,
) -> RecordIter<'a, Octs, Data> {
RecordIter::new(self, true)
}
#[must_use]
pub fn into_records<Data: ParseAnyRecordData<'a, Octs>>(
self,
) -> AnyRecordIter<'a, Octs, Data> {
AnyRecordIter::new(self)
}
pub fn next_section(mut self) -> Result<Option<Self>, ParseError> {
let section = match self.section.next_section() {
Some(section) => section,
None => return Ok(None),
};
while self.skip_next().is_some() {}
let _ = self.count?;
Ok(Some(RecordSection::new(self.parser, section)))
}
fn skip_next(&mut self) -> Option<Result<(), ParseError>> {
match self.count {
Ok(count) if count > 0 => {
match ParsedRecord::skip(&mut self.parser) {
Ok(_) => {
self.count = Ok(count - 1);
Some(Ok(()))
}
Err(err) => {
self.count = Err(err);
Some(Err(err))
}
}
}
_ => None,
}
}
}
impl<Octs: ?Sized> Clone for RecordSection<'_, Octs> {
fn clone(&self) -> Self {
*self
}
}
impl<Octs: ?Sized> Copy for RecordSection<'_, Octs> {}
impl<'a, Octs: Octets + ?Sized> Iterator for RecordSection<'a, Octs> {
type Item = Result<ParsedRecord<'a, Octs>, ParseError>;
fn next(&mut self) -> Option<Self::Item> {
match self.count {
Ok(count) if count > 0 => {
match ParsedRecord::parse(&mut self.parser) {
Ok(record) => {
self.count = Ok(count - 1);
Some(Ok(record))
}
Err(err) => {
self.count = Err(err);
Some(Err(err))
}
}
}
_ => None,
}
}
}
pub struct MessageIter<'a, Octs: ?Sized> {
inner: Option<RecordSection<'a, Octs>>,
}
impl<'a, Octs: Octets + ?Sized> Iterator for MessageIter<'a, Octs> {
type Item = Result<(ParsedRecord<'a, Octs>, Section), ParseError>;
fn next(&mut self) -> Option<Self::Item> {
let inner = self.inner.as_mut()?;
if let Some(item) = inner.next() {
return Some(item.map(|item| (item, inner.section)));
}
let inner = self.inner.take()?;
match inner.next_section() {
Ok(section) => {
self.inner = section;
self.next()
}
Err(err) => Some(Err(err)),
}
}
}
#[derive(Debug)]
pub struct RecordIter<'a, Octs: ?Sized, Data> {
section: RecordSection<'a, Octs>,
in_only: bool,
marker: PhantomData<Data>,
}
impl<'a, Octs, Data> RecordIter<'a, Octs, Data>
where
Octs: Octets + ?Sized,
Data: ParseRecordData<'a, Octs>,
{
fn new(section: RecordSection<'a, Octs>, in_only: bool) -> Self {
RecordIter {
section,
in_only,
marker: PhantomData,
}
}
#[must_use]
pub fn unwrap(self) -> RecordSection<'a, Octs> {
self.section
}
pub fn next_section(
self,
) -> Result<Option<RecordSection<'a, Octs>>, ParseError> {
self.section.next_section()
}
}
impl<Octs: ?Sized, Data> Clone for RecordIter<'_, Octs, Data> {
fn clone(&self) -> Self {
RecordIter {
section: self.section,
in_only: self.in_only,
marker: PhantomData,
}
}
}
impl<'a, Octs, Data> Iterator for RecordIter<'a, Octs, Data>
where
Octs: Octets + ?Sized,
Data: ParseRecordData<'a, Octs>,
{
type Item = Result<Record<ParsedName<Octs::Range<'a>>, Data>, ParseError>;
fn next(&mut self) -> Option<Self::Item> {
loop {
let record = match self.section.next() {
Some(Ok(record)) => record,
Some(Err(err)) => return Some(Err(err)),
None => return None,
};
if self.in_only && record.class() != Class::IN {
continue;
}
match record.into_record() {
Ok(Some(record)) => return Some(Ok(record)),
Err(err) => return Some(Err(err)),
Ok(None) => {}
}
}
}
}
#[derive(Debug)]
pub struct AnyRecordIter<'a, Octs: ?Sized, Data> {
section: RecordSection<'a, Octs>,
marker: PhantomData<Data>,
}
impl<'a, Octs, Data> AnyRecordIter<'a, Octs, Data>
where
Octs: Octets + ?Sized,
Data: ParseAnyRecordData<'a, Octs>,
{
fn new(section: RecordSection<'a, Octs>) -> Self {
Self {
section,
marker: PhantomData,
}
}
#[must_use]
pub fn unwrap(self) -> RecordSection<'a, Octs> {
self.section
}
pub fn next_section(
self,
) -> Result<Option<RecordSection<'a, Octs>>, ParseError> {
self.section.next_section()
}
}
impl<Octs: ?Sized, Data> Clone for AnyRecordIter<'_, Octs, Data> {
fn clone(&self) -> Self {
Self {
section: self.section,
marker: PhantomData,
}
}
}
impl<'a, Octs, Data> Iterator for AnyRecordIter<'a, Octs, Data>
where
Octs: Octets + ?Sized,
Data: ParseAnyRecordData<'a, Octs>,
{
type Item = Result<Record<ParsedName<Octs::Range<'a>>, Data>, ParseError>;
fn next(&mut self) -> Option<Self::Item> {
let record = match self.section.next() {
Some(Ok(record)) => record,
Some(Err(err)) => return Some(Err(err)),
None => return None,
};
Some(record.into_any_record())
}
}
#[derive(Clone, Copy, Debug)]
pub struct ShortMessage(());
impl fmt::Display for ShortMessage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("short message")
}
}
#[cfg(feature = "std")]
impl std::error::Error for ShortMessage {}
#[derive(Clone, Copy, Debug)]
pub enum CopyRecordsError {
Parse(ParseError),
Push(PushError),
}
impl From<ParseError> for CopyRecordsError {
fn from(err: ParseError) -> Self {
CopyRecordsError::Parse(err)
}
}
impl From<PushError> for CopyRecordsError {
fn from(err: PushError) -> Self {
CopyRecordsError::Push(err)
}
}
impl fmt::Display for CopyRecordsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
CopyRecordsError::Parse(ref err) => err.fmt(f),
CopyRecordsError::Push(ref err) => err.fmt(f),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for CopyRecordsError {}
#[cfg(test)]
mod test {
use super::*;
#[cfg(feature = "std")]
use crate::base::message_builder::MessageBuilder;
#[cfg(feature = "std")]
use crate::base::name::Name;
#[cfg(feature = "std")]
use crate::rdata::{AllRecordData, Ns};
#[cfg(feature = "std")]
use std::vec::Vec;
#[cfg(feature = "std")]
fn get_test_message() -> Message<Vec<u8>> {
let msg = MessageBuilder::new_vec();
let mut msg = msg.answer();
msg.push((
Name::vec_from_str("foo.example.com.").unwrap(),
86000,
Cname::new(Name::vec_from_str("baz.example.com.").unwrap()),
))
.unwrap();
let mut msg = msg.authority();
msg.push((
Name::vec_from_str("bar.example.com.").unwrap(),
86000,
Ns::new(Name::vec_from_str("baz.example.com.").unwrap()),
))
.unwrap();
msg.into_message()
}
#[test]
fn short_message() {
assert!(Message::from_octets(&[0u8; 11]).is_err());
assert!(Message::from_octets(&[0u8; 12]).is_ok());
}
#[test]
#[cfg(feature = "std")]
fn canonical_name() {
use crate::rdata::A;
let mut msg = MessageBuilder::new_vec().question();
msg.push((Name::vec_from_str("example.com.").unwrap(), Rtype::A))
.unwrap();
let msg_ref = msg.as_message();
assert_eq!(
Name::vec_from_str("example.com.").unwrap(),
msg_ref.canonical_name().unwrap()
);
let mut msg = msg.answer();
msg.push((
Name::vec_from_str("bar.example.com.").unwrap(),
86000,
Cname::new(Name::vec_from_str("baz.example.com.").unwrap()),
))
.unwrap();
msg.push((
Name::vec_from_str("example.com.").unwrap(),
86000,
Cname::new(Name::vec_from_str("foo.example.com.").unwrap()),
))
.unwrap();
msg.push((
Name::vec_from_str("foo.example.com.").unwrap(),
86000,
Cname::new(Name::vec_from_str("bar.example.com.").unwrap()),
))
.unwrap();
let msg_ref = msg.as_message();
assert_eq!(
Name::vec_from_str("baz.example.com.").unwrap(),
msg_ref.canonical_name().unwrap()
);
msg.push((
Name::vec_from_str("baz.example.com").unwrap(),
86000,
Cname::new(Name::vec_from_str("foo.example.com").unwrap()),
))
.unwrap();
assert!(msg.as_message().canonical_name().is_none());
msg.push((
Name::vec_from_str("baz.example.com").unwrap(),
86000,
A::from_octets(127, 0, 0, 1),
))
.unwrap();
assert!(msg.as_message().canonical_name().is_none());
}
#[test]
#[cfg(feature = "std")]
fn message_iterator() {
let msg = get_test_message();
let mut iter = msg.iter();
let (_rr, section) = iter.next().unwrap().unwrap();
assert_eq!(Section::Answer, section);
let (_rr, section) = iter.next().unwrap().unwrap();
assert_eq!(Section::Authority, section);
}
#[test]
#[cfg(feature = "std")]
fn copy_records() {
let msg = get_test_message();
let target = MessageBuilder::new_vec().question();
let res = msg.copy_records(target.answer(), |rr| {
if let Ok(Some(rr)) =
rr.into_record::<AllRecordData<_, ParsedName<_>>>()
{
if rr.rtype() == Rtype::CNAME {
return Some(rr);
}
}
None
});
assert!(res.is_ok());
if let Ok(target) = res {
let msg = target.into_message();
assert_eq!(1, msg.header_counts().ancount());
assert_eq!(0, msg.header_counts().arcount());
}
}
}