module Cidr
( Cidr(..),
cidr_from_string,
- contains
+ combine_all
) where
import IPv4Address
data Cidr = None | Cidr { ipv4address :: IPv4Address,
maskbits :: Maskbits }
- deriving (Eq, Show)
+ deriving (Eq)
+
+
+instance Show Cidr where
+ show Cidr.None = "None"
+ show cidr = (show (ipv4address cidr)) ++ "/" ++ (show (maskbits cidr))
-- Returns the mask portion of a CIDR address. That is, everything
where
addr1masked = apply_mask addr1 mbits1
addr2masked = apply_mask addr2 mbits1
+
+
+contains_proper :: Cidr -> Cidr -> Bool
+contains_proper cidr1 cidr2 =
+ (cidr1 `contains` cidr2) && (not (cidr1 == cidr2))
+
+
+-- A CIDR range is redundant (with respect to the given list) if
+-- another CIDR range in that list properly contains it.
+redundant :: [Cidr] -> Cidr -> Bool
+redundant cidrlist cidr = any ((flip contains_proper) cidr) cidrlist
+
+
+-- We want to get rid of all the Cidrs that are properly contained
+-- in some other Cidr.
+combine_all :: [Cidr] -> [Cidr]
+combine_all cidrs =
+ filter (not . (redundant cidrs)) cidrs
+
+
+-- Determine whether or not two CIDR ranges are adjacent. If two
+-- ranges lie consecutively within the IP space, they can be
+-- combined. For example, 10.1.0.0/24 and 10.0.1.0/24 are adjacent,
+-- and can be combined in to 10.1.0.0/23.
+adjacent :: Cidr -> Cidr -> Bool
+adjacent Cidr.None _ = False
+adjacent _ Cidr.None = False
+adjacent cidr1 cidr2
+ | mbits1 /= mbits2 = False
+ | mbits1 == Maskbits.Zero = False -- They're equal.
+ | otherwise = (mbits1 == (most_sig_bit_different addr1 addr2))
+ where
+ addr1 = ipv4address cidr1
+ addr2 = ipv4address cidr2
+ mbits1 = maskbits cidr1
+ mbits2 = maskbits cidr2