1use core::fmt::Debug;
11use core::future::Future;
12use core::net::SocketAddr;
13use core::pin::Pin;
14use core::str::FromStr;
15use core::task::{Context, Poll};
16use std::io;
17use std::sync::Arc;
18
19use bytes::{Buf, Bytes, BytesMut};
20use futures_util::stream::{Stream, StreamExt};
21use h2::client::SendRequest;
22use http::header::{self, CONTENT_LENGTH};
23use http::{Method, Request};
24use rustls::ClientConfig;
25use rustls::pki_types::ServerName;
26use tokio::time::timeout;
27use tokio_rustls::TlsConnector;
28use tracing::{debug, warn};
29
30use crate::error::NetError;
31use crate::http::{RequestContext, SetHeaders, Version};
32use crate::proto::op::{DnsRequest, DnsResponse};
33use crate::runtime::iocompat::AsyncIoStdAsTokio;
34use crate::runtime::{DnsTcpStream, RuntimeProvider, Spawn};
35use crate::xfer::{CONNECT_TIMEOUT, DnsExchange, DnsRequestSender, DnsResponseStream};
36
37#[derive(Clone)]
39#[must_use = "futures do nothing unless polled"]
40pub struct HttpsClientStream {
41 context: Arc<RequestContext>,
42 h2: SendRequest<Bytes>,
43 is_shutdown: bool,
44}
45
46impl HttpsClientStream {
47 pub fn builder<P: RuntimeProvider>(
49 client_config: Arc<ClientConfig>,
50 provider: P,
51 ) -> HttpsClientStreamBuilder<P> {
52 HttpsClientStreamBuilder {
53 provider,
54 client_config,
55 bind_addr: None,
56 set_headers: None,
57 }
58 }
59}
60
61impl DnsRequestSender for HttpsClientStream {
62 fn send_message(&mut self, mut request: DnsRequest) -> DnsResponseStream {
114 if self.is_shutdown {
115 panic!("can not send messages after stream is shutdown")
116 }
117
118 request.metadata.id = 0;
120
121 let bytes = match request.to_vec() {
122 Ok(bytes) => bytes,
123 Err(err) => return NetError::from(err).into(),
124 };
125
126 Box::pin(send(
127 self.h2.clone(),
128 Bytes::from(bytes),
129 self.context.clone(),
130 ))
131 .into()
132 }
133
134 fn shutdown(&mut self) {
135 self.is_shutdown = true;
136 }
137
138 fn is_shutdown(&self) -> bool {
139 self.is_shutdown
140 }
141}
142
143impl Stream for HttpsClientStream {
144 type Item = Result<(), NetError>;
145
146 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
147 if self.is_shutdown {
148 return Poll::Ready(None);
149 }
150
151 match self.h2.poll_ready(cx) {
153 Poll::Ready(Ok(())) => Poll::Ready(Some(Ok(()))),
154 Poll::Pending => Poll::Pending,
155 Poll::Ready(Err(e)) => Poll::Ready(Some(Err(NetError::from(format!(
156 "h2 stream errored: {e}",
157 ))))),
158 }
159 }
160}
161
162#[derive(Clone)]
164pub struct HttpsClientStreamBuilder<P> {
165 provider: P,
166 client_config: Arc<ClientConfig>,
167 bind_addr: Option<SocketAddr>,
168 set_headers: Option<Arc<dyn SetHeaders>>,
169}
170
171impl<P: RuntimeProvider> HttpsClientStreamBuilder<P> {
172 pub fn bind_addr(&mut self, bind_addr: SocketAddr) {
174 self.bind_addr = Some(bind_addr);
175 }
176
177 pub fn set_headers(&mut self, headers: Arc<dyn SetHeaders>) {
179 self.set_headers.replace(headers);
180 }
181
182 pub async fn exchange(
184 self,
185 name_server: SocketAddr,
186 server_name: Arc<str>,
187 path: Arc<str>,
188 ) -> Result<DnsExchange<P>, NetError> {
189 let mut handle = self.provider.create_handle();
190 let stream = self.build(name_server, server_name, path).await?;
191 let (exchange, bg) = DnsExchange::from_stream(stream);
192 handle.spawn_bg(bg);
193 Ok(exchange)
194 }
195
196 pub fn build(
204 self,
205 name_server: SocketAddr,
206 server_name: Arc<str>,
207 path: Arc<str>,
208 ) -> impl Future<Output = Result<HttpsClientStream, NetError>> + Send + 'static {
209 connect(
210 self.provider.connect_tcp(name_server, self.bind_addr, None),
211 self.client_config,
212 name_server,
213 server_name,
214 path,
215 self.set_headers,
216 )
217 }
218}
219
220pub fn connect(
222 tcp: impl Future<Output = Result<impl DnsTcpStream, io::Error>> + Send + 'static,
223 mut client_config: Arc<ClientConfig>,
224 name_server: SocketAddr,
225 server_name: Arc<str>,
226 query_path: Arc<str>,
227 set_headers: Option<Arc<dyn SetHeaders>>,
228) -> impl Future<Output = Result<HttpsClientStream, NetError>> + Send + 'static {
229 if client_config.alpn_protocols.is_empty() {
231 let mut client_cfg = (*client_config).clone();
232 client_cfg.alpn_protocols = vec![ALPN_H2.to_vec()];
233
234 client_config = Arc::new(client_cfg);
235 }
236
237 let context = Arc::new(RequestContext {
238 version: Version::Http2,
239 server_name,
240 query_path,
241 set_headers,
242 });
243
244 async move {
245 let tls_server_name = match ServerName::try_from(&*context.server_name) {
246 Ok(dns_name) => dns_name.to_owned(),
247 Err(err) => {
248 return Err(NetError::from(format!(
249 "bad server name {:?}: {err}",
250 context.server_name
251 )));
252 }
253 };
254
255 let tcp = tcp.await?;
256 let future = timeout(
257 CONNECT_TIMEOUT,
258 TlsConnector::from(client_config).connect(tls_server_name, AsyncIoStdAsTokio(tcp)),
259 );
260
261 let tls = match future.await {
262 Ok(Ok(tls)) => tls,
263 Ok(Err(err)) => return Err(NetError::from(err)),
264 Err(_) => return Err(NetError::Timeout),
265 };
266
267 let mut handshake = h2::client::Builder::new();
268 handshake.enable_push(false);
269 let (h2, driver) = handshake.handshake(tls).await?;
270
271 debug!("h2 connection established to: {name_server}");
272 tokio::spawn(async {
273 if let Err(e) = driver.await {
274 warn!("h2 connection failed: {e}");
275 }
276 });
277
278 Ok(HttpsClientStream {
279 h2,
280 context,
281 is_shutdown: false,
282 })
283 }
284}
285
286async fn send(
287 h2: SendRequest<Bytes>,
288 message: Bytes,
289 cx: Arc<RequestContext>,
290) -> Result<DnsResponse, NetError> {
291 let mut h2 = match h2.ready().await {
292 Ok(h2) => h2,
293 Err(err) => {
294 return Err(NetError::from(format!("h2 send_request error: {err}")));
296 }
297 };
298
299 let request = cx
301 .build(message.remaining())
302 .map_err(|err| NetError::from(format!("bad http request: {err}")))?;
303
304 debug!("request: {:#?}", request);
305
306 let (response_future, mut send_stream) = h2
308 .send_request(request, false)
309 .map_err(|err| NetError::from(format!("h2 send_request error: {err}")))?;
310
311 send_stream
312 .send_data(message, true)
313 .map_err(|e| NetError::from(format!("h2 send_data error: {e}")))?;
314
315 let mut response_stream = response_future
316 .await
317 .map_err(|err| NetError::from(format!("received a stream error: {err}")))?;
318
319 debug!("got response: {:#?}", response_stream);
320
321 let content_length = response_stream
323 .headers()
324 .get(CONTENT_LENGTH)
325 .map(|v| v.to_str())
326 .transpose()
327 .map_err(|e| NetError::from(format!("bad headers received: {e}")))?
328 .map(usize::from_str)
329 .transpose()
330 .map_err(|e| NetError::from(format!("bad headers received: {e}")))?;
331
332 let mut response_bytes =
336 BytesMut::with_capacity(content_length.unwrap_or(512).clamp(512, 4_096));
337
338 while let Some(partial_bytes) = response_stream.body_mut().data().await {
339 let partial_bytes =
340 partial_bytes.map_err(|e| NetError::from(format!("bad http request: {e}")))?;
341
342 debug!("got bytes: {}", partial_bytes.len());
343 response_bytes.extend(partial_bytes);
344
345 if let Some(content_length) = content_length {
347 if response_bytes.len() >= content_length {
348 break;
349 }
350 }
351 }
352
353 if let Some(content_length) = content_length {
355 if response_bytes.len() != content_length {
356 return Err(NetError::from(format!(
358 "expected byte length: {}, got: {}",
359 content_length,
360 response_bytes.len()
361 )));
362 }
363 }
364
365 if !response_stream.status().is_success() {
367 let error_string = String::from_utf8_lossy(response_bytes.as_ref());
368
369 return Err(NetError::from(format!(
371 "http unsuccessful code: {}, message: {}",
372 response_stream.status(),
373 error_string
374 )));
375 } else {
376 {
378 let content_type = response_stream
380 .headers()
381 .get(header::CONTENT_TYPE)
382 .map(|h| {
383 h.to_str().map_err(|err| {
384 NetError::from(format!("ContentType header not a string: {err}"))
386 })
387 })
388 .unwrap_or(Ok(crate::http::MIME_APPLICATION_DNS))?;
389
390 if content_type != crate::http::MIME_APPLICATION_DNS {
391 return Err(NetError::from(format!(
392 "ContentType unsupported (must be '{}'): '{}'",
393 crate::http::MIME_APPLICATION_DNS,
394 content_type
395 )));
396 }
397 }
398 };
399
400 DnsResponse::from_buffer(response_bytes.to_vec()).map_err(NetError::from)
402}
403
404pub async fn message_from<R>(
409 this_server_name: Option<Arc<str>>,
410 this_server_endpoint: Arc<str>,
411 request: Request<R>,
412) -> Result<BytesMut, NetError>
413where
414 R: Stream<Item = Result<Bytes, h2::Error>> + 'static + Send + Debug + Unpin,
415{
416 debug!("Received request: {:#?}", request);
417
418 let this_server_name = this_server_name.as_deref();
419 match crate::http::verify(
420 Version::Http2,
421 this_server_name,
422 &this_server_endpoint,
423 &request,
424 ) {
425 Ok(_) => (),
426 Err(err) => return Err(err),
427 }
428
429 let mut content_length = None;
431 if let Some(length) = request.headers().get(CONTENT_LENGTH) {
432 let length = usize::from_str(length.to_str()?)?;
433 debug!("got message length: {}", length);
434 content_length = Some(length);
435 }
436
437 match *request.method() {
438 Method::GET => Err(format!("GET unimplemented: {}", request.method()).into()),
439 Method::POST => message_from_post(request.into_body(), content_length).await,
440 _ => Err(format!("bad method: {}", request.method()).into()),
441 }
442}
443
444pub(crate) async fn message_from_post<R>(
446 mut request_stream: R,
447 length: Option<usize>,
448) -> Result<BytesMut, NetError>
449where
450 R: Stream<Item = Result<Bytes, h2::Error>> + 'static + Send + Debug + Unpin,
451{
452 let mut bytes = BytesMut::with_capacity(length.unwrap_or(0).clamp(512, 4_096));
453
454 loop {
455 match request_stream.next().await {
456 Some(Ok(mut frame)) => bytes.extend_from_slice(&frame.split_off(0)),
457 Some(Err(err)) => return Err(err.into()),
458 None => {
459 return if let Some(length) = length {
460 if bytes.len() == length {
462 Ok(bytes)
463 } else {
464 Err("not all bytes received".into())
465 }
466 } else {
467 Ok(bytes)
468 };
469 }
470 };
471
472 if let Some(length) = length {
473 if bytes.len() == length {
475 return Ok(bytes);
476 }
477 }
478 }
479}
480
481const ALPN_H2: &[u8] = b"h2";
482
483#[cfg(test)]
484mod tests {
485 use core::net::SocketAddr;
486
487 use rustls::KeyLogFile;
488 use test_support::subscribe;
489
490 use super::*;
491 use crate::proto::op::{DnsRequestOptions, Edns, Message, Query};
492 use crate::proto::rr::{Name, RData, RecordType};
493 use crate::runtime::TokioRuntimeProvider;
494 use crate::tls::client_config;
495 use crate::xfer::FirstAnswer;
496
497 #[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
498 #[tokio::test]
499 async fn test_https_google() {
500 subscribe();
501
502 let google = SocketAddr::from(([8, 8, 8, 8], 443));
503 let mut request = Message::query();
504 let query = Query::query(Name::from_str("www.example.com.").unwrap(), RecordType::A);
505 request.add_query(query);
506 request.metadata.recursion_desired = true;
507 let mut edns = Edns::new();
508 edns.set_version(0);
509 edns.set_max_payload(1232);
510 request.edns = Some(edns);
511
512 let request = DnsRequest::new(request, DnsRequestOptions::default());
513
514 let mut client_config = client_config_h2();
515 client_config.key_log = Arc::new(KeyLogFile::new());
516
517 let provider = TokioRuntimeProvider::new();
518 let https_builder = HttpsClientStream::builder(Arc::new(client_config), provider);
519 let connect = https_builder.build(google, Arc::from("dns.google"), Arc::from("/dns-query"));
520
521 let mut https = connect.await.expect("https connect failed");
522
523 let response = https
524 .send_message(request)
525 .first_answer()
526 .await
527 .expect("send_message failed");
528
529 assert!(
530 response
531 .answers
532 .iter()
533 .any(|record| matches!(record.data, RData::A(_)))
534 );
535
536 let mut request = Message::query();
539 let query = Query::query(
540 Name::from_str("www.example.com.").unwrap(),
541 RecordType::AAAA,
542 );
543 request.add_query(query);
544 request.metadata.recursion_desired = true;
545 let mut edns = Edns::new();
546 edns.set_version(0);
547 edns.set_max_payload(1232);
548 request.edns = Some(edns);
549
550 let request = DnsRequest::new(request, DnsRequestOptions::default());
551
552 let response = https
553 .send_message(request.clone())
554 .first_answer()
555 .await
556 .expect("send_message failed");
557
558 assert!(
559 response
560 .answers
561 .iter()
562 .any(|record| matches!(record.data, RData::AAAA(_)))
563 );
564 }
565
566 #[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
567 #[tokio::test]
568 async fn test_https_google_with_pure_ip_address_server() {
569 subscribe();
570
571 let google = SocketAddr::from(([8, 8, 8, 8], 443));
572 let mut request = Message::query();
573 let query = Query::query(Name::from_str("www.example.com.").unwrap(), RecordType::A);
574 request.add_query(query);
575 request.metadata.recursion_desired = true;
576 let mut edns = Edns::new();
577 edns.set_version(0);
578 edns.set_max_payload(1232);
579 request.edns = Some(edns);
580
581 let request = DnsRequest::new(request, DnsRequestOptions::default());
582
583 let mut client_config = client_config_h2();
584 client_config.key_log = Arc::new(KeyLogFile::new());
585
586 let provider = TokioRuntimeProvider::new();
587 let https_builder = HttpsClientStream::builder(Arc::new(client_config), provider);
588 let connect = https_builder.build(
589 google,
590 Arc::from(google.ip().to_string()),
591 Arc::from("/dns-query"),
592 );
593
594 let mut https = connect.await.expect("https connect failed");
595
596 let response = https
597 .send_message(request)
598 .first_answer()
599 .await
600 .expect("send_message failed");
601
602 assert!(
603 response
604 .answers
605 .iter()
606 .any(|record| matches!(record.data, RData::A(_)))
607 );
608
609 let mut request = Message::query();
612 let query = Query::query(
613 Name::from_str("www.example.com.").unwrap(),
614 RecordType::AAAA,
615 );
616 request.add_query(query);
617 request.metadata.recursion_desired = true;
618 let mut edns = Edns::new();
619 edns.set_version(0);
620 edns.set_max_payload(1232);
621 request.edns = Some(edns);
622
623 let request = DnsRequest::new(request, DnsRequestOptions::default());
624
625 let response = https
626 .send_message(request.clone())
627 .first_answer()
628 .await
629 .expect("send_message failed");
630
631 assert!(
632 response
633 .answers
634 .iter()
635 .any(|record| matches!(record.data, RData::AAAA(_)))
636 );
637 }
638
639 #[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
640 #[tokio::test]
641 #[ignore = "cloudflare has been unreliable as a public test service"]
642 async fn test_https_cloudflare() {
643 subscribe();
644
645 let cloudflare = SocketAddr::from(([1, 1, 1, 1], 443));
646 let mut request = Message::query();
647 let query = Query::query(Name::from_str("www.example.com.").unwrap(), RecordType::A);
648 request.add_query(query);
649 request.metadata.recursion_desired = true;
650 let mut edns = Edns::new();
651 edns.set_version(0);
652 edns.set_max_payload(1232);
653 request.edns = Some(edns);
654
655 let request = DnsRequest::new(request, DnsRequestOptions::default());
656
657 let client_config = client_config_h2();
658 let provider = TokioRuntimeProvider::new();
659 let https_builder = HttpsClientStream::builder(Arc::new(client_config), provider);
660 let connect = https_builder.build(
661 cloudflare,
662 Arc::from("cloudflare-dns.com"),
663 Arc::from("/dns-query"),
664 );
665
666 let mut https = connect.await.expect("https connect failed");
667
668 let response = https
669 .send_message(request)
670 .first_answer()
671 .await
672 .expect("send_message failed");
673
674 assert!(
675 response
676 .answers
677 .iter()
678 .any(|record| matches!(record.data, RData::A(_)))
679 );
680
681 let mut request = Message::query();
684 let query = Query::query(
685 Name::from_str("www.example.com.").unwrap(),
686 RecordType::AAAA,
687 );
688 request.add_query(query);
689 request.metadata.recursion_desired = true;
690 let mut edns = Edns::new();
691 edns.set_version(0);
692 edns.set_max_payload(1232);
693 request.edns = Some(edns);
694
695 let request = DnsRequest::new(request, DnsRequestOptions::default());
696
697 let response = https
698 .send_message(request)
699 .first_answer()
700 .await
701 .expect("send_message failed");
702
703 assert!(
704 response
705 .answers
706 .iter()
707 .any(|record| matches!(record.data, RData::AAAA(_)))
708 );
709 }
710
711 fn client_config_h2() -> ClientConfig {
712 let mut config = client_config().unwrap();
713 config.alpn_protocols = vec![ALPN_H2.to_vec()];
714 config
715 }
716
717 #[tokio::test]
718 async fn test_from_post() {
719 subscribe();
720 let message = Message::query();
721 let msg_bytes = message.to_vec().unwrap();
722 let len = msg_bytes.len();
723 let stream = TestBytesStream(vec![Ok(Bytes::from(msg_bytes))]);
724 let cx = RequestContext {
725 version: Version::Http2,
726 server_name: Arc::from("ns.example.com"),
727 query_path: Arc::from("/dns-query"),
728 set_headers: None,
729 };
730
731 let request = cx.build(len).unwrap();
732 let request = request.map(|()| stream);
733
734 let bytes = message_from(
735 Some(Arc::from("ns.example.com")),
736 "/dns-query".into(),
737 request,
738 )
739 .await
740 .unwrap();
741
742 let msg_from_post = Message::from_vec(bytes.as_ref()).expect("bytes failed");
743 assert_eq!(message, msg_from_post);
744 }
745
746 #[derive(Debug)]
747 struct TestBytesStream(Vec<Result<Bytes, h2::Error>>);
748
749 impl Stream for TestBytesStream {
750 type Item = Result<Bytes, h2::Error>;
751
752 fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
753 match self.0.pop() {
754 Some(Ok(bytes)) => Poll::Ready(Some(Ok(bytes))),
755 Some(Err(err)) => Poll::Ready(Some(Err(err))),
756 None => Poll::Ready(None),
757 }
758 }
759 }
760}