IPv6Addr 0.6.0.2 → 0.6.1.0
raw patch · 8 files changed
+101/−140 lines, 8 filesdep ~attoparsecdep ~basedep ~iproutePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: attoparsec, base, iproute, network, network-info, random, text
API changes (from Hackage documentation)
- Text.IPv6Addr: instance Eq IPv6Addr
- Text.IPv6Addr.Types: instance Eq IPv6AddrToken
- Text.IPv6Addr.Types: instance Show IPv6Addr
- Text.IPv6Addr.Types: instance Show IPv6AddrToken
+ Text.IPv6Addr: instance GHC.Classes.Eq Text.IPv6Addr.Types.IPv6Addr
+ Text.IPv6Addr: toUNC :: IPv6Addr -> Text
+ Text.IPv6Addr.Types: instance GHC.Classes.Eq Text.IPv6Addr.Types.IPv6AddrToken
+ Text.IPv6Addr.Types: instance GHC.Show.Show Text.IPv6Addr.Types.IPv6Addr
+ Text.IPv6Addr.Types: instance GHC.Show.Show Text.IPv6Addr.Types.IPv6AddrToken
Files
- IPv6Addr.cabal +4/−2
- LICENSE +1/−1
- README.md +1/−1
- Text/IPv6Addr.hs +26/−26
- Text/IPv6Addr/Internal.hs +50/−67
- Text/IPv6Addr/Manip.hs +14/−28
- Text/IPv6Addr/Types.hs +1/−13
- tests/Main.hs +4/−2
IPv6Addr.cabal view
@@ -1,5 +1,5 @@ name: IPv6Addr-version: 0.6.0.2+version: 0.6.1.0 synopsis: Library to deal with IPv6 address text representations. description: Library to deal with IPv6 address text representations, canonization and manipulations. homepage: https://github.com/MichelBoucey/IPv6Addr@@ -7,7 +7,7 @@ license-file: LICENSE author: Michel Boucey maintainer: michel.boucey@gmail.com-copyright: Copyright © 2011-2015 - Michel Boucey+copyright: Copyright (c) 2011-2015 - Michel Boucey category: Network build-type: Simple extra-source-files: README.md@@ -22,6 +22,7 @@ other-extensions: OverloadedStrings build-depends: base >=4.6 && <5, text >=1.1, iproute >=1.3, network >=2.5, random >=1.0, attoparsec >=0.12, network-info >=0.2 default-language: Haskell2010+ GHC-Options: -Wall Test-Suite tests Type: exitcode-stdio-1.0@@ -34,3 +35,4 @@ test-framework, test-framework-hunit, text+
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2011-2015, Michel Boucey+Copyright (c) 2011-2016, Michel Boucey All rights reserved. Redistribution and use in source and binary forms, with or without
README.md view
@@ -1,1 +1,1 @@-IPv6Addr is a Haskell library to Deal with IPv6 address text representations, canonization and manipulations.+IPv6Addr is a Haskell library to deal with IPv6 address text representations, canonization and manipulations.
Text/IPv6Addr.hs view
@@ -1,16 +1,5 @@--- --------------------------------------------------------------------------------- Module : Text.IPv6Addr--- Copyright : Copyright © Michel Boucey 2011-2015--- License : BSD-style--- Maintainer : michel.boucey@gmail.com------ Dealing with IPv6 address text representations, canonization and manipulations.------- ------------------------------------------------------------------------------ {-# LANGUAGE OverloadedStrings #-}+{-# OPTIONS_GHC -fno-warn-orphans #-} module Text.IPv6Addr (@@ -25,23 +14,22 @@ , toHostName -- * Utils , toIP6ARPA+ , toUNC , getIPv6AddrOf , randIPv6Addr , randIPv6AddrWithPrefix ) where --- import Control.Applicative (pure,(<$>),(<*>))-import Control.Applicative (pure,(<$>))-import Data.IP (IPv6)-import Data.Maybe (fromJust,isNothing)-import Data.Monoid ((<>))-import qualified Data.Text as T-import Network (HostName)-import System.Random (randomRIO)+import Data.IP (IPv6)+import Data.Maybe (fromJust, isNothing)+import Data.Monoid ((<>))+import qualified Data.Text as T+import Network (HostName)+import System.Random (randomRIO) -import Text.IPv6Addr.Internal-import Text.IPv6Addr.Manip (randIPv6AddrChunk,randPartialIPv6Addr)-import Text.IPv6Addr.Types+import Text.IPv6Addr.Internal+import Text.IPv6Addr.Manip (randPartialIPv6Addr)+import Text.IPv6Addr.Types instance Eq IPv6Addr where (==) (IPv6Addr a) (IPv6Addr b) = show (maybePureIPv6Addr a) == show (maybePureIPv6Addr b)@@ -88,6 +76,17 @@ trans ':' = T.empty trans c = "." <> T.pack [c] +-- | Returns the Windows UNC path name of the given IPv6 Address.+--+-- > toUNC (IPv6Addr "2001:0DB8:002a:1005:230:48ff:fe73:989d") == "2001-db8-2a-1005-230-48ff-fe73-989d.ipv6-literal.net"+--+toUNC :: IPv6Addr -> T.Text+toUNC a =+ (T.concatMap trans $ fromIPv6Addr $ fromJust $ maybePureIPv6Addr $ fromIPv6Addr a) <> ".ipv6-literal.net"+ where+ trans ':' = "-"+ trans c = T.pack [c]+ -- | Given an 'IPv6Addr', returns the corresponding 'HostName'. toHostName :: IPv6Addr -> HostName toHostName = show@@ -136,9 +135,9 @@ ] return $ ipv6TokensToIPv6Addr tks else case maybeIPv6AddrTokens (fromJust p) of- Just tks -> do + Just tks -> do ntks <- do let ctks = countChunks tks- case snd ctks of+ case (snd ctks :: Int) of 0 -> return $ 8 - fst ctks 1 -> return $ 6 - fst ctks _ -> return 0@@ -166,4 +165,5 @@ case last ts of SixteenBit _ -> ts ++ [Colon] AllZeros -> ts ++ [Colon]- _ -> ts + _ -> ts+
Text/IPv6Addr/Internal.hs view
@@ -1,16 +1,3 @@--- --------------------------------------------------------------------------------- | --- Module : Text.IPv6Addr--- Copyright : Copyright © Michel Boucey 2011-2015--- License : BSD-Style--- Maintainer : michel.boucey@gmail.com------ Dealing with IPv6 address text representations, canonization and manipulations.------- ------------------------------------------------------------------------------ {-# LANGUAGE OverloadedStrings #-} module Text.IPv6Addr.Internal@@ -29,21 +16,19 @@ , networkInterfacesIPv6AddrList ) where -import Control.Monad (replicateM)-import Data.Attoparsec.Text-import Data.Char (isDigit,isHexDigit,toLower)-import Data.Monoid ((<>))-import Control.Applicative ((<|>),(<*))-import Data.List (group,isSuffixOf,elemIndex,elemIndices,intersperse)-import Numeric (showHex)-import qualified Data.Text as T-import qualified Data.Text.Read as R (decimal)-import Data.Maybe (fromJust)-import Network.Info--import Text.IPv6Addr.Types+import Control.Applicative ((<|>))+import Data.Attoparsec.Text+import Data.Char (isDigit)+import Data.List (elemIndex, elemIndices, group,+ intersperse, isSuffixOf)+import Data.Maybe (fromJust)+import Data.Monoid ((<>))+import qualified Data.Text as T+import qualified Data.Text.Read as R (decimal)+import Network.Info+import Numeric (showHex) -tok0 = "0"+import Text.IPv6Addr.Types -- | Returns the 'T.Text' of an IPv6 address. fromIPv6Addr :: IPv6Addr -> T.Text@@ -55,25 +40,25 @@ -- | Returns the corresponding 'T.Text' of an IPv6 address token. ipv6TokenToText :: IPv6AddrToken -> T.Text-ipv6TokenToText (SixteenBit s) = s +ipv6TokenToText (SixteenBit s) = s ipv6TokenToText Colon = ":" ipv6TokenToText DoubleColon = "::"-ipv6TokenToText AllZeros = tok0 -- "A single 16-bit 0000 field MUST be represented as 0" (RFC 5952, 4.1)+ipv6TokenToText AllZeros = "0" -- "A single 16-bit 0000 field MUST be represented as 0" (RFC 5952, 4.1) ipv6TokenToText (IPv4Addr a) = a -- | Returns 'True' if a list of 'IPv6AddrToken' constitutes a valid IPv6 Address. isIPv6Addr :: [IPv6AddrToken] -> Bool isIPv6Addr [] = False isIPv6Addr [DoubleColon] = True-isIPv6Addr [DoubleColon,SixteenBit tok1] = True+isIPv6Addr [DoubleColon,SixteenBit "1"] = True isIPv6Addr tks = diffNext tks && (do let cdctks = countDoubleColon tks- let lentks = length tks- let lasttk = last tks- let lenconst = (lentks == 15 && cdctks == 0) || (lentks < 15 && cdctks == 1)+ lentks = length tks+ lasttk = last tks+ lenconst = (lentks == 15 && cdctks == 0) || (lentks < 15 && cdctks == 1) firstValidToken tks &&- (case countIPv4Addr tks of+ (case countIPv4Addr tks :: Int of 0 -> case lasttk of SixteenBit _ -> lenconst DoubleColon -> lenconst@@ -82,7 +67,7 @@ 1 -> case lasttk of IPv4Addr _ -> (lentks == 13 && cdctks == 0) || (lentks < 12 && cdctks == 1) _ -> False- otherwise -> False))+ _ -> False)) where diffNext [] = False diffNext [_] = True diffNext (t:ts) = do@@ -97,26 +82,28 @@ AllZeros -> False _ -> diffNext ts _ -> diffNext ts- firstValidToken l = + firstValidToken l = case head l of SixteenBit _ -> True DoubleColon -> True AllZeros -> True _ -> False countDoubleColon l = length $ elemIndices DoubleColon l- tok1 = "1" -countIPv4Addr = foldr oneMoreIPv4Addr 0+countIPv4Addr :: [IPv6AddrToken] -> Int+countIPv4Addr =+ foldr oneMoreIPv4Addr 0 where- oneMoreIPv4Addr t c = case t of- IPv4Addr _ -> c + 1- otherwise -> c+ oneMoreIPv4Addr t c =+ case t of+ IPv4Addr _ -> c + 1+ _ -> c -- | This is the main function which returns 'Just' the list of a tokenized IPv6 -- address text representation validated against RFC 4291 and canonized -- in conformation with RFC 5952, or 'Nothing'. maybeTokIPv6Addr :: T.Text -> Maybe [IPv6AddrToken]-maybeTokIPv6Addr t = +maybeTokIPv6Addr t = case maybeIPv6AddrTokens t of Just ltks -> if isIPv6Addr ltks then Just $ (ipv4AddrReplacement . toDoubleColon . fromDoubleColon) ltks@@ -141,12 +128,13 @@ -- | Tokenize a 'T.Text' into 'Just' a list of 'IPv6AddrToken', or 'Nothing'. maybeIPv6AddrTokens :: T.Text -> Maybe [IPv6AddrToken]-maybeIPv6AddrTokens s = +maybeIPv6AddrTokens s = case readText s of Done r l -> if r==T.empty then Just l else Nothing Fail {} -> Nothing+ Partial _ -> Nothing where- readText s = feed (parse (many1 $ ipv4Addr <|> sixteenBit <|> doubleColon <|> colon) s) T.empty+ readText _s = feed (parse (many1 $ ipv4Addr <|> sixteenBit <|> doubleColon <|> colon) _s) T.empty -- | An embedded IPv4 address have to be rewritten to output a pure IPv6 Address -- text representation in hexadecimal digits. But some well-known prefixed IPv6@@ -195,7 +183,7 @@ _ -> [t] where toHex a = map (\x -> T.pack $ showHex (read (T.unpack x)::Int) "") $ T.split (=='.') a- addZero d = if T.length d == 1 then tok0 <> d else d+ addZero d = if T.length d == 1 then "0" <> d else d expandTokens :: [IPv6AddrToken] -> [IPv6AddrToken] expandTokens = map expandToken@@ -204,21 +192,21 @@ expandToken t = t fromDoubleColon :: [IPv6AddrToken] -> [IPv6AddrToken]-fromDoubleColon tks = +fromDoubleColon tks = if DoubleColon `notElem` tks then tks else do let s = splitAt (fromJust $ elemIndex DoubleColon tks) tks- let fsts = fst s- let snds = if not (null (snd s)) then tail(snd s) else []- let fste = if null fsts then [] else fsts ++ [Colon]- let snde = if null snds then [] else Colon : snds+ fsts = fst s+ snds = if not (null (snd s)) then tail(snd s) else []+ fste = if null fsts then [] else fsts ++ [Colon]+ snde = if null snds then [] else Colon : snds fste ++ allZerosTokensReplacement(quantityOfAllZerosTokenToReplace tks) ++ snde where allZerosTokensReplacement x = intersperse Colon (replicate x AllZeros)- quantityOfAllZerosTokenToReplace x =- ntks tks - foldl (\c x -> if (x /= DoubleColon) && (x /= Colon) then c+1 else c) 0 x+ quantityOfAllZerosTokenToReplace _x =+ ntks tks - foldl (\c _x -> if (_x /= DoubleColon) && (_x /= Colon) then c+1 else c) 0 _x where- ntks tks = if countIPv4Addr tks == 1 then 7 else 8+ ntks _tks = if countIPv4Addr _tks == 1 then 7 else 8 toDoubleColon :: [IPv6AddrToken] -> [IPv6AddrToken] toDoubleColon tks =@@ -239,7 +227,7 @@ firstLongestZerosRunIndex x y = sum . snd . unzip $ Prelude.takeWhile (/=(True,y)) x longestLengthZerosRun x = maximum $ map longest x- where longest t = case t of+ where longest _t = case _t of (True,i) -> i _ -> 0 zerosRunsList x = map helper $ groupZerosRuns x@@ -256,12 +244,6 @@ where networkInterfacesIPv6Addr (NetworkInterface n _ a _) = (n,a) -fullSixteenBit :: T.Text -> Maybe IPv6AddrToken-fullSixteenBit t =- case parse ipv6AddrFullChunk t of- Done a b -> if a==T.empty then Just $ SixteenBit $ T.pack b else Nothing- _ -> Nothing- macAddr :: Parser (Maybe [IPv6AddrToken]) macAddr = do n1 <- count 2 hexaChar <* ":"@@ -293,26 +275,26 @@ then do n4 <- manyDigits if n4 /= T.empty then return $ IPv4Addr $ T.intercalate "." [n1,n2,n3,n4]- else parserFailure - else parserFailure - else parserFailure - else parserFailure + else parserFailure+ else parserFailure+ else parserFailure+ else parserFailure where parserFailure = fail "ipv4Addr parsing failure" manyDigits = do ds <- takeWhile1 isDigit- case R.decimal ds of+ case R.decimal ds :: Either String (Integer, T.Text) of Right (n,_) -> return (if n < 256 then T.pack $ show n else T.empty) Left _ -> return T.empty doubleColon :: Parser IPv6AddrToken doubleColon = do- string "::"+ _ <- string "::" return DoubleColon colon :: Parser IPv6AddrToken colon = do- string ":"+ _ <- string ":" return Colon ipv6AddrFullChunk :: Parser String@@ -320,3 +302,4 @@ hexaChar :: Parser Char hexaChar = satisfy (inClass "0-9a-fA-F")+
Text/IPv6Addr/Manip.hs view
@@ -1,16 +1,3 @@--- --------------------------------------------------------------------------------- |--- Module : Text.IPv6Addr--- Copyright : Copyright © Michel Boucey 2011-2015--- License : BSD-Style--- Maintainer : michel.boucey@gmail.com------ Dealing with IPv6 address text representations, canonization and manipulations.------- ------------------------------------------------------------------------------ module Text.IPv6Addr.Manip ( randIPv6AddrChunk , randPartialIPv6Addr@@ -19,24 +6,22 @@ , getTokMacAddrOf ) where -import Control.Applicative ((<$>))-import Control.Monad (replicateM)-import Data.Attoparsec.Text as A-import Data.Char (intToDigit,isHexDigit)-import Data.List (intersperse)-import Data.Maybe (fromJust)-import qualified Data.Text as T-import Network.Info-import System.Random (randomRIO)+import Control.Monad (replicateM)+import Data.Attoparsec.Text as A+import Data.Char (intToDigit)+import Data.List (intersperse)+import qualified Data.Text as T+import Network.Info+import System.Random (randomRIO) -import Text.IPv6Addr.Internal-import Text.IPv6Addr.Types+import Text.IPv6Addr.Internal+import Text.IPv6Addr.Types -- | Returns 'Just' a random 'SixteenBit' token based on a mask \"____\", each -- underscore being replaced by a random hexadecimal digit. -- -- > randIPv6AddrChunk "_f__" == Just (SixteenBit "bfd4")--- +-- randIPv6AddrChunk :: String -> IO IPv6AddrToken randIPv6AddrChunk m = mapM getHex m >>= \g -> return $ SixteenBit $ T.dropWhile (=='0') $ T.pack g@@ -51,9 +36,9 @@ | n > 0 && n < 9 = intersperse Colon <$> replicateM n (randIPv6AddrChunk "____") | otherwise = return [] --- | Given a MAC address, returns the corresponding 'IPv6AddrToken' list, or an empty list.+-- | Given a MAC address, returns 'Just' the corresponding 'IPv6AddrToken' list, or 'Nothing'. ----- > macAddrToIPv6AddrTokens "fa:1d:58:cc:95:16" == [SixteenBit "fa1d",Colon,SixteenBit "58cc",Colon,SixteenBit "9516"]+-- > macAddrToIPv6AddrTokens "fa:1d:58:cc:95:16" == Just [SixteenBit "fa1d",Colon,SixteenBit "58cc",Colon,SixteenBit "9516"] -- macAddrToIPv6AddrTokens :: T.Text -> Maybe [IPv6AddrToken] macAddrToIPv6AddrTokens t =@@ -82,5 +67,6 @@ getTokMacAddrOf s = maybe Nothing (macAddrToIPv6AddrTokens . T.pack . show) <$> (lookup s <$> networkInterfacesMacAddrList) where- networkInterfacesMacAddrList = getNetworkInterfaces >>= \n -> return $ map networkInterfacesMac n + networkInterfacesMacAddrList = getNetworkInterfaces >>= \n -> return $ map networkInterfacesMac n where networkInterfacesMac (NetworkInterface n _ _ m) = (n,m)+
Text/IPv6Addr/Types.hs view
@@ -1,16 +1,3 @@--- --------------------------------------------------------------------------------- |--- Module : Text.IPv6Addr--- Copyright : Copyright © Michel Boucey 2011-2015--- License : BSD-Style--- Maintainer : michel.boucey@gmail.com------ Dealing with IPv6 address text representations, canonization and manipulations.------- ------------------------------------------------------------------------------ module Text.IPv6Addr.Types where import qualified Data.Text as T@@ -27,3 +14,4 @@ | DoubleColon -- ^ A double-colon stands for a unique compression of many consecutive 16-Bit chunks | IPv4Addr T.Text -- ^ An embedded IPv4 address as representation of the last 32-Bit deriving (Eq,Show)+
tests/Main.hs view
@@ -2,16 +2,16 @@ module Main where -import Data.Maybe-import Data.Text import Test.Framework import Test.Framework.Providers.HUnit import Test.HUnit import Text.IPv6Addr +main :: IO () main = defaultMain $ hUnitTestToTests tests +tests :: Test.HUnit.Test tests = TestList [ (~?=) (maybeIPv6Addr ":") Nothing , (~?=) (maybeIPv6Addr "::") (Just (IPv6Addr "::"))@@ -100,4 +100,6 @@ , (~?=) (toIP6ARPA (IPv6Addr "fdda:5cc1:23:4::1f")) "f.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.4.0.0.0.3.2.0.0.1.c.c.5.a.d.d.f.IP6.ARPA." , (~?=) (toIP6ARPA (IPv6Addr "2001:db8::")) "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.IP6.ARPA." , (~?=) (toIP6ARPA (IPv6Addr "4321:0:1:2:3:4:567:89ab")) "b.a.9.8.7.6.5.0.4.0.0.0.3.0.0.0.2.0.0.0.1.0.0.0.0.0.0.0.1.2.3.4.IP6.ARPA."+ , (~?=) (toUNC (IPv6Addr "2001:0DB8:002a:1005:230:48ff:FE73:989d")) "2001-db8-2a-1005-230-48ff-fe73-989d.ipv6-literal.net"+ , (~?=) (toUNC (IPv6Addr "2001:0db8:85a3:0000:0000:8a2e:0370:7334")) "2001-db8-85a3--8a2e-370-7334.ipv6-literal.net" ]