diff --git a/example-encrypted-dns.toml b/example-encrypted-dns.toml index c44df81..6fb46fa 100644 --- a/example-encrypted-dns.toml +++ b/example-encrypted-dns.toml @@ -114,6 +114,11 @@ daemonize = false # chroot = "/var/empty" +## Queries sent to that name will return the client IP address. +## This can be very useful for debugging, or to check that relaying works. + +my_ip = "my.ip" + #################################### # DNSCrypt settings # diff --git a/src/blacklist.rs b/src/blacklist.rs index 5b9d99b..0c163c0 100644 --- a/src/blacklist.rs +++ b/src/blacklist.rs @@ -43,7 +43,7 @@ impl BlackList { while line.ends_with('.') { line = &line[..line.len() - 1]; } - let qname = line.as_bytes().to_vec().to_ascii_lowercase(); + let qname = line.as_bytes().to_ascii_lowercase(); if qname.is_empty() { bail!("Unexpected blacklist rule at line {}", line_nb) } @@ -53,7 +53,7 @@ impl BlackList { } pub fn find(&self, qname: &[u8]) -> bool { - let qname = qname.to_vec().to_ascii_lowercase(); + let qname = qname.to_ascii_lowercase(); let mut qname = qname.as_slice(); let map = &self.inner.map; let mut iterations = self.max_iterations; diff --git a/src/config.rs b/src/config.rs index 4c952ed..ac23033 100644 --- a/src/config.rs +++ b/src/config.rs @@ -81,6 +81,7 @@ pub struct Config { pub daemonize: bool, pub pid_file: Option, pub log_file: Option, + pub my_ip: Option, #[cfg(feature = "metrics")] pub metrics: Option, pub anonymized_dns: Option, diff --git a/src/dns.rs b/src/dns.rs index e767f9d..448cf02 100644 --- a/src/dns.rs +++ b/src/dns.rs @@ -2,7 +2,7 @@ use crate::dnscrypt_certs::*; use crate::errors::*; use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; -use std::net::{Ipv4Addr, Ipv6Addr}; +use std::net::IpAddr; use std::sync::Arc; pub const DNS_MAX_HOSTNAME_SIZE: usize = 256; @@ -622,7 +622,7 @@ pub fn serve_blocked_response(client_packet: Vec) -> Result, Error> Ok(packet) } -pub fn serve_a_response(client_packet: Vec, ip: Ipv4Addr) -> Result, Error> { +pub fn serve_ip_response(client_packet: Vec, ip: IpAddr, ttl: u32) -> Result, Error> { ensure!(client_packet.len() >= DNS_HEADER_SIZE, "Short packet"); ensure!(qdcount(&client_packet) == 1, "No question"); ensure!( @@ -637,31 +637,21 @@ pub fn serve_a_response(client_packet: Vec, ip: Ipv4Addr) -> Result, authoritative_response(&mut packet); ancount_inc(&mut packet)?; packet.write_u16::(0xc000 + DNS_HEADER_SIZE as u16)?; - packet.write_u16::(DNS_TYPE_A)?; - packet.write_u16::(DNS_CLASS_INET)?; - packet.write_u32::(60)?; - packet.extend_from_slice(&ip.octets()); - Ok(packet) -} - -pub fn serve_aaaa_response(client_packet: Vec, ip: Ipv6Addr) -> Result, Error> { - ensure!(client_packet.len() >= DNS_HEADER_SIZE, "Short packet"); - ensure!(qdcount(&client_packet) == 1, "No question"); - ensure!( - !is_response(&client_packet), - "Question expected, but got a response instead" - ); - let offset = skip_name(&client_packet, DNS_HEADER_SIZE)?; - let mut packet = client_packet; - ensure!(packet.len() - offset >= 4, "Short packet"); - packet.truncate(offset + 4); - an_ns_ar_count_clear(&mut packet); - authoritative_response(&mut packet); - ancount_inc(&mut packet)?; - packet.write_u16::(0xc000 + DNS_HEADER_SIZE as u16)?; - packet.write_u16::(DNS_TYPE_AAAA)?; - packet.write_u16::(DNS_CLASS_INET)?; - packet.write_u32::(60)?; - packet.extend_from_slice(&ip.octets()); + match ip { + IpAddr::V4(ip) => { + packet.write_u16::(DNS_TYPE_A)?; + packet.write_u16::(DNS_CLASS_INET)?; + packet.write_u32::(ttl)?; + packet.write_u16::(4)?; + packet.extend_from_slice(&ip.octets()); + } + IpAddr::V6(ip) => { + packet.write_u16::(DNS_TYPE_AAAA)?; + packet.write_u16::(DNS_CLASS_INET)?; + packet.write_u32::(ttl)?; + packet.write_u16::(16)?; + packet.extend_from_slice(&ip.octets()); + } + }; Ok(packet) } diff --git a/src/globals.rs b/src/globals.rs index beb25ce..14ebf52 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -49,6 +49,7 @@ pub struct Globals { pub anonymized_dns_allow_non_reserved_ports: bool, pub anonymized_dns_blacklisted_ips: Vec, pub access_control_tokens: Option>, + pub my_ip: Option>, #[cfg(feature = "metrics")] #[derivative(Debug = "ignore")] pub varz: Varz, diff --git a/src/main.rs b/src/main.rs index 9050b90..980e396 100644 --- a/src/main.rs +++ b/src/main.rs @@ -704,6 +704,7 @@ fn main() -> Result<(), Error> { anonymized_dns_allow_non_reserved_ports, anonymized_dns_blacklisted_ips, access_control_tokens, + my_ip: config.my_ip.map(|ip| ip.as_bytes().to_ascii_lowercase()), #[cfg(feature = "metrics")] varz: Varz::default(), }); diff --git a/src/resolver.rs b/src/resolver.rs index 1f447aa..b3c9157 100644 --- a/src/resolver.rs +++ b/src/resolver.rs @@ -8,7 +8,7 @@ use byteorder::{BigEndian, ByteOrder}; use rand::prelude::*; use siphasher::sip128::Hasher128; use std::hash::Hasher; -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use tokio::net::{TcpStream, UdpSocket}; use tokio::prelude::*; @@ -169,16 +169,15 @@ pub async fn get_cached_response_or_resolve( mut packet: &mut Vec, ) -> Result, Error> { let packet_qname = dns::qname(&packet)?; - if &packet_qname == b"my.ip" { - let client_ip = match client_ctx { - ClientCtx::Udp(u) => u.client_addr, - ClientCtx::Tcp(t) => t.client_connection.peer_addr()?, + if let Some(my_ip) = &globals.my_ip { + if &packet_qname.to_ascii_lowercase() == my_ip { + let client_ip = match client_ctx { + ClientCtx::Udp(u) => u.client_addr, + ClientCtx::Tcp(t) => t.client_connection.peer_addr()?, + } + .ip(); + return serve_ip_response(packet.to_vec(), client_ip, 1); } - .ip(); - return match client_ip { - IpAddr::V4(ip) => serve_a_response(packet.to_vec(), ip), - IpAddr::V6(ip) => serve_aaaa_response(packet.to_vec(), ip), - }; } if let Some(blacklist) = &globals.blacklist { if blacklist.find(&packet_qname) {