Skip to content

Commit

Permalink
fix: dhcp should not block program from launching
Browse files Browse the repository at this point in the history
  • Loading branch information
XOR-op committed Mar 2, 2025
1 parent fffc9bf commit dfa59aa
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 41 deletions.
7 changes: 2 additions & 5 deletions boltconn/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,11 +329,8 @@ impl App {
.map_err(|e| anyhow!("Load intercept rules failed: {}", e))?,
);

// this is atomic
self.dns.replace_resolvers(&self.outbound_iface, group)?;

// start atomic replacing

self.dns.replace_resolvers(&self.outbound_iface, group);
self.dns.replace_ns_policy(ns_policy);
self.dns.replace_hosts(&config.dns.hosts);
self.dns_hijack_ctrl.update(
Expand Down Expand Up @@ -456,7 +453,7 @@ async fn initialize_dns(
&config.hosts,
ns_policy,
group,
)?)
))
})
}

Expand Down
26 changes: 10 additions & 16 deletions boltconn/src/network/dns/dns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::network::dns::hosts::HostsResolver;
use crate::network::dns::ns_policy::{DispatchedDnsResolver, NameserverPolicies};
use crate::network::dns::provider::IfaceProvider;
use crate::network::dns::{default_resolver_opt, AuxiliaryResolver, NameServerConfigEnum};
use crate::proxy::error::{DnsError, TransportError};
use crate::proxy::error::TransportError;
use arc_swap::ArcSwap;
use hickory_proto::op::{Message, MessageType, ResponseCode};
use hickory_proto::rr::{DNSClass, RData, Record, RecordType};
Expand Down Expand Up @@ -99,17 +99,17 @@ impl Dns {
hosts: &HashMap<String, IpAddr>,
ns_policy: NameserverPolicies,
configs: Vec<NameServerConfigEnum>,
) -> Result<Dns, DnsError> {
let resolvers = Self::build_resolvers(iface_name, configs)?;
) -> Dns {
let resolvers = Self::build_resolvers(iface_name, configs);
let host_resolver = HostsResolver::new(hosts);
Ok(Dns {
Dns {
name: name.to_string(),
table: DnsTable::new(),
preference,
host_resolver: ArcSwap::new(Arc::new(host_resolver)),
ns_policy: ArcSwap::new(Arc::new(ns_policy)),
resolvers: ArcSwap::new(Arc::new(resolvers)),
})
}
}

pub fn replace_hosts(&self, hosts: &HashMap<String, IpAddr>) {
Expand All @@ -122,21 +122,15 @@ impl Dns {
}

// This function is atomic
pub fn replace_resolvers(
&self,
iface_name: &str,
configs: Vec<NameServerConfigEnum>,
) -> Result<(), DnsError> {
let resolvers = Self::build_resolvers(iface_name, configs)?;
pub fn replace_resolvers(&self, iface_name: &str, configs: Vec<NameServerConfigEnum>) {
let resolvers = Self::build_resolvers(iface_name, configs);
self.resolvers.store(Arc::new(resolvers));
Ok(())
}

fn build_resolvers(
iface_name: &str,
configs: Vec<NameServerConfigEnum>,
) -> Result<Vec<AuxiliaryResolver<AsyncResolver<GenericConnector<IfaceProvider>>>>, DnsError>
{
) -> Vec<AuxiliaryResolver<AsyncResolver<GenericConnector<IfaceProvider>>>> {
let mut resolvers = Vec::new();
for config in configs.into_iter() {
let resolver = match config {
Expand All @@ -148,11 +142,11 @@ impl Dns {
GenericConnector::new(IfaceProvider::new(iface_name)),
))
}
NameServerConfigEnum::Dhcp(dhcp) => AuxiliaryResolver::new_dhcp(&dhcp)?,
NameServerConfigEnum::Dhcp(dhcp) => AuxiliaryResolver::new_dhcp(&dhcp),
};
resolvers.push(resolver);
}
Ok(resolvers)
resolvers
}
}

Expand Down
46 changes: 27 additions & 19 deletions boltconn/src/network/dns/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ mod ns_policy;
mod provider;

use crate::config::DnsConfigError;
use crate::proxy::error::{DnsError, TransportError};
use crate::proxy::error::DnsError;
pub use bootstrap::BootstrapResolver;
pub use dns::{Dns, GenericDns};
use hickory_resolver::config::{
Expand Down Expand Up @@ -167,32 +167,40 @@ struct DhcpDnsRecord {
}

impl DhcpDnsRecord {
pub fn new(iface: &str) -> Result<Self, DnsError> {
let iface_addr = crate::platform::get_iface_address(iface)
.map_err(|_| DnsError::DhcpNameServer("failed to get iface address"))?;
let ns_addr = crate::platform::dhcp::get_dhcp_dns(iface)?;
tracing::debug!(
"DHCP DNS: iface={}, iface_addr={}, ns_addr={}",
iface,
iface_addr,
ns_addr
);
Ok(Self {
pub fn new(iface: &str) -> Self {
let mut iface_addr = crate::platform::get_iface_address(iface).ok();
let ns_addr = match crate::platform::dhcp::get_dhcp_dns(iface) {
Ok(addr) => addr,
Err(e) => {
tracing::warn!(
"DHCP DNS: iface={}, iface_addr={:?}, error={}, use empty address",
iface,
iface_addr,
e
);
// we don't want the replayable fault stop the program from running
// e.g. start offline but soon connect to a network with DHCP
iface_addr = None;
IpAddr::V4(std::net::Ipv4Addr::new(127, 0, 0, 1))
}
};
Self {
iface: iface.to_string(),
iface_addr,
iface_addr: iface_addr.unwrap_or(IpAddr::V4(std::net::Ipv4Addr::new(127, 0, 0, 1))),
ns_addr,
last_checked: std::time::Instant::now(),
resolver: Self::create_resolver(ns_addr, iface),
})
}
}

// return if the record is updated
pub fn refresh(&mut self) -> Result<bool, TransportError> {
pub fn refresh(&mut self) -> Result<bool, DnsError> {
if self.last_checked.elapsed() < Duration::from_secs(30) {
Ok(false)
} else {
// when error occurs, update the record in a best-effort way
let addr = crate::platform::get_iface_address(&self.iface)?;
let addr = crate::platform::get_iface_address(&self.iface)
.map_err(|_| DnsError::DhcpNameServer("failed to get iface address"))?;
if addr != self.iface_addr {
let new_dns = crate::platform::dhcp::get_dhcp_dns(&self.iface)?;
self.iface_addr = addr;
Expand Down Expand Up @@ -241,8 +249,8 @@ impl<T> AuxiliaryResolver<T> {
Self::Resolver(resolver)
}

pub fn new_dhcp(iface: &str) -> Result<Self, DnsError> {
let record = DhcpDnsRecord::new(iface)?;
Ok(Self::Dhcp(Mutex::new(record)))
pub fn new_dhcp(iface: &str) -> Self {
let record = DhcpDnsRecord::new(iface);
Self::Dhcp(Mutex::new(record))
}
}
2 changes: 1 addition & 1 deletion boltconn/src/network/dns/ns_policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ impl NameserverPolicies {
}
}
NameServerConfigEnum::Dhcp(iface) => {
DispatchedDnsResolver::Iface(AuxiliaryResolver::new_dhcp(&iface)?)
DispatchedDnsResolver::Iface(AuxiliaryResolver::new_dhcp(&iface))
}
};
let matcher = m.build();
Expand Down

0 comments on commit dfa59aa

Please sign in to comment.