use bytes::{Bytes, Buf}; use errors::*; use ser::packet::{DnsPacketData, short_blob, remaining_bytes}; use ser::text::*; use std::fmt; use std::io::Cursor; #[derive(Clone, PartialEq, Eq, Debug)] pub struct ShortText(Bytes); // RFC 1035 names this `` impl DnsPacketData for ShortText { fn deserialize(data: &mut Cursor) -> Result { Ok(ShortText(short_blob(data)?)) } } impl DnsTextData for ShortText { fn dns_parse(data: &mut &str) -> ::errors::Result { let raw = next_quoted_field(data)?; ensure!(raw.len() < 256, "short text must be at most 255 bytes long"); Ok(ShortText(raw.into())) } fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result { write!(f, "{}", quote(&self.0)) } } /// RFC 1035 names this `One or more `. No following /// field allowed. /// /// Used for TXT and SPF. #[derive(Clone, PartialEq, Eq, Debug)] pub struct LongText(Vec); impl DnsPacketData for LongText { fn deserialize(data: &mut Cursor) -> Result { let mut texts = Vec::new(); loop { texts.push(short_blob(data)?); if !data.has_remaining() { break; } } Ok(LongText(texts)) } } impl DnsTextData for LongText { fn dns_parse(data: &mut &str) -> ::errors::Result { let mut result = Vec::new(); // `next_quoted_field` should skip trailing whitespace, we only // need to skip the beginning whitespace for the first // `is_empty` check. skip_whitespace(data); while !data.is_empty() { let part = next_quoted_field(data)?; ensure!(part.len() < 256, "long text component must be at most 255 bytes long"); result.push(part.into()); } Ok(LongText(result)) } fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result { // actually emit as "multiple fields" (i.e. space separated) for part in &self.0 { write!(f, "{}", quote(part))?; } Ok(()) } } // similart to ShortText, but text output doesn't use quotes. #[derive(Clone, PartialEq, Eq, Debug)] pub struct UnquotedShortText(Bytes); impl DnsPacketData for UnquotedShortText { fn deserialize(data: &mut Cursor) -> Result { Ok(UnquotedShortText(short_blob(data)?)) } } impl DnsTextData for UnquotedShortText { fn dns_parse(data: &mut &str) -> ::errors::Result { let raw = next_quoted_field(data)?; ensure!(raw.len() < 256, "short text must be at most 255 bytes long"); Ok(UnquotedShortText(raw.into())) } fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result { write!(f, "{}", escape(&self.0)) } } /// A single (possibly quoted) , but no length /// restriction. /// /// Last field, but no whitespace allowed (unless quoted of course). #[derive(Clone, PartialEq, Eq, Debug)] pub struct RemainingText(Bytes); impl DnsPacketData for RemainingText { fn deserialize(data: &mut Cursor) -> Result { Ok(RemainingText(remaining_bytes(data))) } } impl DnsTextData for RemainingText { fn dns_parse(data: &mut &str) -> ::errors::Result { Ok(RemainingText(next_quoted_field(data)?.into())) } fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result { write!(f, "{}", quote(&self.0)) } }