You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
encrypted-dns-server/src/anonymized_dns.rs

90 lines
3.0 KiB
Rust

use crate::*;
use byteorder::{BigEndian, ByteOrder};
use failure::ensure;
use std::net::{IpAddr, Ipv6Addr, SocketAddr};
use std::sync::Arc;
use tokio::net::UdpSocket;
pub const ANONYMIZED_DNSCRYPT_QUERY_MAGIC: [u8; 10] =
[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00];
pub const ANONYMIZED_DNSCRYPT_OVERHEAD: usize = 16 + 2;
pub async fn handle_anonymized_dns(
globals: Arc<Globals>,
client_ctx: ClientCtx,
encrypted_packet: &[u8],
) -> Result<(), Error> {
ensure!(
encrypted_packet.len() > ANONYMIZED_DNSCRYPT_OVERHEAD,
"Short packet"
);
let ip_bin = &encrypted_packet[..16];
let ip_v6 = Ipv6Addr::new(
BigEndian::read_u16(&ip_bin[0..2]),
BigEndian::read_u16(&ip_bin[2..4]),
BigEndian::read_u16(&ip_bin[4..6]),
BigEndian::read_u16(&ip_bin[6..8]),
BigEndian::read_u16(&ip_bin[8..10]),
BigEndian::read_u16(&ip_bin[10..12]),
BigEndian::read_u16(&ip_bin[12..14]),
BigEndian::read_u16(&ip_bin[14..16]),
);
let ip = match ip_v6.to_ipv4() {
Some(ip_v4) => IpAddr::V4(ip_v4),
None => IpAddr::V6(ip_v6),
};
#[cfg(feature = "metrics")]
globals.varz.anonymized_queries.inc();
ensure!(ip.is_global(), "Forbidden upstream address");
ensure!(
!globals.anonymized_dns_blacklisted_ips.contains(&ip),
"Blacklisted upstream IP"
);
let port = BigEndian::read_u16(&encrypted_packet[16..18]);
ensure!(
globals.anonymized_dns_allowed_ports.contains(&port),
"Forbidden upstream port"
);
let upstream_address = SocketAddr::new(ip, port);
ensure!(
!globals.listen_addrs.contains(&upstream_address)
&& globals.external_addr != upstream_address,
"Would be relaying to self"
);
let encrypted_packet = &encrypted_packet[ANONYMIZED_DNSCRYPT_OVERHEAD..];
let encrypted_packet_len = encrypted_packet.len();
ensure!(
encrypted_packet_len >= DNSCRYPT_UDP_QUERY_MIN_SIZE
&& encrypted_packet_len <= DNSCRYPT_UDP_QUERY_MAX_SIZE,
"Unexpected encapsulated query length"
);
ensure!(
encrypted_packet_len > 8 && [0u8, 0, 0, 0, 0, 0, 0, 1] != encrypted_packet[..8],
"Protocol confusion with QUIC"
);
let mut ext_socket = UdpSocket::bind(&globals.external_addr).await?;
ext_socket.connect(&upstream_address).await?;
ext_socket.send(&encrypted_packet).await?;
let mut response = vec![0u8; DNSCRYPT_UDP_RESPONSE_MAX_SIZE];
loop {
let fut = ext_socket.recv_from(&mut response[..]);
let (response_len, response_addr) = fut.await?;
if response_addr == upstream_address
&& (DNSCRYPT_UDP_RESPONSE_MIN_SIZE..=DNSCRYPT_UDP_RESPONSE_MAX_SIZE)
.contains(&response_len)
&& response[..DNSCRYPT_RESPONSE_MAGIC_SIZE] == DNSCRYPT_RESPONSE_MAGIC
{
response.truncate(response_len);
break;
}
}
#[cfg(feature = "metrics")]
globals.varz.anonymized_responses.inc();
respond_to_query(client_ctx, response).await
}