Many DNS fixes!
This commit is contained in:
Generated
+332
-471
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -34,7 +34,7 @@ rand = { package = "rand", version = "0.8.5" }
|
|||||||
sqlite = "0.36.0"
|
sqlite = "0.36.0"
|
||||||
uuid = { version = "1.11.0", features = ["serde", "v4"] }
|
uuid = { version = "1.11.0", features = ["serde", "v4"] }
|
||||||
mio = { version = "1.0.0", features = ["os-poll", "net"] }
|
mio = { version = "1.0.0", features = ["os-poll", "net"] }
|
||||||
ureq = { version = "2.10", optional = true }
|
ureq = { version = "3.0.10", optional = true }
|
||||||
lru = "0.12"
|
lru = "0.12"
|
||||||
derive_more = { version = "1.0.0", features = ["display", "error", "from"] }
|
derive_more = { version = "1.0.0", features = ["display", "error", "from"] }
|
||||||
lazy_static = "1.5.0"
|
lazy_static = "1.5.0"
|
||||||
|
|||||||
+111
-10
@@ -60,20 +60,27 @@ impl BlockchainFilter {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_packet(&self, qname: &str, qtype: QueryType, zone: String, answers: Vec<DnsRecord>) -> Option<DnsPacket> {
|
fn create_packet(&self, qname: &str, qtype: QueryType, zone: String, answers: Vec<DnsRecord>, ns_records: Vec<DnsRecord>, glue_records: Vec<DnsRecord>) -> Option<DnsPacket> {
|
||||||
if !answers.is_empty() {
|
if !answers.is_empty() {
|
||||||
// Create DnsPacket
|
// Create DnsPacket with answers
|
||||||
let mut packet = DnsPacket::new();
|
let mut packet = DnsPacket::new();
|
||||||
packet.header.authoritative_answer = true;
|
packet.header.authoritative_answer = true;
|
||||||
packet.questions.push(DnsQuestion::new(String::from(qname), qtype));
|
packet.questions.push(DnsQuestion::new(String::from(qname), qtype));
|
||||||
for answer in answers {
|
for answer in answers {
|
||||||
packet.answers.push(answer);
|
packet.answers.push(answer);
|
||||||
}
|
}
|
||||||
packet.authorities.push(DnsRecord::NS { domain: zone, host: String::from(NAME_SERVER), ttl: TransientTtl(600) });
|
// Add NS records to authority section
|
||||||
|
for ns_record in ns_records {
|
||||||
|
packet.authorities.push(ns_record);
|
||||||
|
}
|
||||||
|
// Add GLUE records to additional section (resources)
|
||||||
|
for glue_record in glue_records {
|
||||||
|
packet.resources.push(glue_record);
|
||||||
|
}
|
||||||
//trace!("Returning packet: {:?}", &packet);
|
//trace!("Returning packet: {:?}", &packet);
|
||||||
Some(packet)
|
Some(packet)
|
||||||
} else {
|
} else {
|
||||||
// Create DnsPacket
|
// Create DnsPacket without answers
|
||||||
let mut packet = DnsPacket::new();
|
let mut packet = DnsPacket::new();
|
||||||
packet.header.authoritative_answer = true;
|
packet.header.authoritative_answer = true;
|
||||||
packet.header.rescode = ResultCode::NXDOMAIN;
|
packet.header.rescode = ResultCode::NXDOMAIN;
|
||||||
@@ -85,7 +92,7 @@ impl BlockchainFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_by_ns(qname: &str, qtype: QueryType, top_domain: &String, data: &DomainData) -> (bool, Option<DnsPacket>) {
|
fn resolve_by_ns(qname: &str, qtype: QueryType, top_domain: &String, data: &DomainData, recursive: bool) -> (bool, Option<DnsPacket>) {
|
||||||
// First we search for NS records, collecting nameserver domains
|
// First we search for NS records, collecting nameserver domains
|
||||||
let mut hosts = Vec::new();
|
let mut hosts = Vec::new();
|
||||||
for record in data.records.iter() {
|
for record in data.records.iter() {
|
||||||
@@ -103,7 +110,27 @@ impl BlockchainFilter {
|
|||||||
return (false, None);
|
return (false, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Searching glue records
|
// If non-recursive, return a referral response with NS and GLUE records
|
||||||
|
if !recursive {
|
||||||
|
trace!("Non-recursive query for delegated domain {}, returning referral", qname);
|
||||||
|
let ns_records = BlockchainFilter::get_ns_records(data, top_domain);
|
||||||
|
let glue_records = BlockchainFilter::get_glue_records(data, top_domain, &hosts);
|
||||||
|
|
||||||
|
let mut packet = DnsPacket::new();
|
||||||
|
packet.header.authoritative_answer = false; // Not authoritative for the answer, but for the zone
|
||||||
|
packet.questions.push(DnsQuestion::new(String::from(qname), qtype));
|
||||||
|
// Add NS records to authority section
|
||||||
|
for ns_record in ns_records {
|
||||||
|
packet.authorities.push(ns_record);
|
||||||
|
}
|
||||||
|
// Add GLUE records to additional section (resources)
|
||||||
|
for glue_record in glue_records {
|
||||||
|
packet.resources.push(glue_record);
|
||||||
|
}
|
||||||
|
return (true, Some(packet));
|
||||||
|
}
|
||||||
|
|
||||||
|
// For recursive queries, search for glue records to query external servers
|
||||||
let mut servers = Vec::new();
|
let mut servers = Vec::new();
|
||||||
for record in data.records.iter() {
|
for record in data.records.iter() {
|
||||||
match &record {
|
match &record {
|
||||||
@@ -138,10 +165,71 @@ impl BlockchainFilter {
|
|||||||
|
|
||||||
(false, None)
|
(false, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extract NS records from domain data and return them
|
||||||
|
fn get_ns_records(data: &DomainData, top_domain: &str) -> Vec<DnsRecord> {
|
||||||
|
data.records.iter()
|
||||||
|
.filter_map(|record| {
|
||||||
|
if let DnsRecord::NS { domain, host, ttl } = record {
|
||||||
|
if domain == "@" {
|
||||||
|
return Some(DnsRecord::NS {
|
||||||
|
domain: String::from(top_domain),
|
||||||
|
host: host.clone(),
|
||||||
|
ttl: *ttl
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extract GLUE records (A/AAAA records for NS hosts within the same domain)
|
||||||
|
fn get_glue_records(data: &DomainData, top_domain: &str, ns_hosts: &[String]) -> Vec<DnsRecord> {
|
||||||
|
let mut glue_records = Vec::new();
|
||||||
|
|
||||||
|
for record in data.records.iter() {
|
||||||
|
match record {
|
||||||
|
DnsRecord::A { domain, addr, ttl } => {
|
||||||
|
let full_domain = if domain == "@" {
|
||||||
|
String::from(top_domain)
|
||||||
|
} else {
|
||||||
|
format!("{}.{}", domain, top_domain)
|
||||||
|
};
|
||||||
|
|
||||||
|
if ns_hosts.iter().any(|ns| ns == &full_domain) {
|
||||||
|
glue_records.push(DnsRecord::A {
|
||||||
|
domain: full_domain,
|
||||||
|
addr: addr.clone(),
|
||||||
|
ttl: *ttl
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DnsRecord::AAAA { domain, addr, ttl } => {
|
||||||
|
let full_domain = if domain == "@" {
|
||||||
|
String::from(top_domain)
|
||||||
|
} else {
|
||||||
|
format!("{}.{}", domain, top_domain)
|
||||||
|
};
|
||||||
|
|
||||||
|
if ns_hosts.iter().any(|ns| ns == &full_domain) {
|
||||||
|
glue_records.push(DnsRecord::AAAA {
|
||||||
|
domain: full_domain,
|
||||||
|
addr: addr.clone(),
|
||||||
|
ttl: *ttl
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glue_records
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DnsFilter for BlockchainFilter {
|
impl DnsFilter for BlockchainFilter {
|
||||||
fn lookup(&self, qname: &str, qtype: QueryType) -> Option<DnsPacket> {
|
fn lookup(&self, qname: &str, qtype: QueryType, recursive: bool) -> Option<DnsPacket> {
|
||||||
let top_domain;
|
let top_domain;
|
||||||
let subdomain;
|
let subdomain;
|
||||||
let parts: Vec<&str> = qname.rsplitn(3, '.').collect();
|
let parts: Vec<&str> = qname.rsplitn(3, '.').collect();
|
||||||
@@ -192,7 +280,7 @@ impl DnsFilter for BlockchainFilter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Check if this domain has NS records and needs to resolve all records through them
|
// Check if this domain has NS records and needs to resolve all records through them
|
||||||
let (has_ns, result) = Self::resolve_by_ns(qname, qtype, &top_domain, &data);
|
let (has_ns, result) = Self::resolve_by_ns(qname, qtype, &top_domain, &data, recursive);
|
||||||
if has_ns {
|
if has_ns {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -237,7 +325,7 @@ impl DnsFilter for BlockchainFilter {
|
|||||||
let mut domain_exists = !answers.is_empty() || subdomain.is_empty();
|
let mut domain_exists = !answers.is_empty() || subdomain.is_empty();
|
||||||
if answers.is_empty() {
|
if answers.is_empty() {
|
||||||
// If there are no records found we search for *.domain.tld record
|
// If there are no records found we search for *.domain.tld record
|
||||||
for mut record in data.records {
|
for mut record in data.records.iter_mut() {
|
||||||
let record_domain = record.get_domain().unwrap_or(String::new());
|
let record_domain = record.get_domain().unwrap_or(String::new());
|
||||||
if record.get_querytype() == qtype && record_domain == "*" {
|
if record.get_querytype() == qtype && record_domain == "*" {
|
||||||
match &mut record {
|
match &mut record {
|
||||||
@@ -263,7 +351,20 @@ impl DnsFilter for BlockchainFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(mut packet) = self.create_packet(qname, qtype, zone, answers) {
|
// Extract NS records and GLUE records for the response
|
||||||
|
let ns_records = BlockchainFilter::get_ns_records(&data, &top_domain);
|
||||||
|
let ns_hosts: Vec<String> = ns_records.iter()
|
||||||
|
.filter_map(|record| {
|
||||||
|
if let DnsRecord::NS { host, .. } = record {
|
||||||
|
Some(host.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let glue_records = BlockchainFilter::get_glue_records(&data, &top_domain, &ns_hosts);
|
||||||
|
|
||||||
|
if let Some(mut packet) = self.create_packet(qname, qtype, zone, answers, ns_records, glue_records) {
|
||||||
if domain_exists && packet.answers.is_empty() {
|
if domain_exists && packet.answers.is_empty() {
|
||||||
packet.header.rescode = ResultCode::NOERROR;
|
packet.header.rescode = ResultCode::NOERROR;
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-7
@@ -226,7 +226,7 @@ where T: Read {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> StreamPacketBuffer<'a, T> where T: Read + 'a {
|
impl<'a, T> StreamPacketBuffer<'a, T> where T: Read + 'a {
|
||||||
pub fn new(stream: &'a mut T) -> StreamPacketBuffer<'_, T> {
|
pub fn new(stream: &'a mut T) -> StreamPacketBuffer<'a, T> {
|
||||||
StreamPacketBuffer {
|
StreamPacketBuffer {
|
||||||
stream,
|
stream,
|
||||||
buffer: Vec::new(),
|
buffer: Vec::new(),
|
||||||
@@ -300,14 +300,16 @@ impl<'a, T> PacketBuffer for StreamPacketBuffer<'a, T> where T: Read + 'a {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const BUF_SIZE: usize = 4096;
|
||||||
|
|
||||||
pub struct BytePacketBuffer {
|
pub struct BytePacketBuffer {
|
||||||
pub buf: [u8; 512],
|
pub buf: [u8; BUF_SIZE],
|
||||||
pub pos: usize
|
pub pos: usize
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BytePacketBuffer {
|
impl BytePacketBuffer {
|
||||||
pub fn new() -> BytePacketBuffer {
|
pub fn new() -> BytePacketBuffer {
|
||||||
BytePacketBuffer { buf: [0; 512], pos: 0 }
|
BytePacketBuffer { buf: [0; BUF_SIZE], pos: 0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,7 +321,7 @@ impl Default for BytePacketBuffer {
|
|||||||
|
|
||||||
impl PacketBuffer for BytePacketBuffer {
|
impl PacketBuffer for BytePacketBuffer {
|
||||||
fn read(&mut self) -> Result<u8> {
|
fn read(&mut self) -> Result<u8> {
|
||||||
if self.pos >= 512 {
|
if self.pos >= BUF_SIZE {
|
||||||
return Err(BufferError::EndOfBuffer);
|
return Err(BufferError::EndOfBuffer);
|
||||||
}
|
}
|
||||||
let res = self.buf[self.pos];
|
let res = self.buf[self.pos];
|
||||||
@@ -329,21 +331,21 @@ impl PacketBuffer for BytePacketBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get(&mut self, pos: usize) -> Result<u8> {
|
fn get(&mut self, pos: usize) -> Result<u8> {
|
||||||
if pos >= 512 {
|
if pos >= BUF_SIZE {
|
||||||
return Err(BufferError::EndOfBuffer);
|
return Err(BufferError::EndOfBuffer);
|
||||||
}
|
}
|
||||||
Ok(self.buf[pos])
|
Ok(self.buf[pos])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_range(&mut self, start: usize, len: usize) -> Result<&[u8]> {
|
fn get_range(&mut self, start: usize, len: usize) -> Result<&[u8]> {
|
||||||
if start + len >= 512 {
|
if start + len >= BUF_SIZE {
|
||||||
return Err(BufferError::EndOfBuffer);
|
return Err(BufferError::EndOfBuffer);
|
||||||
}
|
}
|
||||||
Ok(&self.buf[start..start + len as usize])
|
Ok(&self.buf[start..start + len as usize])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&mut self, val: u8) -> Result<()> {
|
fn write(&mut self, val: u8) -> Result<()> {
|
||||||
if self.pos >= 512 {
|
if self.pos >= BUF_SIZE {
|
||||||
return Err(BufferError::EndOfBuffer);
|
return Err(BufferError::EndOfBuffer);
|
||||||
}
|
}
|
||||||
self.buf[self.pos] = val;
|
self.buf[self.pos] = val;
|
||||||
|
|||||||
+87
-57
@@ -4,7 +4,7 @@ use std::io::Write;
|
|||||||
#[cfg(feature = "doh")]
|
#[cfg(feature = "doh")]
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::marker::{Send, Sync};
|
use std::marker::{Send, Sync};
|
||||||
use std::net::{SocketAddr, TcpStream, ToSocketAddrs, UdpSocket};
|
use std::net::{Ipv4Addr, SocketAddr, TcpStream, ToSocketAddrs, UdpSocket};
|
||||||
#[cfg(feature = "doh")]
|
#[cfg(feature = "doh")]
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
#[cfg(feature = "doh")]
|
#[cfg(feature = "doh")]
|
||||||
@@ -32,6 +32,11 @@ use crate::dns::protocol::{DnsPacket, DnsQuestion, QueryType};
|
|||||||
use crate::dns::protocol::DnsRecord;
|
use crate::dns::protocol::DnsRecord;
|
||||||
#[cfg(feature = "doh")]
|
#[cfg(feature = "doh")]
|
||||||
use lru::LruCache;
|
use lru::LruCache;
|
||||||
|
use ureq::Agent;
|
||||||
|
use ureq::config::Config;
|
||||||
|
use ureq::http::Uri;
|
||||||
|
use ureq::unversioned::resolver::{ArrayVec, ResolvedSocketAddrs, Resolver};
|
||||||
|
use ureq::unversioned::transport::{DefaultConnector, NextTimeout};
|
||||||
|
|
||||||
#[derive(Debug, Display, From, Error)]
|
#[derive(Debug, Display, From, Error)]
|
||||||
pub enum ClientError {
|
pub enum ClientError {
|
||||||
@@ -387,7 +392,7 @@ impl DnsClient for DnsNetworkClient {
|
|||||||
|
|
||||||
#[cfg(feature = "doh")]
|
#[cfg(feature = "doh")]
|
||||||
pub struct HttpsDnsClient {
|
pub struct HttpsDnsClient {
|
||||||
agent: ureq::Agent,
|
agent: Agent,
|
||||||
/// Counter for assigning packet ids
|
/// Counter for assigning packet ids
|
||||||
seq: AtomicUsize,
|
seq: AtomicUsize,
|
||||||
}
|
}
|
||||||
@@ -402,63 +407,88 @@ impl HttpsDnsClient {
|
|||||||
.collect::<Vec<SocketAddr>>();
|
.collect::<Vec<SocketAddr>>();
|
||||||
trace!("Using bootstraps: {:?}", &servers);
|
trace!("Using bootstraps: {:?}", &servers);
|
||||||
|
|
||||||
let cache: LruCache<String, Vec<SocketAddr>> = LruCache::new(NonZeroUsize::new(10).unwrap());
|
let agent_config = Agent::config_builder()
|
||||||
let cache = RwLock::new(cache);
|
|
||||||
|
|
||||||
let agent = ureq::AgentBuilder::new()
|
|
||||||
.user_agent(&client_name)
|
.user_agent(&client_name)
|
||||||
.timeout(std::time::Duration::from_secs(3))
|
.timeout_global(Some(std::time::Duration::from_secs(3)))
|
||||||
.max_idle_connections_per_host(4)
|
.max_idle_connections_per_host(4)
|
||||||
.max_idle_connections(16)
|
.max_idle_connections(16)
|
||||||
.resolver(move |addr: &str| {
|
|
||||||
let addr = match addr.find(':') {
|
|
||||||
Some(index) => addr[0..index].to_string(),
|
|
||||||
None => addr.to_string()
|
|
||||||
};
|
|
||||||
trace!("Resolving {}", addr);
|
|
||||||
if let Some(addrs) = cache.write().unwrap().get(&addr) {
|
|
||||||
trace!("Found bootstrap ip in cache");
|
|
||||||
return Ok(addrs.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
let port = 10000 + (rand::random::<u16>() % 50000);
|
|
||||||
let mut dns_client = DnsNetworkClient::new(port);
|
|
||||||
dns_client.run().unwrap();
|
|
||||||
|
|
||||||
let mut result: Vec<IpAddr> = Vec::new();
|
|
||||||
for server in &servers {
|
|
||||||
if let Ok(res) = dns_client.send_udp_query(&addr, QueryType::A, server, true) {
|
|
||||||
for answer in &res.answers {
|
|
||||||
if let DnsRecord::A { addr, .. } = answer {
|
|
||||||
result.push(IpAddr::V4(*addr))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Ok(res) = dns_client.send_udp_query(&addr, QueryType::AAAA, server, true) {
|
|
||||||
for answer in &res.answers {
|
|
||||||
if let DnsRecord::AAAA { addr, .. } = answer {
|
|
||||||
result.push(IpAddr::V6(*addr))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dns_client.stop();
|
|
||||||
|
|
||||||
result.sort();
|
|
||||||
result.dedup();
|
|
||||||
let addrs = result
|
|
||||||
.into_iter()
|
|
||||||
.map(|ip| SocketAddr::new(ip, 443))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
trace!("Resolved addresses: {:?}", &addrs);
|
|
||||||
cache.write().unwrap().put(addr, addrs.clone());
|
|
||||||
Ok(addrs)
|
|
||||||
})
|
|
||||||
.build();
|
.build();
|
||||||
|
let agent = Agent::with_parts(agent_config, DefaultConnector::default(), BootstrapResolver::new(servers));
|
||||||
Self { agent, seq: AtomicUsize::new(1) }
|
Self { agent, seq: AtomicUsize::new(1) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct BootstrapResolver {
|
||||||
|
servers: Vec<SocketAddr>,
|
||||||
|
cache: RwLock<LruCache<String, Vec<SocketAddr>>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BootstrapResolver {
|
||||||
|
pub fn new(servers: Vec<SocketAddr>) -> Self {
|
||||||
|
let cache: LruCache<String, Vec<SocketAddr>> = LruCache::new(NonZeroUsize::new(10).unwrap());
|
||||||
|
let cache = RwLock::new(cache);
|
||||||
|
Self { servers, cache }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Resolver for BootstrapResolver {
|
||||||
|
// TODO use timeout parameter
|
||||||
|
fn resolve(&self, uri: &Uri, _config: &Config, _timeout: NextTimeout) -> std::result::Result<ResolvedSocketAddrs, ureq::Error> {
|
||||||
|
let domain = uri.host().unwrap_or("localhost");
|
||||||
|
let port = uri.port_u16().unwrap_or(443);
|
||||||
|
let addr = match domain.find(':') {
|
||||||
|
Some(index) => domain[0..index].to_string(),
|
||||||
|
None => domain.to_string()
|
||||||
|
};
|
||||||
|
trace!("Resolving {}", addr);
|
||||||
|
if let Some(addrs) = self.cache.write().unwrap().get(&addr) {
|
||||||
|
trace!("Found bootstrap ip in cache");
|
||||||
|
let mut results: ResolvedSocketAddrs = ArrayVec::from_fn(|_| SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0));
|
||||||
|
for addr in addrs {
|
||||||
|
results.push(addr.to_owned());
|
||||||
|
}
|
||||||
|
return Ok(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
let client_port = 10000 + (rand::random::<u16>() % 50000);
|
||||||
|
let mut dns_client = DnsNetworkClient::new(client_port);
|
||||||
|
dns_client.run().unwrap();
|
||||||
|
|
||||||
|
let mut result: Vec<IpAddr> = Vec::new();
|
||||||
|
let mut results: ResolvedSocketAddrs = ArrayVec::from_fn(|_| SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0));
|
||||||
|
for server in &self.servers {
|
||||||
|
if let Ok(res) = dns_client.send_udp_query(&addr, QueryType::A, server, true) {
|
||||||
|
for answer in &res.answers {
|
||||||
|
if let DnsRecord::A { addr, .. } = answer {
|
||||||
|
results.push(SocketAddr::new(IpAddr::V4(*addr), port));
|
||||||
|
result.push(IpAddr::V4(*addr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Ok(res) = dns_client.send_udp_query(&addr, QueryType::AAAA, server, true) {
|
||||||
|
for answer in &res.answers {
|
||||||
|
if let DnsRecord::AAAA { addr, .. } = answer {
|
||||||
|
results.push(SocketAddr::new(IpAddr::V6(*addr), port));
|
||||||
|
result.push(IpAddr::V6(*addr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dns_client.stop();
|
||||||
|
|
||||||
|
result.sort();
|
||||||
|
result.dedup();
|
||||||
|
let addrs = result
|
||||||
|
.into_iter()
|
||||||
|
.map(|ip| SocketAddr::new(ip, port))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
trace!("Resolved addresses: {:?}", &addrs);
|
||||||
|
self.cache.write().unwrap().put(addr, addrs.clone());
|
||||||
|
Ok(results)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "doh")]
|
#[cfg(feature = "doh")]
|
||||||
impl DnsClient for HttpsDnsClient {
|
impl DnsClient for HttpsDnsClient {
|
||||||
fn get_sent_count(&self) -> usize {
|
fn get_sent_count(&self) -> usize {
|
||||||
@@ -497,20 +527,20 @@ impl DnsClient for HttpsDnsClient {
|
|||||||
|
|
||||||
let response = self.agent
|
let response = self.agent
|
||||||
.post(doh_url)
|
.post(doh_url)
|
||||||
.set("Content-Type", "application/dns-message")
|
.header("Content-Type", "application/dns-message")
|
||||||
.send_bytes(req_buffer.buffer.as_slice());
|
.send(req_buffer.buffer.as_slice());
|
||||||
|
|
||||||
match response {
|
match response {
|
||||||
Ok(response) => {
|
Ok(response) => {
|
||||||
match response.status() {
|
match response.status().as_u16() {
|
||||||
200 => {
|
200 => {
|
||||||
match response.header("Content-Length") {
|
match response.headers().get("Content-Length") {
|
||||||
None => warn!("No 'Content-Length' header in DoH response!"),
|
None => warn!("No 'Content-Length' header in DoH response!"),
|
||||||
Some(str) => {
|
Some(str) => {
|
||||||
match str.parse::<usize>() {
|
match str.to_str().unwrap_or("0").parse::<usize>() {
|
||||||
Ok(size) => {
|
Ok(size) => {
|
||||||
let mut bytes: Vec<u8> = Vec::with_capacity(size);
|
let mut bytes: Vec<u8> = Vec::with_capacity(size);
|
||||||
response.into_reader()
|
response.into_body().into_reader()
|
||||||
.take(4096)
|
.take(4096)
|
||||||
.read_to_end(&mut bytes)?;
|
.read_to_end(&mut bytes)?;
|
||||||
let mut buffer = VectorPacketBuffer::new();
|
let mut buffer = VectorPacketBuffer::new();
|
||||||
|
|||||||
+2
-2
@@ -1,14 +1,14 @@
|
|||||||
use crate::dns::protocol::{DnsPacket, QueryType};
|
use crate::dns::protocol::{DnsPacket, QueryType};
|
||||||
|
|
||||||
pub trait DnsFilter {
|
pub trait DnsFilter {
|
||||||
fn lookup(&self, qname: &str, qtype: QueryType) -> Option<DnsPacket>;
|
fn lookup(&self, qname: &str, qtype: QueryType, recursive: bool) -> Option<DnsPacket>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DummyFilter {}
|
pub struct DummyFilter {}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
impl DnsFilter for DummyFilter {
|
impl DnsFilter for DummyFilter {
|
||||||
fn lookup(&self, qname: &str, qtype: QueryType) -> Option<DnsPacket> {
|
fn lookup(&self, qname: &str, qtype: QueryType, recursive: bool) -> Option<DnsPacket> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -53,7 +53,7 @@ impl HostsFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DnsFilter for HostsFilter {
|
impl DnsFilter for HostsFilter {
|
||||||
fn lookup(&self, qname: &str, qtype: QueryType) -> Option<DnsPacket> {
|
fn lookup(&self, qname: &str, qtype: QueryType, _recursive: bool) -> Option<DnsPacket> {
|
||||||
let mut packet = DnsPacket::new();
|
let mut packet = DnsPacket::new();
|
||||||
if let Some(list) = self.hosts.get(qname) {
|
if let Some(list) = self.hosts.get(qname) {
|
||||||
for addr in list {
|
for addr in list {
|
||||||
|
|||||||
+1
-1
@@ -53,7 +53,7 @@ pub trait DnsResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for filter in context.filters.iter() {
|
for filter in context.filters.iter() {
|
||||||
if let Some(packet) = filter.lookup(qname, qtype) {
|
if let Some(packet) = filter.lookup(qname, qtype, recursive) {
|
||||||
context.cache.store(&packet.answers)?;
|
context.cache.store(&packet.answers)?;
|
||||||
return Ok(packet);
|
return Ok(packet);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user