zone.lisp: Support `DNAME' records. master
authorMark Wooding <mdw@distorted.org.uk>
Tue, 30 Apr 2024 16:33:39 +0000 (17:33 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Tue, 30 Apr 2024 16:33:39 +0000 (17:33 +0100)
frontend.lisp
net.lisp
zone.lisp

index e170731..1c1a442 100644 (file)
@@ -22,7 +22,7 @@
 ;;; Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 (defpackage #:zone.frontend
-  (:use #:common-lisp #:mdw.sys-base #:optparse #:net #:zone
+  (:use #:common-lisp #:mdw.base #:mdw.sys-base #:optparse #:net #:zone
        #+(or cmu clisp) #:mop
        #+sbcl #:sb-mop)
   (:export #:main))
       (if (and path
               (not (pathname-name path)))
          (setf var path)
-         (option-parse-error "path `~A' doesn't name a directory." arg)))))
+         (option-parse-error "path `~A' doesn't name a directory." arg))))
+  (let ((duration-units (make-hash-table :test #'equal)))
+    (dolist (item '((("Gs") #.(* 1000 1000 1000))
+                   (("Ms") #.(* 1000 1000))
+                   (("ks") 1000)
+                   (("hs") 100)
+                   (("das") 10)
+                   (("yr" "year" "years" "y") #.(* 365 24 60 60))
+                   (("wk" "week" "weeks" "w") #.(* 7 24 60 60))
+                   (("day" "days" "dy" "d") #.(* 24 60 60))
+                   (("hr" "hour" "hours" "h") #.(* 60 60))
+                   (("min" "minute" "minutes" "m") 60)
+                   (("s" "second" "seconds" "sec" "") 1)))
+      (dolist (name (car item))
+       (setf (gethash name duration-units) (cadr item))))
+    (defopthandler dur (var arg) ()
+      (let ((len (length arg)))
+         (multiple-value-bind (n i) (parse-integer arg :junk-allowed t)
+           (unless n
+             (option-parse-error "invalid duration `~A': ~
+                                  integer expected" arg))
+           (loop (cond ((or (>= i len)
+                            (not (whitespace-char-p (char arg i))))
+                        (return))
+                       (t
+                        (incf i))))
+           (let ((u0 i))
+             (loop (cond ((or (>= i len)
+                              (whitespace-char-p (char arg i)))
+                          (return))
+                         (t
+                          (incf i))))
+             (let* ((u1 i)
+                    (unit (subseq arg u0 u1))
+                    (scale (gethash unit duration-units)))
+               (unless scale
+                 (option-parse-error "invalid duration `~A': ~
+                                      unknown unit `~A'"
+                                     arg unit))
+               (setf var (* n scale)))))))))
 
 (define-program
     :version "1.0.0" :usage "ZONEDEF..."
                           "Designate NET as a preferred subnet.")
                      (#\D "debug" (set opt-debug)
                           "Produce stack backtrace on error.")
+                     "Timeout options"
+                     (#\E "expire" (:arg "DURATION")
+                          (dur *default-zone-expire*)
+                          "Set default zone expiry period.")
+                     (#\N "min-ttl" (:arg "DURATION")
+                          (dur *default-zone-min-ttl*)
+                          "Set default zone minimum/negative time-to-live.")
+                     (#\R "refresh" (:arg "DURATION")
+                          (dur *default-zone-refresh*)
+                          "Set default zone refresh period.")
+                     (#\T "ttl" (:arg "DURATION")
+                          (dur *default-zone-ttl*)
+                          "Set default zone time-to-live.")
+                     (#\Y "retry" (:arg "DURATION")
+                          (dur *default-zone-retry*)
+                          "Set default zone retry period.")
                      "Output options"
                      (#\d "directory" (:arg "DIRECTORY")
                           (dir *zone-output-path*)
                 (progv *zone-config* (mapcar #'symbol-value *zone-config*)
                   (load f :verbose nil :print nil :if-does-not-exist :error)
                   (delete-package *package*))))
-            (zone-save opt-zones :format opt-format)))
+            (zone-save opt-zones :format opt-format)
+            t))
       (with-unix-error-reporting ()
        (unless (option-parse-try
                  (do-options ()
index d245e91..aa7e395 100644 (file)
--- a/net.lisp
+++ b/net.lisp
                                 (cons ipn ipns)))
                           ipns
                           :initial-value nil)))
-      (or merged (error "No matching addresses.")))))
+      (or merged
+         (error "No addresses match ~S~:[ in family ~S~;~*~]."
+                form (eq family t) family)))))
 
 (export 'net-host)
 (defun net-host (net-form host &optional (family t))
                                                   :initial-value nil))
                     (car list))))
       (unless (host-addrs host)
-       (error "No matching addresses."))
+       (error "No addresses match ~S~:[ in family ~S~;~*~]."
+              addr (eq family t) family))
       host)))
 
 (export 'host-create)
index 96cddfb..a80428f 100644 (file)
--- a/zone.lisp
+++ b/zone.lisp
   "The default zone source: the current host's name.")
 
 (export '*default-zone-refresh*)
-(defvar *default-zone-refresh* (* 24 60 60)
-  "Default zone refresh interval: one day.")
+(defvar *default-zone-refresh* (* 8 60 60)
+  "Default zone refresh interval: eight hours.")
 
 (export '*default-zone-admin*)
 (defvar *default-zone-admin* nil
   "Default zone administrator's email address.")
 
 (export '*default-zone-retry*)
-(defvar *default-zone-retry* (* 60 60)
-  "Default znoe retry interval: one hour.")
+(defvar *default-zone-retry* (* 20 60)
+  "Default zone retry interval: twenty minutes.")
 
 (export '*default-zone-expire*)
-(defvar *default-zone-expire* (* 14 24 60 60)
-  "Default zone expiry time: two weeks.")
+(defvar *default-zone-expire* (* 3 24 60 60)
+  "Default zone expiry time: three days.")
 
 (export '*default-zone-min-ttl*)
 (defvar *default-zone-min-ttl* (* 4 60 60)
-  "Default zone minimum TTL/negative TTL: four hours.")
+  "Default zone minimum/negative TTL: four hours.")
 
 (export '*default-zone-ttl*)
-(defvar *default-zone-ttl* (* 8 60 60)
-  "Default zone TTL (for records without explicit TTLs): 8 hours.")
+(defvar *default-zone-ttl* (* 4 60 60)
+  "Default zone TTL (for records without explicit TTLs): four hours.")
 
 (export '*default-mx-priority*)
 (defvar *default-mx-priority* 50
        (retry *default-zone-retry*)
        (expire *default-zone-expire*)
        (min-ttl *default-zone-min-ttl*)
-       (ttl min-ttl)
+       (ttl *default-zone-ttl*)
        (serial (make-zone-serial raw-zname))
        &aux
        (zname (zone-parse-host raw-zname root-domain)))
   ":cname HOST"
   (rec :data (zone-parse-host data zname)))
 
+(defzoneparse :dname (name data rec :zname zname)
+  ":dname HOST"
+  (rec :data (zone-parse-host data zname)))
+
 (defmethod zone-record-rrdata ((type (eql :cname)) zr)
   (rec-name (zr-data zr))
   5)
@@ -1615,6 +1619,9 @@ $TTL ~2@*~D~2%"
 (defmethod zone-write-record ((format (eql :bind)) (type (eql :cname)) zr)
   (bind-format-record zr "~A~%" (bind-hostname (zr-data zr))))
 
+(defmethod zone-write-record ((format (eql :bind)) (type (eql :dname)) zr)
+  (bind-format-record zr "~A~%" (bind-hostname (zr-data zr))))
+
 (defmethod zone-write-record ((format (eql :bind)) (type (eql :ns)) zr)
   (bind-format-record zr "~A~%" (bind-hostname (zr-data zr))))