Mercurial > core / lisp/lib/net/proto/dns.lisp
changeset 698: |
96958d3eb5b0 |
parent: |
a2fe095379f9
|
author: |
Richard Westhaver <ellis@rwest.io> |
date: |
Fri, 04 Oct 2024 22:04:59 -0400 |
permissions: |
-rw-r--r-- |
description: |
fixes |
1 ;;; lib/net/proto/dns.lisp --- Domain Name Services 6 (in-package :net/proto/dns) 8 (define-condition dns-error (dns-condition protocol-error) ()) 10 (define-condition dns-servers-exhausted (dns-error) 12 (:report (lambda (c s) (declare (ignore c)) (format s "All DNS servers failed to provide an answer for the query.")))) 14 (defconstant +dns-port+ 53) 15 (defconstant +dns-buffer-length+ 4096) 17 (defvar *cloudflare-servers* 18 '("1.1.1.1" "1.0.0.1")) 19 (defvar *dnswatch-servers* 20 '("84.200.69.80" "84.200.70.40")) 21 (defvar *google-servers* 22 '("8.8.8.8" "8.8.4.4")) 23 (defvar *opendns-servers* 24 '("208.67.222.123" "208.67.220.123")) 25 (defvar *quad9-servers* 26 '("9.9.9.9" "149.112.112.112")) 30 (append *dnswatch-servers* *quad9-servers* 31 *cloudflare-servers* *opendns-servers* 34 (defun try-server (server send send-length recv recv-length &key (attempts 1) (timeout 1)) 36 (let ((socket (sb-bsd-sockets:socket-connect 37 (make-instance 'inet-socket 38 :type :datagram :protocol :udp) 39 (make-inet-address server) +dns-port+))) 42 do (sb-bsd-sockets:socket-send socket send send-length) 43 (sb-ext:with-timeout timeout 44 (let ((received (nth-value 1 (socket-receive socket recv recv-length)))) 45 (when (and received (< 0 received)) 47 (socket-close socket))) 51 (defmacro with-query-buffer ((send pos hostname type &rest header-args) &body body) 52 `(let* ((,send (make-array 512 :element-type '(unsigned-byte 8) :initial-element 0)) 53 (,pos (encode-header ,send 0 :id 42 :recursion-desired T :question-count 1 ,@header-args)) 54 (,pos (encode-query ,send ,pos ,hostname :type ,type :class 1))) 55 (declare (dynamic-extent ,send)) 58 (defun dns-query (hostname &key (type T) (dns-servers *dns-servers*) (attempts 1) (timeout 1)) 59 (with-simple-restart (abort "Abort the DNS query.") 60 (let ((recv (make-array +dns-buffer-length+ :element-type '(unsigned-byte 8) :initial-element 0))) 61 (declare (dynamic-extent recv)) 62 (with-query-buffer (send send-length hostname type) 63 (loop for server in dns-servers 64 for recv-length = (try-server server send send-length recv +dns-buffer-length+ :attempts attempts :timeout timeout) 66 (with-simple-restart (continue "Skip this DNS server.") 67 (return (decode-response server recv 0 recv-length)))) 68 finally (with-simple-restart (continue "Return NIL instead.") 69 (error 'dns-servers-exhausted))))))) 71 (defun query-data (hostname &rest args &key type dns-servers attempts timeout) 72 (declare (ignore dns-servers attempts timeout)) 73 (loop for record in (getf (apply #'dns-query hostname args) :answers) 74 when (eql type (getf record :type)) 75 collect (getf record :data))) 77 (defun resolve (hostname &rest args &key type dns-servers attempts timeout) 78 (declare (ignore dns-servers attempts timeout)) 80 (handler-bind ((dns-server-failure #'continue)) 82 (apply #'query-data hostname args) 83 (append (apply #'query-data hostname :type :A args) 84 (apply #'query-data hostname :type :AAAA args))))) 85 (values (first list) list T))) 86 (dns-servers-exhausted () 87 (values NIL NIL NIL)))) 89 (defun hostname (ip &rest args &key type dns-servers attempts timeout) 90 (declare (ignore type dns-servers attempts timeout)) 92 (handler-bind ((dns-server-failure #'continue)) 93 (let* ((ipv6-p (find #\: ip)) 95 (loop for byte across (usocket:ipv6-host-to-vector ip) 96 collect (format NIL "~x" (ldb (byte 4 4) byte)) 97 collect (format NIL "~x" (ldb (byte 4 0) byte))) 99 (list (apply #'query-data (format NIL "~{~a.~}~:[in-addr~;ip6~].arpa" (nreverse parts) ipv6-p) :type :PTR args))) 100 (values (first list) list T))) 102 (values NIL NIL NIL))))