Unlike direct resolution, oblivious hostname resolution over DoH involves three parties:
-
The Client, which generates queries.
-
The Proxy, which receives encrypted queries from the Client and passes them on to a Target.
-
The Target, which receives proxied queries from the Client via the Proxy and produces proxied answers.
--- [ Request encrypted with Target public key ] -->
+---------+ +-----------+ +-----------+
| Client +-------------> Oblivious +-------------> Oblivious |
| <-------------+ Proxy <-------------+ Target |
+---------+ +-----------+ +-----------+
<-- [ Response encrypted with symmetric key ] ---
Oblivious DoH queries are created by the Client and are sent to the Proxy as HTTP requests using the POST method. Clients are configured with a Proxy URI Template [
RFC 6570] and the Target URI. The scheme for both the Proxy URI Template and the Target URI
MUST be "https". The Proxy URI Template uses the Level 3 encoding defined in
Section 1.2 of
RFC 6570 and contains two variables: "targethost", which indicates the hostname of the Target server; and "targetpath", which indicates the path on which the Target is accessible. Examples of Proxy URI Templates are shown below:
https://dnsproxy.example/dns-query{?targethost,targetpath}
https://dnsproxy.example/{targethost}/{targetpath}
The URI Template
MUST contain both the "targethost" and "targetpath" variables exactly once and
MUST NOT contain any other variables. The variables
MUST be within the path or query components of the URI. Clients
MUST ignore configurations that do not conform to this template. See
Section 4.2 for an example request.
Oblivious DoH messages have no cache value, since both requests and responses are encrypted using ephemeral key material. Requests and responses
MUST NOT be cached.
Clients
MUST set the HTTP Content-Type header to "application/oblivious-dns-message" to indicate that this request is an Oblivious DoH query intended for proxying. Clients also
SHOULD set this same value for the HTTP Accept header.
A correctly encoded request has the HTTP Content-Type header "application/oblivious-dns-message", uses the HTTP POST method, and contains "targethost" and "targetpath" variables. If the Proxy fails to match the "targethost" and "targetpath" variables from the path, it
MUST treat the request as malformed. The Proxy constructs the URI of the Target with the "https" scheme, using the value of "targethost" as the URI host and the percent-decoded value of "targetpath" as the URI path. Proxies
MUST check that Client requests are correctly encoded and
MUST return a 4xx (Client Error) if the check fails, along with the Proxy-Status response header with an "error" parameter of type "http_request_error" [
RFC 9209].
Proxies
MAY choose to not forward connections to non-standard ports. In such cases, Proxies can indicate the error with a 403 response status code, along with a Proxy-Status response header with an "error" parameter of type "http_request_denied" and with an appropriate explanation in "details".
If the Proxy cannot establish a connection to the Target, it can indicate the error with a 502 response status code, along with a Proxy-Status response header with an "error" parameter whose type indicates the reason. For example, if DNS resolution fails, the error type might be "dns_timeout", whereas if the TLS connection fails, the error type might be "tls_protocol_error".
Upon receipt of requests from a Proxy, Targets
MUST validate that the request has the HTTP Content-Type header "application/oblivious-dns-message" and uses the HTTP POST method. Targets can respond with a 4xx response status code if this check fails.
The following example shows how a Client requests that a Proxy, "dnsproxy.example", forward an encrypted message to "dnstarget.example". The URI Template for the Proxy is "https://dnsproxy.example/dns-query{?targethost,targetpath}". The URI for the Target is "https://dnstarget.example/dns-query".
:method = POST
:scheme = https
:authority = dnsproxy.example
:path = /dns-query?targethost=dnstarget.example&targetpath=/dns-query
accept = application/oblivious-dns-message
content-type = application/oblivious-dns-message
content-length = 106
<Bytes containing an encrypted Oblivious DNS query>
The Proxy then sends the following request on to the Target:
:method = POST
:scheme = https
:authority = dnstarget.example
:path = /dns-query
accept = application/oblivious-dns-message
content-type = application/oblivious-dns-message
content-length = 106
<Bytes containing an encrypted Oblivious DNS query>
The response to an Oblivious DoH query is generated by the Target. It
MUST set the Content-Type HTTP header to "application/oblivious-dns-message" for all successful responses. The body of the response contains an encrypted DNS message; see
Section 6.
The response from a Target
MUST set the Content-Type HTTP header to "application/oblivious-dns-message", and that same type
MUST be used on all successful responses sent by the Proxy to the Client. A Client
MUST only consider a response that contains the Content-Type header before processing the payload. A response without the appropriate header
MUST be treated as an error and be handled appropriately. All other aspects of the HTTP response and error handling are inherited from standard DoH.
Proxies forward responses from the Target to the Client, without any modifications to the body or status code. The Proxy also
SHOULD add a Proxy-Status response header with a "received-status" parameter indicating that the status code was generated by the Target.
Note that if a Client receives a 3xx status code and chooses to follow a redirect, the subsequent request
MUST also be performed through a Proxy in order to avoid directly exposing requests to the Target.
Requests that cannot be processed by the Target result in 4xx (Client Error) responses. If the Target and Client keys do not match, it is an authorization failure (HTTP status code 401; see
Section 15.5.2 of [
HTTP]). Otherwise, if the Client's request is invalid, such as in the case of decryption failure, wrong message type, or deserialization failure, this is a bad request (HTTP status code 400; see
Section 15.5.1 of [
HTTP]).
Even in the case of DNS responses indicating failure, such as SERVFAIL or NXDOMAIN, a successful HTTP response with a 2xx status code is used as long as the DNS response is valid. This is identical to how DoH [
RFC 8484] handles HTTP response codes.
The following example shows a 2xx (Successful) response that can be sent from a Target to a Client via a Proxy.
:status = 200
content-type = application/oblivious-dns-message
content-length = 154
<Bytes containing an encrypted Oblivious DNS response>
Proxies forward requests and responses between Clients and Targets as specified in
Section 4.1. Metadata sent with these messages could inadvertently weaken or remove Oblivious DoH privacy properties. Proxies
MUST NOT send any Client-identifying information about Clients to Targets, such as "Forwarded" HTTP headers [
RFC 7239]. Additionally, Clients
MUST NOT include any private state in requests to Proxies, such as HTTP cookies. See
Section 11.3 for related discussion about Client authentication information.