IPv6Addr 0.4 → 0.5
raw patch · 7 files changed
+97/−65 lines, 7 filesdep +iproutedep +networkdep ~basedep ~bytestringdep ~network-info
Dependencies added: iproute, network
Dependency ranges changed: base, bytestring, network-info
Files
- IPv6Addr.cabal +7/−5
- LICENSE +1/−1
- Text/IPv6Addr.hs +55/−27
- Text/IPv6Addr/Internal.hs +9/−11
- Text/IPv6Addr/Manip.hs +14/−14
- Text/IPv6Addr/Types.hs +5/−2
- tests/Main.hs +6/−5
IPv6Addr.cabal view
@@ -1,8 +1,8 @@ Name: IPv6Addr-Version: 0.4+Version: 0.5 License: BSD3 License-File: LICENSE-Copyright: Copyright © 2011-2013 - Michel Boucey+Copyright: Copyright © 2011-2014 - Michel Boucey Author: Michel Boucey <michel.boucey@gmail.com> Maintainer: Michel Boucey <michel.boucey@gmail.com> Bug-Reports: mailto:michel.boucey@gmail.com@@ -18,9 +18,11 @@ Library Build-Depends: attoparsec,- base >= 3 && <= 5,- bytestring >= 0.9,- network-info >= 0.2,+ base < 5,+ bytestring,+ iproute,+ network,+ network-info, random, text
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2011-2013 - Michel Boucey+Copyright (c) 2011-2014 - Michel Boucey All rights reserved.
Text/IPv6Addr.hs view
@@ -1,7 +1,7 @@ -- ----------------------------------------------------------------------------- -- Module : Text.IPv6Addr--- Copyright : (c) Michel Boucey 2011-2013+-- Copyright : Copyright © Michel Boucey 2011-2014 -- License : BSD-style -- Maintainer : michel.boucey@gmail.com --@@ -16,19 +16,29 @@ , maybeIPv6Addr , maybePureIPv6Addr , maybeFullIPv6Addr+ , sameIPv6Addr+ , fromIPv6Addr+ , toIPv6+ , toHostName+ , toIP6ARPA , getIPv6AddrOf- , ip6arpa , randIPv6Addr ) where -import Control.Applicative ((<$>))+import Control.Applicative (pure,(<$>),(<*>))+import Data.IP (IPv6) import Data.Maybe (fromJust) import qualified Data.Text as T+import Network (HostName)+import System.Random (randomRIO) import Text.IPv6Addr.Internal-import Text.IPv6Addr.Manip (sixteenBitArbToken,partialRandAddr)+import Text.IPv6Addr.Manip (randIPv6AddrChunk,randPartialIPv6Addr) import Text.IPv6Addr.Types +instance Eq IPv6Addr where+ (==) (IPv6Addr a) (IPv6Addr b) = show (maybePureIPv6Addr a) == show (maybePureIPv6Addr b)+ -- | Returns 'Just' the text representation of a canonized -- 'IPv6Addr' in conformation with RFC 5952, or 'Nothing'. --@@ -39,45 +49,63 @@ -- | Returns 'Just' a pure 'IPv6Addr', or 'Nothing'. ----- > maybePureIPv6Addr "::ffff:192.0.2.128" == Just (IPv6Addr "::ffff:c000:280")+-- > mabePureIPv6Addr "::ffff:192.0.2.128" == Just (IPv6Addr "::ffff:c000:280") -- maybePureIPv6Addr :: T.Text -> Maybe IPv6Addr maybePureIPv6Addr t = maybeTokPureIPv6Addr t >>= ipv6TokensToIPv6Addr --- | Returns 'Just' a pure and expanded 'IPv6Addr', or 'Nothing'.+-- | Returns 'Just' a pure and fully expanded 'IPv6Addr', or 'Nothing'. ----- > maybeFullIPv6Addr "::ffff:192.0.2.128" == Just (IPv6Addr "0000:0000:0000:0000:0000:ffff:c000:0280")+-- > mayebFullIPv6Addr "::ffff:192.0.2.128" == Just (IPv6Addr "0000:0000:0000:0000:0000:ffff:c000:0280") -- maybeFullIPv6Addr :: T.Text -> Maybe IPv6Addr-maybeFullIPv6Addr t =- maybeTokPureIPv6Addr t >>= (ipv6TokensToIPv6Addr . expandTokens . fromDoubleColon)+maybeFullIPv6Addr t = maybeTokPureIPv6Addr t >>= (ipv6TokensToIPv6Addr . expandTokens . fromDoubleColon) --- | Returns 'Just' the reverse lookup domain name corresponding of the given IPv6 address--- (RFC 3596 Section 2.5), or 'Nothing'.+-- | Returns 'True' if arguments are two textual representations of the same IPv6 address.+sameIPv6Addr :: T.Text -> T.Text -> Bool+sameIPv6Addr a b =+ case maybePureIPv6Addr a of+ Nothing -> False+ Just a' -> case maybePureIPv6Addr b of+ Nothing -> False+ Just b' -> a' == b'++-- | Returns the reverse lookup domain name corresponding of the given IPv6 address (RFC 3596 Section 2.5). ----- > ip6arpa (IPv6Addr "4321:0:1:2:3:4:567:89ab") == Just "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."+-- > 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." ---ip6arpa :: IPv6Addr -> T.Text-ip6arpa t =- rev (fromIPv6Addr $ fromJust $ maybeFullIPv6Addr $ fromIPv6Addr t) T.empty+toIP6ARPA :: IPv6Addr -> T.Text+toIP6ARPA a =+ T.append (T.reverse $ T.concatMap trans $ fromIPv6Addr $ fromJust $ maybeFullIPv6Addr $ fromIPv6Addr a) (T.pack "IP6.ARPA.") where- rev i o = if i == T.empty- then o `T.append` T.pack "ip6.arpa."- else do let c = T.last i- rev (T.init i)- (if c /= ':'- then o `T.append` T.pack [c] `T.append` T.pack "."- else o)+ trans ':' = T.empty+ trans c = T.append (T.pack ".") (T.pack [c]) --- | Returns 'Just' the canonized 'IPv6Addr' of the given network interface,+-- | Given an 'IPv6Addr', returns the corresponding 'HostName'.+toHostName :: IPv6Addr -> HostName+toHostName = show++-- | Given an 'IPv6addr', returns the corresponding 'IPv6' address.+toIPv6 :: IPv6Addr -> IPv6+toIPv6 a = read $ show a++-- | Returns 'Just' the canonized 'IPv6Addr' of the given local network interface, -- or 'Nothing'. -- -- > getIPv6AddrOf "eth0" -- getIPv6AddrOf :: String -> IO (Maybe IPv6Addr)-getIPv6AddrOf s =- maybe Nothing (maybeIPv6Addr . T.pack . show) <$> (lookup s <$> networkInterfacesIPv6AddrList)+getIPv6AddrOf s = maybe Nothing (maybeIPv6Addr . T.pack . show) <$> (lookup s <$> networkInterfacesIPv6AddrList) --- | Returns a random 'IPv6Addr'+-- | Returns a random 'IPv6Addr'. randIPv6Addr :: IO IPv6Addr-randIPv6Addr = IPv6Addr . ipv6TokensToText <$> partialRandAddr 8+randIPv6Addr = do+ r <- randomRIO (1,8)+ tks <- case r of+ 8 -> randPartialIPv6Addr 8+ _ -> do r' <- randomRIO (1,8-r)+ case r + r' of+ 7 -> concat <$> sequence [randPartialIPv6Addr r,pure [Colon,AllZeros,Colon],randPartialIPv6Addr r']+ 8 -> randPartialIPv6Addr 8+ _ -> concat <$> sequence [randPartialIPv6Addr r,pure [DoubleColon],randPartialIPv6Addr r']+ return $ fromJust $ ipv6TokensToIPv6Addr tks
Text/IPv6Addr/Internal.hs view
@@ -2,7 +2,7 @@ -- | -- Module : Text.IPv6Addr--- Copyright : (c) Michel Boucey 2011-2013+-- Copyright : Copyright © Michel Boucey 2011-2014 -- License : BSD-Style -- Maintainer : michel.boucey@gmail.com --@@ -55,8 +55,7 @@ ipv6TokenToText (SixteenBit s) = s ipv6TokenToText Colon = T.pack ":" ipv6TokenToText DoubleColon = T.pack "::"--- "A single 16-bit 0000 field MUST be represented as 0" (RFC 5952, 4.1)-ipv6TokenToText AllZeros = tok0 -- +ipv6TokenToText AllZeros = tok0 -- "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.@@ -178,8 +177,7 @@ tokffff = T.pack "ffff" tok5efe = T.pack "5efe" --- | Rewrites 'Just' an embedded 'IPv4Addr' into the corresponding list of pure--- 'IPv6Addr' tokens.+-- | Rewrites 'Just' an embedded 'IPv4Addr' into the corresponding list of pure 'IPv6Addr' tokens. -- -- > ipv4AddrToIPv6AddrTokens (IPv4Addr "127.0.0.1") == [SixteenBits "7f0",Colon,SixteenBits "1"] --@@ -188,9 +186,9 @@ case t of IPv4Addr a -> do let m = toHex a- [ SixteenBit ((!!) m 0 `T.append` addZero ((!!) m 1))+ [ SixteenBit ((!!) m 0 `T.append` addZero ((!!) m 1)) , Colon- , SixteenBit ((!!) m 2 `T.append` addZero ((!!) m 3))]+ , SixteenBit ((!!) m 2 `T.append` addZero ((!!) m 3)) ] _ -> [t] where toHex a = map (\x -> T.pack $ showHex (read (T.unpack x)::Int) "") $ T.split (=='.') a@@ -257,7 +255,7 @@ fullSixteenBit :: T.Text -> Maybe IPv6AddrToken fullSixteenBit t =- case parse fourHexaChars t of+ case parse ipv6AddrFullChunk t of Done a b -> if a==T.empty then Just $ SixteenBit $ T.pack b else Nothing _ -> Nothing @@ -273,7 +271,7 @@ sixteenBit :: Parser IPv6AddrToken sixteenBit = do- r <- fourHexaChars <|> count 3 hexaChar <|> count 2 hexaChar <|> count 1 hexaChar+ r <- ipv6AddrFullChunk <|> count 3 hexaChar <|> count 2 hexaChar <|> count 1 hexaChar -- "Leading zeros MUST be suppressed" (RFC 5952, 4.1) let r' = T.dropWhile (=='0') $ T.pack r return $ if T.null r'@@ -315,8 +313,8 @@ string $ T.pack ":" return Colon -fourHexaChars :: Parser String-fourHexaChars = count 4 hexaChar+ipv6AddrFullChunk :: Parser String+ipv6AddrFullChunk = count 4 hexaChar hexaChar :: Parser Char hexaChar = satisfy (inClass "0-9a-fA-F")
Text/IPv6Addr/Manip.hs view
@@ -2,7 +2,7 @@ -- | -- Module : Text.IPv6Addr--- Copyright : (c) Michel Boucey 2011-2013+-- Copyright : Copyright © Michel Boucey 2011-2014 -- License : BSD-Style -- Maintainer : michel.boucey@gmail.com --@@ -12,8 +12,8 @@ -- ----------------------------------------------------------------------------- module Text.IPv6Addr.Manip- ( sixteenBitArbToken- , partialRandAddr+ ( randIPv6AddrChunk+ , randPartialIPv6Addr , macAddrToIPv6AddrTokens , getTokIPv6AddrOf , getTokMacAddrOf@@ -32,24 +32,24 @@ import Text.IPv6Addr.Internal import Text.IPv6Addr.Types --- | Returns 'Just' an arbitrary 'SixteenBit' token based on a mask \"____\", each+-- | Returns 'Just' a random 'SixteenBit' token based on a mask \"____\", each -- underscore being replaced by a random hexadecimal digit. ----- > sixteenBitArbToken "_f__" == Just (SixteenBit "bfd4")+-- > randIPv6AddrChunk "_f__" == Just (SixteenBit "bfd4") -- -sixteenBitArbToken :: String -> IO IPv6AddrToken-sixteenBitArbToken m =+randIPv6AddrChunk :: String -> IO IPv6AddrToken+randIPv6AddrChunk m = mapM getHex m >>= \g -> return $ SixteenBit $ T.dropWhile (=='0') $ T.pack g where getHex c- | c == '_' = randomRIO(0,15) >>= \r -> return $ intToDigit r+ | c == '_' = intToDigit <$> randomRIO (0,15) | otherwise = return c --- | Generates a partial 'IPv6Addr' with n 'SixteenBit'-partialRandAddr :: Int -> IO [IPv6AddrToken]-partialRandAddr n- | n > 0 && n < 9 = intersperse Colon <$> replicateM n (sixteenBitArbToken "____")- | otherwise = return []+-- | Generates a random partial 'IPv6Addr' with n 'SixteenBit'+randPartialIPv6Addr :: Int -> IO [IPv6AddrToken]+randPartialIPv6Addr n+ | n > 0 && n < 9 = intersperse Colon <$> replicateM n (randIPv6AddrChunk "____")+ | otherwise = return [] -- | Given a MAC address, returns the corresponding 'IPv6AddrToken' list, or an empty list. --@@ -58,7 +58,7 @@ macAddrToIPv6AddrTokens :: T.Text -> Maybe [IPv6AddrToken] macAddrToIPv6AddrTokens t = case parse macAddr t of- Done a b -> if a==T.empty then intersperse Colon <$> b else Nothing+ Done a b -> if a == T.empty then intersperse Colon <$> b else Nothing _ -> Nothing --
Text/IPv6Addr/Types.hs view
@@ -2,7 +2,7 @@ -- | -- Module : Text.IPv6Addr--- Copyright : (c) Michel Boucey 2011-2013+-- Copyright : Copyright © Michel Boucey 2011-2014 -- License : BSD-Style -- Maintainer : michel.boucey@gmail.com --@@ -15,7 +15,10 @@ import qualified Data.Text as T -data IPv6Addr = IPv6Addr T.Text deriving (Eq,Show)+data IPv6Addr = IPv6Addr T.Text++instance Show IPv6Addr where+ show (IPv6Addr addr) = T.unpack addr data IPv6AddrToken = SixteenBit T.Text -- ^ A four hexadecimal digits group representing a 16-Bit chunk
tests/Main.hs view
@@ -94,9 +94,10 @@ , (~?=) (maybeFullIPv6Addr "a:bb:ccc:dddd:1cDc::1") (Just (IPv6Addr "000a:00bb:0ccc:dddd:1cdc:0000:0000:0001")) , (~?=) (maybeFullIPv6Addr "FE80::0202:B3FF:FE1E:8329") (Just (IPv6Addr "fe80:0000:0000:0000:0202:b3ff:fe1e:8329")) , (~?=) (maybeFullIPv6Addr "aDb6::CE67") (Just (IPv6Addr "adb6:0000:0000:0000:0000:0000:0000:ce67"))- , (~?=) (ip6arpa (IPv6Addr "::1")) "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa."- , (~?=) (ip6arpa (IPv6Addr "2b02:0b08:0:7::0001")) "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.0.0.0.0.0.0.0.8.0.b.0.2.0.b.2.ip6.arpa."- , (~?=) (ip6arpa (IPv6Addr "2b02:b08:0:7::1")) "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.0.0.0.0.0.0.0.8.0.b.0.2.0.b.2.ip6.arpa."- , (~?=) (ip6arpa (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."- , (~?=) (ip6arpa (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."+ , (~?=) (toIP6ARPA (IPv6Addr "::1")) "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA."+ , (~?=) (toIP6ARPA (IPv6Addr "2b02:0b08:0:7::0001")) "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.0.0.0.0.0.0.0.8.0.b.0.2.0.b.2.IP6.ARPA."+ , (~?=) (toIP6ARPA (IPv6Addr "2b02:b08:0:7::1")) "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.0.0.0.0.0.0.0.8.0.b.0.2.0.b.2.IP6.ARPA."+ , (~?=) (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." ]