SSL builder.rs
Interaktion und Portierbarkeitunbekannt
use byteorder::{ByteOrder, BigEndian, WriteBytesExt};
use {Opcode, ResponseCode, Header, QueryType, QueryClass};
/// Allows to build a DNS packet /// /// Both query and answer packets may be built with this interface, although, /// much of functionality is not implemented yet. #[derive(Debug)] pubstruct Builder {
buf: Vec<u8>,
}
impl Builder { /// Creates a new query /// /// Initially all sections are empty. You're expected to fill /// the questions section with `add_question` pubfn new_query(id: u16, recursion: bool) -> Builder { letmut buf = Vec::with_capacity(512); let head = Header {
id: id,
query: true,
opcode: Opcode::StandardQuery,
authoritative: false,
truncated: false,
recursion_desired: recursion,
recursion_available: false,
authenticated_data: false,
checking_disabled: false,
response_code: ResponseCode::NoError,
questions: 0,
answers: 0,
nameservers: 0,
additional: 0,
};
buf.extend([0u8; 12].iter());
head.write(&mut buf[..12]);
Builder { buf: buf }
} /// Adds a question to the packet /// /// # Panics /// /// * Answers, nameservers or additional section has already been written /// * There are already 65535 questions in the buffer. /// * When name is invalid pubfn add_question(&mutself, qname: &str, prefer_unicast: bool,
qtype: QueryType, qclass: QueryClass)
-> &mut Builder
{ if &self.buf[6..12] != b"\x00\x00\x00\x00\x00\x00" {
panic!("Too late to add a question");
} self.write_name(qname); self.buf.write_u16::<BigEndian>(qtype as u16).unwrap(); let prefer_unicast: u16 = if prefer_unicast { 0x8000 } else { 0x0000 }; self.buf.write_u16::<BigEndian>(qclass as u16 | prefer_unicast).unwrap(); let oldq = BigEndian::read_u16(&self.buf[4..6]); if oldq == 65535 {
panic!("Too many questions");
}
BigEndian::write_u16(&mutself.buf[4..6], oldq+1); self
} fn write_name(&mutself, name: &str) { for part in name.split('.') {
assert!(part.len() < 63); let ln = part.len() as u8; self.buf.push(ln); self.buf.extend(part.as_bytes());
} self.buf.push(0);
} /// Returns the final packet /// /// When packet is not truncated method returns `Ok(packet)`. If /// packet is truncated the method returns `Err(packet)`. In both /// cases the packet is fully valid. /// /// In the server implementation you may use /// `x.build().unwrap_or_else(|x| x)`. /// /// In the client implementation it's probably unwise to send truncated /// packet, as it doesn't make sense. Even panicking may be more /// appropriate. // TODO(tailhook) does the truncation make sense for TCP, and how // to treat it for EDNS0? pubfn build(mutself) -> Result<Vec<u8>,Vec<u8>> { // TODO(tailhook) optimize labels ifself.buf.len() > 512 {
Header::set_truncated(&mutself.buf[..12]);
Err(self.buf)
} else {
Ok(self.buf)
}
}
}
#[cfg(test)] mod test { use QueryType as QT; use QueryClass as QC; usesuper::Builder;