chiark / gitweb /
zone: Clean up the :cidr-delegation parser.
[zone] / zone.lisp
index 611a6ac8af75676810ca65ff0fdae7363349054a..ea9fda3f93a1ab94c6df42690957943462fa6c10 100644 (file)
--- a/zone.lisp
+++ b/zone.lisp
@@ -27,7 +27,9 @@
 ;;; Packaging.
 
 (defpackage #:zone
-  (:use #:common-lisp #:mdw.base #:mdw.str #:collect #:safely #:net)
+  (:use #:common-lisp
+       #:mdw.base #:mdw.str #:collect #:safely
+       #:net #:services)
   (:export #:soa #:mx #:zone #:zone-record #:zone-subdomain
           #:*default-zone-source* #:*default-zone-refresh*
             #:*default-zone-retry* #:*default-zone-expire*
@@ -612,6 +614,31 @@ (defzoneparse :alias (name data rec :zname zname)
         :type :cname
         :data name)))
 
+(defzoneparse :srv (name data rec :zname zname)
+  ":srv (((SERVICE &key :port) (PROVIDER &key :port :prio :weight :ip)*)*)"
+  (dolist (srv data)
+    (destructuring-bind (servopts &rest providers) srv
+      (destructuring-bind
+         (service &key ((:port default-port)) (protocol :tcp))
+         (listify servopts)
+       (unless default-port
+         (let ((serv (serv-by-name service protocol)))
+           (setf default-port (and serv (serv-port serv)))))
+       (let ((rname (format nil "~(_~A._~A~).~A" service protocol name)))
+         (dolist (prov providers)
+           (destructuring-bind
+               (srvname
+                &key
+                (port default-port)
+                (prio *default-mx-priority*)
+                (weight 0)
+                ip)
+               (listify prov)
+             (let ((host (zone-parse-host srvname zname)))
+               (when ip (rec :name host :type :a :data (parse-ipaddr ip)))
+               (rec :name rname
+                    :data (list prio weight port host))))))))))
+
 (defzoneparse :net (name data rec)
   ":net (NETWORK*)"
   (dolist (net (listify data))
@@ -629,9 +656,7 @@ (defzoneparse :net (name data rec)
 (defzoneparse (:rev :reverse) (name data rec)
   ":reverse ((NET :bytes BYTES) ZONE*)"
   (setf data (listify data))
-  (destructuring-bind
-      (net &key bytes)
-      (listify (car data))
+  (destructuring-bind (net &key bytes) (listify (car data))
     (setf net (zone-parse-net net name))
     (unless bytes
       (setf bytes (ipnet-changeable-bytes (ipnet-mask net))))
@@ -655,18 +680,15 @@ (defzoneparse (:rev :reverse) (name data rec)
                     :ttl (zr-ttl zr) :data (zr-name zr))
                (setf (gethash name seen) t)))))))))
 
-(defzoneparse (:cidr-delegation :cidr) (name data rec)
+(defzoneparse (:cidr-delegation :cidr) (name data rec :zname zname)
   ":cidr-delegation ((NET :bytes BYTES) (TARGET-NET [TARGET-ZONE])*)"
-  (destructuring-bind
-      (net &key bytes)
-      (listify (car data))
+  (setf data (listify data))
+  (destructuring-bind (net &key bytes) (listify (car data))
     (setf net (zone-parse-net net name))
     (unless bytes
       (setf bytes (ipnet-changeable-bytes (ipnet-mask net))))
-    (dolist (map (cdr data))
-      (destructuring-bind
-         (tnet &optional tdom)
-         (listify map)
+    (dolist (map (or (cdr data) (list (list net))))
+      (destructuring-bind (tnet &optional tdom) (listify map)
        (setf tnet (zone-parse-net tnet name))
        (unless (ipnet-subnetp net tnet)
          (error "~A is not a subnet of ~A."
@@ -678,25 +700,25 @@ (defzoneparse (:cidr-delegation :cidr) (name data rec)
                  (join-strings
                   #\.
                   (append (reverse (loop
-                                      for i from (1- bytes) downto 0
-                                      until (zerop (logand mask
-                                                           (ash #xff
-                                                                (* 8 i))))
-                                      collect (logand #xff
-                                                      (ash net (* -8 i)))))
+                                    for i from (1- bytes) downto 0
+                                    until (zerop (logand mask
+                                                         (ash #xff
+                                                              (* 8 i))))
+                                    collect (ldb (byte 8 (* i 8)) net)))
                           (list name))))))
-       (setf tdom (string-downcase tdom))
+       (setf tdom (string-downcase (stringify tdom)))
        (dotimes (i (ipnet-hosts tnet))
-         (let* ((addr (ipnet-host tnet i))
-                (tail (join-strings #\.
-                                    (loop
+         (unless (zerop i)
+           (let* ((addr (ipnet-host tnet i))
+                  (tail (join-strings #\.
+                                      (loop
                                        for i from 0 below bytes
                                        collect
-                                         (logand #xff
-                                                 (ash addr (* 8 i)))))))
-           (rec :name (format nil "~A.~A" tail name)
-                :type :cname
-                :data (format nil "~A.~A" tail tdom))))))))
+                                       (logand #xff
+                                               (ash addr (* 8 i)))))))
+             (rec :name (format nil "~A.~A" tail name)
+                  :type :cname
+                  :data (format nil "~A.~A" tail tdom)))))))))
 
 ;;;--------------------------------------------------------------------------
 ;;; Zone file output.
@@ -810,6 +832,9 @@ (defgeneric bind-record-format-args (type data)
   (:method ((type (eql :ns)) data) (list "~A" (bind-hostname data)))
   (:method ((type (eql :mx)) data)
     (list "~2D ~A" (cdr data) (bind-hostname (car data))))
+  (:method ((type (eql :srv)) data)
+    (destructuring-bind (prio weight port host) data
+      (list "~2D ~5D ~5D ~A" prio weight port (bind-hostname host))))
   (:method ((type (eql :txt)) data) (list "~S" (stringify data))))
 
 ;;;----- That's all, folks --------------------------------------------------