X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=src%2FCidr.hs;h=ab1ef51cce7af37bb5e3bdbec269a512ca59976f;hb=fbd4a98a9a0996d41e3715a2698114b8a061f2cd;hp=553bd15c06061daf2928fce8ae49dee71f56c1c8;hpb=706e492881f05238ace00fefc6ec9cb0000ea2e9;p=hath.git diff --git a/src/Cidr.hs b/src/Cidr.hs index 553bd15..ab1ef51 100644 --- a/src/Cidr.hs +++ b/src/Cidr.hs @@ -1,193 +1,93 @@ module Cidr -( Cidr, - from_string, - is_valid_cidr, - min_first_octet, - max_first_octet, - min_second_octet, - max_second_octet, - min_third_octet, - max_third_octet, - min_fourth_octet, - max_fourth_octet +( Cidr(..), + cidr_from_string, + contains ) where -import Data.Char (digitToInt, intToDigit) -import Numeric (readInt, showIntAtBase) -import Text.Regex.Posix - +import IPv4Address import ListUtils +import Maskable +import Maskbits +import Octet -type Maskbits = Int -type Octet = Int -type OctetList = (Octet, Octet, Octet, Octet) -type BaseTwoOctetList = (String, String, String, String) - -data Cidr = Cidr { octet1 :: Octet, - octet2 :: Octet, - octet3 :: Octet, - octet4 :: Octet, - maskbits :: Maskbits } - deriving (Show) - --- Will return True if the passed String is in CIDR notation, False --- otherwise. -is_valid_cidr :: String -> Bool -is_valid_cidr cidr = cidr =~ "([0-9]{1,3}\\.){3}[0-9]{1,3}/[0-9]{1,2}" - -first :: (a,b,c,d) -> a -first (w,_,_,_) = w - -second :: (a,b,c,d) -> b -second (_,x,_,_) = x - -third :: (a,b,c,d) -> c -third (_,_,y,_) = y - -fourth :: (a,b,c,d) -> d -fourth (_,_,_,z) = z - -min_first_octet :: Cidr -> Octet -min_first_octet cidr = first (min_octets cidr) - -min_second_octet :: Cidr -> Octet -min_second_octet cidr = second (min_octets cidr) - -min_third_octet :: Cidr -> Octet -min_third_octet cidr = third (min_octets cidr) - -min_fourth_octet :: Cidr -> Octet -min_fourth_octet cidr = fourth (min_octets cidr) -max_first_octet :: Cidr -> Octet -max_first_octet cidr = first (max_octets cidr) - -max_second_octet :: Cidr -> Octet -max_second_octet cidr = second (max_octets cidr) - -max_third_octet :: Cidr -> Octet -max_third_octet cidr = third (max_octets cidr) - -max_fourth_octet :: Cidr -> Octet -max_fourth_octet cidr = fourth (max_octets cidr) +data Cidr = None | Cidr { ipv4address :: IPv4Address, + maskbits :: Maskbits } + deriving (Eq, Show) -- Returns the mask portion of a CIDR address. That is, everything -- after the trailing slash. -maskbits_from_string :: String -> Maskbits -maskbits_from_string s = read ((splitWith (`elem` "/") s) !! 1) +maskbits_from_cidr_string :: String -> Maskbits +maskbits_from_cidr_string s = + maskbits_from_string ((splitWith (`elem` "/") s) !! 1) -- Takes an IP address String in CIDR notation, and returns a list of --- its octets (converted to Int). -octets_from_string :: String -> [Octet] -octets_from_string s = map read (take 4 (splitWith (`elem` "./") s)) +-- its octets (as Ints). +octets_from_cidr_string :: String -> [Octet] +octets_from_cidr_string s = + map octet_from_string (take 4 (splitWith (`elem` "./") s)) -from_string :: String -> Cidr -from_string s = Cidr (octs !! 0) (octs !! 1) (octs !! 2) (octs !! 3) mbits +cidr_from_string :: String -> Cidr +cidr_from_string s + | addr == IPv4Address.None = Cidr.None + | mbits == Maskbits.None = Cidr.None + | otherwise = Cidr addr mbits where - octs = octets_from_string s - mbits = maskbits_from_string s - - --- The base_two_to_base_ten function requires a way to determine --- whether or not the character it's currently parsing is valid. This --- should do it. -is_binary_digit :: Char -> Bool -is_binary_digit c = - if c `elem` ['0','1'] then - True - else - False - - --- Takes an Int, and returns its base-two representation as a String. -base_two :: Int -> String -base_two n = showIntAtBase 2 intToDigit n "" - - --- Takes a set of octets, and converts them to base-two --- individually. The results are then zero-padded on the left to 8 --- characters, and concatenated together. -octets_base_two :: Cidr -> String -octets_base_two cidr = - s1 ++ s2 ++ s3 ++ s4 - where - s1 = ((pad_left_to 8 '0') . base_two) (octet1 cidr) - s2 = ((pad_left_to 8 '0') . base_two) (octet2 cidr) - s3 = ((pad_left_to 8 '0') . base_two) (octet3 cidr) - s4 = ((pad_left_to 8 '0') . base_two) (octet4 cidr) - - -base_two_octetlist_to_octetlist :: BaseTwoOctetList -> OctetList -base_two_octetlist_to_octetlist b2ol = - (oct1, oct2, oct3, oct4) - where - oct1 = base_two_to_base_ten (first b2ol) - oct2 = base_two_to_base_ten (second b2ol) - oct3 = base_two_to_base_ten (third b2ol) - oct4 = base_two_to_base_ten (fourth b2ol) - - --- Convert a base-two String to an Int. -base_two_to_base_ten :: String -> Int -base_two_to_base_ten s = - if (length parsed) == 0 then - 0 - else - fst (parsed !! 0) - where - parsed = readInt 2 is_binary_digit digitToInt s - - --- Returns the minimum address (as a base-two string) satisfying the --- given CIDR string. -min_base_two_address :: Cidr -> String -min_base_two_address cidr = - pad_right_to 32 '0' netpart - where - netpart = take (maskbits cidr) (octets_base_two cidr) - - --- Returns the maximum address (as a base-two string) satisfying the --- given CIDR string. -max_base_two_address :: Cidr -> String -max_base_two_address cidr = - pad_right_to 32 '1' netpart + addr = ipv4address_from_octets (oct1) (oct2) (oct3) (oct4) + oct1 = (octs !! 0) + oct2 = (octs !! 1) + oct3 = (octs !! 2) + oct4 = (octs !! 3) + octs = octets_from_cidr_string s + mbits = maskbits_from_cidr_string s + + + +-- Return true if the first argument (a CIDR range) contains the +-- second (another CIDR range). There are a lot of ways we can be fed +-- junk here. For lack of a better alternative, just return False when +-- we are given nonsense. +contains :: Cidr -> Cidr -> Bool +contains Cidr.None _ = False +contains _ Cidr.None = False +contains (Cidr _ Maskbits.None) _ = False +contains (Cidr IPv4Address.None _) _ = False +contains _ (Cidr _ Maskbits.None) = False +contains _ (Cidr IPv4Address.None _) = False + +-- If the number of bits in the network part of the first address is +-- larger than the number of bits in the second, there is no way that +-- the first range can contain the second. For, if the number of +-- network bits is larger, then the number of host bits must be +-- smaller, and if cidr1 has fewer hosts than cidr2, cidr1 most +-- certainly does not contain cidr2. +-- +-- On the other hand, if the first argument (cidr1) has fewer (or the +-- same number of) network bits as the second, it can contain the +-- second. In this case, we need to check that every host in cidr2 is +-- contained in cidr1. If a host in cidr2 is contained in cidr1, then +-- at least mbits1 of an address in cidr2 will match cidr1. For +-- example, +-- +-- cidr1 = 192.168.1.0/23, cidr2 = 192.168.1.100/24 +-- +-- Here, cidr2 contains all of 192.168.1.0 through +-- 192.168.1.255. However, cidr1 contains BOTH 192.168.0.0 through +-- 192.168.0.255 and 192.168.1.0 through 192.168.1.255. In essence, +-- what we want to check is that cidr2 "begins with" something that +-- cidr1 CAN begin with. Since cidr1 can begin with 192.168.1, and +-- cidr2 DOES, cidr1 contains cidr2.. +-- +-- The way that we check this is to apply cidr1's mask to cidr2's +-- address and see if the result is the same as cidr1's mask applied +-- to cidr1's address. +-- +contains (Cidr addr1 (Maskbits mbits1)) (Cidr addr2 (Maskbits mbits2)) + | mbits1 > mbits2 = False + | otherwise = addr1masked == addr2masked where - netpart = take (maskbits cidr) (octets_base_two cidr) - - --- The octet components of min_base_two_address, as a base-two String. -min_base_two_octets :: Cidr -> BaseTwoOctetList -min_base_two_octets cidr = - (oct1, oct2, oct3, oct4) - where - addr = min_base_two_address cidr - oct1 = fst (splitAt 8 addr) - oct2 = fst (splitAt 8 (snd (splitAt 8 addr))) - oct3 = fst (splitAt 8 (snd (splitAt 16 addr))) - oct4 = snd (splitAt 24 addr) - - --- The octet components of max_base_two_address, as a base-two String. -max_base_two_octets :: Cidr -> BaseTwoOctetList -max_base_two_octets cidr = - (oct1, oct2, oct3, oct4) - where - addr = max_base_two_address cidr - oct1 = fst (splitAt 8 addr) - oct2 = fst (splitAt 8 (snd (splitAt 8 addr))) - oct3 = fst (splitAt 8 (snd (splitAt 16 addr))) - oct4 = snd (splitAt 24 addr) - - --- The octet components of min_base_two_address, as Ints. -min_octets :: Cidr -> OctetList -min_octets cidr = base_two_octetlist_to_octetlist (min_base_two_octets cidr) - - --- The octet components of max_base_two_address, as Ints. -max_octets :: Cidr -> OctetList -max_octets cidr = base_two_octetlist_to_octetlist (max_base_two_octets cidr) + addr1masked = apply_mask addr1 (Maskbits mbits1) + addr2masked = apply_mask addr2 (Maskbits mbits1)