module Data.IP.Mask where

import Data.Bits
import Data.IP.Addr
import Data.Word

maskIPv4 :: Int -> IPv4
maskIPv4 :: Int -> IPv4
maskIPv4 Int
len =
    IPv4Addr -> IPv4
IP4 (IPv4Addr -> IPv4) -> IPv4Addr -> IPv4
forall a b. (a -> b) -> a -> b
$ IPv4Addr -> IPv4Addr
forall a. Bits a => a -> a
complement (IPv4Addr -> IPv4Addr) -> IPv4Addr -> IPv4Addr
forall a b. (a -> b) -> a -> b
$ IPv4Addr
0xffffffff IPv4Addr -> Int -> IPv4Addr
forall a. Bits a => a -> Int -> a
`shift` (-Int
len)

maskIPv6 :: Int -> IPv6
maskIPv6 :: Int -> IPv6
maskIPv6 Int
len =
    IPv6Addr -> IPv6
IP6 (IPv6Addr -> IPv6) -> IPv6Addr -> IPv6
forall a b. (a -> b) -> a -> b
$ (Word64, Word64) -> IPv6Addr
toIP6Addr ((Word64, Word64) -> IPv6Addr) -> (Word64, Word64) -> IPv6Addr
forall a b. (a -> b) -> a -> b
$ (Word64 -> Word64) -> (Word64, Word64) -> (Word64, Word64)
forall t b. (t -> b) -> (t, t) -> (b, b)
bimapTup Word64 -> Word64
forall a. Bits a => a -> a
complement ((Word64, Word64) -> (Word64, Word64))
-> (Word64, Word64) -> (Word64, Word64)
forall a b. (a -> b) -> a -> b
$
            (Word64
0xffffffffffffffff, Word64
0xffffffffffffffff) (Word64, Word64) -> Int -> (Word64, Word64)
`shift128` (-Int
len)
 where
   bimapTup :: (t -> b) -> (t, t) -> (b, b)
bimapTup t -> b
f (t
x,t
y) = (t -> b
f t
x, t -> b
f t
y)

shift128 :: (Word64, Word64) -> Int -> (Word64, Word64)
shift128 :: (Word64, Word64) -> Int -> (Word64, Word64)
shift128 (Word64, Word64)
x Int
i
    | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0  = (Word64, Word64)
x (Word64, Word64) -> Int -> (Word64, Word64)
`shiftR128` (-Int
i)
    | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0  = (Word64, Word64)
x (Word64, Word64) -> Int -> (Word64, Word64)
`shiftL128` Int
i
    | Bool
otherwise = (Word64, Word64)
x

shiftL128 :: (Word64, Word64) -> Int -> (Word64, Word64)
shiftL128 :: (Word64, Word64) -> Int -> (Word64, Word64)
shiftL128 (Word64
h, Word64
l) Int
i =
        ( (Word64
h Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
i) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word64
l Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shift` (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
64) ), (Word64
l Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
i))

shiftR128 :: (Word64, Word64) -> Int -> (Word64, Word64)
shiftR128 :: (Word64, Word64) -> Int -> (Word64, Word64)
shiftR128 (Word64
h, Word64
l) Int
i =
    (Word64
h Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
i, (Word64
l Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
i) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word64
h Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shift` (Int
64 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
i) )

fromIP6Addr :: IPv6Addr -> (Word64, Word64)
fromIP6Addr :: IPv6Addr -> (Word64, Word64)
fromIP6Addr (IPv4Addr
w3, IPv4Addr
w2, IPv4Addr
w1, IPv4Addr
w0) =
   ( (IPv4Addr -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral IPv4Addr
w3 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
32) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. IPv4Addr -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral IPv4Addr
w2
   , (IPv4Addr -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral IPv4Addr
w1 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
32) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. IPv4Addr -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral IPv4Addr
w0
   )

toIP6Addr :: (Word64, Word64) -> IPv6Addr
toIP6Addr :: (Word64, Word64) -> IPv6Addr
toIP6Addr (Word64
h, Word64
l) =
    ( Word64 -> IPv4Addr
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> IPv4Addr) -> Word64 -> IPv4Addr
forall a b. (a -> b) -> a -> b
$ (Word64
h Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
32) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
m
    , Word64 -> IPv4Addr
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> IPv4Addr) -> Word64 -> IPv4Addr
forall a b. (a -> b) -> a -> b
$ Word64
h Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
m
    , Word64 -> IPv4Addr
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> IPv4Addr) -> Word64 -> IPv4Addr
forall a b. (a -> b) -> a -> b
$ (Word64
l Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
32) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
m
    , Word64 -> IPv4Addr
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> IPv4Addr) -> Word64 -> IPv4Addr
forall a b. (a -> b) -> a -> b
$ Word64
l Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
m
    )
  where m :: Word64
m = Word64
0xffffffff