X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/zone/blobdiff_plain/9c44003b8aa3a1a03d6f92c16ec782b13e61249a..51a6847e534bc908f97f068c5ed82ed11c85ce15:/net.lisp diff --git a/net.lisp b/net.lisp index 0a27423..64c796d 100644 --- a/net.lisp +++ b/net.lisp @@ -27,7 +27,7 @@ ;;; Packaging. (defpackage #:net - (:use #:common-lisp #:mdw.base #:mdw.str #:mdw.collect) + (:use #:common-lisp #:mdw.base #:mdw.str #:collect) (:export #:ipaddr #:string-ipaddr #:ipaddr-byte #:ipaddr-string #:ipaddrp #:integer-netmask #:ipmask #:ipmask-cidl-slash #:make-ipnet #:string-ipnet #:ipnet #:ipnet-net #:ipnet-mask #:with-ipnet @@ -71,9 +71,9 @@ (defun count-low-zero-bits (n) (defun string-ipaddr (str &key (start 0) (end nil)) "Parse STR as an IP address in dotted-quad form and return the integer -equivalent. STR may be anything at all: it's converted as if by -`stringify'. The START and END arguments may be used to parse out a -substring." + equivalent. STR may be anything at all: it's converted as if by + `stringify'. The START and END arguments may be used to parse out a + substring." (setf str (stringify str)) (unless end (setf end (length str))) @@ -110,7 +110,7 @@ (defun ipaddrp (ip) (defun ipaddr (ip) "Convert IP to an IP address. If it's an integer, return it unchanged; -otherwise convert by `string-ipaddr'." + otherwise convert by `string-ipaddr'." (typecase ip (ipaddr ip) (t (string-ipaddr ip)))) @@ -124,8 +124,8 @@ (defun integer-netmask (i) (defun ipmask (ip) "Transform IP into a netmask. If it's a small integer then it's converted -by `integer-netmask'; if nil, then all-bits-set; otherwise convert using -`ipaddr'." + by `integer-netmask'; if nil, then all-bits-set; otherwise convert using + `ipaddr'." (typecase ip (null (mask 32)) ((integer 0 32) (integer-netmask ip)) @@ -133,7 +133,7 @@ (defun ipmask (ip) (defun ipmask-cidl-slash (mask) "Given a netmask MASK, return an integer N such that (integer-netmask N) = -MASK, or nil if this is impossible." + MASK, or nil if this is impossible." (dotimes (i 33) (when (= mask (integer-netmask i)) (return i)))) @@ -143,7 +143,7 @@ (defun ipmask-cidl-slash (mask) (defun make-ipnet (net mask) "Construct an IP-network object given the NET and MASK; these are -transformed as though by `ipaddr' and `ipmask'." + transformed as though by `ipaddr' and `ipmask'." (let ((net (ipaddr net)) (mask (ipmask mask))) (cons (logand net mask) mask))) @@ -164,12 +164,13 @@ (defun string-ipnet (str &key (start 0) (end nil)) (integer-netmask 32))))) (defun ipnet (net) - "Construct an IP-network object from the given argument. A number of -forms are acceptable: + "Construct an IP-network object from the given argument. A number of forms + are acceptable: - * ADDR -- a single address (equivalent to ADDR 32) - * (NET . MASK|nil) -- a single-object representation. - * IPNET -- return an equivalent (`equal', not necessarily `eql') version." + * ADDR -- a single address (equivalent to ADDR 32) + * (NET . MASK|nil) -- a single-object representation. + * IPNET -- return an equivalent (`equal', not necessarily `eql') + version." (cond ((or (stringp net) (symbolp net)) (string-ipnet net)) (t (apply #'make-ipnet (pairify net 32))))) @@ -183,7 +184,8 @@ (defun ipnet-mask (ipn) (defmacro with-ipnet ((net mask) ipn &body body) "Evaluate BODY with NET and MASK bound to the base address and netmask of -IPN. Either NET or MASK (or, less usefully, both) may be nil if not wanted." + IPN. Either NET or MASK (or, less usefully, both) may be nil if not + wanted." (with-gensyms tmp `(let ((,tmp ,ipn)) (let (,@(and net `((,net (ipnet-net ,tmp)))) @@ -214,7 +216,7 @@ (defun ipnet-hosts (ipn) (defun ipnet-host (ipn host) "Return the address of the given HOST in network IPN. This works even with -a non-contiguous netmask." + a non-contiguous netmask." (check-type host u32) (with-ipnet (net mask) ipn (let ((i 0) (m 1) (a net) (h host)) @@ -246,7 +248,7 @@ (defun ipnet-subnetp (ipn subn) (defun ipnet-changeable-bytes (mask) "Answers how many low-order bytes of MASK are (entirely or partially) -changeable. This is used when constructing reverse zones." + changeable. This is used when constructing reverse zones." (dotimes (i 4 4) (when (/= (ipaddr-byte mask i) 255) (return (- 4 i))))) @@ -254,19 +256,23 @@ (defun ipnet-changeable-bytes (mask) ;;;-------------------------------------------------------------------------- ;;; Name resolution. -#+cmu (defun resolve-hostname (name) "Resolve a hostname to an IP address using the DNS, or return nil." - (let ((he (ext:lookup-host-entry name))) - (and he - (ext:host-entry-addr he)))) + #+cmu (let ((he (ext:lookup-host-entry name))) + (and he (ext:host-entry-addr he))) + #+clisp (let ((he (ext:resolve-host-ipaddr name))) + (and he (string-ipaddr (car (ext:hostent-addr-list he))))) + #+ecl (nth-value 2 (ext:lookup-host-entry name)) + #-(or cmu clisp ecl) nil) -#+cmu (defun canonify-hostname (name) "Resolve a hostname to canonical form using the DNS, or return nil." - (let ((he (ext:lookup-host-entry name))) - (and he - (ext:host-entry-name he)))) + #+cmu (let ((he (ext:lookup-host-entry name))) + (and he (ext:host-entry-name he))) + #+clisp (let ((he (ext:resolve-host-ipaddr name))) + (and he (ext:hostent-name he))) + #+ecl (nth-value 0 (ext:lookup-host-entry name)) + #-(or cmu clisp ecl) name) ;;;-------------------------------------------------------------------------- ;;; Host names and specifiers. @@ -274,13 +280,17 @@ (defun canonify-hostname (name) (defun parse-ipaddr (addr) "Convert the string ADDR into an IP address: tries all sorts of things: - (NET [INDEX]) -- index a network: NET is a network name defined by defnet; - INDEX is an index or one of the special symbols understood by net-host, - and defaults to :next - INTEGER -- an integer IP address - IPADDR -- an IP address in dotted-quad form - HOST -- a host name defined by defhost - DNSNAME -- a name string to look up in the DNS" + (NET [INDEX]) index a network: NET is a network name defined by + defnet; INDEX is an index or one of the special + symbols understood by net-host, and defaults to :next + + INTEGER an integer IP address + + IPADDR an IP address in dotted-quad form + + HOST a host name defined by defhost + + DNSNAME a name string to look up in the DNS" (cond ((listp addr) (destructuring-bind (net host) @@ -325,10 +335,10 @@ (defmacro defhost (name addr) (defstruct (net (:predicate netp)) "A network structure. Slots: -NAME The network's name, as a string -IPNET The network base address and mask -HOSTS Number of hosts in the network -NEXT Index of the next unassigned host" + NAME The network's name, as a string + IPNET The network base address and mask + HOSTS Number of hosts in the network + NEXT Index of the next unassigned host" name ipnet hosts @@ -354,13 +364,13 @@ (defun net-get-as-ipnet (form) (defun process-net-form (root addr subnets) "Unpack a net-form. The return value is a list of entries, each of which -is a list of the form (NAME ADDR MASK). The first entry is merely repeats -the given ROOT and ADDR arguments (unpacking ADDR into separate network -address and mask). The SUBNETS are then processed: they are a list of items -of the form (NAME NUM-HOSTS . SUBNETS), where NAME names the subnet, -NUM-HOSTS is the number of hosts in it, and SUBNETS are its sub-subnets in -the same form. An error is signalled if a net's subnets use up more hosts -than the net has to start with." + is a list of the form (NAME ADDR MASK). The first entry is merely repeats + the given ROOT and ADDR arguments (unpacking ADDR into separate network + address and mask). The SUBNETS are then processed: they are a list of + items of the form (NAME NUM-HOSTS . SUBNETS), where NAME names the subnet, + NUM-HOSTS is the number of hosts in it, and SUBNETS are its sub-subnets in + the same form. An error is signalled if a net's subnets use up more hosts + than the net has to start with." (labels ((frob (subnets limit finger) (when subnets (destructuring-bind (name size &rest subs) (car subnets) @@ -382,7 +392,7 @@ (defun process-net-form (root addr subnets) (defun net-create (name net) "Construct a new network called NAME and add it to the map. The ARGS -describe the new network, in a form acceptable to the ipnet function." + describe the new network, in a form acceptable to the ipnet function." (let ((ipn (ipnet net))) (setf (net-find name) (make-net :name (string-downcase (stringify name)) @@ -399,7 +409,7 @@ (defmacro defnet (name net &rest subnets) (defun net-next-host (net) "Given a NET, return the IP address (as integer) of the next available -address in the network." + address in the network." (unless (< (net-next net) (net-hosts net)) (error "No more hosts left in network ~A" (net-name net))) (let ((next (net-next net))) @@ -408,10 +418,11 @@ (defun net-next-host (net) (defun net-host (net host) "Return the given HOST on the NEXT. HOST may be an index (in range, of -course), or one of the keywords: -:NEXT next host, as by net-next-host -:NET network base address -:BROADCAST network broadcast address" + course), or one of the keywords: + + :NEXT next host, as by net-next-host + :NET network base address + :BROADCAST network broadcast address" (case host (:next (net-next-host net)) (:net (ipnet-net (net-ipnet net)))