hw-ip 0.4.2 → 1.0.0.0
raw patch · 9 files changed
+410/−214 lines, 9 filesdep +appardep +iproutedep ~attoparsecdep ~basedep ~generic-lensPVP ok
version bump matches the API change (PVP)
Dependencies added: appar, iproute
Dependency ranges changed: attoparsec, base, generic-lens, hedgehog, hspec, hw-bits, hw-hspec-hedgehog, text
API changes (from Hackage documentation)
- HaskellWorks.Data.Network.Ip: Ipv4Address :: Word32 -> Ipv4Address
- HaskellWorks.Data.Network.Ip: Ipv4Block :: !Ipv4Address -> !Ipv4NetMask -> Ipv4Block
- HaskellWorks.Data.Network.Ip: Ipv4NetMask :: Word8 -> Ipv4NetMask
- HaskellWorks.Data.Network.Ip: bitPower :: Ipv4NetMask -> Word64
- HaskellWorks.Data.Network.Ip: blockSize :: Ipv4Block -> Int
- HaskellWorks.Data.Network.Ip: data Ipv4Block
- HaskellWorks.Data.Network.Ip: firstIpv4Address :: Ipv4Block -> Ipv4Address
- HaskellWorks.Data.Network.Ip: ipv4AddressToString :: Ipv4Address -> String
- HaskellWorks.Data.Network.Ip: ipv4AddressToText :: Ipv4Address -> Text
- HaskellWorks.Data.Network.Ip: ipv4AddressToWords :: Ipv4Address -> (Word8, Word8, Word8, Word8)
- HaskellWorks.Data.Network.Ip: isCanonical :: Ipv4Block -> Bool
- HaskellWorks.Data.Network.Ip: lastIpv4Address :: Ipv4Block -> Ipv4Address
- HaskellWorks.Data.Network.Ip: newtype Ipv4Address
- HaskellWorks.Data.Network.Ip: newtype Ipv4NetMask
- HaskellWorks.Data.Network.Ip: splitBlock :: Ipv4Block -> Maybe (Ipv4Block, Ipv4Block)
- HaskellWorks.Data.Network.Ip: textToMaybeIpv4Address :: Text -> Maybe Ipv4Address
- HaskellWorks.Data.Network.Ip.Parser.Text: ipv4Address :: Parser Ipv4Address
- HaskellWorks.Data.Network.Ip.Type: [$sel:word:Ipv4NetMask] :: Ipv4NetMask -> Word8
- HaskellWorks.Data.Network.Ip.Type: instance GHC.Classes.Eq HaskellWorks.Data.Network.Ip.Type.Ipv4Address
- HaskellWorks.Data.Network.Ip.Type: instance GHC.Classes.Eq HaskellWorks.Data.Network.Ip.Type.Ipv4Block
- HaskellWorks.Data.Network.Ip.Type: instance GHC.Classes.Eq HaskellWorks.Data.Network.Ip.Type.Ipv4NetMask
- HaskellWorks.Data.Network.Ip.Type: instance GHC.Classes.Ord HaskellWorks.Data.Network.Ip.Type.Ipv4Address
- HaskellWorks.Data.Network.Ip.Type: instance GHC.Classes.Ord HaskellWorks.Data.Network.Ip.Type.Ipv4Block
- HaskellWorks.Data.Network.Ip.Type: instance GHC.Classes.Ord HaskellWorks.Data.Network.Ip.Type.Ipv4NetMask
- HaskellWorks.Data.Network.Ip.Type: instance GHC.Enum.Enum HaskellWorks.Data.Network.Ip.Type.Ipv4Address
- HaskellWorks.Data.Network.Ip.Type: instance GHC.Enum.Enum HaskellWorks.Data.Network.Ip.Type.Ipv4NetMask
- HaskellWorks.Data.Network.Ip.Type: instance GHC.Generics.Generic HaskellWorks.Data.Network.Ip.Type.Ipv4Address
- HaskellWorks.Data.Network.Ip.Type: instance GHC.Generics.Generic HaskellWorks.Data.Network.Ip.Type.Ipv4NetMask
- HaskellWorks.Data.Network.Ip.Type: instance GHC.Read.Read HaskellWorks.Data.Network.Ip.Type.Ipv4Address
- HaskellWorks.Data.Network.Ip.Type: instance GHC.Read.Read HaskellWorks.Data.Network.Ip.Type.Ipv4Block
- HaskellWorks.Data.Network.Ip.Type: instance GHC.Show.Show HaskellWorks.Data.Network.Ip.Type.Ipv4Address
- HaskellWorks.Data.Network.Ip.Type: instance GHC.Show.Show HaskellWorks.Data.Network.Ip.Type.Ipv4Block
- HaskellWorks.Data.Network.Ip.Type: instance GHC.Show.Show HaskellWorks.Data.Network.Ip.Type.Ipv4NetMask
+ HaskellWorks.Data.Network.Ip.Internal: word32x4ToWords :: (Word32, Word32, Word32, Word32) -> [Word32]
+ HaskellWorks.Data.Network.Ip.Ip: IpBlockV4 :: Ipv4Block -> IpBlock
+ HaskellWorks.Data.Network.Ip.Ip: IpBlockV6 :: Ipv6Block -> IpBlock
+ HaskellWorks.Data.Network.Ip.Ip: data IpBlock
+ HaskellWorks.Data.Network.Ip.Ip: firstAddress :: IpBlock -> (Word32, Word32, Word32, Word32)
+ HaskellWorks.Data.Network.Ip.Ip: instance GHC.Classes.Eq HaskellWorks.Data.Network.Ip.Ip.IpBlock
+ HaskellWorks.Data.Network.Ip.Ip: instance GHC.Classes.Ord HaskellWorks.Data.Network.Ip.Ip.IpBlock
+ HaskellWorks.Data.Network.Ip.Ip: instance GHC.Generics.Generic HaskellWorks.Data.Network.Ip.Ip.IpBlock
+ HaskellWorks.Data.Network.Ip.Ip: instance GHC.Read.Read HaskellWorks.Data.Network.Ip.Ip.IpBlock
+ HaskellWorks.Data.Network.Ip.Ip: instance GHC.Show.Show HaskellWorks.Data.Network.Ip.Ip.IpBlock
+ HaskellWorks.Data.Network.Ip.Ip: isValidIpBlock :: IpBlock -> Bool
+ HaskellWorks.Data.Network.Ip.Ip: lastAddress :: IpBlock -> (Word32, Word32, Word32, Word32)
+ HaskellWorks.Data.Network.Ip.Ipv4: Ipv4Address :: Word32 -> Ipv4Address
+ HaskellWorks.Data.Network.Ip.Ipv4: Ipv4Block :: !Ipv4Address -> !Ipv4NetMask -> Ipv4Block
+ HaskellWorks.Data.Network.Ip.Ipv4: Ipv4NetMask :: Word8 -> Ipv4NetMask
+ HaskellWorks.Data.Network.Ip.Ipv4: [$sel:base:Ipv4Block] :: Ipv4Block -> !Ipv4Address
+ HaskellWorks.Data.Network.Ip.Ipv4: [$sel:mask:Ipv4Block] :: Ipv4Block -> !Ipv4NetMask
+ HaskellWorks.Data.Network.Ip.Ipv4: [$sel:word8:Ipv4NetMask] :: Ipv4NetMask -> Word8
+ HaskellWorks.Data.Network.Ip.Ipv4: [$sel:word:Ipv4Address] :: Ipv4Address -> Word32
+ HaskellWorks.Data.Network.Ip.Ipv4: bitPower :: Ipv4NetMask -> Word64
+ HaskellWorks.Data.Network.Ip.Ipv4: blockSize :: Ipv4Block -> Int
+ HaskellWorks.Data.Network.Ip.Ipv4: data Ipv4Block
+ HaskellWorks.Data.Network.Ip.Ipv4: firstIpv4Address :: Ipv4Block -> Ipv4Address
+ HaskellWorks.Data.Network.Ip.Ipv4: instance GHC.Classes.Eq HaskellWorks.Data.Network.Ip.Ipv4.Ipv4Address
+ HaskellWorks.Data.Network.Ip.Ipv4: instance GHC.Classes.Eq HaskellWorks.Data.Network.Ip.Ipv4.Ipv4Block
+ HaskellWorks.Data.Network.Ip.Ipv4: instance GHC.Classes.Eq HaskellWorks.Data.Network.Ip.Ipv4.Ipv4NetMask
+ HaskellWorks.Data.Network.Ip.Ipv4: instance GHC.Classes.Ord HaskellWorks.Data.Network.Ip.Ipv4.Ipv4Address
+ HaskellWorks.Data.Network.Ip.Ipv4: instance GHC.Classes.Ord HaskellWorks.Data.Network.Ip.Ipv4.Ipv4Block
+ HaskellWorks.Data.Network.Ip.Ipv4: instance GHC.Classes.Ord HaskellWorks.Data.Network.Ip.Ipv4.Ipv4NetMask
+ HaskellWorks.Data.Network.Ip.Ipv4: instance GHC.Enum.Enum HaskellWorks.Data.Network.Ip.Ipv4.Ipv4Address
+ HaskellWorks.Data.Network.Ip.Ipv4: instance GHC.Enum.Enum HaskellWorks.Data.Network.Ip.Ipv4.Ipv4NetMask
+ HaskellWorks.Data.Network.Ip.Ipv4: instance GHC.Generics.Generic HaskellWorks.Data.Network.Ip.Ipv4.Ipv4Address
+ HaskellWorks.Data.Network.Ip.Ipv4: instance GHC.Generics.Generic HaskellWorks.Data.Network.Ip.Ipv4.Ipv4NetMask
+ HaskellWorks.Data.Network.Ip.Ipv4: instance GHC.Read.Read HaskellWorks.Data.Network.Ip.Ipv4.Ipv4Address
+ HaskellWorks.Data.Network.Ip.Ipv4: instance GHC.Read.Read HaskellWorks.Data.Network.Ip.Ipv4.Ipv4Block
+ HaskellWorks.Data.Network.Ip.Ipv4: instance GHC.Show.Show HaskellWorks.Data.Network.Ip.Ipv4.Ipv4Address
+ HaskellWorks.Data.Network.Ip.Ipv4: instance GHC.Show.Show HaskellWorks.Data.Network.Ip.Ipv4.Ipv4Block
+ HaskellWorks.Data.Network.Ip.Ipv4: instance GHC.Show.Show HaskellWorks.Data.Network.Ip.Ipv4.Ipv4NetMask
+ HaskellWorks.Data.Network.Ip.Ipv4: ipv4AddressToString :: Ipv4Address -> String
+ HaskellWorks.Data.Network.Ip.Ipv4: ipv4AddressToText :: Ipv4Address -> Text
+ HaskellWorks.Data.Network.Ip.Ipv4: ipv4AddressToWords :: Ipv4Address -> (Word8, Word8, Word8, Word8)
+ HaskellWorks.Data.Network.Ip.Ipv4: isCanonical :: Ipv4Block -> Bool
+ HaskellWorks.Data.Network.Ip.Ipv4: isValidIpv4Block :: Ipv4Block -> Bool
+ HaskellWorks.Data.Network.Ip.Ipv4: lastIpv4Address :: Ipv4Block -> Ipv4Address
+ HaskellWorks.Data.Network.Ip.Ipv4: newtype Ipv4Address
+ HaskellWorks.Data.Network.Ip.Ipv4: newtype Ipv4NetMask
+ HaskellWorks.Data.Network.Ip.Ipv4: parseIpv4Address :: Parser Ipv4Address
+ HaskellWorks.Data.Network.Ip.Ipv4: splitBlock :: Ipv4Block -> Maybe (Ipv4Block, Ipv4Block)
+ HaskellWorks.Data.Network.Ip.Ipv4: textToMaybeIpv4Address :: Text -> Maybe Ipv4Address
+ HaskellWorks.Data.Network.Ip.Ipv6: Ipv6Address :: (Word32, Word32, Word32, Word32) -> Ipv6Address
+ HaskellWorks.Data.Network.Ip.Ipv6: Ipv6Block :: !Ipv6Address -> !Ipv6NetMask -> Ipv6Block
+ HaskellWorks.Data.Network.Ip.Ipv6: Ipv6NetMask :: Word8 -> Ipv6NetMask
+ HaskellWorks.Data.Network.Ip.Ipv6: [$sel:base:Ipv6Block] :: Ipv6Block -> !Ipv6Address
+ HaskellWorks.Data.Network.Ip.Ipv6: [$sel:mask:Ipv6Block] :: Ipv6Block -> !Ipv6NetMask
+ HaskellWorks.Data.Network.Ip.Ipv6: [$sel:word:Ipv6NetMask] :: Ipv6NetMask -> Word8
+ HaskellWorks.Data.Network.Ip.Ipv6: [$sel:words:Ipv6Address] :: Ipv6Address -> (Word32, Word32, Word32, Word32)
+ HaskellWorks.Data.Network.Ip.Ipv6: data Ipv6Block
+ HaskellWorks.Data.Network.Ip.Ipv6: instance GHC.Classes.Eq HaskellWorks.Data.Network.Ip.Ipv6.Ipv6Address
+ HaskellWorks.Data.Network.Ip.Ipv6: instance GHC.Classes.Eq HaskellWorks.Data.Network.Ip.Ipv6.Ipv6Block
+ HaskellWorks.Data.Network.Ip.Ipv6: instance GHC.Classes.Eq HaskellWorks.Data.Network.Ip.Ipv6.Ipv6NetMask
+ HaskellWorks.Data.Network.Ip.Ipv6: instance GHC.Classes.Ord HaskellWorks.Data.Network.Ip.Ipv6.Ipv6Address
+ HaskellWorks.Data.Network.Ip.Ipv6: instance GHC.Classes.Ord HaskellWorks.Data.Network.Ip.Ipv6.Ipv6Block
+ HaskellWorks.Data.Network.Ip.Ipv6: instance GHC.Classes.Ord HaskellWorks.Data.Network.Ip.Ipv6.Ipv6NetMask
+ HaskellWorks.Data.Network.Ip.Ipv6: instance GHC.Enum.Enum HaskellWorks.Data.Network.Ip.Ipv6.Ipv6NetMask
+ HaskellWorks.Data.Network.Ip.Ipv6: instance GHC.Generics.Generic HaskellWorks.Data.Network.Ip.Ipv6.Ipv6Address
+ HaskellWorks.Data.Network.Ip.Ipv6: instance GHC.Generics.Generic HaskellWorks.Data.Network.Ip.Ipv6.Ipv6Block
+ HaskellWorks.Data.Network.Ip.Ipv6: instance GHC.Generics.Generic HaskellWorks.Data.Network.Ip.Ipv6.Ipv6NetMask
+ HaskellWorks.Data.Network.Ip.Ipv6: instance GHC.Read.Read HaskellWorks.Data.Network.Ip.Ipv6.Ipv6Address
+ HaskellWorks.Data.Network.Ip.Ipv6: instance GHC.Read.Read HaskellWorks.Data.Network.Ip.Ipv6.Ipv6Block
+ HaskellWorks.Data.Network.Ip.Ipv6: instance GHC.Read.Read HaskellWorks.Data.Network.Ip.Ipv6.Ipv6NetMask
+ HaskellWorks.Data.Network.Ip.Ipv6: instance GHC.Show.Show HaskellWorks.Data.Network.Ip.Ipv6.Ipv6Address
+ HaskellWorks.Data.Network.Ip.Ipv6: instance GHC.Show.Show HaskellWorks.Data.Network.Ip.Ipv6.Ipv6Block
+ HaskellWorks.Data.Network.Ip.Ipv6: instance GHC.Show.Show HaskellWorks.Data.Network.Ip.Ipv6.Ipv6NetMask
+ HaskellWorks.Data.Network.Ip.Ipv6: ipv4BlockToMappedIpv6Block :: Ipv4Block -> Ipv6Block
+ HaskellWorks.Data.Network.Ip.Ipv6: isValidIpv6Block :: Ipv6Block -> Bool
+ HaskellWorks.Data.Network.Ip.Ipv6: masksIpv6 :: Word8 -> [Word32]
+ HaskellWorks.Data.Network.Ip.Ipv6: newtype Ipv6Address
+ HaskellWorks.Data.Network.Ip.Ipv6: newtype Ipv6NetMask
+ HaskellWorks.Data.Network.Ip.Ipv6: parseIpv6Block :: Text -> Either Text Ipv6Block
+ HaskellWorks.Data.Network.Ip.Type: Ipv6Address :: (Word32, Word32, Word32, Word32) -> Ipv6Address
+ HaskellWorks.Data.Network.Ip.Type: Ipv6Block :: !Ipv6Address -> !Ipv6NetMask -> Ipv6Block
+ HaskellWorks.Data.Network.Ip.Type: Ipv6NetMask :: Word8 -> Ipv6NetMask
+ HaskellWorks.Data.Network.Ip.Type: [$sel:base:Ipv6Block] :: Ipv6Block -> !Ipv6Address
+ HaskellWorks.Data.Network.Ip.Type: [$sel:mask:Ipv6Block] :: Ipv6Block -> !Ipv6NetMask
+ HaskellWorks.Data.Network.Ip.Type: [$sel:word8:Ipv4NetMask] :: Ipv4NetMask -> Word8
+ HaskellWorks.Data.Network.Ip.Type: [$sel:word:Ipv6NetMask] :: Ipv6NetMask -> Word8
+ HaskellWorks.Data.Network.Ip.Type: [$sel:words:Ipv6Address] :: Ipv6Address -> (Word32, Word32, Word32, Word32)
+ HaskellWorks.Data.Network.Ip.Type: data Ipv6Block
+ HaskellWorks.Data.Network.Ip.Type: newtype Ipv6Address
+ HaskellWorks.Data.Network.Ip.Type: newtype Ipv6NetMask
Files
- hw-ip.cabal +53/−54
- src/HaskellWorks/Data/Network/Ip.hs +6/−70
- src/HaskellWorks/Data/Network/Ip/Internal.hs +6/−3
- src/HaskellWorks/Data/Network/Ip/Ip.hs +64/−0
- src/HaskellWorks/Data/Network/Ip/Ipv4.hs +140/−0
- src/HaskellWorks/Data/Network/Ip/Ipv6.hs +124/−0
- src/HaskellWorks/Data/Network/Ip/Parser/Text.hs +0/−10
- src/HaskellWorks/Data/Network/Ip/Type.hs +8/−69
- test/HaskellWorks/Data/Network/IpSpec.hs +9/−8
hw-ip.cabal view
@@ -1,65 +1,64 @@--- This file has been generated from package.yaml by hpack version 0.18.1.------ see: https://github.com/sol/hpack--name: hw-ip-version: 0.4.2-synopsis: Library for manipulating IP addresses and CIDR blocks-description: Please see README.md-category: Network-homepage: https://github.com/haskell-works/hw-ip#readme-bug-reports: https://github.com/haskell-works/hw-ip/issues-author: John Ky,- David Turnbull,- Jian Wan-maintainer: newhoggy@gmail.com-copyright: 2018 John Ky-license: BSD3-license-file: LICENSE-build-type: Simple-cabal-version: >= 1.10-+cabal-version: 1.12+name: hw-ip+version: 1.0.0.0+license: BSD3+license-file: LICENSE+copyright: 2018 John Ky, David Turnbull, Jian Wan+maintainer: newhoggy@gmail.com+author: John Ky,+ David Turnbull,+ Jian Wan+homepage: https://github.com/haskell-works/hw-ip#readme+bug-reports: https://github.com/haskell-works/hw-ip/issues+synopsis: Library for manipulating IP addresses and CIDR blocks+description:+ Please see README.md+category: Network+build-type: Simple extra-source-files: README.md source-repository head- type: git- location: https://github.com/haskell-works/hw-ip+ type: git+ location: https://github.com/haskell-works/hw-ip library- hs-source-dirs:- src- build-depends:- attoparsec- , generic-lens- , hw-bits- , text- , base >=4.7 && <5- exposed-modules:+ exposed-modules: HaskellWorks.Data.Network.Ip+ HaskellWorks.Data.Network.Ip.Ip+ HaskellWorks.Data.Network.Ip.Ipv6 HaskellWorks.Data.Network.Ip.Internal- HaskellWorks.Data.Network.Ip.Parser.Text+ HaskellWorks.Data.Network.Ip.Ipv4 HaskellWorks.Data.Network.Ip.Type- other-modules:- Paths_hw_ip- default-language: Haskell2010+ hs-source-dirs: src+ other-modules:+ Paths_hw_ip+ default-language: Haskell2010+ build-depends:+ base >= 4 && < 4.13+ , appar >= 0.1.7 && < 0.2+ , attoparsec >= 0.13.2.2 && < 0.14+ , generic-lens >= 0.5.1.0 && < 1.2+ , hw-bits >= 0.7.0.2 && < 0.8+ , iproute >= 1.7.3 && < 1.8+ , text >= 1.2.2.2 && < 1.3 test-suite hw-ip-test- type: exitcode-stdio-1.0- main-is: Spec.hs- hs-source-dirs:- test- ghc-options: -threaded -rtsopts -with-rtsopts=-N- build-depends:- attoparsec- , generic-lens- , hw-bits- , text- , base- , hedgehog- , hw-hspec-hedgehog- , hw-ip- , hspec- other-modules:- HaskellWorks.Data.Network.IpSpec- default-language: Haskell2010+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ hs-source-dirs: test+ other-modules:+ HaskellWorks.Data.Network.IpSpec+ Paths_hw_ip+ default-language: Haskell2010+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ base >= 4 && < 4.13+ , attoparsec+ , generic-lens+ , hedgehog >= 0.5.3 && < 0.7+ , hspec >= 2.4.4 && < 2.6+ , hw-bits+ , hw-hspec-hedgehog >= 0.1.0.2 && < 0.2+ , hw-ip+ , text
src/HaskellWorks/Data/Network/Ip.hs view
@@ -1,73 +1,9 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE DuplicateRecordFields #-}- module HaskellWorks.Data.Network.Ip- ( Z.Ipv4Address(Ipv4Address)- , Z.Ipv4NetMask(Ipv4NetMask)- , Z.Ipv4Block(Ipv4Block)- , bitPower- , blockSize- , isCanonical- , splitBlock- , textToMaybeIpv4Address- , ipv4AddressToString- , ipv4AddressToText- , ipv4AddressToWords- , firstIpv4Address- , lastIpv4Address+ ( module X ) where -import Control.Monad-import Data.Word-import GHC.Generics-import HaskellWorks.Data.Bits.BitWise--import qualified Data.Attoparsec.Text as AP-import qualified Data.Text as T-import qualified HaskellWorks.Data.Network.Ip.Internal as I-import qualified HaskellWorks.Data.Network.Ip.Parser.Text as APT-import qualified HaskellWorks.Data.Network.Ip.Type as Z--bitPower :: Z.Ipv4NetMask -> Word64-bitPower (Z.Ipv4NetMask m) = fromIntegral (32 - m)--isCanonical :: Z.Ipv4Block -> Bool-isCanonical (Z.Ipv4Block (Z.Ipv4Address b) m) = ((b .>. bitPower m) .<. bitPower m) == b--splitBlock :: Z.Ipv4Block -> Maybe (Z.Ipv4Block, Z.Ipv4Block)-splitBlock (Z.Ipv4Block (Z.Ipv4Address b) (Z.Ipv4NetMask m)) =- if m >= 0 && m < 32- then let !hm = m + 1- !halfMask = Z.Ipv4NetMask hm- !c = fromIntegral ((0x100000000 :: Word64) .>. fromIntegral (m + 1))- in Just- ( Z.Ipv4Block (Z.Ipv4Address b ) halfMask- , Z.Ipv4Block (Z.Ipv4Address (b + c)) halfMask- )- else Nothing--blockSize :: Z.Ipv4Block -> Int-blockSize (Z.Ipv4Block _ m) = 2 ^ bitPower m--firstIpv4Address :: Z.Ipv4Block -> Z.Ipv4Address-firstIpv4Address (Z.Ipv4Block base _) = base--lastIpv4Address :: Z.Ipv4Block -> Z.Ipv4Address-lastIpv4Address b@(Z.Ipv4Block (Z.Ipv4Address base) _) = Z.Ipv4Address (base + fromIntegral (blockSize b) - 1)--textToMaybeIpv4Address :: T.Text -> Maybe Z.Ipv4Address-textToMaybeIpv4Address t = AP.maybeResult =<< AP.parseWith (return mempty) APT.ipv4Address t--ipv4AddressToString :: Z.Ipv4Address -> String-ipv4AddressToString = show--ipv4AddressToText :: Z.Ipv4Address -> T.Text-ipv4AddressToText = T.pack . ipv4AddressToString--ipv4AddressToWords :: Z.Ipv4Address -> (Word8, Word8, Word8, Word8)-ipv4AddressToWords (Z.Ipv4Address w) =- ( fromIntegral (w .>. 24) .&. 0xff- , fromIntegral (w .>. 16) .&. 0xff- , fromIntegral (w .>. 8) .&. 0xff- , fromIntegral (w .&. 0xff)- )+import HaskellWorks.Data.Network.Ip.Internal as X+import HaskellWorks.Data.Network.Ip.Ip as X+import HaskellWorks.Data.Network.Ip.Ipv4 as X+import HaskellWorks.Data.Network.Ip.Ipv6 as X+import HaskellWorks.Data.Network.Ip.Type as X
src/HaskellWorks/Data/Network/Ip/Internal.hs view
@@ -29,6 +29,9 @@ <|> ds 1 9 #<*># ds 0 9 <|> ds 0 9 +whitespace :: AP.Parser ()+whitespace = void $ many (AP.satisfy isSpace)+ ipv4Address :: AP.Parser Word32 ipv4Address = fourOctetsToWord32 <$> (octet <* AP.char '.')@@ -36,9 +39,6 @@ <*> (octet <* AP.char '.') <*> octet -whitespace :: AP.Parser ()-whitespace = void $ many (AP.satisfy isSpace)- ipv4NetMask :: AP.Parser Word8 ipv4NetMask = d 3 #<*># ds 0 2 <|> d 2 #<*># ds 0 9@@ -57,3 +57,6 @@ _ <- AP.char '/' mask <- ipv4NetMask return (addr, mask)++word32x4ToWords :: (Word32, Word32, Word32, Word32) -> [Word32]+word32x4ToWords (a, b, c, d) = [a, b, c, d]
+ src/HaskellWorks/Data/Network/Ip/Ip.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE OverloadedStrings #-}++module HaskellWorks.Data.Network.Ip.Ip+ ( IpBlock(..)+ , isValidIpBlock+ , firstAddress+ , lastAddress+ ) where++import Control.Applicative+import Control.Monad+import Data.Char+import Data.Maybe+import Data.Word+import GHC.Generics+import HaskellWorks.Data.Bits.BitWise+import Text.Read++import qualified Data.Attoparsec.Text as AP+import qualified Data.Bits as B+import qualified Data.Text as T+import qualified HaskellWorks.Data.Network.Ip.Internal as I+import qualified HaskellWorks.Data.Network.Ip.Ipv4 as I4+import qualified HaskellWorks.Data.Network.Ip.Ipv6 as I6+import qualified Text.ParserCombinators.ReadPrec as RP++data IpBlock = IpBlockV4 I4.Ipv4Block | IpBlockV6 I6.Ipv6Block+ deriving (Eq, Ord, Generic)++instance Show IpBlock where+ showsPrec _ (IpBlockV4 a) = shows a+ showsPrec _ (IpBlockV6 a) = shows a++instance Read IpBlock where+ readsPrec _ s =+ case readMaybe s :: Maybe I4.Ipv4Block of+ Just ipv4 -> [(IpBlockV4 ipv4, "")]++ Nothing ->+ case readMaybe s :: Maybe I6.Ipv6Block of+ Just ipv6 -> [(IpBlockV6 ipv6, "")]+ Nothing -> []++isValidIpBlock :: IpBlock -> Bool+isValidIpBlock (IpBlockV4 b) = I4.isValidIpv4Block b+isValidIpBlock (IpBlockV6 b) = I6.isValidIpv6Block b++firstAddress :: IpBlock -> (Word32, Word32, Word32, Word32)+firstAddress (IpBlockV4 i4b) = firstAddress (IpBlockV6 (I6.ipv4BlockToMappedIpv6Block i4b))+firstAddress (IpBlockV6 (I6.Ipv6Block ip _)) = I6.words ip++lastAddress :: IpBlock -> (Word32, Word32, Word32, Word32)+lastAddress (IpBlockV4 ib) = (0, 0, 0xFFFF, I4.word (I4.lastIpv4Address ib))+lastAddress (IpBlockV6 (I6.Ipv6Block ip (I6.Ipv6NetMask msk))) =+ let (w1, w2, w3, w4) = I6.words ip+ lt = I6.masksIpv6 $ fromIntegral msk+ w1' = w1 .|. (lt !! 0)+ w2' = w2 .|. (lt !! 1)+ w3' = w3 .|. (lt !! 2)+ w4' = w4 .|. (lt !! 3) in+ (w1', w2', w3', w4')
+ src/HaskellWorks/Data/Network/Ip/Ipv4.hs view
@@ -0,0 +1,140 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE InstanceSigs #-}++module HaskellWorks.Data.Network.Ip.Ipv4+ ( Ipv4Address(..)+ , Ipv4NetMask(..)+ , Ipv4Block(..)+ , isValidIpv4Block+ , bitPower+ , blockSize+ , isCanonical+ , splitBlock+ , textToMaybeIpv4Address+ , parseIpv4Address+ , ipv4AddressToString+ , ipv4AddressToText+ , ipv4AddressToWords+ , firstIpv4Address+ , lastIpv4Address+ ) where++import Control.Applicative+import Control.Monad+import Data.Char+import Data.Maybe+import Data.Word+import GHC.Generics+import HaskellWorks.Data.Bits.BitWise+import Text.Read++import qualified Data.Attoparsec.Text as AP+import qualified Data.Bits as B+import qualified Data.Text as T+import qualified HaskellWorks.Data.Network.Ip.Internal as I+import qualified Text.ParserCombinators.ReadPrec as RP++newtype Ipv4Address = Ipv4Address+ { word :: Word32+ } deriving (Enum, Eq, Ord, Generic)++instance Show Ipv4Address where+ showsPrec _ (Ipv4Address w) =+ shows ((w .>. 24) .&. 0xff) . ('.':) .+ shows ((w .>. 16) .&. 0xff) . ('.':) .+ shows ((w .>. 8) .&. 0xff) . ('.':) .+ shows ( w .&. 0xff)++instance Read Ipv4Address where+ readsPrec :: Int -> String -> [(Ipv4Address, String)]+ readsPrec _ s = case AP.parseWith (return mempty) (I.whitespace *> I.ipv4Address) (T.pack s) of+ Just result -> case result of+ AP.Done i r -> [(Ipv4Address r, T.unpack i)]+ AP.Partial _ -> []+ AP.Fail a b c -> []+ Nothing -> []++newtype Ipv4NetMask = Ipv4NetMask+ { word8 :: Word8+ } deriving (Enum, Eq, Ord, Show, Generic)++data Ipv4Block = Ipv4Block+ { base :: !Ipv4Address+ , mask :: !Ipv4NetMask+ } deriving (Eq, Ord)++instance Show Ipv4Block where+ showsPrec _ (Ipv4Block b (Ipv4NetMask m)) = shows b . ('/':) . shows m++instance Read Ipv4Block where+ readsPrec :: Int -> String -> [(Ipv4Block, String)]+ readsPrec _ s = case AP.parseWith (return mempty) (I.whitespace *> I.ipv4Block) (T.pack s) of+ Just result -> case result of+ AP.Done i (a, m) ->+ case validIpv4Block $ Ipv4Block (Ipv4Address a) (Ipv4NetMask m) of+ Just b -> [(b, T.unpack i)]+ Nothing -> []+ AP.Partial _ -> []+ AP.Fail a b c -> []+ Nothing -> []++-- shift the address left by the amount of mask bits to reveal only host bits+-- if any bits left are non-zero, then the mask is not big enough+validIpv4Block :: Ipv4Block -> Maybe Ipv4Block+validIpv4Block b@(Ipv4Block (Ipv4Address word) (Ipv4NetMask mask)) =+ if word `B.shiftL` fromIntegral mask `B.xor` 0 == 0+ then pure b+ else Nothing++isValidIpv4Block :: Ipv4Block -> Bool+isValidIpv4Block = isJust . validIpv4Block++firstIpv4Address :: Ipv4Block -> Ipv4Address+firstIpv4Address (Ipv4Block base _) = base++lastIpv4Address :: Ipv4Block -> Ipv4Address+lastIpv4Address b@(Ipv4Block (Ipv4Address base) _) = Ipv4Address (base + fromIntegral (blockSize b) - 1)++bitPower :: Ipv4NetMask -> Word64+bitPower (Ipv4NetMask m) = fromIntegral (32 - m)++isCanonical :: Ipv4Block -> Bool+isCanonical (Ipv4Block (Ipv4Address b) m) = ((b .>. bitPower m) .<. bitPower m) == b++splitBlock :: Ipv4Block -> Maybe (Ipv4Block, Ipv4Block)+splitBlock (Ipv4Block (Ipv4Address b) (Ipv4NetMask m)) =+ if m >= 0 && m < 32+ then let !hm = m + 1+ !halfMask = Ipv4NetMask hm+ !c = fromIntegral ((0x100000000 :: Word64) .>. fromIntegral (m + 1))+ in Just+ ( Ipv4Block (Ipv4Address b ) halfMask+ , Ipv4Block (Ipv4Address (b + c)) halfMask+ )+ else Nothing++blockSize :: Ipv4Block -> Int+blockSize (Ipv4Block _ m) = 2 ^ bitPower m++textToMaybeIpv4Address :: T.Text -> Maybe Ipv4Address+textToMaybeIpv4Address t = AP.maybeResult =<< AP.parseWith (return mempty) parseIpv4Address t++ipv4AddressToString :: Ipv4Address -> String+ipv4AddressToString = show++ipv4AddressToText :: Ipv4Address -> T.Text+ipv4AddressToText = T.pack . ipv4AddressToString++ipv4AddressToWords :: Ipv4Address -> (Word8, Word8, Word8, Word8)+ipv4AddressToWords (Ipv4Address w) =+ ( fromIntegral (w .>. 24) .&. 0xff+ , fromIntegral (w .>. 16) .&. 0xff+ , fromIntegral (w .>. 8) .&. 0xff+ , fromIntegral (w .&. 0xff)+ )++parseIpv4Address :: AP.Parser Ipv4Address+parseIpv4Address = Ipv4Address <$> I.ipv4Address
+ src/HaskellWorks/Data/Network/Ip/Ipv6.hs view
@@ -0,0 +1,124 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}++module HaskellWorks.Data.Network.Ip.Ipv6+ ( Ipv6Address(..)+ , Ipv6NetMask(..)+ , Ipv6Block(..)+ , ipv4BlockToMappedIpv6Block+ , parseIpv6Block+ , masksIpv6+ , isValidIpv6Block+ ) where++import Control.Applicative+import Control.Monad+import Data.Bits+import Data.Char+import Data.Generics.Product.Any+import Data.Maybe+import Data.Word+import GHC.Generics+import Prelude hiding (words)+import Text.Read++import qualified Data.Attoparsec.Text as AP+import qualified Data.Bits as B+import qualified Data.IP as D+import qualified Data.String as S+import qualified Data.Text as T+import qualified HaskellWorks.Data.Network.Ip.Internal as I+import qualified HaskellWorks.Data.Network.Ip.Ipv4 as I4+import qualified Text.ParserCombinators.ReadPrec as RP++newtype Ipv6Address = Ipv6Address+ { words :: (Word32, Word32, Word32, Word32)+ } deriving (Eq, Ord, Generic)++instance Show Ipv6Address where+ showsPrec _ (Ipv6Address w) = shows (D.fromHostAddress6 w)++instance Read Ipv6Address where+ readsPrec :: Int -> String -> [(Ipv6Address, String)]+ readsPrec _ s =+ case readMaybe s :: Maybe D.IPv6 of+ Just ip -> [(Ipv6Address (D.toHostAddress6 ip), "")]+ Nothing -> []++newtype Ipv6NetMask = Ipv6NetMask+ { word :: Word8+ } deriving (Enum, Eq, Ord, Show, Generic)++instance Read Ipv6NetMask where+ readsPrec _ s =+ case Ipv6NetMask <$> m of+ Just maskv6 -> [(maskv6, "")]+ Nothing -> []+ where+ m = mfilter (\a -> a >= 0 && a <= 128) (readMaybe s)++data Ipv6Block = Ipv6Block+ { base :: !Ipv6Address+ , mask :: !Ipv6NetMask+ } deriving (Eq, Ord, Generic)++instance Read Ipv6Block where+ readsPrec _ s =+ case T.unpack <$> T.split (== '/') (T.pack s) of+ [addr, mask] ->+ case readMaybe addr :: Maybe Ipv6Address of+ Just ipv6 ->+ case readMaybe mask of+ Just maskv6 ->+ let i6b = Ipv6Block ipv6 maskv6 in+ [(i6b, "") | isValidIpv6Block i6b]+ Nothing -> []+ Nothing -> []+ _ -> []++instance Show Ipv6Block where+ showsPrec _ (Ipv6Block b (Ipv6NetMask m)) = shows b . ('/':) . shows m++parseIpv6Block :: T.Text -> Either T.Text Ipv6Block+parseIpv6Block t =+ case T.unpack <$> T.split (== '/') t of+ [addr, mask] ->+ case readMaybe addr :: Maybe Ipv6Address of+ Just ipv6 ->+ case readMaybe mask of+ Just maskv6 -> Right $ Ipv6Block ipv6 maskv6+ Nothing -> Left "cannot read mask"+ Nothing -> Left "cannot read addr"+ _ -> Left "invalid input string"++masksIpv6 :: Word8 -> [Word32]+masksIpv6 m =+ let e = 0xFFFFFFFF :: Word32+ -- bits: number of bits which should be 1+ maskValue bits = e `shiftR` (32 - bits) in+ if m < 32 then+ [maskValue (32 - fromIntegral m), e, e, e]+ else if m < 64 then+ [0, maskValue (64 - fromIntegral m), e, e]+ else if m < 96 then+ [0, 0, maskValue (96 - fromIntegral m), e]+ else if m < 128 then+ [0, 0, 0, maskValue (128 - fromIntegral m)]+ else+ [0, 0, 0, 0]++isValidIpv6Block :: Ipv6Block -> Bool+isValidIpv6Block (Ipv6Block b (Ipv6NetMask m)) =+ let lt = masksIpv6 m+ ipv6 = I.word32x4ToWords (words b) in+ ipv6 == zipWith (.&.) ipv6 (zipWith xor ipv6 lt)++ipv4BlockToMappedIpv6Block :: I4.Ipv4Block -> Ipv6Block+ipv4BlockToMappedIpv6Block (I4.Ipv4Block b m) =+ -- RFC-4291, "IPv4-Mapped IPv6 Address"+ Ipv6Block (Ipv6Address (0, 0, 0xFFFF, I4.word b)) (Ipv6NetMask (96 + I4.word8 m))
− src/HaskellWorks/Data/Network/Ip/Parser/Text.hs
@@ -1,10 +0,0 @@-module HaskellWorks.Data.Network.Ip.Parser.Text- ( ipv4Address- ) where--import qualified Data.Attoparsec.Text as AP-import qualified HaskellWorks.Data.Network.Ip.Internal as I-import qualified HaskellWorks.Data.Network.Ip.Type as HW--ipv4Address :: AP.Parser HW.Ipv4Address-ipv4Address = HW.Ipv4Address <$> I.ipv4Address
src/HaskellWorks/Data/Network/Ip/Type.hs view
@@ -1,75 +1,14 @@-{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DuplicateRecordFields #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE InstanceSigs #-}-{-# LANGUAGE OverloadedStrings #-} module HaskellWorks.Data.Network.Ip.Type- ( Ipv4Address(..)- , Ipv4NetMask(..)- , Ipv4Block(..)+ ( I4.Ipv4Address(..)+ , I4.Ipv4NetMask(..)+ , I4.Ipv4Block(..)+ , I6.Ipv6Address(..)+ , I6.Ipv6NetMask(..)+ , I6.Ipv6Block(..) ) where -import Data.Maybe-import Data.Word-import GHC.Generics-import HaskellWorks.Data.Bits.BitWise-import Control.Monad--import qualified Data.Attoparsec.Text as AP-import qualified Data.Bits as B-import qualified Data.Text as T-import qualified HaskellWorks.Data.Network.Ip.Internal as I-import qualified Text.ParserCombinators.ReadPrec as RP--newtype Ipv4Address = Ipv4Address- { word :: Word32- } deriving (Enum, Eq, Ord, Generic)--instance Show Ipv4Address where- showsPrec _ (Ipv4Address w) =- shows ((w .>. 24) .&. 0xff) . ('.':) .- shows ((w .>. 16) .&. 0xff) . ('.':) .- shows ((w .>. 8) .&. 0xff) . ('.':) .- shows ( w .&. 0xff)--instance Read Ipv4Address where- readsPrec :: Int -> String -> [(Ipv4Address, String)]- readsPrec _ s = case AP.parseWith (return mempty) (I.whitespace *> I.ipv4Address) (T.pack s) of- Just result -> case result of- AP.Done i r -> [(Ipv4Address r, T.unpack i)]- AP.Partial _ -> []- AP.Fail a b c -> []- Nothing -> []--newtype Ipv4NetMask = Ipv4NetMask- { word :: Word8- } deriving (Enum, Eq, Ord, Show, Generic)--data Ipv4Block = Ipv4Block- { base :: !Ipv4Address- , mask :: !Ipv4NetMask- } deriving (Eq, Ord)--instance Show Ipv4Block where- showsPrec _ (Ipv4Block b (Ipv4NetMask m)) = shows b . ('/':) . shows m--instance Read Ipv4Block where- readsPrec :: Int -> String -> [(Ipv4Block, String)]- readsPrec _ s = case AP.parseWith (return mempty) (I.whitespace *> I.ipv4Block) (T.pack s) of- Just result -> case result of- AP.Done i (a, m) ->- case validIpv4Block $ Ipv4Block (Ipv4Address a) (Ipv4NetMask m) of- Just b -> [(b, T.unpack i)]- Nothing -> []- AP.Partial _ -> []- AP.Fail a b c -> []- Nothing -> []---- shift the address left by the amount of mask bits to reveal only host bits--- if any bits left are non-zero, then the mask is not big enough-validIpv4Block :: Ipv4Block -> Maybe Ipv4Block-validIpv4Block b@(Ipv4Block (Ipv4Address word) (Ipv4NetMask mask)) =- if word `B.shiftL` fromIntegral mask `B.xor` 0 == 0- then pure b- else Nothing+import qualified HaskellWorks.Data.Network.Ip.Ipv4 as I4+import qualified HaskellWorks.Data.Network.Ip.Ipv6 as I6
test/HaskellWorks/Data/Network/IpSpec.hs view
@@ -3,6 +3,7 @@ module HaskellWorks.Data.Network.IpSpec (spec) where import HaskellWorks.Data.Network.Ip+import HaskellWorks.Data.Network.Ip.Ipv4 import HaskellWorks.Data.Network.Ip.Internal import HaskellWorks.Hspec.Hedgehog import Hedgehog@@ -24,23 +25,23 @@ AP.parseOnly octet (T.pack . show $ b) === Right b describe "Ipv4Address" $ do- it "should implement show" $ require $ property $ do+ it "should implement show" $ requireTest $ do show (Ipv4Address 0x000000ff) === "0.0.0.255" show (Ipv4Address 0x0000ff00) === "0.0.255.0" show (Ipv4Address 0x00ff0000) === "0.255.0.0" show (Ipv4Address 0xff000000) === "255.0.0.0" - it "should implement read" $ require $ property $ do+ it "should implement read" $ requireTest $ do read "1.2.3.4" === Ipv4Address 0x01020304 read "10.20.30.40" === Ipv4Address 0x0a141e28 read "1.2.3.12" === Ipv4Address 0x0102030c read "1.2.3.160" === Ipv4Address 0x010203a0 - it "should be possible to extract the octets" $ require $ property $ do+ it "should be possible to extract the octets" $ requireTest $ do ipv4AddressToWords (Ipv4Address 0x01020304) === (1, 2, 3, 4) describe "Ipv4Block" $ do- it "should implement show" $ require $ property $ do+ it "should implement show" $ requireTest $ do show (Ipv4Block (Ipv4Address 0x000000ff) (Ipv4NetMask 32)) === "0.0.0.255/32" show (Ipv4Block (Ipv4Address 0x0000ff00) (Ipv4NetMask 32)) === "0.0.255.0/32" show (Ipv4Block (Ipv4Address 0x00ff0000) (Ipv4NetMask 32)) === "0.255.0.0/32"@@ -60,22 +61,22 @@ show (firstIpv4Address $ Ipv4Block (Ipv4Address 0xff000000) (Ipv4NetMask 21)) === "255.0.0.0" show (lastIpv4Address $ Ipv4Block (Ipv4Address 0xff000000) (Ipv4NetMask 21)) === "255.0.7.255" - it "should implement read" $ require $ property $ do+ it "should implement read" $ requireTest $ do read "1.0.0.0/8" === Ipv4Block (Ipv4Address 0x01000000) (Ipv4NetMask 8) read "1.2.0.0/16" === Ipv4Block (Ipv4Address 0x01020000) (Ipv4NetMask 16) read "1.2.3.4/32" === Ipv4Block (Ipv4Address 0x01020304) (Ipv4NetMask 32) - it "should implement splitBlock" $ require $ property $ do+ it "should implement splitBlock" $ requireTest $ do splitBlock (Ipv4Block (Ipv4Address 0x00000000) (Ipv4NetMask 32)) === Nothing splitBlock (Ipv4Block (Ipv4Address 0x00000000) (Ipv4NetMask 31)) === Just (Ipv4Block (Ipv4Address 0x00000000) (Ipv4NetMask 32), Ipv4Block (Ipv4Address 0x00000001) (Ipv4NetMask 32)) splitBlock (Ipv4Block (Ipv4Address 0x00000000) (Ipv4NetMask 30)) === Just (Ipv4Block (Ipv4Address 0x00000000) (Ipv4NetMask 31), Ipv4Block (Ipv4Address 0x00000002) (Ipv4NetMask 31)) splitBlock (Ipv4Block (Ipv4Address 0x00000000) (Ipv4NetMask 0)) === Just (Ipv4Block (Ipv4Address 0x00000000) (Ipv4NetMask 1), Ipv4Block (Ipv4Address 0x80000000) (Ipv4NetMask 1)) - it "should implement blockSize" $ require $ property $ do+ it "should implement blockSize" $ requireTest $ do blockSize (Ipv4Block (Ipv4Address 0x00000000) (Ipv4NetMask 32)) === 1 blockSize (Ipv4Block (Ipv4Address 0x00000000) (Ipv4NetMask 0)) === 0x100000000 - it "should validate masks" $ require $ property $ do+ it "should validate masks" $ requireTest $ do (TR.readMaybe "1.2.3.4/8" :: Maybe Ipv4Block) === Nothing (TR.readMaybe "1.2.3.4/0" :: Maybe Ipv4Block) === Nothing (TR.readMaybe "1.2.3.4/32" :: Maybe Ipv4Block) === (Just $ Ipv4Block (Ipv4Address 0x01020304) (Ipv4NetMask 32))