-fn build_proof(resolver: SocketAddr, domain: Name, ty: u16) -> Result<Vec<u8>, Error> {
- let mut stream = TcpStream::connect(resolver)?;
- let mut res = Vec::new();
- send_query(&mut stream, domain, ty)?;
- let mut reached_root = false;
- for _ in 0..10 {
- let rrsig_opt = read_response(&mut stream, &mut res)?;
- if let Some(rrsig) = rrsig_opt {
- if rrsig.name.as_str() == "." {
- reached_root = true;
- } else {
- if rrsig.name == rrsig.key_name {
- send_query(&mut stream, rrsig.key_name, DS::TYPE)?;
- } else {
- send_query(&mut stream, rrsig.key_name, DnsKey::TYPE)?;
+macro_rules! build_proof_impl {
+ ($stream: ident, $send_query: ident, $read_response: ident $(, $async_ok: tt)?) => { {
+ // We require the initial query to have already gone out, and assume our resolver will
+ // return any CNAMEs all the way to the final record in the response. From there, we just
+ // have to take any RRSIGs in the response and walk them up to the root. We do so
+ // iteratively, sending DNSKEY and DS lookups after every response, deduplicating requests
+ // using `dnskeys_requested`.
+ let mut res = Vec::new(); // The actual proof stream
+ let mut min_ttl = u32::MAX; // Min TTL of any answer record
+ const MAX_REQUESTS: usize = 20;
+ let mut rrsig_key_names = Vec::with_capacity(4); // Last response's RRSIG key_names
+ let mut dnskeys_requested = Vec::with_capacity(MAX_REQUESTS);
+ let mut pending_queries = 1;
+ let mut queries_made = 1;
+ while pending_queries != 0 && queries_made <= MAX_REQUESTS {
+ let response_min_ttl = $read_response(&mut $stream, &mut res, &mut rrsig_key_names)
+ $(.await?; $async_ok)??; // Either await?; Ok(())?, or just ?
+ pending_queries -= 1;
+ min_ttl = cmp::min(min_ttl, response_min_ttl);
+ rrsig_key_names.sort_unstable();
+ rrsig_key_names.dedup();
+ for key_name in rrsig_key_names.drain(..) {
+ if !dnskeys_requested.contains(&key_name) {
+ $send_query(&mut $stream, &key_name, DnsKey::TYPE)
+ $(.await?; $async_ok)??; // Either await?; Ok(())?, or just ?
+ pending_queries += 1;
+ queries_made += 1;
+ dnskeys_requested.push(key_name.clone());
+
+ if key_name.as_str() != "." {
+ $send_query(&mut $stream, &key_name, DS::TYPE)
+ $(.await?; $async_ok)??; // Either await?; Ok(())?, or just ?
+ pending_queries += 1;
+ queries_made += 1;
+ }