hickory_proto/quic/
quic_server.rs

1// Copyright 2015-2022 Benjamin Fry <benjaminfry@me.com>
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// https://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// https://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8use alloc::sync::Arc;
9use std::{io, net::SocketAddr};
10
11use quinn::crypto::rustls::QuicServerConfig;
12use quinn::{Connection, Endpoint, ServerConfig};
13use rustls::server::ResolvesServerCert;
14use rustls::server::ServerConfig as TlsServerConfig;
15use rustls::version::TLS13;
16
17use crate::{error::ProtoError, rustls::default_provider, udp::UdpSocket};
18
19use super::{
20    quic_config,
21    quic_stream::{self, QuicStream},
22};
23
24/// A DNS-over-QUIC Server, see QuicClientStream for the client counterpart
25pub struct QuicServer {
26    endpoint: Endpoint,
27}
28
29impl QuicServer {
30    /// Construct the new Acceptor with the associated pkcs12 data
31    pub async fn new(
32        name_server: SocketAddr,
33        server_cert_resolver: Arc<dyn ResolvesServerCert>,
34    ) -> Result<Self, ProtoError> {
35        // setup a new socket for the server to use
36        let socket = <tokio::net::UdpSocket as UdpSocket>::bind(name_server).await?;
37        Self::with_socket(socket, server_cert_resolver)
38    }
39
40    /// Construct the new server with an existing socket
41    pub fn with_socket(
42        socket: tokio::net::UdpSocket,
43        server_cert_resolver: Arc<dyn ResolvesServerCert>,
44    ) -> Result<Self, ProtoError> {
45        let mut config = TlsServerConfig::builder_with_provider(Arc::new(default_provider()))
46            .with_protocol_versions(&[&TLS13])
47            .unwrap() // The ring default provider is guaranteed to support TLS 1.3
48            .with_no_client_auth()
49            .with_cert_resolver(server_cert_resolver);
50
51        config.alpn_protocols = vec![quic_stream::DOQ_ALPN.to_vec()];
52
53        let mut server_config =
54            ServerConfig::with_crypto(Arc::new(QuicServerConfig::try_from(config)?));
55        server_config.transport = Arc::new(quic_config::transport());
56
57        let socket = socket.into_std()?;
58
59        let endpoint_config = quic_config::endpoint();
60        let endpoint = Endpoint::new(
61            endpoint_config,
62            Some(server_config),
63            socket,
64            Arc::new(quinn::TokioRuntime),
65        )?;
66
67        Ok(Self { endpoint })
68    }
69
70    /// Get the next incoming stream
71    ///
72    /// # Returns
73    ///
74    /// A remote connection that could have many potential bi-directional streams and the remote socket address
75    pub async fn next(&mut self) -> Result<Option<(QuicStreams, SocketAddr)>, ProtoError> {
76        let connecting = match self.endpoint.accept().await {
77            Some(conn) => conn,
78            None => return Ok(None),
79        };
80
81        let remote_addr = connecting.remote_address();
82        let connection = connecting.await?;
83        Ok(Some((QuicStreams { connection }, remote_addr)))
84    }
85
86    /// Returns the address this server is listening on
87    ///
88    /// This can be useful in tests, where a random port can be associated with the server by binding on `127.0.0.1:0` and then getting the
89    ///   associated port address with this function.
90    pub fn local_addr(&self) -> Result<SocketAddr, io::Error> {
91        self.endpoint.local_addr()
92    }
93}
94
95/// A stream of bi-directional QUIC streams
96pub struct QuicStreams {
97    connection: Connection,
98}
99
100impl QuicStreams {
101    /// Get the next bi directional stream from the client
102    pub async fn next(&mut self) -> Option<Result<QuicStream, ProtoError>> {
103        match self.connection.accept_bi().await {
104            Ok((send_stream, receive_stream)) => {
105                Some(Ok(QuicStream::new(send_stream, receive_stream)))
106            }
107            Err(e) => Some(Err(e.into())),
108        }
109    }
110}