zone.lisp: Add support for CAA records (RFC 6844).
[zone] / zone.lisp
index f3ea23c..2267026 100644 (file)
--- a/zone.lisp
+++ b/zone.lisp
   min-ttl
   serial)
 
-(export 'zone-text-name)
-(defun zone-text-name (zone)
-  (princ-to-string (zone-name zone)))
-
 (export 'mx)
 (defstruct (mx (:predicate mxp))
   "Mail-exchange record information."
   name
   records)
 
+(export 'zone-text-name)
+(defun zone-text-name (zone)
+  (princ-to-string (zone-name zone)))
+
 ;;;--------------------------------------------------------------------------
 ;;; Zone defaults.  It is intended that scripts override these.
 
                                      :ttl ttl :records (cdr r))
                                     sub)))
                         (t
-                         (error "Unexpected record form ~A" (car r))))))))
+                         (error "Unexpected record form ~A" r)))))))
 
           (process (rec dom ttl)
             ;; Recursirvely process the record list REC, with a list DOM of
 (defmacro defrevzone (head &body zf)
   "Define a reverse zone, with the correct name."
   (destructuring-bind (nets &rest args
-                           &key &allow-other-keys
-                                (family '*address-family*)
-                                prefix-bits)
+                           &key (family '*address-family*)
+                                prefix-bits
+                                &allow-other-keys)
       (listify head)
     (with-gensyms (ipn)
       `(dolist (,ipn (net-parse-to-ipnets ',nets ,family))
       (rec :type :txt
           :data (nreverse things)))))
 
-(defenum sshfp-algorithm () (:rsa 1) (:dsa 2) (:ecdsa 3))
+(defenum sshfp-algorithm () (:rsa 1) (:dsa 2) (:ecdsa 3) (:ed25519 4))
 (defenum sshfp-type () (:sha-1 1) (:sha-256 2))
 
 (export '*sshfp-pathname-defaults*)
     (rec-octet-vector data))
   52)
 
+(defenum dnssec-algorithm ()
+  (:rsamd5 1)
+  (:dh 2)
+  (:dsa 3)
+  (:rsasha1 5)
+  (:dsa-nsec3-sha1 6)
+  (:rsasha1-nsec3-sha1 7)
+  (:rsasha256 8)
+  (:rsasha512 10)
+  (:ecc-gost 12)
+  (:ecdsap256sha256 13)
+  (:ecdsap384sha384 14))
+
+(defenum dnssec-digest ()
+  (:sha1 1)
+  (:sha256 2))
+
+(defzoneparse :ds (name data rec)
+  ":ds ((TAG ALGORITHM DIGEST-TYPE DIGEST)*)"
+  (dolist (ds data)
+    (destructuring-bind (tag alg hashtype hash) ds
+      (rec :data (list tag
+                      (lookup-enum 'dnssec-algorithm alg :min 0 :max 255)
+                      (lookup-enum 'dnssec-digest hashtype :min 0 :max 255)
+                      (decode-hex hash))))))
+
+(defmethod zone-record-rrdata ((type (eql :ds)) zr)
+  (destructuring-bind (tag alg hashtype hash) zr
+    (rec-u16 tag)
+    (rec-u8 alg)
+    (rec-u8 hashtype)
+    (rec-octet-vector hash)))
+
 (defzoneparse :mx (name data rec :zname zname)
   ":mx ((HOST :prio INT :ip IPADDR)*)"
   (dolist (mx (listify data))
     (rec-name host))
   33)
 
+(defenum caa-flag () (:critical 128))
+
+(defzoneparse :caa (name data rec)
+  ":caa ((TAG VALUE FLAG*)*)"
+  (dolist (prop data)
+    (destructuring-bind (tag value &rest flags) prop
+      (setf flags (reduce #'logior
+                         (mapcar (lambda (item)
+                                   (lookup-enum 'caa-flag item
+                                                :min 0 :max 255))
+                                 flags)))
+      (ecase tag
+       ((:issue :issuewild :iodef)
+        (rec :name name
+             :data (list flags tag value)))))))
+
+(defmethod zone-record-rrdata ((type (eql :caa)) zr)
+  (destructuring-bind (flags tag value) (zr-data zr)
+    (rec-u8 flags)
+    (rec-string (string-downcase tag))
+    (rec-raw-string value))
+  257)
+
 (defzoneparse :net (name data rec)
   ":net (NETWORK*)"
   (dolist (net (listify data))
@@ -1583,6 +1639,15 @@ $TTL ~2@*~D~2%"
     (bind-format-record zr "~2D ~2D ~2D " usage selector match)
     (bind-write-hex data 12)))
 
+(defmethod zone-write-record ((format (eql :bind)) (type (eql :caa)) zr)
+  (destructuring-bind (flags tag value) (zr-data zr)
+    (bind-format-record zr "~3D ~(~A~) ~S~%" flags tag value)))
+
+(defmethod zone-write-record ((format (eql :bind)) (type (eql :ds)) zr)
+  (destructuring-bind (tag alg hashtype hash) (zr-data zr)
+    (bind-format-record zr "~5D ~2D ~2D " tag alg hashtype)
+    (bind-write-hex hash 12)))
+
 (defmethod zone-write-record ((format (eql :bind)) (type (eql :txt)) zr)
   (bind-format-record zr "~{~#[\"\"~;~S~:;(~@{~%~8T~S~} )~]~}~%"
                      (zr-data zr)))