Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added .unreleased/telio_dns_cleanup
Empty file.
2 changes: 1 addition & 1 deletion crates/telio-core/src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2332,7 +2332,7 @@ impl Runtime {

if is_meshnet_exit_node {
if let Some(dns) = &self.entities.dns.lock().await.resolver {
self.reconfigure_dns_peer(dns, &dns.get_default_dns_servers())
self.reconfigure_dns_peer(dns, &dns.get_exit_node_dns_servers())
.await?;
}
} else {
Expand Down
34 changes: 17 additions & 17 deletions crates/telio-dns/src/dns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
use async_trait::async_trait;
use ipnet::IpNet;
use neptun::noise::Tunn;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::net::IpAddr;
use std::{net::SocketAddr, sync::Arc};
use telio_crypto::{PublicKey, SecretKey};
use telio_wg::uapi::Peer;
Expand All @@ -15,7 +15,10 @@ use tokio::net::UdpSocket;
use tokio::sync::{Mutex, RwLock};
use x25519_dalek::{PublicKey as PublicKeyDalek, StaticSecret};

use telio_model::features::{FeatureDns, TtlValue};
use telio_model::{
constants::{DNS_EXIT_IPV4, DNS_EXIT_IPV6, DNS_VIRTUAL_IPV4, DNS_VIRTUAL_IPV6},
features::{FeatureDns, TtlValue},
};

//debug tools
use telio_utils::{telio_log_debug, telio_log_error};
Expand All @@ -38,10 +41,10 @@ pub trait DnsResolver {
fn get_peer(&self, allowed_ips: Vec<IpNet>) -> Peer;
/// Get default allowed IPs of this DNS server.
fn get_default_dns_allowed_ips(&self) -> Vec<IpNet>;
/// Get DNS virtual peer addresses.
/// Get allowed IPs when connected to exit node.
fn get_exit_connected_dns_allowed_ips(&self) -> Vec<IpNet>;
/// Get default DNS server IP addresses.
fn get_default_dns_servers(&self) -> Vec<IpAddr>;
/// Get DNS server IP addresses when connected to exit node.
fn get_exit_node_dns_servers(&self) -> Vec<IpAddr>;
/// Change DNS peer's public key
async fn set_peer_public_key(&self, key: PublicKey);
}
Expand Down Expand Up @@ -156,25 +159,22 @@ impl DnsResolver for LocalDnsResolver {

fn get_default_dns_allowed_ips(&self) -> Vec<IpNet> {
vec![
IpAddr::V4(Ipv4Addr::new(100, 64, 0, 2)).into(),
IpAddr::V4(Ipv4Addr::new(100, 64, 0, 3)).into(),
IpAddr::V6(Ipv6Addr::new(0xfd74, 0x656c, 0x696f, 0, 0, 0, 0, 2)).into(),
IpAddr::V6(Ipv6Addr::new(0xfd74, 0x656c, 0x696f, 0, 0, 0, 0, 3)).into(),
IpAddr::V4(DNS_VIRTUAL_IPV4).into(),
IpAddr::V4(DNS_EXIT_IPV4).into(),
IpAddr::V6(DNS_VIRTUAL_IPV6).into(),
IpAddr::V6(DNS_EXIT_IPV6).into(),
]
}

fn get_exit_connected_dns_allowed_ips(&self) -> Vec<IpNet> {
vec![
IpAddr::V4(Ipv4Addr::new(100, 64, 0, 2)).into(),
IpAddr::V6(Ipv6Addr::new(0xfd74, 0x656c, 0x696f, 0, 0, 0, 0, 2)).into(),
IpAddr::V4(DNS_VIRTUAL_IPV4).into(),
IpAddr::V6(DNS_VIRTUAL_IPV6).into(),
]
}

fn get_default_dns_servers(&self) -> Vec<IpAddr> {
vec![
IpAddr::V4(Ipv4Addr::new(100, 64, 0, 3)),
IpAddr::V6(Ipv6Addr::new(0xfd74, 0x656c, 0x696f, 0, 0, 0, 0, 3)),
]
fn get_exit_node_dns_servers(&self) -> Vec<IpAddr> {
vec![IpAddr::V4(DNS_EXIT_IPV4), IpAddr::V6(DNS_EXIT_IPV6)]
}

async fn set_peer_public_key(&self, pubkey: PublicKey) {
Expand Down Expand Up @@ -257,7 +257,7 @@ mod tests {
"100.64.0.3".parse::<IpAddr>().unwrap(),
"fd74:656c:696f::3".parse::<IpAddr>().unwrap(),
],
resolver.get_default_dns_servers()
resolver.get_exit_node_dns_servers()
);
}
}
2 changes: 1 addition & 1 deletion crates/telio-dns/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::forwarder::ForwardError;
use crate::udp_forwarder::ForwardError;
use crate::zone::NordZoneError;
use std::{io, net::AddrParseError};
use thiserror::Error;
Expand Down
8 changes: 5 additions & 3 deletions crates/telio-dns/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@
//! Easily create and run in process dns resolver.

mod dns;
// TODO: LLT-7053 remove after integrating forwarder
#[allow(dead_code)]
mod forwarder;
mod nameserver;
mod packet_decoder;
mod packet_encoder;
mod resolver;
mod udp_forwarder;
mod upstream;
mod zone;

pub mod bind_tun;
Expand All @@ -35,3 +34,6 @@ pub mod fuzz {
pub use super::packet_decoder::{find_nord_query, parse_dns_query_packet};
pub use super::packet_encoder::fuzz_build_response;
}

/// DNS port number
pub const DNS_PORT: u16 = 53;
62 changes: 49 additions & 13 deletions crates/telio-dns/src/nameserver.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use crate::error::Result as DnsResult;
use crate::DNS_PORT;
use crate::{
forwarder::UdpForwarder,
packet_decoder::{find_nord_query, normalize_qname, parse_dns_query_packet, DnsParseError},
packet_encoder::{DnsBuildError, DnsResponseBuilder},
resolver::Resolver,
udp_forwarder::UdpForwarder,
upstream::UpstreamState,
zone::{AuthoritativeZone, ClonableZones, ForwardZone, NordZone, Records, NORD_ZONE},
};
use async_trait::async_trait;
Expand Down Expand Up @@ -44,7 +46,6 @@ const UDP_HEADER: usize = 8;
const TCP_MIN_HEADER: usize = 20;
const MAX_CONCURRENT_QUERIES: usize = 256;
const IDLE_TIME: Duration = Duration::from_secs(1);
const DNS_PORT: u16 = 53;

#[derive(Debug, Error)]
enum PacketError {
Expand Down Expand Up @@ -157,6 +158,7 @@ pub struct LocalNameServer {
zones: Arc<ClonableZones>,
task_handle: Option<JoinHandle<()>>,
forwarder: Option<UdpForwarder>,
upstreams: Arc<Mutex<UpstreamState>>,
}

impl LocalNameServer {
Expand All @@ -166,8 +168,9 @@ impl LocalNameServer {
forward_ips: &[IpAddr],
use_raw_forwarder: bool,
) -> DnsResult<Arc<RwLock<Self>>> {
let upstreams = Arc::new(Mutex::new(UpstreamState::default()));
let raw_forwarder: Option<UdpForwarder> = if use_raw_forwarder {
Some(UdpForwarder::new().await?)
Some(UdpForwarder::new(upstreams.clone()).await?)
} else {
None
};
Expand All @@ -176,6 +179,7 @@ impl LocalNameServer {
zones: Arc::new(ClonableZones::new()),
task_handle: None,
forwarder: raw_forwarder,
upstreams,
}));
ns.forward(forward_ips).await?;
Ok(ns)
Expand Down Expand Up @@ -908,11 +912,8 @@ impl NameServer for Arc<RwLock<LocalNameServer>> {
}

async fn forward_to_addrs(&self, to: &[SocketAddr]) -> DnsResult<()> {
let ns = self.read().await;
if let Some(forwarder) = &ns.forwarder {
forwarder.set_upstreams(to.to_vec()).await;
}

let upstreams = self.read().await.upstreams.clone();
upstreams.lock().await.set(to.to_vec());
Ok(())
}

Expand Down Expand Up @@ -1070,6 +1071,41 @@ mod tests {
assert!(ns.forwarder.is_some());
}

#[tokio::test]
async fn forward_updates_shared_upstreams() {
let nameserver = LocalNameServer::new(&[IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8))], false)
.await
.unwrap();
{
let ns = nameserver.read().await;
let state = ns.upstreams.lock().await;
assert_eq!(
state.addrs(),
[SocketAddr::new(
IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8)),
DNS_PORT
)]
);
assert_eq!(state.generation(), 1);
}

nameserver
.forward(&[IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1))])
.await
.unwrap();

let ns = nameserver.read().await;
let state = ns.upstreams.lock().await;
assert_eq!(
state.addrs(),
[SocketAddr::new(
IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1)),
DNS_PORT
)]
);
assert_eq!(state.generation(), 2);
}

#[tokio::test]
async fn nameserver_skips_forwarder_by_default() {
let nameserver = LocalNameServer::new(&[IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8))], false)
Expand Down Expand Up @@ -1195,7 +1231,7 @@ mod tests {
// Tests PacketError::InvalidUdpChecksum
#[test]
fn packet_error_invalid_udp_checksum() {
let mut udp_seg = build_udp_segment(12345, 53, &[0; 4]);
let mut udp_seg = build_udp_segment(12345, DNS_PORT, &[0; 4]);
// Corrupt UDP checksum (bytes 6-7)
udp_seg[6] ^= 0xFF;
let packet = build_ipv4_packet(IpNextHeaderProtocols::Udp, &udp_seg);
Expand Down Expand Up @@ -1235,7 +1271,7 @@ mod tests {
0x01, b'a', 0x00,
// QTYPE and QCLASS intentionally missing → hickory fails to decode
];
let udp_seg = build_udp_segment(12345, 53, dns_payload);
let udp_seg = build_udp_segment(12345, DNS_PORT, dns_payload);
let packet = build_ipv4_packet(IpNextHeaderProtocols::Udp, &udp_seg);
let ns = test_nameserver().await;
let mut response = vec![0u8; MAX_PACKET];
Expand All @@ -1260,7 +1296,7 @@ mod tests {
},
payload: PayloadRequestInfo::Udp {
source_port: 12345,
destination_port: 53,
destination_port: DNS_PORT,
dns_request: None,
},
};
Expand All @@ -1282,7 +1318,7 @@ mod tests {
},
payload: PayloadRequestInfo::Udp {
source_port: 12345,
destination_port: 53,
destination_port: DNS_PORT,
dns_request: None,
},
};
Expand All @@ -1308,7 +1344,7 @@ mod tests {
},
payload: PayloadRequestInfo::Udp {
source_port: 12345,
destination_port: 53,
destination_port: DNS_PORT,
dns_request: None,
},
};
Expand Down
Loading
Loading