use futures::future::BoxFuture;
use log::{debug, warn};
use tokio::net::UdpSocket;
use crate::ClientQuery;
use crate::dns_parser;
use crate::errors::{DnsError, DnsResult};
use crate::load_balancer::LoadBalancingStrategy;
use crate::stats::SharedStats;
use std::net::SocketAddr;
use std::sync::Arc;
pub async fn recv_from_peer(
socket: &UdpSocket,
buf: &mut [u8],
peer: SocketAddr,
) -> std::io::Result<usize> {
loop {
let (len, source) = socket.recv_from(buf).await?;
if source == peer {
return Ok(len);
}
debug!("Ignoring datagram from unexpected source {source}, expected {peer}");
}
}
#[allow(dead_code)]
pub fn create_resolver(
upstream_servers: Vec<String>,
server_timeout: u64,
dns_packet_len_max: usize,
stats: Option<Arc<SharedStats>>,
load_balancing_strategy: LoadBalancingStrategy,
) -> impl Fn(Vec<u8>) -> BoxFuture<'static, DnsResult<Vec<u8>>> + Send + Sync + 'static {
create_resolver_with_client_ip(
upstream_servers,
server_timeout,
dns_packet_len_max,
stats,
load_balancing_strategy,
String::new(),
false,
24,
56,
true,
)
}
pub fn create_resolver_with_client_ip(
upstream_servers: Vec<String>,
server_timeout: u64,
dns_packet_len_max: usize,
stats: Option<Arc<SharedStats>>,
load_balancing_strategy: LoadBalancingStrategy,
client_ip: String,
enable_ecs: bool,
ecs_prefix_v4: u8,
ecs_prefix_v6: u8,
spoof_protection: bool,
) -> impl Fn(Vec<u8>) -> BoxFuture<'static, DnsResult<Vec<u8>>> + Send + Sync + 'static {
let upstream_servers_arc = Arc::new(upstream_servers);
let stats_arc = stats.map(|s| Arc::clone(&s));
let client_ip_clone = client_ip.clone();
let enable_ecs_clone = enable_ecs;
let ecs_prefix_v4_clone = ecs_prefix_v4;
let ecs_prefix_v6_clone = ecs_prefix_v6;
move |data: Vec<u8>| {
let upstream_servers_ref = Arc::clone(&upstream_servers_arc);
let client_query = match &stats_arc {
Some(stats) => {
if enable_ecs_clone && !client_ip_clone.is_empty() {
ClientQuery::new_with_client_ip(
data,
(*upstream_servers_ref).clone(),
server_timeout,
dns_packet_len_max,
Arc::clone(stats),
load_balancing_strategy,
client_ip_clone.clone(),
enable_ecs_clone,
ecs_prefix_v4_clone,
ecs_prefix_v6_clone,
spoof_protection,
)
} else {
ClientQuery {
spoof_protection,
..ClientQuery::new(
data,
(*upstream_servers_ref).clone(),
server_timeout,
dns_packet_len_max,
Arc::clone(stats),
load_balancing_strategy,
)
}
}
}
None => {
warn!("No stats available for resolver function");
ClientQuery {
data,
upstream_servers: (*upstream_servers_ref).clone(),
server_timeout,
dns_packet_len_max,
max_udp_response_size: dns_parser::DNS_MAX_UDP_PACKET_SIZE,
stats: None,
load_balancing_strategy,
client_ip: if enable_ecs_clone && !client_ip_clone.is_empty() {
Some(client_ip_clone.clone())
} else {
None
},
enable_ecs: enable_ecs_clone,
ecs_prefix_v4: ecs_prefix_v4_clone,
ecs_prefix_v6: ecs_prefix_v6_clone,
spoof_protection,
}
}
};
Box::pin(async move {
match client_query.process().await {
Ok(data) => Ok(data),
Err(e) => Err(DnsError::UpstreamError(format!("Error: {e}"))),
}
}) as BoxFuture<'static, _>
}
}