-async fn build_proof_async(resolver: SocketAddr, domain: Name, ty: u16) -> Result<Vec<u8>, Error> {
- let mut stream = TokioTcpStream::connect(resolver).await?;
- let mut res = Vec::new();
- send_query_async(&mut stream, domain, ty).await?;
- let mut reached_root = false;
- for _ in 0..10 {
- let rrsig_opt = read_response_async(&mut stream, &mut res).await?;
- if let Some(rrsig) = rrsig_opt {
- if rrsig.name.as_str() == "." {
- reached_root = true;
- } else {
- if rrsig.name == rrsig.key_name {
- send_query_async(&mut stream, rrsig.key_name, DS::TYPE).await?;
- } else {
- send_query_async(&mut stream, rrsig.key_name, DnsKey::TYPE).await?;
- }
+async fn send_query_async(stream: &mut TokioTcpStream, query: &[u8]) -> Result<(), Error> {
+ stream.write_all(&query).await?;
+ Ok(())
+}
+
+type MsgBuf = [u8; u16::MAX as usize];
+
+fn read_response(stream: &mut TcpStream, response_buf: &mut MsgBuf) -> Result<u16, Error> {
+ let mut len_bytes = [0; 2];
+ stream.read_exact(&mut len_bytes)?;
+ let len = u16::from_be_bytes(len_bytes);
+ stream.read_exact(&mut response_buf[..len as usize])?;
+ Ok(len)
+}
+
+#[cfg(feature = "tokio")]
+async fn read_response_async(stream: &mut TokioTcpStream, response_buf: &mut MsgBuf) -> Result<u16, Error> {
+ let mut len_bytes = [0; 2];
+ stream.read_exact(&mut len_bytes).await?;
+ let len = u16::from_be_bytes(len_bytes);
+ stream.read_exact(&mut response_buf[..len as usize]).await?;
+ Ok(len)
+}
+
+macro_rules! build_proof_impl {
+ ($stream: ident, $send_query: ident, $read_response: ident, $domain: expr, $ty: expr $(, $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 builder, initial_query) = ProofBuilder::new($domain, $ty);
+ $send_query(&mut $stream, &initial_query)
+ $(.await?; $async_ok)??; // Either await?; Ok(())?, or just ?
+ let mut response_buf = [0; u16::MAX as usize];
+ while builder.awaiting_responses() {
+ let response_len = $read_response(&mut $stream, &mut response_buf)
+ $(.await?; $async_ok)??; // Either await?; Ok(())?, or just ?
+ let new_queries = builder.process_response(&response_buf[..response_len as usize])
+ .map_err(|()| Error::new(ErrorKind::Other, "Bad response"))?;
+ for query in new_queries {
+ $send_query(&mut $stream, &query)
+ $(.await?; $async_ok)??; // Either await?; Ok(())?, or just ?