module Arbor.File.Format.Asif.Data.Ip
( stringToIpv4
, stringToIpv6
, ipv4ToString
, ipv4CidrToString
, isIpv4
, ipv6ToString
, ipv6toStringCollapseV4
, ipv6CidrToString
, ipv6CidrToStringCollapseV4
, word32ToIpv4
, word32x4ToIpv6
, ipv4ToWord32
, ipv6ToWord32x4
, ipv4ToIpv6
, word64ToIpList
) where
import Arbor.File.Format.Asif.Data.Read
import Control.Lens ((&))
import Data.Word
import HaskellWorks.Data.Bits.BitWise
import Text.Read
import qualified Data.Bits as B
import qualified HaskellWorks.Data.Network.Ip.Ipv4 as IP4
import qualified HaskellWorks.Data.Network.Ip.Ipv6 as IP6
stringToIpv4 :: String -> Maybe IP4.IpAddress
stringToIpv4 str = if '.' `elem` str
then readMaybe str
else word32ToIpv4 <$> stringToAnyDigits str
stringToIpv6 :: String -> Maybe IP6.IpAddress
stringToIpv6 = readMaybe
ipv4ToString :: IP4.IpAddress -> String
ipv4ToString = IP4.showIpAddress
ipv4CidrToString :: IP4.IpBlock v -> String
ipv4CidrToString = show
isIpv4 :: IP6.IpAddress -> Maybe IP4.IpAddress
isIpv4 ip =
let (a, b, c, d) = ipv6ToWord32x4 ip
in if a == 0 && b == 0 && c == 0xFFFF
then Just $ IP4.IpAddress d
else Nothing
ipv6ToString :: IP6.IpAddress -> String
ipv6ToString = IP6.showIpAddress
ipv6toStringCollapseV4 :: IP6.IpAddress -> String
ipv6toStringCollapseV4 ip
= case isIpv4 ip of
Just d -> d & ipv4ToString
_ -> ip & ipv6ToString
ipv6CidrToString :: IP6.IpBlock v -> String
ipv6CidrToString = show
ipv6CidrToStringCollapseV4 :: IP6.IpBlock v -> String
ipv6CidrToStringCollapseV4 block =
let IP6.IpBlock ip (IP6.IpNetMask m) = block
in case isIpv4 ip of
Just d -> ipv4CidrToString $ IP4.IpBlock d (IP4.IpNetMask m)
Nothing -> ipv6CidrToString block
word32ToIpv4 :: Word32 -> IP4.IpAddress
word32ToIpv4 = IP4.IpAddress
word32x4ToIpv6 :: (Word32, Word32, Word32, Word32) -> IP6.IpAddress
word32x4ToIpv6 = IP6.IpAddress
ipv4ToWord32 :: IP4.IpAddress -> Word32
ipv4ToWord32 = IP4.word
ipv6ToWord32x4 :: IP6.IpAddress -> (Word32, Word32, Word32, Word32)
ipv6ToWord32x4 (IP6.IpAddress w128) = w128
ipv4ToIpv6 :: IP4.IpAddress -> IP6.IpAddress
ipv4ToIpv6 = IP6.fromIpv4
word64ToIpList :: Int -> Word64 -> [Word32] -> [Word32]
word64ToIpList _ 0 = id
word64ToIpList o w = (ip:) . word64ToIpList o (w .&. comp b)
where p = B.countTrailingZeros w
hi = o .<. 6
ip = fromIntegral (p .|. hi)
b = 1 .<. fromIntegral p