rust-dnsbox/lib/dnsbox-base/src/common_types/text.rs

116 lines
3.2 KiB
Rust

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 `<character-string>`
impl DnsPacketData for ShortText {
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
Ok(ShortText(short_blob(data)?))
}
}
impl DnsTextData for ShortText {
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
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 <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)?);
if !data.has_remaining() { break; }
}
Ok(LongText(texts))
}
}
impl DnsTextData for LongText {
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
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<Bytes>) -> Result<Self> {
Ok(UnquotedShortText(short_blob(data)?))
}
}
impl DnsTextData for UnquotedShortText {
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
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) <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)))
}
}
impl DnsTextData for RemainingText {
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> ::errors::Result<Self> {
Ok(RemainingText(next_quoted_field(data)?.into()))
}
fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result {
write!(f, "{}", quote(&self.0))
}
}