(let ((w (ipaddr-width addr)))
(if (<= 0 mask w)
(integer-netmask w mask)
- (error "Mask out of range.")))))
+ (error "Prefix length out of range.")))))
(export 'mask-ipaddr)
(defun mask-ipaddr (addr mask)
(print-unreadable-object (ipn stream :type t)
(write-string (ipnet-string ipn) stream)))
-(defun parse-subnet (class width max str &key (start 0) (end nil))
+(defun parse-subnet (class width max str &key (start 0) (end nil) (slashp t))
"Parse a subnet description from a (substring of) STR."
(setf-default end (length str))
- (let ((sl (position #\/ str :start start :end end)))
+ (let ((sl (and slashp (position #\/ str :start start :end end))))
(multiple-value-bind (addr lo hi)
(parse-partial-ipaddr class str :max max
:start start :end (or sl end))
(error "Mask selects bits not present in base address"))
(values addr mask)))))
-(export 'ipnet-subnet)
-(defun ipnet-subnet (base-ipn sub-net sub-mask)
- "Construct a subnet of IPN, using the NET and MASK.
+(defun check-subipnet (base-ipn sub-addr sub-mask)
+ "Verify that SUB-NET/SUB-MASK is an appropriate subnet of BASE-IPN.
- The NET must either be zero or agree with IPN at all positions indicated
- by their respective masks."
+ The BASE-IPN is an `ipnet'; SUB-ADDR and SUB-MASK are plain integers. If
+ the subnet is invalid (i.e., the subnet disagrees with its putative parent
+ over some of the fixed address bits) then an error is signalled; otherwise
+ return the combined base address (as an `ipaddr') and mask (as an
+ integer)."
(with-ipnet (base-net base-addr base-mask) base-ipn
- (let* ((sub-net (ipaddr sub-net (ipnet-net base-ipn)))
- (sub-addr (ipaddr-addr sub-net))
- (sub-mask (ipmask sub-net sub-mask))
- (common (logand base-mask sub-mask))
+ (let* ((common (logand base-mask sub-mask))
(base-overlap (logand base-addr common))
(sub-overlap (logand sub-addr common))
(full-mask (logior base-mask sub-mask)))
- (unless (or (zerop sub-overlap)
- (= sub-overlap base-overlap))
+ (unless (or (zerop sub-overlap) (= sub-overlap base-overlap))
(error "Subnet doesn't match base network"))
- (ipaddr-ipnet (integer-ipaddr (logand full-mask
- (logior base-addr sub-addr))
- base-net)
- full-mask))))
+ (values (integer-ipaddr (logand full-mask (logior base-addr sub-addr))
+ base-net)
+ full-mask))))
(export 'string-ipnet)
(defun string-ipnet (str &key (start 0) (end nil))
(make-ipnet (make-instance addr-class :addr addr)
(make-instance addr-class :addr mask)))))
-(export 'string-subipnet)
-(defun string-subipnet (ipn str &key (start 0) (end nil))
- (setf str (stringify str))
+(defun parse-subipnet (ipn str &key (start 0) (end nil) (slashp t))
+ "Parse STR as a subnet of IPN.
+
+ This is mostly a convenience interface over `parse-subnet'."
(let* ((addr-class (extract-class-name (ipnet-net ipn)))
(width (ipaddr-width addr-class))
(max (- width
(or (ipmask-cidl-slash width (ipnet-mask ipn))
(error "Base network has complex netmask")))))
(multiple-value-bind (addr mask)
- (parse-subnet addr-class width max str :start start :end end)
- (ipnet-subnet ipn
- (make-instance addr-class :addr addr)
- (make-instance addr-class :addr mask)))))
+ (parse-subnet addr-class width max (stringify str)
+ :start start :end end :slashp slashp)
+ (check-subipnet ipn addr mask))))
+
+(export 'string-subipnet)
+(defun string-subipnet (ipn str &key (start 0) (end nil))
+ "Parse an IP subnet from a parent net IPN and a suffix string STR."
+ (multiple-value-bind (addr mask)
+ (parse-subipnet ipn str :start start :end end)
+ (ipaddr-ipnet addr mask)))
(defun ipnet (net)
"Construct an IP-network object from the given argument.
(defun ipnet-host (ipn host)
"Return the address of the given HOST in network IPN.
- This works even with a non-contiguous netmask."
- (ipnet-index-host (ipnet-host-map ipn) host))
+ The HOST may be a an integer index into the network (this works even with
+ a non-contiguous netmask) or a string or symbolic suffix (as for
+ `string-subnet')."
+ (etypecase host
+ (integer
+ (ipnet-index-host (ipnet-host-map ipn) host))
+ ((or symbol string)
+ (multiple-value-bind (addr mask)
+ (parse-subipnet ipn host :slashp nil)
+ (unless (= mask (mask (ipaddr-width addr)))
+ (error "Host address incomplete"))
+ addr))))
(export 'ipaddr-networkp)
(defun ipaddr-networkp (ip ipn)
(defun net-host (net-form host &optional (family t))
"Return the given HOST on the NET, as an anonymous `host' object.
- HOST may be an index (in range, of course), or one of the keywords:
+ HOST may be an index (in range, of course), a suffix (as a symbol or
+ string, as for `string-subnet'), or one of the keywords:
:next next host, as by net-next-host
:net network base address
otherwise return all available addresses."
(flet ((hosts (ipns host)
(mapcar (lambda (ipn) (ipnet-host ipn host))
- (remove host ipns :key #'ipnet-hosts :test-not #'<))))
+ (if (integerp host)
+ (remove host ipns :key #'ipnet-hosts :test #'>=)
+ ipns))))
(let* ((net (and (typep net-form '(or string symbol))
(net-find net-form)))
(ipns (net-parse-to-ipnets net-form family))