use bytes::{Bytes, Buf}; use common_types::Type; use errors::*; use ser::packet::{DnsPacketData, 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, } impl NxtTypeBitmap { pub fn from_set(set: BTreeSet) -> Result { 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) -> Result { // remember raw encoding let raw = { let mut data: Cursor = 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, }) } } impl DnsTextData for NxtTypeBitmap { fn dns_parse(context: &DnsTextContext, data: &mut &str) -> Result { 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(()) } }