diff options
Diffstat (limited to 'src/dns/server.rs')
-rw-r--r-- | src/dns/server.rs | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/src/dns/server.rs b/src/dns/server.rs new file mode 100644 index 0000000..65d15df --- /dev/null +++ b/src/dns/server.rs @@ -0,0 +1,85 @@ +use super::{ + binding::Binding, + packet::{question::DnsQuestion, Packet}, + resolver::Resolver, +}; +use crate::{config::Config, database::Database, Result}; +use moka::future::Cache; +use std::{net::SocketAddr, sync::Arc, time::Duration}; +use tokio::task::JoinHandle; +use tracing::{error, info}; + +pub struct DnsServer { + addr: SocketAddr, + config: Arc<Config>, + database: Arc<Database>, + cache: Cache<DnsQuestion, (Packet, u64)>, +} + +impl DnsServer { + pub async fn new(config: Config, database: Database) -> Result<Self> { + let addr = format!("[::]:{}", config.dns_port).parse::<SocketAddr>()?; + let cache = Cache::builder() + .time_to_live(Duration::from_secs(60 * 60)) + .max_capacity(config.dns_cache_size) + .build(); + + info!("Created DNS cache with size of {}", config.dns_cache_size); + + Ok(Self { + addr, + config: Arc::new(config), + database: Arc::new(database), + cache, + }) + } + + pub async fn run(&self) -> Result<(JoinHandle<()>, JoinHandle<()>)> { + let tcp = Binding::tcp(self.addr).await?; + let tcp_handle = self.listen(tcp); + + let udp = Binding::udp(self.addr).await?; + let udp_handle = self.listen(udp); + + info!( + "Fallback DNS Server is set to: {:?}", + self.config.dns_fallback + ); + info!( + "Listening for TCP and UDP traffic on [::]:{}", + self.config.dns_port + ); + + Ok((udp_handle, tcp_handle)) + } + + fn listen(&self, mut binding: Binding) -> JoinHandle<()> { + let config = self.config.clone(); + let database = self.database.clone(); + let cache = self.cache.clone(); + tokio::spawn(async move { + let mut id = 0; + loop { + let Ok(connection) = binding.connect().await else { continue }; + info!("Received request on {}", binding.name()); + + let resolver = Resolver::new( + id, + connection, + config.clone(), + database.clone(), + cache.clone(), + ); + + let name = binding.name().to_string(); + tokio::spawn(async move { + if let Err(err) = resolver.handle_query().await { + error!("{} request {} failed: {:?}", name, id, err); + }; + }); + + id += 1; + } + }) + } +} |