iproute-1.7.15: Data/IP/Op.hs
module Data.IP.Op where
import Data.Bits
import Data.IP.Addr
import Data.IP.Mask
import Data.IP.Range
----------------------------------------------------------------
-- |
--
-- >>> toIPv4 [127,0,2,1] `masked` intToMask 7
-- 126.0.0.0
class Eq a => Addr a where
-- |
-- The 'masked' function takes an 'Addr' and a contiguous
-- mask and returned a masked 'Addr'.
masked :: a -> a -> a
-- |
--
-- The 'intToMask' function takes an 'Int' representing the number of bits to
-- be set in the returned contiguous mask. When this integer is positive the
-- bits will be starting from the MSB and from the LSB otherwise.
--
-- >>> intToMask 16 :: IPv4
-- 255.255.0.0
--
-- >>> intToMask (-16) :: IPv4
-- 0.0.255.255
--
-- >>> intToMask 16 :: IPv6
-- ffff::
--
-- >>> intToMask (-16) :: IPv6
-- ::ffff
intToMask :: Int -> a
instance Addr IPv4 where
masked = maskedIPv4
intToMask = maskIPv4
instance Addr IPv6 where
masked = maskedIPv6
intToMask = maskIPv6
----------------------------------------------------------------
-- |
-- The >:> operator takes two 'AddrRange'. It returns 'True' if
-- the first 'AddrRange' contains the second 'AddrRange'. Otherwise,
-- it returns 'False'.
--
-- >>> makeAddrRange ("127.0.2.1" :: IPv4) 8 >:> makeAddrRange "127.0.2.1" 24
-- True
-- >>> makeAddrRange ("127.0.2.1" :: IPv4) 24 >:> makeAddrRange "127.0.2.1" 8
-- False
-- >>> makeAddrRange ("2001:DB8::1" :: IPv6) 16 >:> makeAddrRange "2001:DB8::1" 32
-- True
-- >>> makeAddrRange ("2001:DB8::1" :: IPv6) 32 >:> makeAddrRange "2001:DB8::1" 16
-- False
(>:>) :: Addr a => AddrRange a -> AddrRange a -> Bool
a >:> b = mlen a <= mlen b && (addr b `masked` mask a) == addr a
-- |
-- The 'isMatchedTo' function take an 'Addr' address and an 'AddrRange',
-- and returns 'True' if the range contains the address.
--
-- >>> ("127.0.2.0" :: IPv4) `isMatchedTo` makeAddrRange "127.0.2.1" 24
-- True
-- >>> ("127.0.2.0" :: IPv4) `isMatchedTo` makeAddrRange "127.0.2.1" 32
-- False
-- >>> ("2001:DB8::1" :: IPv6) `isMatchedTo` makeAddrRange "2001:DB8::1" 32
-- True
-- >>> ("2001:DB8::" :: IPv6) `isMatchedTo` makeAddrRange "2001:DB8::1" 128
-- False
isMatchedTo :: Addr a => a -> AddrRange a -> Bool
isMatchedTo a r = a `masked` mask r == addr r
-- |
-- The 'makeAddrRange' functions takes an 'Addr' address and a mask
-- length. It creates a bit mask from the mask length and masks
-- the 'Addr' address, then returns 'AddrRange' made of them.
--
-- >>> makeAddrRange (toIPv4 [127,0,2,1]) 8
-- 127.0.0.0/8
-- >>> makeAddrRange (toIPv6 [0x2001,0xDB8,0,0,0,0,0,1]) 8
-- 2000::/8
makeAddrRange :: Addr a => a -> Int -> AddrRange a
makeAddrRange ad len = AddrRange adr msk len
where
msk = intToMask len
adr = ad `masked` msk
-- | Convert IPv4 range to IPV4-embedded-in-IPV6 range
ipv4RangeToIPv6 :: AddrRange IPv4 -> AddrRange IPv6
ipv4RangeToIPv6 range =
makeAddrRange
(toIPv6 [0, 0, 0, 0, 0, 0xffff, (i1 `shift` 8) .|. i2, (i3 `shift` 8) .|. i4])
(masklen + 96)
where
(ip, masklen) = addrRangePair range
[i1, i2, i3, i4] = fromIPv4 ip
-- |
-- The 'unmakeAddrRange' functions take a 'AddrRange' and
-- returns the network address and a mask length.
--
-- >>> addrRangePair ("127.0.0.0/8" :: AddrRange IPv4)
-- (127.0.0.0,8)
-- >>> addrRangePair ("2000::/8" :: AddrRange IPv6)
-- (2000::,8)
addrRangePair :: Addr a => AddrRange a -> (a, Int)
addrRangePair (AddrRange adr _ len) = (adr, len)