101 lines
2.4 KiB
Rust
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(())
|
|
}
|
|
}
|