Skip to content

Commit

Permalink
tmp commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jaytaph committed Nov 15, 2023
1 parent df8e9f9 commit 484ad85
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 258 deletions.
15 changes: 7 additions & 8 deletions src/dns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ struct IpEntry {
}

/// A DNS entry is a simple domain name to IP address mapping
#[derive(Default)]
struct DNSEntry {
// domain name
domain_name: String,
Expand All @@ -29,14 +30,11 @@ struct DNSEntry {
rr_ipv6_ptr: usize,
}

impl Default for DNSEntry {
fn default() -> DNSEntry {
impl DNSEntry {
pub(crate) fn new(domain: &str) -> DNSEntry {
DNSEntry {
domain_name: String::new(),
ipv4: Vec::new(),
ipv6: Vec::new(),
rr_ipv4_ptr: 0,
rr_ipv6_ptr: 0,
domain_name: domain.to_string(),
..Default::default()
}
}
}
Expand Down Expand Up @@ -70,7 +68,8 @@ impl DNSEntry {
}

/// Type of DNS resolution
enum ResolveType {
#[derive(Debug, PartialEq, Clone)]
pub enum ResolveType {
/// Only resolve IPV4 addresses (A)
Ipv4,
/// Only resolve IPV6 addresses (AAAA)
Expand Down
33 changes: 23 additions & 10 deletions src/dns/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,27 +43,40 @@ mod test {

#[test]
fn test_cache() {
let mut cache = Cache::new(2);
let mut cache = Cache::new(3);

cache.insert("example.com", DNSEntry::default());
cache.insert("example.org", DNSEntry::default());
cache.insert("example.net", DNSEntry::default());

assert_eq!(cache.values.len(), 2);
assert_eq!(cache.lru.len(), 2);
assert_eq!(cache.values.len(), 3);
assert_eq!(cache.lru.len(), 3);
assert_eq!(cache.lru[0], "example.com");
assert_eq!(cache.lru[1], "example.org");
assert_eq!(cache.lru[2], "example.net");

cache.get("example.org");
assert_eq!(cache.values.len(), 2);
assert_eq!(cache.lru.len(), 2);
assert_eq!(cache.lru[0], "example.org");
assert_eq!(cache.lru[1], "example.com");
assert_eq!(cache.lru[0], "example.com");
assert_eq!(cache.lru[1], "example.net");
assert_eq!(cache.lru[2], "example.org");

cache.insert("example.net", DNSEntry::default());
assert_eq!(cache.values.len(), 3);
assert_eq!(cache.lru.len(), 3);
assert_eq!(cache.lru[0], "example.com");
assert_eq!(cache.lru[1], "example.org");
assert_eq!(cache.lru[2], "example.net");

cache.get("example.com");
assert_eq!(cache.lru[0], "example.org");
assert_eq!(cache.lru[1], "example.net");
assert_eq!(cache.lru[2], "example.com");

assert_eq!(cache.values.len(), 2);
assert_eq!(cache.lru.len(), 2);
cache.insert("new.com", DNSEntry::default());
assert_eq!(cache.values.len(), 3);
assert_eq!(cache.lru.len(), 3);
assert_eq!(cache.lru[0], "example.net");
assert_eq!(cache.lru[1], "example.org");
assert_eq!(cache.lru[1], "example.com");
assert_eq!(cache.lru[2], "new.com");
}
}
134 changes: 0 additions & 134 deletions src/dns/default.rs
Original file line number Diff line number Diff line change
@@ -1,134 +0,0 @@
use std::collections::HashMap;
use std::net::IpAddr;
use wildmatch::WildMatch;
use crate::dns::DNSEntry;

/// Local override table that can be used instead of using /etc/hosts or similar 3rd party dns system.
pub struct LocalOverrideTable {
/// Entries in the local override table. First iteration of the resolver: a simple list that
/// will be queried O(n). Later iterations will use a more efficient data structure like a tree
/// per domain part (e.g. com, org, net, etc.)
entries: Vec<DNSEntry>,
round_robin_ptrs: HashMap<String, usize>,
}

impl Default for LocalOverrideTable {
fn default() -> LocalOverrideTable {
LocalOverrideTable {
entries: Vec::new(),
round_robin_ptrs: HashMap::new(),
}
}
}

impl LocalOverrideTable {

pub fn resolve(&mut self, domain: &str) -> Option<IpAddr> {
let mut ips = Vec::new();
let mut wildcard_ips = Vec::new();

// For now it's ok to iterate the entries list, but later we should use a more efficient
// data structure.
for entry in &self.entries {
// We separate wildcard matches and specific matches.
if WildMatch::new(&entry.domain_name).matches(domain) {
wildcard_ips.push(entry.ip);
}
if entry.domain_name == domain {
ips.push(entry.ip);
}
}

// if we haven't found a specific domain match, we use the wildcard domain, otherwise
// the specific matches take precedence.
if ips.len() == 0 {
ips = wildcard_ips
}

// If there is only one ip for a domain, return it
if ips.len() == 1 {
return Some(*ips.get(0).unwrap());
}

// If there are multiple ips for a domain, use round robin to fetch the next one
if ips.len() > 1 {
let mut rr_ptr = *self.round_robin_ptrs.get(domain).unwrap_or(&0);
if rr_ptr >= ips.len() {
rr_ptr = 0;
}

let ip = ips.get(rr_ptr).expect("Invalid round robin pointer");
self.round_robin_ptrs.insert(domain.to_string(), rr_ptr + 1 % ips.len());

return Some(*ip);
}

None
}
}


#[cfg(test)]
mod test {
use core::str::FromStr;
use crate::dns::DnsResolver;
use super::*;

#[test]
fn test_local_override() {
let mut resolver = DnsResolver::new();
resolver.local_override_enabled = true;
resolver.local_override.entries.push(DNSEntry {
domain_name: "example.com".to_string(),
ip: IpAddr::from_str("1.2.3.4").unwrap(),
});

resolver.local_override.entries.push(DNSEntry {
domain_name: "foo.example.com".to_string(),
ip: IpAddr::from_str("2.3.4.5").unwrap(),
});

resolver.local_override.entries.push(DNSEntry {
domain_name: "*.wilcard.com".to_string(),
ip: IpAddr::from_str("6.6.6.6").unwrap(),
});

resolver.local_override.entries.push(DNSEntry {
domain_name: "specific.wilcard.com".to_string(),
ip: IpAddr::from_str("8.8.8.8").unwrap(),
});

resolver.local_override.entries.push(DNSEntry {
domain_name: "ipv6.com".to_string(),
ip: IpAddr::from_str("2002::1").unwrap(),
});
resolver.local_override.entries.push(DNSEntry {
domain_name: "ipv6.com".to_string(),
ip: IpAddr::from_str("2002::2").unwrap(),
});
resolver.local_override.entries.push(DNSEntry {
domain_name: "ipv6.com".to_string(),
ip: IpAddr::from_str("200.200.200.200").unwrap(),
});

// Simple resolve
assert_eq!(IpAddr::from_str("1.2.3.4").unwrap(), resolver.resolve("example.com").unwrap());
assert!(resolver.resolve("xample.com").is_err());
assert!(resolver.resolve("com").is_err());
assert!(resolver.resolve("example").is_err());

// Wildcard
assert_eq!(IpAddr::from_str("8.8.8.8").unwrap(), resolver.resolve("specific.wilcard.com").unwrap());
assert_eq!(IpAddr::from_str("6.6.6.6").unwrap(), resolver.resolve("something.wilcard.com").unwrap());
assert_eq!(IpAddr::from_str("6.6.6.6").unwrap(), resolver.resolve("foobar.wilcard.com").unwrap());
assert!(resolver.resolve("wilcard.com").is_err());

// round robin
assert_eq!(IpAddr::from_str("2002::1").unwrap(), resolver.resolve("ipv6.com").unwrap());
assert_eq!(IpAddr::from_str("2002::2").unwrap(), resolver.resolve("ipv6.com").unwrap());
assert_eq!(IpAddr::from_str("200.200.200.200").unwrap(), resolver.resolve("ipv6.com").unwrap());
assert_eq!(IpAddr::from_str("2002::1").unwrap(), resolver.resolve("ipv6.com").unwrap());
assert_eq!(IpAddr::from_str("2002::2").unwrap(), resolver.resolve("ipv6.com").unwrap());
assert_eq!(IpAddr::from_str("200.200.200.200").unwrap(), resolver.resolve("ipv6.com").unwrap());
}
}
Loading

0 comments on commit 484ad85

Please sign in to comment.