diff options
Diffstat (limited to 'packet/src/lib.rs')
-rw-r--r-- | packet/src/lib.rs | 156 |
1 files changed, 0 insertions, 156 deletions
diff --git a/packet/src/lib.rs b/packet/src/lib.rs deleted file mode 100644 index c7a8eb9..0000000 --- a/packet/src/lib.rs +++ /dev/null @@ -1,156 +0,0 @@ -use std::net::IpAddr; - -use self::{header::DnsHeader, question::DnsQuestion, record::DnsRecord, query::QueryType}; - -type Error = Box<dyn std::error::Error>; -pub type Result<T> = std::result::Result<T, Error>; - -mod buffer; -mod header; -mod query; -mod question; -mod record; -mod result; - -#[derive(Clone, Debug)] -pub struct Packet { - pub header: DnsHeader, - pub questions: Vec<DnsQuestion>, - pub answers: Vec<DnsRecord>, - pub authorities: Vec<DnsRecord>, - pub resources: Vec<DnsRecord>, -} - -pub use buffer::PacketBuffer; -pub use result::ResultCode; - -pub use query::QueryType as PacketType; -pub use question::DnsQuestion as PacketQuestion; - -impl Packet { - pub fn new() -> Self { - Self { - header: DnsHeader::new(), - questions: Vec::new(), - answers: Vec::new(), - authorities: Vec::new(), - resources: Vec::new(), - } - } - - pub fn from_buffer(buffer: &mut PacketBuffer) -> Result<Self> { - let mut result = Self::new(); - result.header.read(buffer)?; - - for _ in 0..result.header.questions { - let mut question = DnsQuestion::new("".to_string(), QueryType::UNKNOWN(0)); - question.read(buffer)?; - result.questions.push(question); - } - - for _ in 0..result.header.answers { - let rec = DnsRecord::read(buffer)?; - result.answers.push(rec); - } - for _ in 0..result.header.authoritative_entries { - let rec = DnsRecord::read(buffer)?; - result.authorities.push(rec); - } - for _ in 0..result.header.resource_entries { - let rec = DnsRecord::read(buffer)?; - result.resources.push(rec); - } - - Ok(result) - } - - pub fn write(&mut self, buffer: &mut PacketBuffer) -> Result<()> { - self.header.questions = self.questions.len() as u16; - self.header.answers = self.answers.len() as u16; - self.header.authoritative_entries = self.authorities.len() as u16; - self.header.resource_entries = self.resources.len() as u16; - - self.header.write(buffer)?; - - for question in &self.questions { - question.write(buffer)?; - } - for rec in &self.answers { - rec.write(buffer)?; - } - for rec in &self.authorities { - rec.write(buffer)?; - } - for rec in &self.resources { - rec.write(buffer)?; - } - - Ok(()) - } - - /// It's useful to be able to pick a random A record from a packet. When we - /// get multiple IP's for a single name, it doesn't matter which one we - /// choose, so in those cases we can now pick one at random. - pub fn get_random_a(&self) -> Option<IpAddr> { - self.answers - .iter() - .filter_map(|record| match record { - DnsRecord::A { addr, .. } => Some(IpAddr::V4(*addr)), - DnsRecord::AAAA { addr, .. } => Some(IpAddr::V6(*addr)), - _ => None, - }) - .next() - } - - /// A helper function which returns an iterator over all name servers in - /// the authorities section, represented as (domain, host) tuples - fn get_ns<'a>(&'a self, qname: &'a str) -> impl Iterator<Item = (&'a str, &'a str)> { - self.authorities - .iter() - // In practice, these are always NS records in well formed packages. - // Convert the NS records to a tuple which has only the data we need - // to make it easy to work with. - .filter_map(|record| match record { - DnsRecord::NS { domain, host, .. } => Some((domain.as_str(), host.as_str())), - _ => None, - }) - // Discard servers which aren't authoritative to our query - .filter(move |(domain, _)| qname.ends_with(*domain)) - } - - /// We'll use the fact that name servers often bundle the corresponding - /// A records when replying to an NS query to implement a function that - /// returns the actual IP for an NS record if possible. - pub fn get_resolved_ns(&self, qname: &str) -> Option<IpAddr> { - // Get an iterator over the nameservers in the authorities section - self.get_ns(qname) - // Now we need to look for a matching A record in the additional - // section. Since we just want the first valid record, we can just - // build a stream of matching records. - .flat_map(|(_, host)| { - self.resources - .iter() - // Filter for A records where the domain match the host - // of the NS record that we are currently processing - .filter_map(move |record| match record { - DnsRecord::A { domain, addr, .. } if domain == host => Some(IpAddr::V4(*addr)), - DnsRecord::AAAA { domain, addr, .. } if domain == host => Some(IpAddr::V6(*addr)), - _ => None, - }) - }) - // Finally, pick the first valid entry - .next() - } - - /// However, not all name servers are as that nice. In certain cases there won't - /// be any A records in the additional section, and we'll have to perform *another* - /// lookup in the midst. For this, we introduce a method for returning the host - /// name of an appropriate name server. - pub fn get_unresolved_ns<'a>(&'a self, qname: &'a str) -> Option<&'a str> { - // Get an iterator over the nameservers in the authorities section - self.get_ns(qname) - .map(|(_, host)| host) - // Finally, pick the first valid entry - .next() - } -}
\ No newline at end of file |