summaryrefslogtreecommitdiff
path: root/packet/src/lib.rs
diff options
context:
space:
mode:
authorTyler Murphy <tylermurphy534@gmail.com>2023-03-03 00:10:21 -0500
committerTyler Murphy <tylermurphy534@gmail.com>2023-03-03 00:10:21 -0500
commit0f40ab89e3b523ac206077d932a0e2d40d75f7e0 (patch)
treec4914050d1bbca8af77347220c0785c8ebefa213 /packet/src/lib.rs
parentclippy my beloved (diff)
downloadwrapper-0f40ab89e3b523ac206077d932a0e2d40d75f7e0.tar.gz
wrapper-0f40ab89e3b523ac206077d932a0e2d40d75f7e0.tar.bz2
wrapper-0f40ab89e3b523ac206077d932a0e2d40d75f7e0.zip
finialize initial dns + caching
Diffstat (limited to 'packet/src/lib.rs')
-rw-r--r--packet/src/lib.rs156
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