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 std::{io, net::SocketAddr, sync::Arc};
9
10use quinn::{Connection, Endpoint, ServerConfig};
11use rustls::{server::ServerConfig as TlsServerConfig, version::TLS13, Certificate, PrivateKey};
12
13use crate::{error::ProtoError, udp::UdpSocket};
14
15use super::{
16    quic_config,
17    quic_stream::{self, QuicStream},
18};
19
20/// A DNS-over-QUIC Server, see QuicClientStream for the client counterpart
21pub struct QuicServer {
22    endpoint: Endpoint,
23}
24
25impl QuicServer {
26    /// Construct the new Acceptor with the associated pkcs12 data
27    pub async fn new(
28        name_server: SocketAddr,
29        cert: Vec<Certificate>,
30        key: PrivateKey,
31    ) -> Result<Self, ProtoError> {
32        // setup a new socket for the server to use
33        let socket = <tokio::net::UdpSocket as UdpSocket>::bind(name_server).await?;
34        Self::with_socket(socket, cert, key)
35    }
36
37    /// Construct the new server with an existing socket
38    pub fn with_socket(
39        socket: tokio::net::UdpSocket,
40        cert: Vec<Certificate>,
41        key: PrivateKey,
42    ) -> Result<Self, ProtoError> {
43        let mut config = TlsServerConfig::builder()
44            .with_safe_default_cipher_suites()
45            .with_safe_default_kx_groups()
46            .with_protocol_versions(&[&TLS13])
47            .expect("TLS1.3 not supported")
48            .with_no_client_auth()
49            .with_single_cert(cert, key)?;
50
51        config.alpn_protocols = vec![quic_stream::DOQ_ALPN.to_vec()];
52
53        let mut server_config = ServerConfig::with_crypto(Arc::new(config));
54        server_config.transport = Arc::new(quic_config::transport());
55
56        let socket = socket.into_std()?;
57
58        let endpoint_config = quic_config::endpoint();
59        let endpoint = Endpoint::new(
60            endpoint_config,
61            Some(server_config),
62            socket,
63            Arc::new(quinn::TokioRuntime),
64        )?;
65
66        Ok(Self { endpoint })
67    }
68
69    /// Get the next incoming stream
70    ///
71    /// # Returns
72    ///
73    /// A remote connection that could have many potential bi-directional streams and the remote socket address
74    pub async fn next(&mut self) -> Result<Option<(QuicStreams, SocketAddr)>, ProtoError> {
75        let connecting = match self.endpoint.accept().await {
76            Some(conn) => conn,
77            None => return Ok(None),
78        };
79
80        let remote_addr = connecting.remote_address();
81        let connection = connecting.await?;
82        Ok(Some((QuicStreams { connection }, remote_addr)))
83    }
84
85    /// Returns the address this server is listening on
86    ///
87    /// 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
88    ///   associated port address with this function.
89    pub fn local_addr(&self) -> Result<SocketAddr, io::Error> {
90        self.endpoint.local_addr()
91    }
92}
93
94/// A stream of bi-directional QUIC streams
95pub struct QuicStreams {
96    connection: Connection,
97}
98
99impl QuicStreams {
100    /// Get the next bi directional stream from the client
101    pub async fn next(&mut self) -> Option<Result<QuicStream, ProtoError>> {
102        match self.connection.accept_bi().await {
103            Ok((send_stream, receive_stream)) => {
104                Some(Ok(QuicStream::new(send_stream, receive_stream)))
105            }
106            Err(e) => Some(Err(e.into())),
107        }
108    }
109}