2
0
mirror of https://github.com/Revertron/Alfis synced 2024-11-03 15:40:19 +00:00

Added full IPv6 support for DNS-resolver upstreams.

This commit is contained in:
Revertron 2021-03-06 23:53:30 +01:00
parent ce212ab749
commit 1cd1fed178
3 changed files with 79 additions and 10 deletions

View File

@ -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"]

View File

@ -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<Mutex<Vec<PendingQuery>>>,
@ -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()

View File

@ -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<DnsPacket> {
let index: usize = rand::random::<usize>() % 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)?