;; Implementation of a DoH-client, see RFC 8484 (DNS Queries over ;; HTTPS (DoH)) (in-package #:dns) ;; The DoH client is configured with a URI Template [RFC6570] (defvar *doh-base-url* "https://dns.google/dns-query" "Base URL of the service providing DNS-over-HTTP(S). Defaults to the Google-hosted API.") (defun lookup-generic (name type) (multiple-value-bind (stream) (drakma:http-request *doh-base-url* :decode-content t :want-stream t :parameters `(("type" . ,type) ("name" . ,name) ("ct" . "application/dns-message"))) (read-binary 'dns-message stream))) (defun lookup-txt (name) "Look up the TXT records at NAME." (lookup-generic name "TXT")) (defun lookup-mx (name) "Look up the MX records at NAME." (lookup-generic name "MX")) ;; The URI Template defined in this document is processed without any ;; variables when the HTTP method is POST. When the HTTP method is GET, ;; the single variable "dns" is defined as the content of the DNS ;; request (as described in Section 6), encoded with base64url ;; [RFC4648]. ;; When using the POST method, the DNS query is included as the message ;; body of the HTTP request, and the Content-Type request header field ;; indicates the media type of the message. POSTed requests are ;; generally smaller than their GET equivalents. ;; Using the GET method is friendlier to many HTTP cache ;; implementations. ;; The DoH client SHOULD include an HTTP Accept request header field to ;; indicate what type of content can be understood in response. ;; Irrespective of the value of the Accept request header field, the ;; client MUST be prepared to process "application/dns-message" (as ;; described in Section 6) responses but MAY also process other DNS- ;; related media types it receives. ;; In order to maximize HTTP cache friendliness, DoH clients using media ;; formats that include the ID field from the DNS message header, such ;; as "application/dns-message", SHOULD use a DNS ID of 0 in every DNS ;; request. HTTP correlates the request and response, thus eliminating ;; the need for the ID in a media type such as "application/dns- ;; message". The use of a varying DNS ID can cause semantically ;; equivalent DNS queries to be cached separately. ;; DoH clients can use HTTP/2 padding and compression [RFC7540] in the ;; same way that other HTTP/2 clients use (or don't use) them. ;; 4.1.1. HTTP Request Examples ;; These examples use HTTP/2-style formatting from [RFC7540]. ;; These examples use a DoH service with a URI Template of ;; "https://dnsserver.example.net/dns-query{?dns}" to resolve IN A ;; records. ;; The requests are represented as bodies with media type "application/ ;; dns-message". ;; The first example request uses GET to request "www.example.com". ;; :method = GET ;; :scheme = https ;; :authority = dnsserver.example.net ;; :path = /dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB ;; accept = application/dns-message ;; Finally, a GET-based query for "a.62characterlabel-makes-base64url- ;; distinct-from-standard-base64.example.com" is shown as an example to ;; emphasize that the encoding alphabet of base64url is different than ;; regular base64 and that padding is omitted. ;; The only response type defined in this document is "application/dns- ;; message", but it is possible that other response formats will be ;; defined in the future. A DoH server MUST be able to process ;; "application/dns-message" request messages. ;; Each DNS request-response pair is mapped to one HTTP exchange. ;; DNS response codes indicate either success or failure for the DNS ;; query. A successful HTTP response with a 2xx status code (see ;; Section 6.3 of [RFC7231]) is used for any valid DNS response, ;; HTTP responses with non-successful HTTP status codes do not contain ;; replies to the original DNS question in the HTTP request. DoH ;; clients need to use the same semantic processing of non-successful ;; HTTP status codes as other HTTP clients. ;; 4.2.2. HTTP Response Example ;; This is an example response for a query for the IN AAAA records for ;; "www.example.com" with recursion turned on. The response bears one ;; answer record with an address of 2001:db8:abcd:12:1:2:3:4 and a TTL ;; of 3709 seconds. ;; :status = 200 ;; content-type = application/dns-message ;; content-length = 61 ;; cache-control = max-age=3709 ;; <61 bytes represented by the following hex encoding> ;; 00 00 81 80 00 01 00 01 00 00 00 00 03 77 77 77 ;; 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 1c 00 ;; 01 c0 0c 00 1c 00 01 00 00 0e 7d 00 10 20 01 0d ;; b8 ab cd 00 12 00 01 00 02 00 03 00 04 ;; This protocol MUST be used with the https URI scheme [RFC7230]. ;; In particular, DoH servers SHOULD assign an explicit HTTP freshness ;; lifetime (see Section 4.2 of [RFC7234]) so that the DoH client is ;; more likely to use fresh DNS data. This requirement is due to HTTP ;; caches being able to assign their own heuristic freshness (such as ;; that described in Section 4.2.2 of [RFC7234]), which would take ;; control of the cache contents out of the hands of the DoH server. ;; The assigned freshness lifetime of a DoH HTTP response MUST be less ;; than or equal to the smallest TTL in the Answer section of the DNS ;; response. A freshness lifetime equal to the smallest TTL in the ;; Answer section is RECOMMENDED. For example, if a HTTP response ;; carries three RRsets with TTLs of 30, 600, and 300, the HTTP ;; freshness lifetime should be 30 seconds (which could be specified as ;; "Cache-Control: max-age=30"). This requirement helps prevent expired ;; RRsets in messages in an HTTP cache from unintentionally being ;; served. ;; If the DNS response has no records in the Answer section, and the DNS ;; response has an SOA record in the Authority section, the response ;; freshness lifetime MUST NOT be greater than the MINIMUM field from ;; that SOA record (see [RFC2308]). ;; DoH clients MUST account for the Age response header field's value ;; [RFC7234] when calculating the DNS TTL of a response. For example, ;; if an RRset is received with a DNS TTL of 600, but the Age header ;; field indicates that the response has been cached for 250 seconds, ;; the remaining lifetime of the RRset is 350 seconds. This requirement ;; applies to both DoH client HTTP caches and DoH client DNS caches. ;; Those features were introduced to HTTP in HTTP/2 [RFC7540]. ;; Earlier versions of HTTP are capable of conveying the semantic ;; requirements of DoH but may result in very poor performance. ;; In order to maximize interoperability, DoH clients and DoH servers ;; MUST support the "application/dns-message" media type. ;; The data payload for the "application/dns-message" media type is a ;; single message of the DNS on-the-wire format defined in Section 4.2.1 ;; of [RFC1035], which in turn refers to the full wire format defined in ;; Section 4.1 of that RFC. ;; This media type restricts the maximum size of the DNS message to ;; 65535 bytes. ;; When using the GET method, the data payload for this media type MUST ;; be encoded with base64url [RFC4648] and then provided as a variable ;; named "dns" to the URI Template expansion. Padding characters for ;; base64url MUST NOT be included. ;; When using the POST method, the data payload for this media type MUST ;; NOT be encoded and is used directly as the HTTP message body.