2019-07-01 15:43:34 +00:00
|
|
|
use crate::errors::*;
|
2020-03-07 15:57:47 +00:00
|
|
|
use crate::ser::packet::{
|
|
|
|
remaining_bytes, short_blob, write_short_blob, DnsPacketData, DnsPacketWriteContext,
|
|
|
|
};
|
2019-07-01 15:43:34 +00:00
|
|
|
use crate::ser::text::*;
|
2020-03-07 15:57:47 +00:00
|
|
|
use bytes::{Buf, BufMut, Bytes};
|
2017-12-21 12:32:14 +00:00
|
|
|
use std::fmt;
|
|
|
|
use std::io::Cursor;
|
|
|
|
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
|
|
pub struct ShortText(Bytes);
|
|
|
|
|
|
|
|
// RFC 1035 names this `<character-string>`
|
|
|
|
impl DnsPacketData for ShortText {
|
|
|
|
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
|
|
|
|
Ok(ShortText(short_blob(data)?))
|
|
|
|
}
|
2017-12-27 14:24:11 +00:00
|
|
|
|
|
|
|
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
|
|
|
write_short_blob(&self.0, packet)
|
|
|
|
}
|
2017-12-21 12:32:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl DnsTextData for ShortText {
|
2019-07-01 15:43:34 +00:00
|
|
|
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> crate::errors::Result<Self> {
|
2017-12-21 12:32:14 +00:00
|
|
|
let raw = next_quoted_field(data)?;
|
2019-07-01 15:43:34 +00:00
|
|
|
failure::ensure!(raw.len() < 256, "short text must be at most 255 bytes long");
|
2017-12-21 12:32:14 +00:00
|
|
|
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 <character-string>`. No following
|
|
|
|
/// field allowed.
|
|
|
|
///
|
|
|
|
/// Used for TXT and SPF.
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
|
|
pub struct LongText(Vec<Bytes>);
|
|
|
|
|
|
|
|
impl DnsPacketData for LongText {
|
|
|
|
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
|
|
|
|
let mut texts = Vec::new();
|
|
|
|
loop {
|
|
|
|
texts.push(short_blob(data)?);
|
2020-03-07 15:57:47 +00:00
|
|
|
if !data.has_remaining() {
|
|
|
|
break;
|
|
|
|
}
|
2017-12-21 12:32:14 +00:00
|
|
|
}
|
|
|
|
Ok(LongText(texts))
|
|
|
|
}
|
2017-12-27 14:24:11 +00:00
|
|
|
|
|
|
|
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
2019-07-01 15:43:34 +00:00
|
|
|
failure::ensure!(self.0.len() > 0, "empty LongText not allowed");
|
2017-12-27 14:24:11 +00:00
|
|
|
for t in &self.0 {
|
|
|
|
write_short_blob(t, packet)?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2017-12-21 12:32:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl DnsTextData for LongText {
|
2019-07-01 15:43:34 +00:00
|
|
|
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> crate::errors::Result<Self> {
|
2017-12-21 12:32:14 +00:00
|
|
|
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)?;
|
2020-03-07 15:57:47 +00:00
|
|
|
failure::ensure!(
|
|
|
|
part.len() < 256,
|
|
|
|
"long text component must be at most 255 bytes long"
|
|
|
|
);
|
2017-12-21 12:32:14 +00:00
|
|
|
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<Bytes>) -> Result<Self> {
|
|
|
|
Ok(UnquotedShortText(short_blob(data)?))
|
|
|
|
}
|
2017-12-27 14:24:11 +00:00
|
|
|
|
|
|
|
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
|
|
|
write_short_blob(&self.0, packet)
|
|
|
|
}
|
2017-12-21 12:32:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl DnsTextData for UnquotedShortText {
|
2019-07-01 15:43:34 +00:00
|
|
|
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> crate::errors::Result<Self> {
|
2017-12-21 12:32:14 +00:00
|
|
|
let raw = next_quoted_field(data)?;
|
2019-07-01 15:43:34 +00:00
|
|
|
failure::ensure!(raw.len() < 256, "short text must be at most 255 bytes long");
|
2017-12-21 12:32:14 +00:00
|
|
|
Ok(UnquotedShortText(raw.into()))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result {
|
|
|
|
write!(f, "{}", escape(&self.0))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A single (possibly quoted) <character-string>, 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<Bytes>) -> Result<Self> {
|
|
|
|
Ok(RemainingText(remaining_bytes(data)))
|
|
|
|
}
|
2017-12-27 14:24:11 +00:00
|
|
|
|
|
|
|
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
|
|
|
|
packet.reserve(self.0.len());
|
|
|
|
packet.put_slice(&self.0);
|
|
|
|
Ok(())
|
|
|
|
}
|
2017-12-21 12:32:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl DnsTextData for RemainingText {
|
2019-07-01 15:43:34 +00:00
|
|
|
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> crate::errors::Result<Self> {
|
2017-12-21 12:32:14 +00:00
|
|
|
Ok(RemainingText(next_quoted_field(data)?.into()))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result {
|
|
|
|
write!(f, "{}", quote(&self.0))
|
|
|
|
}
|
|
|
|
}
|