refactor(lisp/dns): Split package into multiple files
Adds a package definition file and moves the current client into client.lisp Note that the client is not working at all at this commit as this is a work-in-progress snapshot.
This commit is contained in:
parent
29e1de2fd2
commit
09621f5371
4 changed files with 182 additions and 31 deletions
173
lisp/dns/client.lisp
Normal file
173
lisp/dns/client.lisp
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
;; 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.
|
|
@ -4,12 +4,15 @@ pkgs.nix.buildLisp.library {
|
||||||
name = "dns";
|
name = "dns";
|
||||||
|
|
||||||
deps = with pkgs.third_party.lisp; [
|
deps = with pkgs.third_party.lisp; [
|
||||||
|
drakma
|
||||||
|
lisp-binary
|
||||||
|
iterate
|
||||||
alexandria
|
alexandria
|
||||||
cl-json
|
cl-json
|
||||||
drakma
|
|
||||||
];
|
];
|
||||||
|
|
||||||
srcs = [
|
srcs = [
|
||||||
./resolver.lisp
|
./package.lisp
|
||||||
|
./client.lisp
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
4
lisp/dns/package.lisp
Normal file
4
lisp/dns/package.lisp
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
(defpackage #:dns
|
||||||
|
(:documentation "Simple DNS resolver in Common Lisp")
|
||||||
|
(:use #:cl #:iterate #:lisp-binary)
|
||||||
|
(:export #:lookup-txt #:lookup-mx))
|
|
@ -1,29 +0,0 @@
|
||||||
;; Initial implementation is a simple client for
|
|
||||||
;; https://developers.google.com/speed/public-dns/docs/doh/json
|
|
||||||
|
|
||||||
(defpackage #:dns
|
|
||||||
(:documentation "Simple DNS resolver in Common Lisp")
|
|
||||||
(:use #:cl)
|
|
||||||
(:export #:lookup-txt #:lookup-mx))
|
|
||||||
|
|
||||||
(defvar *doh-base-url* "https://dns.google/resolve"
|
|
||||||
"Base URL of the service providing DNS-over-HTTP(S). Defaults to the
|
|
||||||
Google-hosted API.")
|
|
||||||
|
|
||||||
(defun lookup-generic (name type)
|
|
||||||
(multiple-value-bind (body)
|
|
||||||
(drakma:http-request *doh-base-url*
|
|
||||||
:decode-content t
|
|
||||||
:want-stream t
|
|
||||||
:parameters `(("type" . ,type)
|
|
||||||
("name" . ,name)
|
|
||||||
("ct" . "application/x-javascript")))
|
|
||||||
(cl-json:decode-json body)))
|
|
||||||
|
|
||||||
(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"))
|
|
Loading…
Reference in a new issue