1 use crate::errors::*;
2 use crate::*;
3
4 use byteorder::{BigEndian, ByteOrder};
5 use ipext::IpExt;
6 use siphasher::sip128::Hasher128;
7 use std::hash::Hasher;
8 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
9 use std::sync::Arc;
10 use tokio::net::UdpSocket;
11
12 pub const ANONYMIZED_DNSCRYPT_QUERY_MAGIC: [u8; 10] =
13 [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00];
14
15 pub const ANONYMIZED_DNSCRYPT_OVERHEAD: usize = 16 + 2;
16
17 pub const RELAYED_CERT_CACHE_SIZE: usize = 1000;
18 pub const RELAYED_CERT_CACHE_TTL: u32 = 600;
19
handle_anonymized_dns( globals: Arc<Globals>, client_ctx: ClientCtx, relayed_packet: &[u8], ) -> Result<(), Error>20 pub async fn handle_anonymized_dns(
21 globals: Arc<Globals>,
22 client_ctx: ClientCtx,
23 relayed_packet: &[u8],
24 ) -> Result<(), Error> {
25 ensure!(
26 relayed_packet.len() > ANONYMIZED_DNSCRYPT_OVERHEAD,
27 "Short packet"
28 );
29 let ip_bin = &relayed_packet[..16];
30 let ip_v6 = Ipv6Addr::new(
31 BigEndian::read_u16(&ip_bin[0..2]),
32 BigEndian::read_u16(&ip_bin[2..4]),
33 BigEndian::read_u16(&ip_bin[4..6]),
34 BigEndian::read_u16(&ip_bin[6..8]),
35 BigEndian::read_u16(&ip_bin[8..10]),
36 BigEndian::read_u16(&ip_bin[10..12]),
37 BigEndian::read_u16(&ip_bin[12..14]),
38 BigEndian::read_u16(&ip_bin[14..16]),
39 );
40 let ip = match ip_v6.to_ipv4() {
41 Some(ip_v4) => IpAddr::V4(ip_v4),
42 None => IpAddr::V6(ip_v6),
43 };
44 #[cfg(feature = "metrics")]
45 globals.varz.anonymized_queries.inc();
46
47 ensure!(IpExt::is_global(&ip), "Forbidden upstream address");
48 ensure!(
49 !globals.anonymized_dns_blacklisted_ips.contains(&ip),
50 "Blacklisted upstream IP"
51 );
52 let port = BigEndian::read_u16(&relayed_packet[16..18]);
53 ensure!(
54 (globals.anonymized_dns_allow_non_reserved_ports && port >= 1024)
55 || globals.anonymized_dns_allowed_ports.contains(&port),
56 "Forbidden upstream port"
57 );
58 let upstream_address = SocketAddr::new(ip, port);
59 ensure!(
60 !globals.listen_addrs.contains(&upstream_address)
61 && globals.external_addr != Some(upstream_address),
62 "Would be relaying to self"
63 );
64 let encrypted_packet = &relayed_packet[ANONYMIZED_DNSCRYPT_OVERHEAD..];
65 let encrypted_packet_len = encrypted_packet.len();
66 ensure!(
67 encrypted_packet_len >= ANONYMIZED_DNSCRYPT_QUERY_MAGIC.len() + DNS_HEADER_SIZE
68 && encrypted_packet_len <= DNSCRYPT_UDP_QUERY_MAX_SIZE,
69 "Unexpected encapsulated query length"
70 );
71 ensure!(
72 encrypted_packet_len > 8 && [0u8, 0, 0, 0, 0, 0, 0, 1] != encrypted_packet[..8],
73 "Protocol confusion with QUIC"
74 );
75 debug_assert!(DNSCRYPT_UDP_QUERY_MIN_SIZE > ANONYMIZED_DNSCRYPT_QUERY_MAGIC.len());
76 ensure!(
77 encrypted_packet[..ANONYMIZED_DNSCRYPT_QUERY_MAGIC.len()]
78 != ANONYMIZED_DNSCRYPT_QUERY_MAGIC,
79 "Loop detected"
80 );
81 let ext_socket = match globals.external_addr {
82 Some(x) => UdpSocket::bind(x).await?,
83 None => match upstream_address {
84 SocketAddr::V4(_) => {
85 UdpSocket::bind(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0))).await?
86 }
87 SocketAddr::V6(s) => {
88 UdpSocket::bind(SocketAddr::V6(SocketAddrV6::new(
89 Ipv6Addr::UNSPECIFIED,
90 0,
91 s.flowinfo(),
92 s.scope_id(),
93 )))
94 .await?
95 }
96 },
97 };
98 ext_socket.connect(&upstream_address).await?;
99 ext_socket.send(encrypted_packet).await?;
100 let mut response = vec![0u8; DNSCRYPT_UDP_RESPONSE_MAX_SIZE];
101 let (response_len, is_certificate_response) = loop {
102 let fut = ext_socket.recv_from(&mut response[..]);
103 let (response_len, response_addr) = fut.await?;
104 if response_addr != upstream_address {
105 continue;
106 }
107 if is_encrypted_response(&response, response_len) {
108 break (response_len, false);
109 }
110 if is_certificate_response(&response, encrypted_packet) {
111 break (response_len, true);
112 }
113 };
114 response.truncate(response_len);
115 if is_certificate_response {
116 let mut hasher = globals.hasher;
117 hasher.write(&relayed_packet[..ANONYMIZED_DNSCRYPT_OVERHEAD]);
118 hasher.write(&dns::qname(encrypted_packet)?);
119 let packet_hash = hasher.finish128().as_u128();
120 let cached_response = {
121 match globals.cert_cache.lock().get(&packet_hash) {
122 None => None,
123 Some(response) if !(*response).has_expired() => {
124 trace!("Relayed certificate cached");
125 let mut cached_response = (*response).clone();
126 cached_response.set_tid(dns::tid(encrypted_packet));
127 Some(cached_response.into_response())
128 }
129 Some(_) => {
130 trace!("Relayed certificate expired");
131 None
132 }
133 }
134 };
135 match cached_response {
136 None => {
137 globals.cert_cache.lock().insert(
138 packet_hash,
139 CachedResponse::new(&globals.cert_cache, response.clone()),
140 );
141 }
142 Some(cached_response) => response = cached_response,
143 }
144 }
145
146 #[cfg(feature = "metrics")]
147 globals.varz.anonymized_responses.inc();
148
149 respond_to_query(client_ctx, response).await
150 }
151
152 #[inline]
is_encrypted_response(response: &[u8], response_len: usize) -> bool153 fn is_encrypted_response(response: &[u8], response_len: usize) -> bool {
154 (DNSCRYPT_UDP_RESPONSE_MIN_SIZE..=DNSCRYPT_UDP_RESPONSE_MAX_SIZE).contains(&response_len)
155 && response[..DNSCRYPT_RESPONSE_MAGIC_SIZE] == DNSCRYPT_RESPONSE_MAGIC
156 }
157
is_certificate_response(response: &[u8], query: &[u8]) -> bool158 fn is_certificate_response(response: &[u8], query: &[u8]) -> bool {
159 let prefix = b"2.dnscrypt-cert.";
160 if !((DNS_HEADER_SIZE + prefix.len() + 4..=DNS_MAX_PACKET_SIZE).contains(&query.len())
161 && (DNS_HEADER_SIZE + prefix.len() + 4..=DNS_MAX_PACKET_SIZE).contains(&response.len())
162 && dns::tid(response) == dns::tid(query)
163 && dns::is_response(response)
164 && !dns::is_response(query))
165 {
166 debug!("Unexpected relayed cert response");
167 return false;
168 }
169 let qname = match (dns::qname(query), dns::qname(response)) {
170 (Ok(response_qname), Ok(query_qname)) if response_qname == query_qname => query_qname,
171 _ => {
172 debug!("Relayed cert qname response didn't match the query qname");
173 return false;
174 }
175 };
176 if qname.len() <= prefix.len() || &qname[..prefix.len()] != prefix {
177 debug!("Relayed cert qname response didn't start with the standard prefix");
178 return false;
179 }
180 true
181 }
182