Skip to content

Commit

Permalink
feat: support DNS hosts
Browse files Browse the repository at this point in the history
  • Loading branch information
XOR-op committed Mar 16, 2024
1 parent 62d2eba commit 86d0501
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 7 deletions.
9 changes: 7 additions & 2 deletions boltconn/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,13 @@ impl App {
Err(e) => return Err(anyhow!("Parse dns config failed: {e}")),
};
Arc::new(
Dns::with_config(outbound_iface.as_str(), config.dns.preference, group)
.map_err(|e| anyhow!("DNS failed to initialize: {e}"))?,
Dns::with_config(
outbound_iface.as_str(),
config.dns.preference,
&config.dns.hosts,
group,
)
.map_err(|e| anyhow!("DNS failed to initialize: {e}"))?,
)
};

Expand Down
10 changes: 7 additions & 3 deletions boltconn/src/common/host_matcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,16 @@ impl HostMatcher {
}
false
}

pub fn builder() -> HostMatcherBuilder {
HostMatcherBuilder::new()
}
}

pub struct HostMatcherBuilder(Vec<(String, HostType)>);

impl HostMatcherBuilder {
pub fn new() -> Self {
fn new() -> Self {
Self(Vec::new())
}

Expand All @@ -64,7 +68,7 @@ impl HostMatcherBuilder {

#[test]
fn test_matcher() {
let mut builder = HostMatcherBuilder::new();
let mut builder = HostMatcher::builder();
builder.add_suffix("telemetry.google.com");
builder.add_suffix("analytics.google.com");
builder.add_exact("test.google.com");
Expand All @@ -77,7 +81,7 @@ fn test_matcher() {
assert!(!matcher.matches("me.notgoogle.com"));
assert!(!matcher.matches("ogle.com"));
assert!(!matcher.matches("t-02.test.google.com"));
let mut builder = HostMatcherBuilder::new();
let mut builder = HostMatcher::builder();
builder.add_suffix("ogle.com");
let matcher = builder.build();
assert!(matcher.matches("hi.ogle.com"));
Expand Down
6 changes: 6 additions & 0 deletions boltconn/src/config/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ pub struct RawDnsConfig {
pub preference: DnsPreference,
pub bootstrap: Vec<IpAddr>,
pub nameserver: Vec<String>,
#[serde(default = "default_hosts")]
pub hosts: HashMap<String, IpAddr>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
Expand Down Expand Up @@ -183,6 +185,10 @@ fn default_module() -> Vec<ModuleConfig> {
Default::default()
}

fn default_hosts() -> HashMap<String, IpAddr> {
Default::default()
}

fn default_dns_pref() -> DnsPreference {
DnsPreference::PreferIpv4
}
Expand Down
4 changes: 2 additions & 2 deletions boltconn/src/dispatch/ruleset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ impl RuleSetBuilder {
pub fn new(name: &str, payload: &RuleSchema) -> Option<Self> {
let mut retval = Self {
name: name.to_string(),
domain: HostMatcherBuilder::new(),
domain: HostMatcher::builder(),
domain_keyword: vec![],
ip_cidr: Default::default(),
local_ip_cidr: Default::default(),
Expand Down Expand Up @@ -286,7 +286,7 @@ impl RuleSetBuilder {
});
Self {
name: name.to_string(),
domain: HostMatcherBuilder::new(),
domain: HostMatcher::builder(),
domain_keyword: vec![],
ip_cidr: table,
local_ip_cidr: Default::default(),
Expand Down
10 changes: 10 additions & 0 deletions boltconn/src/network/dns/dns.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use crate::config::DnsPreference;
use crate::network::dns::dns_table::DnsTable;
use crate::network::dns::hosts::HostsResolver;
use crate::network::dns::provider::IfaceProvider;
use arc_swap::ArcSwap;
use hickory_proto::op::{Message, MessageType, ResponseCode};
use hickory_proto::rr::{DNSClass, RData, Record, RecordType};
use hickory_resolver::config::*;
use hickory_resolver::name_server::{GenericConnector, RuntimeProvider};
use hickory_resolver::AsyncResolver;
use std::collections::HashMap;
use std::io;
use std::io::Result;
use std::net::IpAddr;
Expand All @@ -16,6 +18,7 @@ use std::time::Duration;
pub struct GenericDns<P: RuntimeProvider> {
table: DnsTable,
preference: DnsPreference,
host_resolver: ArcSwap<HostsResolver>,
resolvers: ArcSwap<Vec<AsyncResolver<GenericConnector<P>>>>,
}

Expand All @@ -25,6 +28,7 @@ impl Dns {
pub fn with_config(
iface_name: &str,
preference: DnsPreference,
hosts: &HashMap<String, IpAddr>,
configs: Vec<NameServerConfigGroup>,
) -> anyhow::Result<Dns> {
let mut resolvers = Vec::new();
Expand All @@ -36,9 +40,11 @@ impl Dns {
GenericConnector::new(IfaceProvider::new(iface_name)),
));
}
let host_resolver = HostsResolver::new(hosts);
Ok(Dns {
table: DnsTable::new(),
preference,
host_resolver: ArcSwap::new(Arc::new(host_resolver)),
resolvers: ArcSwap::new(Arc::new(resolvers)),
})
}
Expand Down Expand Up @@ -70,6 +76,7 @@ impl<P: RuntimeProvider> GenericDns<P> {
Self {
table: DnsTable::new(),
preference,
host_resolver: ArcSwap::new(Arc::new(HostsResolver::empty())),
resolvers: ArcSwap::new(Arc::new(vec![resolver])),
}
}
Expand Down Expand Up @@ -126,6 +133,9 @@ impl<P: RuntimeProvider> GenericDns<P> {
}

pub async fn genuine_lookup(&self, domain_name: &str) -> Option<IpAddr> {
if let Some(ip) = self.host_resolver.load().resolve(domain_name) {
return Some(ip);
}
match self.preference {
DnsPreference::Ipv4Only => self.genuine_lookup_v4(domain_name).await,
DnsPreference::Ipv6Only => self.genuine_lookup_v6(domain_name).await,
Expand Down
53 changes: 53 additions & 0 deletions boltconn/src/network/dns/hosts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use crate::common::host_matcher::HostMatcher;
use std::collections::HashMap;
use std::net::IpAddr;

pub(super) struct HostsResolver {
matcher: HostMatcher,
exact_resolver: HashMap<String, IpAddr>,
suffix_resolver: Vec<(String, IpAddr)>,
}

impl HostsResolver {
pub fn new(hosts: &HashMap<String, IpAddr>) -> Self {
let mut exact_resolver = HashMap::new();
let mut suffix_resolver = Vec::new();
let mut builder = HostMatcher::builder();
for (host, ip) in hosts {
if let Some(stripped_host) = host.strip_prefix("*.") {
suffix_resolver.push((stripped_host.to_string(), *ip));
builder.add_suffix(stripped_host);
} else {
exact_resolver.insert(host.to_string(), *ip);
builder.add_exact(host);
}
}
Self {
matcher: builder.build(),
exact_resolver,
suffix_resolver,
}
}

pub fn empty() -> Self {
Self {
matcher: HostMatcher::builder().build(),
exact_resolver: HashMap::new(),
suffix_resolver: Vec::new(),
}
}

pub fn resolve(&self, host: &str) -> Option<IpAddr> {
if !self.matcher.matches(host) {
return None;
} else if let Some(ip) = self.exact_resolver.get(host) {
return Some(*ip);
}
for (suffix, ip) in &self.suffix_resolver {
if host.ends_with(suffix) {
return Some(*ip);
}
}
None
}
}
1 change: 1 addition & 0 deletions boltconn/src/network/dns/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#[allow(clippy::module_inception)]
mod dns;
mod dns_table;
mod hosts;
mod provider;

use crate::network::dns::provider::IfaceProvider;
Expand Down

0 comments on commit 86d0501

Please sign in to comment.