1 use crate::dnscrypt_certs::*;
2 use crate::errors::*;
3 
4 use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
5 use std::net::IpAddr;
6 use std::sync::Arc;
7 
8 pub const DNS_MAX_HOSTNAME_SIZE: usize = 256;
9 pub const DNS_HEADER_SIZE: usize = 12;
10 pub const DNS_OFFSET_FLAGS: usize = 2;
11 pub const DNS_MAX_PACKET_SIZE: usize = 0x1600;
12 
13 const DNS_MAX_INDIRECTIONS: usize = 16;
14 const DNS_FLAGS_TC: u16 = 1u16 << 9;
15 const DNS_FLAGS_QR: u16 = 1u16 << 15;
16 const DNS_FLAGS_RA: u16 = 1u16 << 7;
17 const DNS_FLAGS_RD: u16 = 1u16 << 8;
18 const DNS_FLAGS_CD: u16 = 1u16 << 4;
19 const DNS_OFFSET_QUESTION: usize = DNS_HEADER_SIZE;
20 
21 pub const DNS_TYPE_A: u16 = 1;
22 pub const DNS_TYPE_AAAA: u16 = 28;
23 pub const DNS_TYPE_OPT: u16 = 41;
24 pub const DNS_TYPE_TXT: u16 = 16;
25 pub const DNS_TYPE_HINFO: u16 = 13;
26 pub const DNS_CLASS_INET: u16 = 1;
27 
28 pub const DNS_RCODE_SERVFAIL: u8 = 2;
29 pub const DNS_RCODE_NXDOMAIN: u8 = 3;
30 pub const DNS_RCODE_REFUSED: u8 = 5;
31 
32 #[inline]
rcode(packet: &[u8]) -> u833 pub fn rcode(packet: &[u8]) -> u8 {
34     packet[3] & 0x0f
35 }
36 
37 #[inline]
set_rcode(packet: &mut [u8], rcode: u8)38 pub fn set_rcode(packet: &mut [u8], rcode: u8) {
39     packet[3] = (packet[3] & !0x0f) | rcode;
40 }
41 
42 #[inline]
rcode_servfail(packet: &[u8]) -> bool43 pub fn rcode_servfail(packet: &[u8]) -> bool {
44     rcode(packet) == DNS_RCODE_SERVFAIL
45 }
46 
47 #[inline]
set_rcode_servfail(packet: &mut [u8])48 pub fn set_rcode_servfail(packet: &mut [u8]) {
49     set_rcode(packet, DNS_RCODE_SERVFAIL)
50 }
51 
52 #[inline]
rcode_refused(packet: &[u8]) -> bool53 pub fn rcode_refused(packet: &[u8]) -> bool {
54     rcode(packet) == DNS_RCODE_REFUSED
55 }
56 
57 #[inline]
set_rcode_refused(packet: &mut [u8])58 pub fn set_rcode_refused(packet: &mut [u8]) {
59     set_rcode(packet, DNS_RCODE_REFUSED)
60 }
61 
62 #[inline]
rcode_nxdomain(packet: &[u8]) -> bool63 pub fn rcode_nxdomain(packet: &[u8]) -> bool {
64     rcode(packet) == DNS_RCODE_NXDOMAIN
65 }
66 
67 #[inline]
set_rcode_nxdomain(packet: &mut [u8])68 pub fn set_rcode_nxdomain(packet: &mut [u8]) {
69     set_rcode(packet, DNS_RCODE_NXDOMAIN)
70 }
71 
72 #[inline]
qdcount(packet: &[u8]) -> u1673 pub fn qdcount(packet: &[u8]) -> u16 {
74     BigEndian::read_u16(&packet[4..])
75 }
76 
77 #[inline]
ancount(packet: &[u8]) -> u1678 pub fn ancount(packet: &[u8]) -> u16 {
79     BigEndian::read_u16(&packet[6..])
80 }
81 
ancount_inc(packet: &mut [u8]) -> Result<(), Error>82 fn ancount_inc(packet: &mut [u8]) -> Result<(), Error> {
83     let mut ancount = ancount(packet);
84     ensure!(ancount < 0xffff, "Too many answer records");
85     ancount += 1;
86     BigEndian::write_u16(&mut packet[6..], ancount);
87     Ok(())
88 }
89 
90 #[inline]
nscount(packet: &[u8]) -> u1691 fn nscount(packet: &[u8]) -> u16 {
92     BigEndian::read_u16(&packet[8..])
93 }
94 
95 #[inline]
arcount(packet: &[u8]) -> u1696 pub fn arcount(packet: &[u8]) -> u16 {
97     BigEndian::read_u16(&packet[10..])
98 }
99 
arcount_inc(packet: &mut [u8]) -> Result<(), Error>100 fn arcount_inc(packet: &mut [u8]) -> Result<(), Error> {
101     let mut arcount = arcount(packet);
102     ensure!(arcount < 0xffff, "Too many additional records");
103     arcount += 1;
104     BigEndian::write_u16(&mut packet[10..], arcount);
105     Ok(())
106 }
107 
108 #[inline]
arcount_clear(packet: &mut [u8]) -> Result<(), Error>109 fn arcount_clear(packet: &mut [u8]) -> Result<(), Error> {
110     BigEndian::write_u16(&mut packet[10..], 0);
111     Ok(())
112 }
113 
114 #[inline]
an_ns_ar_count_clear(packet: &mut [u8])115 pub fn an_ns_ar_count_clear(packet: &mut [u8]) {
116     packet[6..12].iter_mut().for_each(|x| *x = 0);
117 }
118 
119 #[inline]
tid(packet: &[u8]) -> u16120 pub fn tid(packet: &[u8]) -> u16 {
121     BigEndian::read_u16(&packet[0..])
122 }
123 
124 #[inline]
set_tid(packet: &mut [u8], tid: u16)125 pub fn set_tid(packet: &mut [u8], tid: u16) {
126     BigEndian::write_u16(&mut packet[0..], tid);
127 }
128 
129 #[inline]
set_flags(packet: &mut [u8], flags: u16)130 pub fn set_flags(packet: &mut [u8], flags: u16) {
131     BigEndian::write_u16(&mut packet[DNS_OFFSET_FLAGS..], flags);
132 }
133 
134 #[inline]
authoritative_response(packet: &mut [u8])135 pub fn authoritative_response(packet: &mut [u8]) {
136     let current_rd_cd_flags =
137         BigEndian::read_u16(&packet[DNS_OFFSET_FLAGS..]) & (DNS_FLAGS_CD | DNS_FLAGS_RD);
138     set_flags(packet, current_rd_cd_flags | DNS_FLAGS_QR | DNS_FLAGS_RA);
139 }
140 
141 #[inline]
truncate(packet: &mut [u8])142 pub fn truncate(packet: &mut [u8]) {
143     let current_flags = BigEndian::read_u16(&packet[DNS_OFFSET_FLAGS..]);
144     BigEndian::write_u16(
145         &mut packet[DNS_OFFSET_FLAGS..],
146         current_flags | DNS_FLAGS_TC | DNS_FLAGS_QR | DNS_FLAGS_RA,
147     );
148 }
149 
150 #[inline]
is_response(packet: &[u8]) -> bool151 pub fn is_response(packet: &[u8]) -> bool {
152     BigEndian::read_u16(&packet[DNS_OFFSET_FLAGS..]) & DNS_FLAGS_QR == DNS_FLAGS_QR
153 }
154 
155 #[inline]
is_truncated(packet: &[u8]) -> bool156 pub fn is_truncated(packet: &[u8]) -> bool {
157     BigEndian::read_u16(&packet[DNS_OFFSET_FLAGS..]) & DNS_FLAGS_TC == DNS_FLAGS_TC
158 }
159 
qname(packet: &[u8]) -> Result<Vec<u8>, Error>160 pub fn qname(packet: &[u8]) -> Result<Vec<u8>, Error> {
161     debug_assert!(std::usize::MAX > 0xffff);
162     debug_assert!(DNS_MAX_HOSTNAME_SIZE > 0xff);
163     let packet_len = packet.len();
164     ensure!(packet_len > DNS_OFFSET_QUESTION, "Short packet");
165     ensure!(qdcount(packet) == 1, "Unexpected query count");
166     let mut offset = DNS_HEADER_SIZE;
167     let mut qname = Vec::with_capacity(DNS_MAX_HOSTNAME_SIZE);
168     loop {
169         ensure!(offset < packet_len, "Short packet");
170         match packet[offset] as usize {
171             label_len if label_len & 0xc0 == 0xc0 => bail!("Indirections"),
172             0 => {
173                 if qname.is_empty() {
174                     qname.push(b'.')
175                 }
176                 break;
177             }
178             label_len => {
179                 ensure!(label_len < 0x40, "Long label");
180                 ensure!(packet_len - offset > 1, "Short packet");
181                 offset += 1;
182                 ensure!(packet_len - offset > label_len, "Short packet");
183                 if !qname.is_empty() {
184                     qname.push(b'.')
185                 }
186                 ensure!(
187                     qname.len() < DNS_MAX_HOSTNAME_SIZE - label_len,
188                     "Name too long"
189                 );
190                 qname.extend_from_slice(&packet[offset..offset + label_len]);
191                 offset += label_len;
192             }
193         }
194     }
195     Ok(qname)
196 }
197 
normalize_qname(packet: &mut [u8]) -> Result<(), Error>198 pub fn normalize_qname(packet: &mut [u8]) -> Result<(), Error> {
199     debug_assert!(std::usize::MAX > 0xffff);
200     debug_assert!(DNS_MAX_HOSTNAME_SIZE > 0xff);
201     let packet_len = packet.len();
202     ensure!(packet_len > DNS_OFFSET_QUESTION, "Short packet");
203     ensure!(qdcount(packet) == 1, "Unexpected query count");
204     let mut offset = DNS_HEADER_SIZE;
205     loop {
206         ensure!(offset < packet_len, "Short packet");
207         match packet[offset] as usize {
208             label_len if label_len & 0xc0 == 0xc0 => bail!("Indirections"),
209             0 => {
210                 break;
211             }
212             label_len => {
213                 ensure!(label_len < 0x40, "Long label");
214                 ensure!(packet_len - offset > 1, "Short packet");
215                 offset += 1;
216                 ensure!(packet_len - offset > label_len, "Short packet");
217                 ensure!(
218                     offset - DNS_HEADER_SIZE < DNS_MAX_HOSTNAME_SIZE - label_len,
219                     "Name too long"
220                 );
221                 packet[offset..offset + label_len]
222                     .iter_mut()
223                     .for_each(|x| *x = x.to_ascii_lowercase());
224                 offset += label_len;
225             }
226         }
227     }
228     Ok(())
229 }
230 
qname_tld(qname: &[u8]) -> &[u8]231 pub fn qname_tld(qname: &[u8]) -> &[u8] {
232     qname.rsplit(|c| *c == b'.').next().unwrap_or_default()
233 }
234 
recase_qname(packet: &mut [u8], qname: &[u8]) -> Result<(), Error>235 pub fn recase_qname(packet: &mut [u8], qname: &[u8]) -> Result<(), Error> {
236     debug_assert!(std::usize::MAX > 0xffff);
237     let packet_len = packet.len();
238     ensure!(packet_len > DNS_OFFSET_QUESTION, "Short packet");
239     ensure!(qdcount(packet) == 1, "Unexpected query count");
240     let qname_len = qname.len();
241     let mut offset = DNS_HEADER_SIZE;
242     let mut qname_offset = 0;
243     loop {
244         ensure!(offset < packet_len, "Short packet");
245         match packet[offset] as usize {
246             label_len if label_len & 0xc0 == 0xc0 => bail!("Indirections"),
247             0 => {
248                 ensure!(
249                     (qname_len == 1 && qname[0] == b'.') || qname_offset == qname_len,
250                     "Unterminated reference qname"
251                 );
252                 break;
253             }
254             label_len => {
255                 ensure!(label_len < 0x40, "Long label");
256                 ensure!(packet_len - offset > 1, "Short packet");
257                 ensure!(qname_offset < qname_len, "Short reference qname");
258                 offset += 1;
259                 if qname_offset != 0 {
260                     ensure!(qname[qname_offset] == b'.', "Non-matching reference qname");
261                     qname_offset += 1;
262                 }
263                 ensure!(packet_len - offset > label_len, "Short packet");
264                 ensure!(
265                     qname_len - qname_offset >= label_len,
266                     "Short reference qname"
267                 );
268                 packet[offset..offset + label_len]
269                     .iter_mut()
270                     .zip(&qname[qname_offset..qname_offset + label_len])
271                     .for_each(|(a, b)| {
272                         debug_assert!(a.eq_ignore_ascii_case(b));
273                         *a = *b
274                     });
275                 offset += label_len;
276                 qname_offset += label_len;
277             }
278         }
279     }
280     Ok(())
281 }
282 
skip_name(packet: &[u8], offset: usize) -> Result<usize, Error>283 fn skip_name(packet: &[u8], offset: usize) -> Result<usize, Error> {
284     let packet_len = packet.len();
285     ensure!(offset < packet_len - 1, "Short packet");
286     let mut qname_len: usize = 0;
287     let mut offset = offset;
288     loop {
289         let label_len = match packet[offset] as usize {
290             label_len if label_len & 0xc0 == 0xc0 => {
291                 ensure!(packet_len - offset >= 2, "Incomplete offset");
292                 offset += 2;
293                 break;
294             }
295             label_len => label_len,
296         } as usize;
297         ensure!(label_len < 0x40, "Long label");
298         ensure!(
299             packet_len - offset - 1 > label_len,
300             "Malformed packet with an out-of-bounds name"
301         );
302         qname_len += label_len + 1;
303         ensure!(qname_len <= DNS_MAX_HOSTNAME_SIZE, "Name too long");
304         offset += label_len + 1;
305         if label_len == 0 {
306             break;
307         }
308     }
309     Ok(offset)
310 }
311 
traverse_rrs<F: FnMut(usize) -> Result<(), Error>>( packet: &[u8], mut offset: usize, rrcount: usize, mut cb: F, ) -> Result<usize, Error>312 fn traverse_rrs<F: FnMut(usize) -> Result<(), Error>>(
313     packet: &[u8],
314     mut offset: usize,
315     rrcount: usize,
316     mut cb: F,
317 ) -> Result<usize, Error> {
318     let packet_len = packet.len();
319     for _ in 0..rrcount {
320         offset = skip_name(packet, offset)?;
321         ensure!(packet_len - offset >= 10, "Short packet");
322         let rdlen = BigEndian::read_u16(&packet[offset + 8..]) as usize;
323         ensure!(
324             packet_len - offset >= 10 + rdlen,
325             "Record length would exceed packet length"
326         );
327         cb(offset)?;
328         offset += 10;
329         offset += rdlen;
330     }
331     Ok(offset)
332 }
333 
traverse_rrs_mut<F: FnMut(&mut [u8], usize) -> Result<(), Error>>( packet: &mut [u8], mut offset: usize, rrcount: usize, mut cb: F, ) -> Result<usize, Error>334 fn traverse_rrs_mut<F: FnMut(&mut [u8], usize) -> Result<(), Error>>(
335     packet: &mut [u8],
336     mut offset: usize,
337     rrcount: usize,
338     mut cb: F,
339 ) -> Result<usize, Error> {
340     let packet_len = packet.len();
341     for _ in 0..rrcount {
342         offset = skip_name(packet, offset)?;
343         ensure!(packet_len - offset >= 10, "Short packet");
344         let rdlen = BigEndian::read_u16(&packet[offset + 8..]) as usize;
345         ensure!(
346             packet_len - offset >= 10 + rdlen,
347             "Record length would exceed packet length"
348         );
349         cb(packet, offset)?;
350         offset += 10;
351         offset += rdlen;
352     }
353     Ok(offset)
354 }
355 
min_ttl(packet: &[u8], min_ttl: u32, max_ttl: u32, failure_ttl: u32) -> Result<u32, Error>356 pub fn min_ttl(packet: &[u8], min_ttl: u32, max_ttl: u32, failure_ttl: u32) -> Result<u32, Error> {
357     let packet_len = packet.len();
358     ensure!(packet_len > DNS_OFFSET_QUESTION, "Short packet");
359     ensure!(packet_len <= DNS_MAX_PACKET_SIZE, "Large packet");
360     ensure!(qdcount(packet) == 1, "No question");
361     let mut offset = skip_name(packet, DNS_OFFSET_QUESTION)?;
362     assert!(offset > DNS_OFFSET_QUESTION);
363     ensure!(packet_len - offset > 4, "Short packet");
364     offset += 4;
365     let (ancount, nscount, arcount) = (ancount(packet), nscount(packet), arcount(packet));
366     let rrcount = ancount as usize + nscount as usize + arcount as usize;
367     let mut found_min_ttl = if rrcount > 0 { max_ttl } else { failure_ttl };
368 
369     offset = traverse_rrs(packet, offset, rrcount, |offset| {
370         let qtype = BigEndian::read_u16(&packet[offset..]);
371         let ttl = BigEndian::read_u32(&packet[offset + 4..]);
372         if qtype != DNS_TYPE_OPT && ttl < found_min_ttl {
373             found_min_ttl = ttl;
374         }
375         Ok(())
376     })?;
377     if found_min_ttl < min_ttl {
378         found_min_ttl = min_ttl;
379     }
380     ensure!(packet_len == offset, "Garbage after packet");
381     Ok(found_min_ttl)
382 }
383 
set_ttl(packet: &mut [u8], ttl: u32) -> Result<(), Error>384 pub fn set_ttl(packet: &mut [u8], ttl: u32) -> Result<(), Error> {
385     let packet_len = packet.len();
386     ensure!(packet_len > DNS_OFFSET_QUESTION, "Short packet");
387     ensure!(packet_len <= DNS_MAX_PACKET_SIZE, "Large packet");
388     ensure!(qdcount(packet) == 1, "No question");
389     let mut offset = skip_name(packet, DNS_OFFSET_QUESTION)?;
390     assert!(offset > DNS_OFFSET_QUESTION);
391     ensure!(packet_len - offset > 4, "Short packet");
392     offset += 4;
393     let (ancount, nscount, arcount) = (ancount(packet), nscount(packet), arcount(packet));
394     let rrcount = ancount as usize + nscount as usize + arcount as usize;
395     offset = traverse_rrs_mut(packet, offset, rrcount, |packet, offset| {
396         let qtype = BigEndian::read_u16(&packet[offset..]);
397         if qtype != DNS_TYPE_OPT {
398             BigEndian::write_u32(&mut packet[offset + 4..], ttl)
399         }
400         Ok(())
401     })?;
402     ensure!(packet_len == offset, "Garbage after packet");
403     Ok(())
404 }
405 
add_edns_section(packet: &mut Vec<u8>, max_payload_size: u16) -> Result<(), Error>406 fn add_edns_section(packet: &mut Vec<u8>, max_payload_size: u16) -> Result<(), Error> {
407     let opt_rr: [u8; 11] = [
408         0,
409         (DNS_TYPE_OPT >> 8) as u8,
410         DNS_TYPE_OPT as u8,
411         (max_payload_size >> 8) as u8,
412         max_payload_size as u8,
413         0,
414         0,
415         0,
416         0,
417         0,
418         0,
419     ];
420     ensure!(
421         DNS_MAX_PACKET_SIZE - packet.len() >= opt_rr.len(),
422         "Packet would be too large to add a new record"
423     );
424     arcount_inc(packet)?;
425     packet.extend(&opt_rr);
426     Ok(())
427 }
428 
set_edns_max_payload_size(packet: &mut Vec<u8>, max_payload_size: u16) -> Result<(), Error>429 pub fn set_edns_max_payload_size(packet: &mut Vec<u8>, max_payload_size: u16) -> Result<(), Error> {
430     let packet_len = packet.len();
431     ensure!(packet_len > DNS_OFFSET_QUESTION, "Short packet");
432     ensure!(packet_len <= DNS_MAX_PACKET_SIZE, "Large packet");
433     ensure!(qdcount(packet) == 1, "No question");
434     let mut offset = skip_name(packet, DNS_OFFSET_QUESTION)?;
435     assert!(offset > DNS_OFFSET_QUESTION);
436     ensure!(packet_len - offset >= 4, "Short packet");
437     offset += 4;
438     let (ancount, nscount, arcount) = (ancount(packet), nscount(packet), arcount(packet));
439     offset = traverse_rrs(
440         packet,
441         offset,
442         ancount as usize + nscount as usize,
443         |_offset| Ok(()),
444     )?;
445     let mut edns_payload_set = false;
446     traverse_rrs_mut(packet, offset, arcount as _, |packet, offset| {
447         let qtype = BigEndian::read_u16(&packet[offset..]);
448         if qtype == DNS_TYPE_OPT {
449             ensure!(!edns_payload_set, "Duplicate OPT RR found");
450             BigEndian::write_u16(&mut packet[offset + 2..], max_payload_size);
451             edns_payload_set = true;
452         }
453         Ok(())
454     })?;
455     if edns_payload_set {
456         return Ok(());
457     }
458     add_edns_section(packet, max_payload_size)?;
459     Ok(())
460 }
461 
serve_certificates<'t>( client_packet: &[u8], expected_qname: &str, dnscrypt_encryption_params_set: impl IntoIterator<Item = &'t Arc<DNSCryptEncryptionParams>>, ) -> Result<Option<Vec<u8>>, Error>462 pub fn serve_certificates<'t>(
463     client_packet: &[u8],
464     expected_qname: &str,
465     dnscrypt_encryption_params_set: impl IntoIterator<Item = &'t Arc<DNSCryptEncryptionParams>>,
466 ) -> Result<Option<Vec<u8>>, Error> {
467     ensure!(client_packet.len() >= DNS_HEADER_SIZE, "Short packet");
468     ensure!(qdcount(client_packet) == 1, "No question");
469     ensure!(
470         !is_response(client_packet),
471         "Question expected, but got a response instead"
472     );
473     let offset = skip_name(client_packet, DNS_HEADER_SIZE)?;
474     ensure!(client_packet.len() - offset >= 4, "Short packet");
475     let qtype = BigEndian::read_u16(&client_packet[offset..]);
476     let qclass = BigEndian::read_u16(&client_packet[offset + 2..]);
477     if qtype != DNS_TYPE_TXT || qclass != DNS_CLASS_INET {
478         return Ok(None);
479     }
480     let qname_v = qname(client_packet)?;
481     let qname = std::str::from_utf8(&qname_v)?;
482     if !qname.eq_ignore_ascii_case(expected_qname) {
483         return Ok(None);
484     }
485     let mut packet = (&client_packet[..offset + 4]).to_vec();
486     an_ns_ar_count_clear(&mut packet);
487     authoritative_response(&mut packet);
488     let dnscrypt_encryption_params = dnscrypt_encryption_params_set
489         .into_iter()
490         .max_by_key(|x| x.dnscrypt_cert().ts_end())
491         .ok_or_else(|| anyhow!("No certificates"))?;
492     let cert_bin = dnscrypt_encryption_params.dnscrypt_cert().as_bytes();
493     ensure!(cert_bin.len() <= 0xff, "Certificate too long");
494     ancount_inc(&mut packet)?;
495     packet.write_u16::<BigEndian>(0xc000 + DNS_HEADER_SIZE as u16)?;
496     packet.write_u16::<BigEndian>(DNS_TYPE_TXT)?;
497     packet.write_u16::<BigEndian>(DNS_CLASS_INET)?;
498     packet.write_u32::<BigEndian>(DNSCRYPT_CERTS_RENEWAL)?;
499     packet.write_u16::<BigEndian>(1 + cert_bin.len() as u16)?;
500     packet.write_u8(cert_bin.len() as u8)?;
501     packet.extend_from_slice(cert_bin);
502     ensure!(packet.len() < DNS_MAX_PACKET_SIZE, "Packet too large");
503 
504     Ok(Some(packet))
505 }
506 
serve_truncated_response(client_packet: Vec<u8>) -> Result<Vec<u8>, Error>507 pub fn serve_truncated_response(client_packet: Vec<u8>) -> Result<Vec<u8>, Error> {
508     ensure!(client_packet.len() >= DNS_HEADER_SIZE, "Short packet");
509     ensure!(qdcount(&client_packet) == 1, "No question");
510     ensure!(
511         !is_response(&client_packet),
512         "Question expected, but got a response instead"
513     );
514     let offset = skip_name(&client_packet, DNS_HEADER_SIZE)?;
515     let mut packet = client_packet;
516     ensure!(packet.len() - offset >= 4, "Short packet");
517     packet.truncate(offset + 4);
518     an_ns_ar_count_clear(&mut packet);
519     authoritative_response(&mut packet);
520     truncate(&mut packet);
521     Ok(packet)
522 }
523 
qtype_qclass(packet: &[u8]) -> Result<(u16, u16), Error>524 pub fn qtype_qclass(packet: &[u8]) -> Result<(u16, u16), Error> {
525     ensure!(packet.len() >= DNS_HEADER_SIZE, "Short packet");
526     ensure!(qdcount(packet) == 1, "No question");
527     let offset = skip_name(packet, DNS_HEADER_SIZE)?;
528     ensure!(packet.len() - offset >= 4, "Short packet");
529     let qtype = BigEndian::read_u16(&packet[offset..]);
530     let qclass = BigEndian::read_u16(&packet[offset + 2..]);
531     Ok((qtype, qclass))
532 }
533 
parse_txt_rrdata<F: FnMut(&str) -> Result<(), Error>>( rrdata: &[u8], mut cb: F, ) -> Result<(), Error>534 fn parse_txt_rrdata<F: FnMut(&str) -> Result<(), Error>>(
535     rrdata: &[u8],
536     mut cb: F,
537 ) -> Result<(), Error> {
538     let rrdata_len = rrdata.len();
539     let mut offset = 0;
540     while offset < rrdata_len {
541         let part_len = rrdata[offset] as usize;
542         if part_len == 0 {
543             break;
544         }
545         ensure!(rrdata_len - offset > part_len, "Short TXT RR data");
546         offset += 1;
547         let part_bin = &rrdata[offset..offset + part_len];
548         let part = std::str::from_utf8(part_bin)?;
549         cb(part)?;
550         offset += part_len;
551     }
552     Ok(())
553 }
554 
query_meta(packet: &mut Vec<u8>) -> Result<Option<String>, Error>555 pub fn query_meta(packet: &mut Vec<u8>) -> Result<Option<String>, Error> {
556     let packet_len = packet.len();
557     ensure!(packet_len > DNS_OFFSET_QUESTION, "Short packet");
558     ensure!(packet_len <= DNS_MAX_PACKET_SIZE, "Large packet");
559     ensure!(qdcount(packet) == 1, "No question");
560     let mut offset = skip_name(packet, DNS_OFFSET_QUESTION)?;
561     assert!(offset > DNS_OFFSET_QUESTION);
562     ensure!(packet_len - offset >= 4, "Short packet");
563     offset += 4;
564     let (ancount, nscount, arcount) = (ancount(packet), nscount(packet), arcount(packet));
565     offset = traverse_rrs(
566         packet,
567         offset,
568         ancount as usize + nscount as usize,
569         |_offset| Ok(()),
570     )?;
571     let mut token = None;
572     traverse_rrs(packet, offset, arcount as _, |mut offset| {
573         let qtype = BigEndian::read_u16(&packet[offset..]);
574         let qclass = BigEndian::read_u16(&packet[offset + 2..]);
575         if qtype != DNS_TYPE_TXT || qclass != DNS_CLASS_INET {
576             return Ok(());
577         }
578         let len = BigEndian::read_u16(&packet[offset + 8..]) as usize;
579         offset += 10;
580         ensure!(packet_len - offset >= len, "Short packet");
581         let rrdata = &packet[offset..offset + len];
582         parse_txt_rrdata(rrdata, |txt| {
583             if txt.len() < 7 || !txt.starts_with("token:") {
584                 return Ok(());
585             }
586             ensure!(token.is_none(), "Duplicate token");
587             let found_token = &txt[6..];
588             let found_token = found_token.to_owned();
589             token = Some(found_token);
590             Ok(())
591         })?;
592         Ok(())
593     })?;
594     if token.is_some() {
595         arcount_clear(packet)?;
596         packet.truncate(offset);
597     }
598     Ok(token)
599 }
600 
serve_nxdomain_response(client_packet: Vec<u8>) -> Result<Vec<u8>, Error>601 pub fn serve_nxdomain_response(client_packet: Vec<u8>) -> Result<Vec<u8>, Error> {
602     ensure!(client_packet.len() >= DNS_HEADER_SIZE, "Short packet");
603     ensure!(qdcount(&client_packet) == 1, "No question");
604     ensure!(
605         !is_response(&client_packet),
606         "Question expected, but got a response instead"
607     );
608     let offset = skip_name(&client_packet, DNS_HEADER_SIZE)?;
609     let mut packet = client_packet;
610     ensure!(packet.len() - offset >= 4, "Short packet");
611     packet.truncate(offset + 4);
612     an_ns_ar_count_clear(&mut packet);
613     authoritative_response(&mut packet);
614     set_rcode_nxdomain(&mut packet);
615     Ok(packet)
616 }
617 
serve_blocked_response(client_packet: Vec<u8>) -> Result<Vec<u8>, Error>618 pub fn serve_blocked_response(client_packet: Vec<u8>) -> Result<Vec<u8>, Error> {
619     ensure!(client_packet.len() >= DNS_HEADER_SIZE, "Short packet");
620     ensure!(qdcount(&client_packet) == 1, "No question");
621     ensure!(
622         !is_response(&client_packet),
623         "Question expected, but got a response instead"
624     );
625     let offset = skip_name(&client_packet, DNS_HEADER_SIZE)?;
626     let mut packet = client_packet;
627     ensure!(packet.len() - offset >= 4, "Short packet");
628     packet.truncate(offset + 4);
629     an_ns_ar_count_clear(&mut packet);
630     authoritative_response(&mut packet);
631     let hinfo_cpu = b"Query blocked";
632     let hinfo_rdata = b"by the DNS server";
633     let rdata_len = 1 + hinfo_cpu.len() + 1 + hinfo_rdata.len();
634     ancount_inc(&mut packet)?;
635     packet.write_u16::<BigEndian>(0xc000 + DNS_HEADER_SIZE as u16)?;
636     packet.write_u16::<BigEndian>(DNS_TYPE_HINFO)?;
637     packet.write_u16::<BigEndian>(DNS_CLASS_INET)?;
638     packet.write_u32::<BigEndian>(60)?;
639     packet.write_u16::<BigEndian>(rdata_len as _)?;
640     packet.push(hinfo_cpu.len() as u8);
641     packet.extend_from_slice(hinfo_cpu);
642     packet.push(hinfo_rdata.len() as u8);
643     packet.extend_from_slice(hinfo_rdata);
644     Ok(packet)
645 }
646 
serve_ip_response(client_packet: Vec<u8>, ip: IpAddr, ttl: u32) -> Result<Vec<u8>, Error>647 pub fn serve_ip_response(client_packet: Vec<u8>, ip: IpAddr, ttl: u32) -> Result<Vec<u8>, Error> {
648     ensure!(client_packet.len() >= DNS_HEADER_SIZE, "Short packet");
649     ensure!(qdcount(&client_packet) == 1, "No question");
650     ensure!(
651         !is_response(&client_packet),
652         "Question expected, but got a response instead"
653     );
654     let offset = skip_name(&client_packet, DNS_HEADER_SIZE)?;
655     let mut packet = client_packet;
656     ensure!(packet.len() - offset >= 4, "Short packet");
657     packet.truncate(offset + 4);
658     an_ns_ar_count_clear(&mut packet);
659     authoritative_response(&mut packet);
660     ancount_inc(&mut packet)?;
661     packet.write_u16::<BigEndian>(0xc000 + DNS_HEADER_SIZE as u16)?;
662     match ip {
663         IpAddr::V4(ip) => {
664             packet.write_u16::<BigEndian>(DNS_TYPE_A)?;
665             packet.write_u16::<BigEndian>(DNS_CLASS_INET)?;
666             packet.write_u32::<BigEndian>(ttl)?;
667             packet.write_u16::<BigEndian>(4)?;
668             packet.extend_from_slice(&ip.octets());
669         }
670         IpAddr::V6(ip) => {
671             packet.write_u16::<BigEndian>(DNS_TYPE_AAAA)?;
672             packet.write_u16::<BigEndian>(DNS_CLASS_INET)?;
673             packet.write_u32::<BigEndian>(ttl)?;
674             packet.write_u16::<BigEndian>(16)?;
675             packet.extend_from_slice(&ip.octets());
676         }
677     };
678     Ok(packet)
679 }
680