use alloc::{boxed::Box, fmt, vec::Vec};
use core::{iter, mem, ops::Deref};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use tracing::{debug, warn};
use crate::{
error::*,
op::{Edns, Header, MessageType, OpCode, Query, ResponseCode},
rr::{Record, RecordType},
serialize::binary::{BinDecodable, BinDecoder, BinEncodable, BinEncoder, EncodeMode},
xfer::DnsResponse,
};
#[derive(Clone, Debug, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct Message {
header: Header,
queries: Vec<Query>,
answers: Vec<Record>,
name_servers: Vec<Record>,
additionals: Vec<Record>,
signature: Vec<Record>,
edns: Option<Edns>,
}
impl Message {
pub fn new() -> Self {
Self {
header: Header::new(),
queries: Vec::new(),
answers: Vec::new(),
name_servers: Vec::new(),
additionals: Vec::new(),
signature: Vec::new(),
edns: None,
}
}
pub fn error_msg(id: u16, op_code: OpCode, response_code: ResponseCode) -> Self {
let mut message = Self::new();
message
.set_message_type(MessageType::Response)
.set_id(id)
.set_response_code(response_code)
.set_op_code(op_code);
message
}
pub fn truncate(&self) -> Self {
let mut header = self.header;
header.set_truncated(true);
header
.set_additional_count(0)
.set_answer_count(0)
.set_name_server_count(0);
let mut msg = Self::new();
msg.add_queries(self.queries().iter().cloned());
if let Some(edns) = self.extensions().clone() {
msg.set_edns(edns);
}
msg.set_header(header);
msg
}
pub fn set_header(&mut self, header: Header) -> &mut Self {
self.header = header;
self
}
pub fn set_id(&mut self, id: u16) -> &mut Self {
self.header.set_id(id);
self
}
pub fn set_message_type(&mut self, message_type: MessageType) -> &mut Self {
self.header.set_message_type(message_type);
self
}
pub fn set_op_code(&mut self, op_code: OpCode) -> &mut Self {
self.header.set_op_code(op_code);
self
}
pub fn set_authoritative(&mut self, authoritative: bool) -> &mut Self {
self.header.set_authoritative(authoritative);
self
}
pub fn set_truncated(&mut self, truncated: bool) -> &mut Self {
self.header.set_truncated(truncated);
self
}
pub fn set_recursion_desired(&mut self, recursion_desired: bool) -> &mut Self {
self.header.set_recursion_desired(recursion_desired);
self
}
pub fn set_recursion_available(&mut self, recursion_available: bool) -> &mut Self {
self.header.set_recursion_available(recursion_available);
self
}
pub fn set_authentic_data(&mut self, authentic_data: bool) -> &mut Self {
self.header.set_authentic_data(authentic_data);
self
}
pub fn set_checking_disabled(&mut self, checking_disabled: bool) -> &mut Self {
self.header.set_checking_disabled(checking_disabled);
self
}
pub fn set_response_code(&mut self, response_code: ResponseCode) -> &mut Self {
self.header.set_response_code(response_code);
self
}
pub fn set_query_count(&mut self, query_count: u16) -> &mut Self {
self.header.set_query_count(query_count);
self
}
pub fn set_answer_count(&mut self, answer_count: u16) -> &mut Self {
self.header.set_answer_count(answer_count);
self
}
pub fn set_name_server_count(&mut self, name_server_count: u16) -> &mut Self {
self.header.set_name_server_count(name_server_count);
self
}
pub fn set_additional_count(&mut self, additional_count: u16) -> &mut Self {
self.header.set_additional_count(additional_count);
self
}
pub fn add_query(&mut self, query: Query) -> &mut Self {
self.queries.push(query);
self
}
pub fn add_queries<Q, I>(&mut self, queries: Q) -> &mut Self
where
Q: IntoIterator<Item = Query, IntoIter = I>,
I: Iterator<Item = Query>,
{
for query in queries {
self.add_query(query);
}
self
}
pub fn add_answer(&mut self, record: Record) -> &mut Self {
self.answers.push(record);
self
}
pub fn add_answers<R, I>(&mut self, records: R) -> &mut Self
where
R: IntoIterator<Item = Record, IntoIter = I>,
I: Iterator<Item = Record>,
{
for record in records {
self.add_answer(record);
}
self
}
pub fn insert_answers(&mut self, records: Vec<Record>) {
assert!(self.answers.is_empty());
self.answers = records;
}
pub fn add_name_server(&mut self, record: Record) -> &mut Self {
self.name_servers.push(record);
self
}
pub fn add_name_servers<R, I>(&mut self, records: R) -> &mut Self
where
R: IntoIterator<Item = Record, IntoIter = I>,
I: Iterator<Item = Record>,
{
for record in records {
self.add_name_server(record);
}
self
}
pub fn insert_name_servers(&mut self, records: Vec<Record>) {
assert!(self.name_servers.is_empty());
self.name_servers = records;
}
pub fn add_additional(&mut self, record: Record) -> &mut Self {
self.additionals.push(record);
self
}
pub fn add_additionals<R, I>(&mut self, records: R) -> &mut Self
where
R: IntoIterator<Item = Record, IntoIter = I>,
I: Iterator<Item = Record>,
{
for record in records {
self.add_additional(record);
}
self
}
pub fn insert_additionals(&mut self, records: Vec<Record>) {
assert!(self.additionals.is_empty());
self.additionals = records;
}
pub fn set_edns(&mut self, edns: Edns) -> &mut Self {
self.edns = Some(edns);
self
}
#[cfg(feature = "__dnssec")]
pub fn add_sig0(&mut self, record: Record) -> &mut Self {
assert_eq!(RecordType::SIG, record.record_type());
self.signature.push(record);
self
}
#[cfg(feature = "__dnssec")]
pub fn add_tsig(&mut self, record: Record) -> &mut Self {
assert_eq!(RecordType::TSIG, record.record_type());
self.signature.push(record);
self
}
pub fn header(&self) -> &Header {
&self.header
}
pub fn id(&self) -> u16 {
self.header.id()
}
pub fn message_type(&self) -> MessageType {
self.header.message_type()
}
pub fn op_code(&self) -> OpCode {
self.header.op_code()
}
pub fn authoritative(&self) -> bool {
self.header.authoritative()
}
pub fn truncated(&self) -> bool {
self.header.truncated()
}
pub fn recursion_desired(&self) -> bool {
self.header.recursion_desired()
}
pub fn recursion_available(&self) -> bool {
self.header.recursion_available()
}
pub fn authentic_data(&self) -> bool {
self.header.authentic_data()
}
pub fn checking_disabled(&self) -> bool {
self.header.checking_disabled()
}
pub fn response_code(&self) -> ResponseCode {
self.header.response_code()
}
pub fn query(&self) -> Option<&Query> {
self.queries.first()
}
pub fn queries(&self) -> &[Query] {
&self.queries
}
pub fn queries_mut(&mut self) -> &mut Vec<Query> {
&mut self.queries
}
pub fn take_queries(&mut self) -> Vec<Query> {
mem::take(&mut self.queries)
}
pub fn answers(&self) -> &[Record] {
&self.answers
}
pub fn answers_mut(&mut self) -> &mut Vec<Record> {
&mut self.answers
}
pub fn take_answers(&mut self) -> Vec<Record> {
mem::take(&mut self.answers)
}
pub fn name_servers(&self) -> &[Record] {
&self.name_servers
}
pub fn name_servers_mut(&mut self) -> &mut Vec<Record> {
&mut self.name_servers
}
pub fn take_name_servers(&mut self) -> Vec<Record> {
mem::take(&mut self.name_servers)
}
pub fn additionals(&self) -> &[Record] {
&self.additionals
}
pub fn additionals_mut(&mut self) -> &mut Vec<Record> {
&mut self.additionals
}
pub fn take_additionals(&mut self) -> Vec<Record> {
mem::take(&mut self.additionals)
}
pub fn all_sections(&self) -> impl Iterator<Item = &Record> {
self.answers
.iter()
.chain(self.name_servers().iter())
.chain(self.additionals.iter())
}
#[deprecated(note = "Please use `extensions()`")]
pub fn edns(&self) -> Option<&Edns> {
self.edns.as_ref()
}
#[deprecated(
note = "Please use `extensions_mut()`. You can chain `.get_or_insert_with(Edns::new)` to recover original behavior of adding Edns if not present"
)]
pub fn edns_mut(&mut self) -> &mut Edns {
if self.edns.is_none() {
self.set_edns(Edns::new());
}
self.edns.as_mut().unwrap()
}
pub fn extensions(&self) -> &Option<Edns> {
&self.edns
}
pub fn extensions_mut(&mut self) -> &mut Option<Edns> {
&mut self.edns
}
pub fn max_payload(&self) -> u16 {
let max_size = self.edns.as_ref().map_or(512, Edns::max_payload);
if max_size < 512 { 512 } else { max_size }
}
pub fn version(&self) -> u8 {
self.edns.as_ref().map_or(0, Edns::version)
}
pub fn sig0(&self) -> &[Record] {
&self.signature
}
pub fn signature(&self) -> &[Record] {
&self.signature
}
pub fn take_signature(&mut self) -> Vec<Record> {
mem::take(&mut self.signature)
}
#[cfg(test)]
pub fn update_counts(&mut self) -> &mut Self {
self.header = update_header_counts(
&self.header,
self.truncated(),
HeaderCounts {
query_count: self.queries.len(),
answer_count: self.answers.len(),
nameserver_count: self.name_servers.len(),
additional_count: self.additionals.len(),
},
);
self
}
pub fn read_queries(decoder: &mut BinDecoder<'_>, count: usize) -> ProtoResult<Vec<Query>> {
let mut queries = Vec::with_capacity(count);
for _ in 0..count {
queries.push(Query::read(decoder)?);
}
Ok(queries)
}
#[cfg_attr(not(feature = "__dnssec"), allow(unused_mut))]
pub fn read_records(
decoder: &mut BinDecoder<'_>,
count: usize,
is_additional: bool,
) -> ProtoResult<(Vec<Record>, Option<Edns>, Vec<Record>)> {
let mut records: Vec<Record> = Vec::with_capacity(count);
let mut edns: Option<Edns> = None;
let mut sigs: Vec<Record> = Vec::with_capacity(if is_additional { 1 } else { 0 });
let mut saw_sig0 = false;
let mut saw_tsig = false;
for _ in 0..count {
let record = Record::read(decoder)?;
if saw_tsig {
return Err("tsig must be final resource record".into());
} if !is_additional {
if saw_sig0 {
return Err("sig0 must be final resource record".into());
} records.push(record)
} else {
match record.record_type() {
#[cfg(feature = "__dnssec")]
RecordType::SIG => {
saw_sig0 = true;
sigs.push(record);
}
#[cfg(feature = "__dnssec")]
RecordType::TSIG => {
if saw_sig0 {
return Err("sig0 must be final resource record".into());
} saw_tsig = true;
sigs.push(record);
}
RecordType::OPT => {
if saw_sig0 {
return Err("sig0 must be final resource record".into());
} if edns.is_some() {
return Err("more than one edns record present".into());
}
edns = Some((&record).into());
}
_ => {
if saw_sig0 {
return Err("sig0 must be final resource record".into());
} records.push(record);
}
}
}
}
Ok((records, edns, sigs))
}
pub fn from_vec(buffer: &[u8]) -> ProtoResult<Self> {
let mut decoder = BinDecoder::new(buffer);
Self::read(&mut decoder)
}
pub fn to_vec(&self) -> Result<Vec<u8>, ProtoError> {
let mut buffer = Vec::with_capacity(512);
{
let mut encoder = BinEncoder::new(&mut buffer);
self.emit(&mut encoder)?;
}
Ok(buffer)
}
#[allow(clippy::match_single_binding)]
pub fn finalize(
&mut self,
finalizer: &dyn MessageFinalizer,
inception_time: u32,
) -> ProtoResult<Option<MessageVerifier>> {
debug!("finalizing message: {:?}", self);
let (finals, verifier): (Vec<Record>, Option<MessageVerifier>) =
finalizer.finalize_message(self, inception_time)?;
for fin in finals {
match fin.record_type() {
#[cfg(feature = "__dnssec")]
RecordType::SIG => self.add_sig0(fin),
#[cfg(feature = "__dnssec")]
RecordType::TSIG => self.add_tsig(fin),
_ => self.add_additional(fin),
};
}
Ok(verifier)
}
pub fn into_parts(self) -> MessageParts {
self.into()
}
}
impl From<MessageParts> for Message {
fn from(msg: MessageParts) -> Self {
let MessageParts {
header,
queries,
answers,
name_servers,
additionals,
sig0,
edns,
} = msg;
Self {
header,
queries,
answers,
name_servers,
additionals,
signature: sig0,
edns,
}
}
}
impl Deref for Message {
type Target = Header;
fn deref(&self) -> &Self::Target {
&self.header
}
}
#[derive(Clone, Debug, PartialEq, Eq, Default)]
pub struct MessageParts {
pub header: Header,
pub queries: Vec<Query>,
pub answers: Vec<Record>,
pub name_servers: Vec<Record>,
pub additionals: Vec<Record>,
pub sig0: Vec<Record>,
pub edns: Option<Edns>,
}
impl From<Message> for MessageParts {
fn from(msg: Message) -> Self {
let Message {
header,
queries,
answers,
name_servers,
additionals,
signature,
edns,
} = msg;
Self {
header,
queries,
answers,
name_servers,
additionals,
sig0: signature,
edns,
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct HeaderCounts {
pub query_count: usize,
pub answer_count: usize,
pub nameserver_count: usize,
pub additional_count: usize,
}
pub fn update_header_counts(
current_header: &Header,
is_truncated: bool,
counts: HeaderCounts,
) -> Header {
assert!(counts.query_count <= u16::MAX as usize);
assert!(counts.answer_count <= u16::MAX as usize);
assert!(counts.nameserver_count <= u16::MAX as usize);
assert!(counts.additional_count <= u16::MAX as usize);
let mut header = *current_header;
header
.set_query_count(counts.query_count as u16)
.set_answer_count(counts.answer_count as u16)
.set_name_server_count(counts.nameserver_count as u16)
.set_additional_count(counts.additional_count as u16)
.set_truncated(is_truncated);
header
}
pub type MessageVerifier = Box<dyn FnMut(&[u8]) -> ProtoResult<DnsResponse> + Send>;
pub trait MessageFinalizer: Send + Sync + 'static {
fn finalize_message(
&self,
message: &Message,
current_time: u32,
) -> ProtoResult<(Vec<Record>, Option<MessageVerifier>)>;
fn should_finalize_message(&self, message: &Message) -> bool {
[OpCode::Update, OpCode::Notify].contains(&message.op_code())
|| message
.queries()
.iter()
.any(|q| [RecordType::AXFR, RecordType::IXFR].contains(&q.query_type()))
}
}
pub fn count_was_truncated(result: ProtoResult<usize>) -> ProtoResult<(usize, bool)> {
match result {
Ok(count) => Ok((count, false)),
Err(e) => match e.kind() {
ProtoErrorKind::NotAllRecordsWritten { count } => Ok((*count, true)),
_ => Err(e),
},
}
}
pub trait EmitAndCount {
fn emit(&mut self, encoder: &mut BinEncoder<'_>) -> ProtoResult<usize>;
}
impl<'e, I: Iterator<Item = &'e E>, E: 'e + BinEncodable> EmitAndCount for I {
fn emit(&mut self, encoder: &mut BinEncoder<'_>) -> ProtoResult<usize> {
encoder.emit_all(self)
}
}
#[allow(clippy::too_many_arguments)]
pub fn emit_message_parts<Q, A, N, D>(
header: &Header,
queries: &mut Q,
answers: &mut A,
name_servers: &mut N,
additionals: &mut D,
edns: Option<&Edns>,
signature: &[Record],
encoder: &mut BinEncoder<'_>,
) -> ProtoResult<Header>
where
Q: EmitAndCount,
A: EmitAndCount,
N: EmitAndCount,
D: EmitAndCount,
{
let include_signature = encoder.mode() != EncodeMode::Signing;
let place = encoder.place::<Header>()?;
let query_count = queries.emit(encoder)?;
let answer_count = count_was_truncated(answers.emit(encoder))?;
let nameserver_count = count_was_truncated(name_servers.emit(encoder))?;
let mut additional_count = count_was_truncated(additionals.emit(encoder))?;
if let Some(mut edns) = edns.cloned() {
edns.set_rcode_high(header.response_code().high());
let count = count_was_truncated(encoder.emit_all(iter::once(&Record::from(&edns))))?;
additional_count.0 += count.0;
additional_count.1 |= count.1;
} else if header.response_code().high() > 0 {
warn!(
"response code: {} for request: {} requires EDNS but none available",
header.response_code(),
header.id()
);
}
if include_signature {
let count = count_was_truncated(encoder.emit_all(signature.iter()))?;
additional_count.0 += count.0;
additional_count.1 |= count.1;
}
let counts = HeaderCounts {
query_count,
answer_count: answer_count.0,
nameserver_count: nameserver_count.0,
additional_count: additional_count.0,
};
let was_truncated =
header.truncated() || answer_count.1 || nameserver_count.1 || additional_count.1;
let final_header = update_header_counts(header, was_truncated, counts);
place.replace(encoder, final_header)?;
Ok(final_header)
}
impl BinEncodable for Message {
fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
emit_message_parts(
&self.header,
&mut self.queries.iter(),
&mut self.answers.iter(),
&mut self.name_servers.iter(),
&mut self.additionals.iter(),
self.edns.as_ref(),
&self.signature,
encoder,
)?;
Ok(())
}
}
impl<'r> BinDecodable<'r> for Message {
fn read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Self> {
let mut header = Header::read(decoder)?;
let count = header.query_count() as usize;
let mut queries = Vec::with_capacity(count);
for _ in 0..count {
queries.push(Query::read(decoder)?);
}
let answer_count = header.answer_count() as usize;
let name_server_count = header.name_server_count() as usize;
let additional_count = header.additional_count() as usize;
let (answers, _, _) = Self::read_records(decoder, answer_count, false)?;
let (name_servers, _, _) = Self::read_records(decoder, name_server_count, false)?;
let (additionals, edns, signature) = Self::read_records(decoder, additional_count, true)?;
if let Some(edns) = &edns {
let high_response_code = edns.rcode_high();
header.merge_response_code(high_response_code);
}
Ok(Self {
header,
queries,
answers,
name_servers,
additionals,
signature,
edns,
})
}
}
impl fmt::Display for Message {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
let write_query = |slice, f: &mut fmt::Formatter<'_>| -> Result<(), fmt::Error> {
for d in slice {
writeln!(f, ";; {d}")?;
}
Ok(())
};
let write_slice = |slice, f: &mut fmt::Formatter<'_>| -> Result<(), fmt::Error> {
for d in slice {
writeln!(f, "{d}")?;
}
Ok(())
};
writeln!(f, "; header {header}", header = self.header())?;
if let Some(edns) = self.extensions() {
writeln!(f, "; edns {edns}")?;
}
writeln!(f, "; query")?;
write_query(self.queries(), f)?;
if self.header().message_type() == MessageType::Response
|| self.header().op_code() == OpCode::Update
{
writeln!(f, "; answers {}", self.answer_count())?;
write_slice(self.answers(), f)?;
writeln!(f, "; nameservers {}", self.name_server_count())?;
write_slice(self.name_servers(), f)?;
writeln!(f, "; additionals {}", self.additional_count())?;
write_slice(self.additionals(), f)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_emit_and_read_header() {
let mut message = Message::new();
message
.set_id(10)
.set_message_type(MessageType::Response)
.set_op_code(OpCode::Update)
.set_authoritative(true)
.set_truncated(false)
.set_recursion_desired(true)
.set_recursion_available(true)
.set_response_code(ResponseCode::ServFail);
test_emit_and_read(message);
}
#[test]
fn test_emit_and_read_query() {
let mut message = Message::new();
message
.set_id(10)
.set_message_type(MessageType::Response)
.set_op_code(OpCode::Update)
.set_authoritative(true)
.set_truncated(true)
.set_recursion_desired(true)
.set_recursion_available(true)
.set_response_code(ResponseCode::ServFail)
.add_query(Query::new())
.update_counts();
test_emit_and_read(message);
}
#[test]
fn test_emit_and_read_records() {
let mut message = Message::new();
message
.set_id(10)
.set_message_type(MessageType::Response)
.set_op_code(OpCode::Update)
.set_authoritative(true)
.set_truncated(true)
.set_recursion_desired(true)
.set_recursion_available(true)
.set_authentic_data(true)
.set_checking_disabled(true)
.set_response_code(ResponseCode::ServFail);
message.add_answer(Record::stub());
message.add_name_server(Record::stub());
message.add_additional(Record::stub());
message.update_counts();
test_emit_and_read(message);
}
#[cfg(test)]
fn test_emit_and_read(message: Message) {
let mut byte_vec: Vec<u8> = Vec::with_capacity(512);
{
let mut encoder = BinEncoder::new(&mut byte_vec);
message.emit(&mut encoder).unwrap();
}
let mut decoder = BinDecoder::new(&byte_vec);
let got = Message::read(&mut decoder).unwrap();
assert_eq!(got, message);
}
#[test]
fn test_header_counts_correction_after_emit_read() {
let mut message = Message::new();
message
.set_id(10)
.set_message_type(MessageType::Response)
.set_op_code(OpCode::Update)
.set_authoritative(true)
.set_truncated(true)
.set_recursion_desired(true)
.set_recursion_available(true)
.set_authentic_data(true)
.set_checking_disabled(true)
.set_response_code(ResponseCode::ServFail);
message.add_answer(Record::stub());
message.add_name_server(Record::stub());
message.add_additional(Record::stub());
message.set_query_count(1);
message.set_answer_count(5);
message.set_name_server_count(5);
let got = get_message_after_emitting_and_reading(message);
assert_eq!(got.query_count(), 0);
assert_eq!(got.answer_count(), 1);
assert_eq!(got.name_server_count(), 1);
assert_eq!(got.additional_count(), 1);
}
#[cfg(test)]
fn get_message_after_emitting_and_reading(message: Message) -> Message {
let mut byte_vec: Vec<u8> = Vec::with_capacity(512);
{
let mut encoder = BinEncoder::new(&mut byte_vec);
message.emit(&mut encoder).unwrap();
}
let mut decoder = BinDecoder::new(&byte_vec);
Message::read(&mut decoder).unwrap()
}
#[test]
fn test_legit_message() {
#[rustfmt::skip]
let buf: Vec<u8> = vec![
0x10, 0x00, 0x81,
0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, b'w', b'w', b'w', 0x07, b'e', b'x', b'a', b'm', b'p', b'l', b'e', 0x03, b'c', b'o', b'm', 0x00, 0x00, 0x01, 0x00, 0x01, 0xC0, 0x0C, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x5D, 0xB8, 0xD7, 0x0E, ];
let mut decoder = BinDecoder::new(&buf);
let message = Message::read(&mut decoder).unwrap();
assert_eq!(message.id(), 4_096);
let mut buf: Vec<u8> = Vec::with_capacity(512);
{
let mut encoder = BinEncoder::new(&mut buf);
message.emit(&mut encoder).unwrap();
}
let mut decoder = BinDecoder::new(&buf);
let message = Message::read(&mut decoder).unwrap();
assert_eq!(message.id(), 4_096);
}
#[test]
fn rdata_zero_roundtrip() {
let buf = &[
160, 160, 0, 13, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0,
];
assert!(Message::from_bytes(buf).is_err());
}
#[test]
fn nsec_deserialization() {
const CRASHING_MESSAGE: &[u8] = &[
0, 0, 132, 0, 0, 0, 0, 1, 0, 0, 0, 1, 36, 49, 101, 48, 101, 101, 51, 100, 51, 45, 100,
52, 50, 52, 45, 52, 102, 55, 56, 45, 57, 101, 52, 99, 45, 99, 51, 56, 51, 51, 55, 55,
56, 48, 102, 50, 98, 5, 108, 111, 99, 97, 108, 0, 0, 1, 128, 1, 0, 0, 0, 120, 0, 4,
192, 168, 1, 17, 36, 49, 101, 48, 101, 101, 51, 100, 51, 45, 100, 52, 50, 52, 45, 52,
102, 55, 56, 45, 57, 101, 52, 99, 45, 99, 51, 56, 51, 51, 55, 55, 56, 48, 102, 50, 98,
5, 108, 111, 99, 97, 108, 0, 0, 47, 128, 1, 0, 0, 0, 120, 0, 5, 192, 70, 0, 1, 64,
];
Message::from_vec(CRASHING_MESSAGE).expect("failed to parse message");
}
#[test]
fn prior_to_pointer() {
const MESSAGE: &[u8] = include_bytes!("../../tests/test-data/fuzz-prior-to-pointer.rdata");
let message = Message::from_bytes(MESSAGE).expect("failed to parse message");
let encoded = message.to_bytes().unwrap();
Message::from_bytes(&encoded).expect("failed to parse encoded message");
}
}