DoQ connections are established as described in the QUIC transport specification [
RFC 9000]. During connection establishment, DoQ support is indicated by selecting the Application-Layer Protocol Negotiation (ALPN) token "doq" in the crypto handshake.
By default, a DNS server that supports DoQ
MUST listen for and accept QUIC connections on the dedicated UDP port 853 (
Section 8), unless there is a mutual agreement to use another port.
By default, a DNS client desiring to use DoQ with a particular server
MUST establish a QUIC connection to UDP port 853 on the server, unless there is a mutual agreement to use another port.
DoQ connections
MUST NOT use UDP port 53. This recommendation against use of port 53 for DoQ is to avoid confusion between DoQ and the use of DNS over UDP [
RFC 1035]. The risk of confusion exists even if two parties agreed on port 53, as other parties without knowledge of that agreement might still try to use that port.
In the stub to recursive scenario, the use of port 443 as a mutually agreed alternative port can be operationally beneficial, since port 443 is used by many services using QUIC and HTTP-3 and is thus less likely to be blocked than other ports. Several mechanisms for stubs to discover recursives offering encrypted transports, including the use of custom ports, are the subject of ongoing work.
The mapping of DNS traffic over QUIC streams takes advantage of the QUIC stream features detailed in
Section 2 of
RFC 9000, the QUIC transport specification.
DNS query/response traffic [
RFC 1034] [
RFC 1035] follows a simple pattern in which the client sends a query, and the server provides one or more responses (multiple responses can occur in zone transfers).
The mapping specified here requires that the client select a separate QUIC stream for each query. The server then uses the same stream to provide all the response messages for that query. In order for multiple responses to be parsed, a 2-octet length field is used in exactly the same way as the 2-octet length field defined for DNS over TCP [
RFC 1035]. The practical result of this is that the content of each QUIC stream is exactly the same as the content of a TCP connection that would manage exactly one query.
All DNS messages (queries and responses) sent over DoQ connections
MUST be encoded as a 2-octet length field followed by the message content as specified in [
RFC 1035].
The client
MUST select the next available client-initiated bidirectional stream for each subsequent query on a QUIC connection, in conformance with the QUIC transport specification [
RFC 9000]. Packet losses and other network events might cause queries to arrive in a different order. Servers
SHOULD process queries as they arrive, as not doing so would cause unnecessary delays.
The client
MUST send the DNS query over the selected stream and
MUST indicate through the STREAM FIN mechanism that no further data will be sent on that stream.
The server
MUST send the response(s) on the same stream and
MUST indicate, after the last response, through the STREAM FIN mechanism that no further data will be sent on that stream.
Therefore, a single DNS transaction consumes a single bidirectional client-initiated stream. This means that the client's first query occurs on QUIC stream 0, the second on 4, and so on (see
Section 2.1 of
RFC 9000).
Servers
MAY defer processing of a query until the STREAM FIN has been indicated on the stream selected by the client.
Servers and clients
MAY monitor the number of "dangling" streams. These are open streams where the following events have not occurred after implementation-defined timeouts:
-
the expected queries or responses have not been received or,
-
the expected queries or responses have been received but not the STREAM FIN
Implementations
MAY impose a limit on the number of such dangling streams. If limits are encountered, implementations
MAY close the connection.
When sending queries over a QUIC connection, the DNS Message ID
MUST be set to 0. The stream mapping for DoQ allows for unambiguous correlation of queries and responses, so the Message ID field is not required.
This has implications for proxying DoQ messages to and from other transports. For example, proxies may have to manage the fact that DoQ can support a larger number of outstanding queries on a single connection than, for example, DNS over TCP, because DoQ is not limited by the Message ID space. This issue already exists for DoH, where a Message ID of 0 is recommended.
When forwarding a DNS message from DoQ over another transport, a DNS Message ID
MUST be generated according to the rules of the protocol that is in use. When forwarding a DNS message from another transport over DoQ, the Message ID
MUST be set to 0.
The following error codes are defined for use when abruptly terminating streams, for use as application protocol error codes when aborting reading of streams, or for immediately closing connections:
-
DOQ_NO_ERROR (0x0):
-
No error. This is used when the connection or stream needs to be closed, but there is no error to signal.
-
DOQ_INTERNAL_ERROR (0x1):
-
The DoQ implementation encountered an internal error and is incapable of pursuing the transaction or the connection.
-
DOQ_PROTOCOL_ERROR (0x2):
-
The DoQ implementation encountered a protocol error and is forcibly aborting the connection.
-
DOQ_REQUEST_CANCELLED (0x3):
-
A DoQ client uses this to signal that it wants to cancel an outstanding transaction.
-
DOQ_EXCESSIVE_LOAD (0x4):
-
A DoQ implementation uses this to signal when closing a connection due to excessive load.
-
DOQ_UNSPECIFIED_ERROR (0x5):
-
A DoQ implementation uses this in the absence of a more specific error code.
-
DOQ_ERROR_RESERVED (0xd098ea5e):
-
An alternative error code used for tests.
See
Section 8.4 for details on registering new error codes.
In QUIC, sending STOP_SENDING requests that a peer cease transmission on a stream. If a DoQ client wishes to cancel an outstanding request, it
MUST issue a QUIC STOP_SENDING, and it
SHOULD use the error code DOQ_REQUEST_CANCELLED. It
MAY use a more specific error code registered according to
Section 8.4. The STOP_SENDING request may be sent at any time but will have no effect if the server response has already been sent, in which case the client will simply discard the incoming response. The corresponding DNS transaction
MUST be abandoned.
Servers that receive STOP_SENDING act in accordance with
Section 3.5 of
RFC 9000. Servers
SHOULD NOT continue processing a DNS transaction if they receive a STOP_SENDING.
Servers
MAY impose implementation limits on the total number or rate of cancellation requests. If limits are encountered, servers
MAY close the connection. In this case, servers wanting to help client debugging
MAY use the error code DOQ_EXCESSIVE_LOAD. There is always a trade-off between helping good faith clients debug issues and allowing denial-of-service attackers to test server defenses; depending on circumstances servers might very well choose to send different error codes.
Note that this mechanism provides a way for secondaries to cancel a single zone transfer occurring on a given stream without having to close the QUIC connection.
Servers
MUST NOT continue processing a DNS transaction if they receive a RESET_STREAM request from the client before the client indicates the STREAM FIN. The server
MUST issue a RESET_STREAM to indicate that the transaction is abandoned unless:
-
it has already done so for another reason or
-
it has already both sent the response and indicated the STREAM FIN.
Servers normally complete transactions by sending a DNS response (or responses) on the transaction's stream, including cases where the DNS response indicates a DNS error. For example, a client
SHOULD be notified of a Server Failure (SERVFAIL, [
RFC 1035]) through a response with the Response Code set to SERVFAIL.
If a server is incapable of sending a DNS response due to an internal error, it
SHOULD issue a QUIC RESET_STREAM frame. The error code
SHOULD be set to DOQ_INTERNAL_ERROR. The corresponding DNS transaction
MUST be abandoned. Clients
MAY limit the number of unsolicited QUIC RESET_STREAM frames received on a connection before choosing to close the connection.
Note that this mechanism provides a way for primaries to abort a single zone transfer occurring on a given stream without having to close the QUIC connection.
Other error scenarios can occur due to malformed, incomplete, or unexpected messages during a transaction. These include (but are not limited to):
-
a client or server receives a message with a non-zero Message ID
-
a client or server receives a STREAM FIN before receiving all the bytes for a message indicated in the 2-octet length field
-
a client receives a STREAM FIN before receiving all the expected responses
-
a server receives more than one query on a stream
-
a client receives a different number of responses on a stream than expected (e.g., multiple responses to a query for an A record)
-
a client receives a STOP_SENDING request
-
the client or server does not indicate the expected STREAM FIN after sending requests or responses (see Section 4.2)
-
an implementation receives a message containing the edns-tcp-keepalive EDNS(0) Option [RFC 7828] (see Section 5.5.2)
-
a client or a server attempts to open a unidirectional QUIC stream
-
a server attempts to open a server-initiated bidirectional QUIC stream
-
a server receives a "replayable" transaction in 0-RTT data (for servers not willing to handle this case, see Section 4.5)
If a peer encounters such an error condition, it is considered a fatal error. It
SHOULD forcibly abort the connection using QUIC's CONNECTION_CLOSE mechanism and
SHOULD use the DoQ error code DOQ_PROTOCOL_ERROR. In some cases, it
MAY instead silently abandon the connection, which uses fewer of the local resources but makes debugging at the offending node more difficult.
It is noted that the restrictions on use of the above EDNS(0) option has implications for proxying messages from TCP/DoT/DoH over DoQ.
This specification describes specific error codes in Sections [
4.3.1], [
4.3.2], and [
4.3.3]. These error codes are meant to facilitate investigation of failures and other incidents. New error codes may be defined in future versions of DoQ or registered as specified in
Section 8.4.
Because new error codes can be defined without negotiation, use of an error code in an unexpected context or receipt of an unknown error code
MUST be treated as equivalent to DOQ_UNSPECIFIED_ERROR.
Implementations
MAY wish to test the support for the error code extension mechanism by using error codes not listed in this document, or they
MAY use DOQ_ERROR_RESERVED.
Section 10 of
RFC 9000, the QUIC transport specification, specifies that connections can be closed in three ways:
-
idle timeout
-
immediate close
-
stateless reset
Clients and servers implementing DoQ
SHOULD negotiate use of the idle timeout. Closing on idle timeout is done without any packet exchange, which minimizes protocol overhead. Per
Section 10.1 of
RFC 9000, the QUIC transport specification, the effective value of the idle timeout is computed as the minimum of the values advertised by the two endpoints. Practical considerations on setting the idle timeout are discussed in
Section 5.5.2.
Clients
SHOULD monitor the idle time incurred on their connection to the server, defined by the time spent since the last packet from the server has been received. When a client prepares to send a new DNS query to the server, it
SHOULD check whether the idle time is sufficiently lower than the idle timer. If it is, the client
SHOULD send the DNS query over the existing connection. If not, the client
SHOULD establish a new connection and send the query over that connection.
Clients
MAY discard their connections to the server before the idle timeout expires. A client that has outstanding queries
SHOULD close the connection explicitly using QUIC's CONNECTION_CLOSE mechanism and the DoQ error code DOQ_NO_ERROR.
Clients and servers
MAY close the connection for a variety of other reasons, indicated using QUIC's CONNECTION_CLOSE. Client and servers that send packets over a connection discarded by their peer might receive a stateless reset indication. If a connection fails, all the in-progress transactions on that connection
MUST be abandoned.
A client
MAY take advantage of the session resumption and 0-RTT mechanisms supported by QUIC transport [
RFC 9000] and QUIC TLS [
RFC 9001] if the server supports them. Clients
SHOULD consider potential privacy issues associated with session resumption before deciding to use this mechanism and specifically evaluate the trade-offs presented in the various sections of this document. The privacy issues are detailed in Sections [
7.1] and [
7.2], and the implementation considerations are discussed in
Section 5.5.3.
The 0-RTT mechanism
MUST NOT be used to send DNS requests that are not "replayable" transactions. In this specification, only transactions that have an OPCODE of QUERY or NOTIFY are considered replayable; therefore, other OPCODES
MUST NOT be sent in 0-RTT data. See
Appendix A for a detailed discussion of why NOTIFY is included here.
Servers
MAY support session resumption, and
MAY do that with or without supporting 0-RTT, using the mechanisms described in
Section 4.6.1 of
RFC 9001. Servers supporting 0-RTT
MUST NOT immediately process non-replayable transactions received in 0-RTT data but instead
MUST adopt one of the following behaviors:
-
Queue the offending transaction and only process it after the QUIC handshake has been completed, as defined in Section 4.1.1 of RFC 9001.
-
Reply to the offending transaction with a response code REFUSED and an Extended DNS Error Code (EDE) "Too Early" using the extended RCODE mechanisms defined in [RFC 6891] and the extended DNS errors defined in [RFC 8914]; see Section 8.3.
-
Close the connection with the error code DOQ_PROTOCOL_ERROR.
DoQ queries and responses are sent on QUIC streams, which in theory can carry up to 2
62 bytes. However, DNS messages are restricted in practice to a maximum size of 65535 bytes. This maximum size is enforced by the use of a 2-octet message length field in DNS over TCP [
RFC 1035] and DoT [
RFC 7858], and by the definition of the "application/dns-message" for DoH [
RFC 8484]. DoQ enforces the same restriction.
The Extension Mechanisms for DNS (EDNS(0)) [
RFC 6891] allow peers to specify the UDP message size. This parameter is ignored by DoQ. DoQ implementations always assume that the maximum message size is 65535 bytes.