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

101 lines
2.4 KiB
Rust

use bytes::{Bytes, Buf, BufMut};
use common_types::Type;
use errors::*;
use ser::packet::{DnsPacketData, DnsPacketWriteContext, remaining_bytes};
use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, skip_whitespace};
use std::collections::BTreeSet;
use std::fmt;
use std::io::Cursor;
/// Type Bitmap for NXT. Last field in a record.
///
/// RFC 2535 says for the bitmap: "If the zero bit of the type bit map
/// is a one, it indicates that a different format is being used which
/// will always be the case if a type number greater than 127 is
/// present."
///
/// But this other format isn't specified anywhere...
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct NxtTypeBitmap {
raw: Bytes,
set: BTreeSet<Type>,
}
impl NxtTypeBitmap {
pub fn from_set(set: BTreeSet<Type>) -> Result<Self> {
let mut raw = Vec::new();
for t in &set {
ensure!(t.0 > 0, "type 0 cannot be represented in NXT bitmap");
ensure!(t.0 < 128, "type {} cannot be represented in NXT bitmap", t);
let bit_ndx = t.0 as u8;
let byte_ndx = (bit_ndx / 8) as usize;
if byte_ndx >= raw.len() {
raw.resize(byte_ndx + 1, 0);
}
let mask = 0x80 >> (bit_ndx % 8);
raw[byte_ndx] |= mask;
}
Ok(NxtTypeBitmap {
raw: raw.into(),
set: set,
})
}
}
impl DnsPacketData for NxtTypeBitmap {
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
// remember raw encoding
let raw = {
let mut data: Cursor<Bytes> = data.clone();
remaining_bytes(&mut data)
};
let mut set = BTreeSet::new();
let mut current = 0;
while data.has_remaining() {
ensure!(current < 128, "NXT bitmap too long");
let mut v = data.get_u8();
for _ in 0..7 {
if 0 != v & 0x80 {
ensure!(0 != current, "Type 0 not allowed in NXT bitmap");
set.insert(Type(current));
}
v <<= 1;
current += 1;
}
}
Ok(NxtTypeBitmap{
raw: raw,
set: set,
})
}
fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec<u8>) -> Result<()> {
packet.reserve(self.raw.len());
packet.put_slice(&self.raw);
Ok(())
}
}
impl DnsTextData for NxtTypeBitmap {
fn dns_parse(context: &DnsTextContext, data: &mut &str) -> Result<Self> {
let mut set = BTreeSet::new();
skip_whitespace(data);
while !data.is_empty() {
let t = Type::dns_parse(context, data)?;
set.insert(t);
}
NxtTypeBitmap::from_set(set)
}
fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result {
for t in &self.set {
write!(f, "{}", t)?;
}
Ok(())
}
}