Skip to content

Commit

Permalink
feat: implement endpoint ip resolution service
Browse files Browse the repository at this point in the history
  • Loading branch information
junkurihara committed Oct 25, 2023
1 parent 80c9ae3 commit eba3516
Show file tree
Hide file tree
Showing 12 changed files with 219 additions and 91 deletions.
9 changes: 6 additions & 3 deletions dap-bin/src/config/toml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,15 @@ impl TryInto<ProxyConfig> for &ConfigToml {
proxy_config.bootstrap_dns.ips = val.iter().map(|x| x.parse().unwrap()).collect()
};
info!("Bootstrap DNS: {:?}", proxy_config.bootstrap_dns.ips);

/////////////////////////////
// reboot period
if let Some(val) = self.reboot_period {
proxy_config.bootstrap_dns.rebootstrap_period_sec = Duration::from_secs((val as u64) * 60);
proxy_config.endpoint_resolution_period_sec = Duration::from_secs((val as u64) * 60);
}
info!(
"Target DoH Address is re-fetched every {:?} min via Bootsrap DNS",
proxy_config.bootstrap_dns.rebootstrap_period_sec.as_secs() / 60
"Target DoH and auth server addresses are re-fetched every {:?} min via DoH itself or Bootsrap DNS",
proxy_config.endpoint_resolution_period_sec.as_secs() / 60
);

/////////////////////////////
Expand Down
11 changes: 7 additions & 4 deletions dap-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,18 @@ tokio = { version = "1.33.0", features = [
"sync",
"macros",
] }
futures = { version = "0.3.28", default-features = false }
futures = { version = "0.3.28", default-features = false, features = [
"std",
"async-await",
] }
anyhow = "1.0.75"
tracing = "0.1.40"
thiserror = "1.0.50"
async-trait = "0.1.74"

# network
socket2 = "0.5.5"

# http client
reqwest = { version = "0.11.22", default-features = false, features = [
"json",
Expand All @@ -52,14 +58,11 @@ reqwest = { version = "0.11.22", default-features = false, features = [
] }
url = "2.4.1"


# for bootstrap dns resolver
trust-dns-resolver = { version = "0.23.2", default-features = false, features = [
"tokio-runtime",
] }


# authentication
auth-client = { git = "https://github.com/junkurihara/rust-token-server", package = "rust-token-server-client", branch = "develop" }
serde = { version = "1.0.189", features = ["derive"] }
socket2 = "0.5.5"
7 changes: 4 additions & 3 deletions dap-lib/src/bootstrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ use crate::{
};
use async_trait::async_trait;
use reqwest::Url;
use std::net::SocketAddr;
use std::{net::SocketAddr, sync::Arc};
use trust_dns_resolver::{
config::{NameServerConfigGroup, ResolverConfig, ResolverOpts},
name_server::{GenericConnector, TokioRuntimeProvider},
AsyncResolver, TokioAsyncResolver,
};

#[derive(Clone)]
/// stub resolver using bootstrap DNS resolver
pub struct BootstrapDnsResolver {
/// wrapper of trust-dns-resolver
Expand All @@ -37,7 +38,7 @@ impl BootstrapDnsResolver {
}

#[async_trait]
impl ResolveIps for BootstrapDnsResolver {
impl ResolveIps for Arc<BootstrapDnsResolver> {
/// Lookup the IP addresses associated with a name using the bootstrap resolver
async fn resolve_ips(&self, target_url: &Url) -> Result<ResolveIpResponse> {
// The final dot forces this to be an FQDN, otherwise the search rules as specified
Expand Down Expand Up @@ -88,11 +89,11 @@ mod tests {
let bootstrap_dns = BootstrapDns {
ips: vec![IpAddr::from([8, 8, 8, 8])],
port: 53,
rebootstrap_period_sec: tokio::time::Duration::from_secs(1),
};
let resolver = BootstrapDnsResolver::try_new(&bootstrap_dns, tokio::runtime::Handle::current())
.await
.unwrap();
let resolver = Arc::new(resolver);
let target_url = Url::parse("https://dns.google").unwrap();
let response = resolver.resolve_ips(&target_url).await.unwrap();

Expand Down
10 changes: 9 additions & 1 deletion dap-lib/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,19 @@ pub const MIN_TTL: u32 = 10; // TTL for overridden records (plugin)
// Default Values for Config //
////////////////////////////////
// Can override by specifying values in config.toml

/// Default listen address
pub const LISTEN_ADDRESSES: &[&str] = &["127.0.0.1:50053", "[::1]:50053"];

/// Bootstrap DNS address
pub const BOOTSTRAP_DNS_IPS: &[&str] = &["1.1.1.1"];
/// Bootstrap DNS port
pub const BOOTSTRAP_DNS_PORT: u16 = 53;
pub const REBOOTSTRAP_PERIOD_MIN: u64 = 60;

/// Endpoint resolution period in minutes
pub const ENDPOINT_RESOLUTION_PERIOD_MIN: u64 = 60;

/// Default DoH target server
pub const DOH_TARGET_URL: &[&str] = &["https://dns.google/dns-query"];

pub const MAX_CACHE_SIZE: usize = 16384;
Expand Down
18 changes: 17 additions & 1 deletion dap-lib/src/doh_client/doh_client_main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
use crate::{error::*, globals::Globals, http_client::HttpClientInner};
use crate::{
error::*,
globals::Globals,
http_client::HttpClientInner,
trait_resolve_ips::{ResolveIpResponse, ResolveIps},
};
use async_trait::async_trait;
use std::sync::Arc;
use tokio::sync::RwLock;
use url::Url;

#[derive(Debug)]
/// DoH, ODoH, MODoH client
Expand All @@ -19,3 +26,12 @@ impl DoHClient {
Ok(vec![])
}
}

// TODO: implement ResolveIps for DoHClient
#[async_trait]
impl ResolveIps for Arc<DoHClient> {
/// Resolve ip addresses of the given domain name
async fn resolve_ips(&self, domain: &Url) -> Result<ResolveIpResponse> {
Err(DapError::Other(anyhow!("Not implemented")))
}
}
6 changes: 4 additions & 2 deletions dap-lib/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ pub enum DapError {

#[error("HttpClient error")]
HttpClientError(#[from] reqwest::Error),
#[error("HttpClient build error")]
HttpClientBuildError,
#[error("Failed to resolve Ips for HTTP client")]
FailedToResolveIpsForHttpClient,
#[error("Too many fails to resolve Ips for HTTP client in periodic task")]
TooManyFailsToResolveIps,
#[error("Io Error: {0}")]
Io(#[from] std::io::Error),
#[error("Null TCP stream")]
Expand Down
15 changes: 4 additions & 11 deletions dap-lib/src/globals.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
use crate::{
constants::*,
doh_client::{DoHClient, DoHMethod},
http_client::HttpClient,
};
use crate::{constants::*, doh_client::DoHMethod, http_client::HttpClient};
use auth_client::AuthenticationConfig;
use std::{
net::{IpAddr, SocketAddr},
sync::Arc,
};
use tokio::{
sync::{Notify, RwLock},
time::Duration,
};
use tokio::{sync::Notify, time::Duration};
use url::Url;

#[derive(Debug)]
Expand Down Expand Up @@ -39,6 +32,7 @@ pub struct ProxyConfig {

/// bootstrap DNS
pub bootstrap_dns: BootstrapDns,
pub endpoint_resolution_period_sec: Duration,

// udp and tcp proxy setting
pub udp_buffer_size: usize,
Expand Down Expand Up @@ -70,7 +64,6 @@ pub struct ProxyConfig {
pub struct BootstrapDns {
pub ips: Vec<IpAddr>,
pub port: u16,
pub rebootstrap_period_sec: Duration,
}

#[derive(PartialEq, Eq, Debug, Clone)]
Expand Down Expand Up @@ -115,8 +108,8 @@ impl Default for ProxyConfig {
bootstrap_dns: BootstrapDns {
ips: BOOTSTRAP_DNS_IPS.iter().map(|v| v.parse().unwrap()).collect(),
port: BOOTSTRAP_DNS_PORT,
rebootstrap_period_sec: Duration::from_secs(REBOOTSTRAP_PERIOD_MIN * 60),
},
endpoint_resolution_period_sec: Duration::from_secs(ENDPOINT_RESOLUTION_PERIOD_MIN * 60),

udp_buffer_size: UDP_BUFFER_SIZE,
udp_channel_capacity: UDP_CHANNEL_CAPACITY,
Expand Down
50 changes: 33 additions & 17 deletions dap-lib/src/http_client/http_client_main.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
use std::sync::Arc;

use crate::{
error::*,
trait_resolve_ips::{ResolveIpResponse, ResolveIps},
trait_resolve_ips::{resolve_ips, ResolveIpResponse, ResolveIps},
};
use futures::future::join_all;
use reqwest::{header::HeaderMap, Client, IntoUrl, RequestBuilder, Url};
use std::sync::Arc;
use tokio::{sync::RwLock, time::Duration};

#[derive(Debug)]
Expand All @@ -18,8 +16,14 @@ pub struct HttpClient {
/// This would be targets for DoH, nexthop relay for ODoH (path including target, not mid-relays for dynamic randomization)
endpoints: Vec<Url>,

/// default headers
default_headers: Option<HeaderMap>,

/// timeout for http request
timeout_sec: Duration,

/// rebootstrap period for endpoint ip resolution
rebootstrap_period_sec: Duration,
}

impl HttpClient {
Expand All @@ -29,21 +33,44 @@ impl HttpClient {
timeout_sec: Duration,
default_headers: Option<&HeaderMap>,
resolver_ips: impl ResolveIps,
rebootstrap_period_sec: Duration,
) -> Result<Self> {
let resolved_ips = resolve_ips(endpoints, resolver_ips).await?;
Ok(Self {
inner: Arc::new(RwLock::new(
HttpClientInner::new(timeout_sec, default_headers, &resolved_ips).await?,
)),
default_headers: default_headers.cloned(),
timeout_sec,
endpoints: endpoints.to_vec(),
rebootstrap_period_sec,
})
}

/// Get inner client pointer
pub fn inner(&self) -> Arc<RwLock<HttpClientInner>> {
self.inner.clone()
}

/// Get endpoints
pub fn endpoints(&self) -> &[Url] {
&self.endpoints
}

/// Get default headers
pub fn default_headers(&self) -> Option<&HeaderMap> {
self.default_headers.as_ref()
}

/// Get timeout
pub fn timeout_sec(&self) -> Duration {
self.timeout_sec
}

/// Get rebootstrap period
pub fn rebootstrap_period_sec(&self) -> Duration {
self.rebootstrap_period_sec
}
}

#[derive(Debug)]
Expand Down Expand Up @@ -79,23 +106,12 @@ impl HttpClientInner {
}

/// Post wrapper
pub async fn post(&self, url: impl IntoUrl) -> RequestBuilder {
pub fn post(&self, url: impl IntoUrl) -> RequestBuilder {
self.client.post(url)
}

/// Get wrapper
pub async fn get(&self, url: impl IntoUrl) -> RequestBuilder {
pub fn get(&self, url: impl IntoUrl) -> RequestBuilder {
self.client.get(url)
}
}

/// Resolve ip addresses for given endpoints
async fn resolve_ips(endpoints: &[Url], resolver_ips: impl ResolveIps) -> Result<Vec<ResolveIpResponse>> {
let resolve_ips_fut = endpoints.iter().map(|endpoint| resolver_ips.resolve_ips(endpoint));
let resolve_ips = join_all(resolve_ips_fut).await;
if resolve_ips.iter().any(|resolve_ip| resolve_ip.is_err()) {
return Err(DapError::HttpClientBuildError);
}
let resolve_ips_vec = resolve_ips.into_iter().map(|resolve_ip| resolve_ip.unwrap()).collect();
Ok(resolve_ips_vec)
}
Loading

0 comments on commit eba3516

Please sign in to comment.