about summary refs log blame commit diff
path: root/lisp/dns/client.lisp
blob: 0f355589db13c8276f96e688ae83111047d1d76b (plain) (tree)












































































































































































                                                                             
;; 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.