From 1cd1fed17899303dfdcad7ba96e64313a172c85c Mon Sep 17 00:00:00 2001 From: Revertron Date: Sat, 6 Mar 2021 23:53:30 +0100 Subject: [PATCH] Added full IPv6 support for DNS-resolver upstreams. --- alfis.toml | 6 ++-- src/dns/client.rs | 78 ++++++++++++++++++++++++++++++++++++++++++---- src/dns/resolve.rs | 5 +-- 3 files changed, 79 insertions(+), 10 deletions(-) diff --git a/alfis.toml b/alfis.toml index 6df3bc7..b753c51 100644 --- a/alfis.toml +++ b/alfis.toml @@ -10,7 +10,9 @@ peers = ["test2-ip4.alfis.name:4244", "test2-ip6.alfis.name:4244"] # DNS server options [dns] -listen = "0.0.0.0:5300" +listen = "127.0.0.1:53" threads = 20 #AdGuard DNS servers to filter ads and trackers -forwarders = ["94.140.14.14:53", "94.140.15.15:53"] +#forwarders = ["94.140.14.14:53", "94.140.15.15:53"] +#forwarders = ["[301:2522::53]:53", "[301:2923::53]:53"] +forwarders = ["[301:2522::53]:53", "[301:2923::53]:53", "94.140.14.14:53", "94.140.15.15:53"] diff --git a/src/dns/client.rs b/src/dns/client.rs index 95aadce..b23e0bd 100644 --- a/src/dns/client.rs +++ b/src/dns/client.rs @@ -2,7 +2,7 @@ use std::io::Write; use std::marker::{Send, Sync}; -use std::net::{TcpStream, UdpSocket, ToSocketAddrs}; +use std::net::{TcpStream, UdpSocket, ToSocketAddrs, SocketAddr}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::mpsc::{channel, Sender}; use std::sync::{Arc, Mutex}; @@ -49,8 +49,11 @@ pub struct DnsNetworkClient { /// Counter for assigning packet ids seq: AtomicUsize, - /// The listener socket - socket: UdpSocket, + /// The requesting socket for IPv4 + socket_ipv4: UdpSocket, + + /// The requesting socket for IPv6 + socket_ipv6: UdpSocket, /// Queries in progress pending_queries: Arc>>, @@ -75,7 +78,8 @@ impl DnsNetworkClient { total_sent: AtomicUsize::new(0), total_failed: AtomicUsize::new(0), seq: AtomicUsize::new(0), - socket: UdpSocket::bind(("0.0.0.0", port)).unwrap(), + socket_ipv4: UdpSocket::bind(format!("0.0.0.0:{}", port)).expect("Error binding IPv4"), + socket_ipv6: UdpSocket::bind(format!("[::]:{}", port)).expect("Error binding IPv6"), pending_queries: Arc::new(Mutex::new(Vec::new())), } } @@ -152,7 +156,15 @@ impl DnsNetworkClient { // Send query let mut req_buffer = BytePacketBuffer::new(); packet.write(&mut req_buffer, 512)?; - self.socket.send_to(&req_buffer.buf[0..req_buffer.pos], server)?; + let addr: SocketAddr = server.to_socket_addrs()?.next().expect("Wrong resolver address"); + match addr { + SocketAddr::V4(addr) => { + self.socket_ipv4.send_to(&req_buffer.buf[0..req_buffer.pos], addr)?; + } + SocketAddr::V6(addr) => { + self.socket_ipv6.send_to(&req_buffer.buf[0..req_buffer.pos], addr)?; + } + } // Wait for response match rx.recv() { @@ -183,7 +195,61 @@ impl DnsClient for DnsNetworkClient { fn run(&self) -> Result<()> { // Start the thread for handling incoming responses { - let socket_copy = self.socket.try_clone()?; + let socket_copy = self.socket_ipv4.try_clone()?; + let pending_queries_lock = self.pending_queries.clone(); + + Builder::new() + .name("DnsNetworkClient-worker-thread".into()) + .spawn(move || { + loop { + // Read data into a buffer + let mut res_buffer = BytePacketBuffer::new(); + match socket_copy.recv_from(&mut res_buffer.buf) { + Ok(_) => {} + Err(_) => { + continue; + } + } + + // Construct a DnsPacket from buffer, skipping the packet if parsing + // failed + let packet = match DnsPacket::from_buffer(&mut res_buffer) { + Ok(packet) => packet, + Err(err) => { + println!("DnsNetworkClient failed to parse packet with error: {:?}", err); + continue; + } + }; + + // Acquire a lock on the pending_queries list, and search for a + // matching PendingQuery to which to deliver the response. + if let Ok(mut pending_queries) = pending_queries_lock.lock() { + let mut matched_query = None; + for (i, pending_query) in pending_queries.iter().enumerate() { + if pending_query.seq == packet.header.id { + // Matching query found, send the response + let _ = pending_query.tx.send(Some(packet.clone())); + + // Mark this index for removal from list + matched_query = Some(i); + + break; + } + } + + if let Some(idx) = matched_query { + pending_queries.remove(idx); + } else { + println!("Discarding response for: {:?}", packet.questions[0]); + } + } + } + })?; + } + + // Start the save thread for IPv6 + { + let socket_copy = self.socket_ipv6.try_clone()?; let pending_queries_lock = self.pending_queries.clone(); Builder::new() diff --git a/src/dns/resolve.rs b/src/dns/resolve.rs index 2ce159b..6e53c06 100644 --- a/src/dns/resolve.rs +++ b/src/dns/resolve.rs @@ -8,6 +8,7 @@ use derive_more::{Display, Error, From}; use crate::dns::context::ServerContext; use crate::dns::protocol::{DnsPacket, QueryType, ResultCode}; +use rand::seq::IteratorRandom; #[derive(Debug, Display, From, Error)] pub enum ResolveError { @@ -83,8 +84,8 @@ impl DnsResolver for ForwardingDnsResolver { } fn perform(&mut self, qname: &str, qtype: QueryType) -> Result { - let index: usize = rand::random::() % self.upstreams.len(); - let upstream = self.upstreams[index].as_ref(); + let mut random = rand::thread_rng(); + let upstream = self.upstreams.iter().choose(&mut random).unwrap(); let result = match self.context.cache.lookup(qname, qtype) { None => { self.context.client.send_query(qname, qtype, upstream, true)?