packages feed

ip6addr 0.2 → 0.3

raw patch · 13 files changed

+350/−422 lines, 13 filesdep ~basenew-component:exe:ip6addrcan

Dependency ranges changed: base

Files

ChangeLog view
@@ -1,13 +1,25 @@+2010-11-20	Michel Boucey <michel.boucey@gmail.com>++	- Version 0.3 released.+	- The command-line tool 'ip6addrval' is renamed (for the+	  last time) 'ip6addrcan'. This tool now outputs rewrited+	  valid IPv6 addresses canonized in conformation with+	  RFC 5952, which updates RFC 4291.+	- ip6addrgen is not updated yet from RFC 4291 to RFC 5952.+	  Outputted adresses from ip6addrgen have to be pipelined+	  through ip6addrcan.+ 2010-08-09	Michel Boucey <michel.boucey@gmail.com>  	- Version 0.2 released.-	- The command-line tool 'ip6addr' is renamed ip6addrval.+	- The command-line tool 'ip6addr' is renamed 'ip6addrval'. 	  This tool now validates CIDR suffix if exists and           outputs IPv6 adresses with CIDR prefixes cutted off. 	- The command-line tool 'ip6addrgen' is added.           This tool generates random IPv6 adresses.-          Two options : -n to provide a count of IPv6 adresses to output,-          -p to provide an uncompressed prefix to apply to each outputted address.+          Two options : -n to provide a count of IPv6 adresses+	  to output, -p to provide an uncompressed prefix to apply+	  to each outputted address. 	 2009-09-11	Michel Boucey <michel.boucey@gmail.com> 
LICENSE view
@@ -1,4 +1,8 @@-ip6addr provides command-line tools to filters parsed IPv6 Addresses against RFC 4291 and to generate random IPv6 addresses
+ip6addr provides command-line tools (written in Haskell) to deal with text representation of IPv6 Addresses:
+
+- ip6addrcan parses and canonizes IPv6 addresses against RFC 4291 and RFC 5952.
+
+- ip6addrgen generates random IPv6 addresses.
 
 Copyright (c) 2009-2010, Michel Boucey All rights reserved.
 
− Makefile
@@ -1,19 +0,0 @@-RHS=runhaskell Setup.hs--all: clean configure build install--clean:-	$(RHS) clean--configure: clean-	$(RHS) configure--build: clean configure-	$(RHS) build--.PHONY: test-test:-	perl ./test/test.pl--install: clean configure build-	$(RHS) install
− README
@@ -1,4 +0,0 @@-ip6addr provides command-line tools written in Haskell for filtering
-IPv6 addresses parsed against RFC 4291 and generating random IPv6 addresses
-
-Copyright (c) 2009-2010, Michel Boucey All rights reserved.
ip6addr.cabal view
@@ -1,23 +1,27 @@ Name:           ip6addr-Version:        0.2+Version:        0.3 Author:         Michel Boucey <michel.boucey@gmail.com> Maintainer:     Michel Boucey <michel.boucey@gmail.com> Homepage:       http://www.cybervisible.fr/ip6addr Category:       Network,Console-Synopsis:       Command-line tools to filter parsed IPv6 Addresses against RFC 4291 and generate random IPv6 adresses-Description:    ip6addr consists of two command-line tools: ip6addrval which filters IPv6 addresses parsed against RFC 4291. By default, ip6addrval outputs only validated inputs, i.e. IPv6 addresses, removing CIDR suffix if necessary. -e option throws out discarded inputs to stderr (which have of course to be redirected). The second command-line tool, ip6addrgen, generates random IPv6 adresses. -p option allows to provide a prefix to all IPv6 adresses to generate. -n option allows to provide the amount of IPv6 addresses to generate.+Synopsis:       Command-line tools to deal with IPv6 Addresses text representation+Description:    ip6addr consists of two command-line tools: ip6addrcan which filters IPv6 addresses parsed against RFC 4291 and canonized in conformation with RFC 5952. By default, ip6addrcan outputs only validated inputs, i.e. IPv6 addresses, removing CIDR suffix if necessary. Already compressed IPv6 adresses are recomputed. -e option throws out discarded inputs to stderr (which have of course to be redirected). The second command-line tool, ip6addrgen, generates random IPv6 adresses. -p option allows to provide a prefix to all IPv6 adresses to generate. -n option allows to provide the amount of IPv6 addresses to generate. Outputted IPv6 addresses have to be pipelined through ip6addrcan to be canonized. License:        BSD3 License-File:   LICENSE Build-Type:     Simple Cabal-Version:  >= 1.2 -Executable ip6addrval+extra-source-files:src/IPv6Addr.hs,+                   src/CidrSuffix.hs,+                   ChangeLog++Executable ip6addrcan     Hs-Source-Dirs: src -    Main-Is:  IP6AddrVal.hs-    Build-Depends:  base >4 && <5+    Main-Is:  IP6AddrCan.hs+    Build-Depends:  base >= 4 && <= 5  Executable ip6addrgen     Hs-Source-Dirs: src     Main-Is:  IP6AddrGen.hs-    Build-Depends:  base >4 && <5,+    Build-Depends:  base >= 4 && <= 5,                     random
src/CidrSuffix.hs view
@@ -1,48 +1,23 @@---   ip6addr filters parsed IPv6 Addresses against RFC 4291
---   Copyright (c) 2009-2010, Michel Boucey
---   All rights reserved.
-
---   Redistribution and use in source and binary forms,
---   with or without modification, are permitted provided that
---   the following conditions are met:
-
---   Redistributions of source code must retain the above copyright notice,
---   this list of conditions and the following disclaimer. Redistributions in
---   binary form must reproduce the above copyright notice, this list of
---   conditions and the following disclaimer in the documentation and/or other
---   materials provided with the distribution. The name of the author may not be
---   used to endorse or promote products derived from this software without
---   specific prior written permission.
-
---   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
---   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
---   THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
---   PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
---   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
---   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
---   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
---   OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
---   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
---   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
---   ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-module CidrSuffix where
+module CidrSuffix (removeCidrSuffix) where
 
 import Data.Char (isDigit)
 import Data.List (groupBy)
 import Data.Function (on)
 
 isCidrSuffix :: String -> Bool
-isCidrSuffix s = if all isDigit s && ((length s > 1 && head s /= '0')||(length s == 1))
-				 then t >= 0 && t <= 128 else False
-				 where t = read s::Int
+isCidrSuffix s =
+    (all isDigit s && ((length s > 1 && head s /= '0')||(length s == 1)))
+    && (t >= 0 && t <= 128)
+    where t = read s::Int
 
 removeCidrSuffix :: String -> String
 removeCidrSuffix [] = []
 removeCidrSuffix s
-		  | l == 1 = s
-		  | l == 3 = if g !! 1 == "/" && (isCidrSuffix $ last g) then head g else []
+                  | l == 1 = s
+                  | l == 3 =
+                      if g !! 1 == "/" && isCidrSuffix (last g)
+                      then head g else []
 		  | otherwise = []
-		  where
-			g = groupBy ((==) `on` (=='/')) s
-			l = length g
+                  where
+                      g = groupBy ((==) `on` (=='/')) s
+                      l = length g
+ src/IP6AddrCan.hs view
@@ -0,0 +1,51 @@+import System.IO+import System.Exit+import System.Environment+import System.Console.GetOpt++-- local import+import IPv6Addr+import CidrSuffix++data Flag = Help | Version | Stderr deriving (Show,Eq)++options :: [OptDescr Flag]+options =+          [Option "v" [] (NoArg Version) "Show version number"+          ,Option "e" [] (NoArg Stderr)  "Throw out discarded inputs to stderr"+          ,Option "h" [] (NoArg Help)    "Show usage"]++parseArgs args = case getOpt RequireOrder options args of+                 ([],[],[])           -> evalInputs . lines =<< getContents+                 ([Version],[],[])    -> putStrLn version >> exit+                 ([Help],[],[])       -> putStrLn (usageInfo help options) >> exit+                 ([Stderr],[],[])     -> evalInputsErr . lines =<< getContents+                 ([Stderr],inputs,[]) -> evalInputsErr inputs+                 ([],inputs,[])       -> evalInputs inputs+                 (_,_,errs)           -> hPutStr stderr (concat errs ++ usageInfo help options)+                                             >> exitWith (ExitFailure 1)++evalInputs :: [String] -> IO ()+evalInputs [] = exit+evalInputs (i:is) =+    case maybeIPv6Addr a of+        Just b -> putStrLn b >> evalInputs is+        Nothing -> evalInputs is+    where a = removeCidrSuffix i++evalInputsErr :: [String] -> IO ()+evalInputsErr [] = exit+evalInputsErr (i:is) =+    case maybeIPv6Addr a of+        Just b -> putStrLn b >> evalInputsErr is+        Nothing -> hPutStrLn stderr i >> evalInputsErr is+    where a = removeCidrSuffix i+			   +version = "ip6addrcan version 0.3"++help   = "Usage: ip6addrcan [-v|-h] | [-e] [address ...]\n"++exit   = exitWith ExitSuccess++main :: IO ()+main = getArgs >>= parseArgs
src/IP6AddrGen.hs view
@@ -1,70 +1,49 @@---   ip6addrgen generates random IPv6 Addresses---   Copyright (c) 2010, Michel Boucey---   All rights reserved.----   Redistribution and use in source and binary forms,---   with or without modification, are permitted provided that---   the following conditions are met:----   Redistributions of source code must retain the above copyright notice,---   this list of conditions and the following disclaimer. Redistributions in---   binary form must reproduce the above copyright notice, this list of---   conditions and the following disclaimer in the documentation and/or other---   materials provided with the distribution. The name of the author may not be---   used to endorse or promote products derived from this software without---   specific prior written permission.----   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"---   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,---   THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR---   PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR---   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,---   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,---   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;---   OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,---   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR---   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF---   ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- import System.IO import System.Exit import Control.Monad (replicateM,replicateM_) import System.Environment import System.Console.GetOpt-import Data.List (intercalate)+import Data.List (groupBy,intercalate) import System.Random (randomRIO)-import Data.Char (isDigit,intToDigit,toUpper)---- local import-import IsIPv6Addr+import Data.Char (isDigit,intToDigit,toLower,isHexDigit)+import Data.Function (on)  -- IPv6 address prefix validation and random rewrite of trailing zero(s)-	++tokenizeIPv6Input :: String -> [String]+tokenizeIPv6Input = groupBy ((==) `on` (==':'))++is16bitsToken :: String -> Bool+is16bitsToken s = l < 5 && l > 0 && all isHexDigit s where l = length s+ ipv6PrefixToken :: String -> Char ipv6PrefixToken s-                 | s ==":" = 'c'-                 | is16bitsToken s == True = '6'+                 | s == ":" = 'c'+                 | is16bitsToken s = '6'                  | otherwise = '?' 		    inputIPv6PrefixToInternalRep :: [String] -> String inputIPv6PrefixToInternalRep = map ipv6PrefixToken  readLast16bitsTokenOfPrefix :: (Monad m) => String -> m (String,Int)-readLast16bitsTokenOfPrefix s = do let p = span (== '0') $ reverse s in return ((reverse $ snd p),(length $ fst p))+readLast16bitsTokenOfPrefix s =+    let p = span (== '0') $ reverse s in return (reverse(snd p),length (fst p))  prefixRewrite :: String -> IO ()							-prefixRewrite s =  do-			t <- readLast16bitsTokenOfPrefix s-			putStr $ map toUpper $fst t-			g <- genNhex $ snd t-			putStr g+prefixRewrite s =+    do+        t <- readLast16bitsTokenOfPrefix s+        putStr $ map toLower $fst t+        g <- genNhex $ snd t+        putStr g 				 -- IPv6 Address random generation  genRandomHex :: IO Char-genRandomHex = do-			r <- randomRIO(0,15)::IO Int-			return (toUpper $ intToDigit r)			+genRandomHex =+    do+        r <- randomRIO(0,15)::IO Int+        return (toLower $ intToDigit r)			 					 genNhex :: Int -> IO String genNhex n = replicateM n genRandomHex@@ -79,23 +58,24 @@ mkRandomIPv6Addr = n16bitsToken 8 >> putStr "\n"  mkRandomIPv6AddrWithPrefix :: String -> String -> IO ()-mkRandomIPv6AddrWithPrefix s p =	do-					let c = count16bitsToken p-					if c < 9-						then-							do-								prefixRewrite s-								if c == 8 then putStr "" else putStr ":"-								n16bitsToken (8 - c)-								putStr "\n"-						else putStr "Prefix too long\n"  >> exit+mkRandomIPv6AddrWithPrefix s p =+    do+        let c = count16bitsToken p+        if c < 9 then+            do+                prefixRewrite s+                if c == 8 then putStr "" else putStr ":"+                n16bitsToken (8 - c)+                putStr "\n"+                else putStr "Prefix too long\n"  >> exit  ipv6AddrGen :: Int -> String -> IO () ipv6AddrGen n []	=	replicateM_ n mkRandomIPv6Addr -ipv6AddrGen n s 	= 	let p = inputIPv6PrefixToInternalRep $ tokenizeIPv6Input s in-						if ('?' `notElem` p) && (head p /= 'c') && (last p /= 'c')-						then do replicateM_ n (mkRandomIPv6AddrWithPrefix s p)-						else putStr "Bad input for -p option\n"+ipv6AddrGen n s 	=+    let p = inputIPv6PrefixToInternalRep $ tokenizeIPv6Input s in+    if ('?' `notElem` p) && (head p /= 'c') && (last p /= 'c')+    then replicateM_ n (mkRandomIPv6AddrWithPrefix s p)+    else putStr "Bad input for -p option\n" 			 -- GetOpt stuff @@ -103,29 +83,29 @@  options :: [OptDescr Flag] options =-          [Option ['n'] []  (ReqArg Count "count")  "Number of IPv6 adresses to output"-		  ,Option ['p'] [] 	(ReqArg Prefix "prefix") "An uncompressed IPv6 prefix"-		  ,Option ['v'] [] 	(NoArg Version) "Show version number"-          ,Option ['h'] []	(NoArg Help)    "Show usage"]+          [Option "n" [] (ReqArg Count "count")  "Number of IPv6 adresses to output"+          ,Option "p" [] (ReqArg Prefix "prefix") "An uncompressed IPv6 prefix"+          ,Option "v" [] (NoArg Version) "Show version number"+          ,Option "h" [] (NoArg Help)    "Show usage"]  safeReadN :: String -> String -> IO ()-safeReadN n p = if all (\x -> isDigit x) n-				then do ipv6AddrGen (read n :: Int) p >> exit-				else putStrLn "Bad input for -n option" >> exit+safeReadN n p =+    if all isDigit n+    then ipv6AddrGen (read n :: Int) p >> exit+    else putStrLn "Bad input for -n option" >> exit  parseArgs :: [String] -> IO ()				-parseArgs args = case getOpt RequireOrder options args of-					([],[],[])					-> mkRandomIPv6Addr >> exit-					([Count n],_,_)				-> safeReadN n ""-					([Prefix p],_,_)			-> ipv6AddrGen 1 p >> exit-					([Count n,Prefix p],_,_)	-> safeReadN n p-					([Prefix p,Count n],_,_)	-> safeReadN n p-					([Prefix p,Count n,_],_,_)	-> putStrLn version >> exit-					([Version],_,_)    			-> putStrLn version >> exit-					([Help],_,_)      			-> putStrLn (usageInfo help options) >> exit-					(_,_,_)           			-> hPutStr stderr (usageInfo help options)+parseArgs args =+    case getOpt RequireOrder options args of+        ([Count n],_,_) -> safeReadN n ""+        ([Prefix p],_,_) -> ipv6AddrGen 1 p >> exit+        ([Count n,Prefix p],_,_) -> safeReadN n p+        ([Prefix p,Count n],_,_) -> safeReadN n p+        ([Version],_,_) -> putStrLn version >> exit+        ([Help],_,_) -> putStrLn (usageInfo help options) >> exit+        (_,_,_) -> putStrLn (usageInfo help options) >> exit -version = "0.1"+version = "ip6addrgen version 0.2"  help = "Usage: ip6addrgen [-v|-h] | [-n] [-p]\n" 
− src/IP6AddrVal.hs
@@ -1,78 +0,0 @@---   ip6addrval filters parsed IPv6 Addresses against RFC 4291---   Copyright (c) 2009-2010, Michel Boucey---   All rights reserved.----   Redistribution and use in source and binary forms,---   with or without modification, are permitted provided that---   the following conditions are met:----   Redistributions of source code must retain the above copyright notice,---   this list of conditions and the following disclaimer. Redistributions in---   binary form must reproduce the above copyright notice, this list of---   conditions and the following disclaimer in the documentation and/or other---   materials provided with the distribution. The name of the author may not be---   used to endorse or promote products derived from this software without---   specific prior written permission.----   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"---   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,---   THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR---   PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR---   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,---   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,---   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;---   OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,---   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR---   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF---   ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.--import System.IO-import System.Exit-import System.Environment-import System.Console.GetOpt---- local import-import IsIPv6Addr-import CidrSuffix--data Flag = Help | Version | Stderr-            deriving (Show,Eq)--options :: [OptDescr Flag]-options =-          [Option ['v'] [] (NoArg Version) "Show version number"-          ,Option ['e'] [] (NoArg Stderr)  "Throw out discarded inputs to stderr"-          ,Option ['h'] [] (NoArg Help)    "Show usage"]--parseArgs args = case getOpt RequireOrder options args of-                 ([],[],[])           -> evalInputs . lines =<< getContents-                 ([Version],[],[])    -> putStrLn version >> exit-                 ([Help],[],[])       -> putStrLn (usageInfo help options) >> exit-                 ([Stderr],[],[])     -> evalInputsErr . lines =<< getContents-                 ([Stderr],inputs,[]) -> evalInputsErr inputs-                 ([],inputs,[])       -> evalInputs inputs-                 (_,_,errs)           -> hPutStr stderr (concat errs ++ usageInfo help options)-											>> exitWith (ExitFailure 1)--evalInputs :: [String] -> IO ()-evalInputs [] = exit-evalInputs (i:is) = if isIPv6Addr a-                    then hPutStrLn stdout a >> evalInputs is-                    else evalInputs is-			where a = removeCidrSuffix i-					-evalInputsErr :: [String] -> IO ()-evalInputsErr [] = exit-evalInputsErr (i:is) = if isIPv6Addr a-                       then hPutStrLn stdout a >> evalInputsErr is-                       else hPutStrLn stderr i >> evalInputsErr is-  	 		   where a = removeCidrSuffix i-					-version = "0.2"--help   = "Usage: ip6addrval [-v|-h] | [-e] [address ...]\n"--exit   = exitWith ExitSuccess--main :: IO ()-main = getArgs >>= parseArgs
+ src/IPv6Addr.hs view
@@ -0,0 +1,199 @@+module IPv6Addr (maybeIPv6Addr) where++import Data.Char (isDigit,isHexDigit,toLower)+import Data.List (group,groupBy,intercalate,intersperse,elemIndex)+import Data.Function (on)+import Data.Maybe++tokenizedBy :: String -> Char -> [String]+tokenizedBy s c = groupBy ((==) `on` ( == c)) s++-- Parsing embedded IPv4 address++data IPv4AddrToken = Dot | EightBits String  deriving (Eq,Show)++dot :: String -> Maybe IPv4AddrToken+dot s = if s == "." then Just Dot else Nothing++eightBitsToken :: String -> Maybe IPv4AddrToken+eightBitsToken s =+    let t = read s::Int+    in+        if not(null s) && all isDigit s && t >= 0 && t <= 255+            then Just (EightBits s) else Nothing++ipv4Token :: String -> Maybe IPv4AddrToken+ipv4Token s+    | isJust(dot s) = Just Dot+    | isJust(eightBitsToken s) = Just (EightBits s)+    | otherwise  = Nothing++ipv4Addr :: String -> Maybe IPv6AddrToken+ipv4Addr s =+    do+        let r = map ipv4Token (s `tokenizedBy` '.')+        if (Nothing `notElem` r) && (length r == 7)+           then Just (IPv4Addr s) else Nothing++-- Parsing IPv6 Address++type IPv6Addr = String++data IPv6AddrToken = SixteenBits String | AllZeros  | Colon  | DoubleColon+                     | IPv4Addr String deriving (Eq,Show)++colon :: String -> Maybe IPv6AddrToken+colon s = if s == ":" then Just Colon  else Nothing++doubleColon :: String -> Maybe IPv6AddrToken+doubleColon s = if s == "::" then Just DoubleColon else Nothing++sixteenBits:: String -> Maybe IPv6AddrToken+sixteenBits s =+    if length s < 5 then+         do+              -- "Leading zeros MUST be suppressed" (RFC 5952, 4.1)+              let s'= dropWhile (=='0') s+              if length s' < 5 && all isHexDigit s'+                 then case s' of+                     "" -> Just AllZeros+                     -- Hexadecimal digits MUST be in lowercase (RFC 4.3)+                     otherwise -> Just (SixteenBits (map toLower s'))+                 else Nothing+    else Nothing++ipv6AddrToken :: String -> Maybe IPv6AddrToken+ipv6AddrToken s+           | isJust s' = s'+           | isJust(colon s) = Just Colon+           | isJust(doubleColon s) = Just DoubleColon+           | isJust(ipv4Addr s) = Just (IPv4Addr s)+           | otherwise = Nothing+           where s' = sixteenBits s++ipv6TokenToString :: IPv6AddrToken -> String+ipv6TokenToString (SixteenBits t) = t+ipv6TokenToString Colon = ":"+ipv6TokenToString DoubleColon = "::"+-- "A single 16-bit 0000 field MUST be represented as 0" (RFC 5952, 4.1)+ipv6TokenToString AllZeros = "0"+ipv6TokenToString (IPv4Addr i) = i++countIPv4Addr :: [Maybe IPv6AddrToken] -> Int+countIPv4Addr ts =+    foldr oneMoreIPv4Token 0 ts+        where+                   oneMoreIPv4Token t c =+                       case t of+                           Just (IPv4Addr _) -> c + 1+                           otherwise -> c++countDoubleColon :: [Maybe IPv6AddrToken] -> Int+countDoubleColon ts =+    foldr oneMoreDoubleColon 0 ts+        where+                   oneMoreDoubleColon t c =+                       case t of+                           Just DoubleColon -> c + 1+                           otherwise -> c++firstValidToken :: [Maybe IPv6AddrToken] -> Bool+firstValidToken ts =+    case head ts of+        Just (SixteenBits _) -> True+        Just DoubleColon -> True+        Just AllZeros -> True+        otherwise -> False++ipv6AddrConstraints :: [Maybe IPv6AddrToken] -> Bool+ipv6AddrConstraints [] = False+ipv6AddrConstraints [Just DoubleColon] = True+ipv6AddrConstraints [Just DoubleColon,Just (SixteenBits "1")] = True+ipv6AddrConstraints ts  =+    do+        let cdcts = countDoubleColon ts+        let lents = length ts+        let lastt = last ts+        let lenconst = ( (lents == 15 && cdcts <= 0) || (lents < 15 && cdcts == 1) )+        ((firstValidToken ts && all isJust ts) &&+            (case countIPv4Addr ts of+                0 -> case lastt of+                          Just (SixteenBits _) -> lenconst+                          Just DoubleColon -> lenconst+                          Just AllZeros -> lenconst+                          otherwise -> False+                1 -> case lastt of+                          Just (IPv4Addr _) -> (lents == 13 && cdcts <= 0) || (lents < 13 && cdcts == 1)+                          otherwise -> False+                otherwise -> False))+ +maybeIPv6Addr :: String -> Maybe IPv6Addr+maybeIPv6Addr "::" = Just "::"+maybeIPv6Addr s =+    do+        let s'  = map ipv6AddrToken (s `tokenizedBy` ':')+        if ipv6AddrConstraints s'+            then+                (if Just DoubleColon `notElem` s' then+                    Just (replaceTheLongestZerosRun s') else+                    Just (replaceTheLongestZerosRun (expendDoubleColon s')))+            else Nothing+			+expendDoubleColon :: [Maybe IPv6AddrToken] -> [Maybe IPv6AddrToken]+expendDoubleColon mit = do+    let s = splitAt (fromJust $ elemIndex (Just DoubleColon) mit) mit+    let fsts = fst s+    let snds = if length(snd s) >= 1 then tail(snd s) else []+    let fste = if null fsts then [] else fsts ++ [Just Colon]+    let snde = if null snds then [] else Just Colon : snds+    fste ++ allZerosTokensReplacement(quantityOfAllZerosTokenToReplace mit) ++ snde+		+quantityOfAllZerosTokenToReplace x =+    8 - foldl (\c x -> if (x /= Just DoubleColon) && (x /= Just Colon)+                            then c+1 else c) 0 x++allZerosTokensReplacement x = intersperse (Just Colon) (replicate x (Just AllZeros))++-- "the longest run of consecutive 16-bit 0 fields MUST be shortened" (RFC 5952, 4.2.3)+-- All the stuff to deal with replacement of the longest zeros run by a double colon++longestLengthZerosRun x = maximum $ map longest x+                    where+                        longest t =+                            case t of+                                (True,i) -> i+                                otherwise -> 0++firstLongestZerosRunIndex :: (Num b) => [(Bool, b)] -> b -> b+firstLongestZerosRunIndex x y = sum $ snd $ unzip $ takeWhile (/=(True,y)) x++zerosRunsList :: [Maybe IPv6AddrToken] -> [(Bool, Int)]+zerosRunsList x = map helper $ groupZerosRuns x+                  where+                      helper h =+                          if head h == "0"+                          then (True,lh)+                          else (False,lh)+                          where lh = length h++groupZerosRuns :: [Maybe IPv6AddrToken] -> [[String]]+groupZerosRuns lts = group $ filter (/=":") $ map ipv6TokenToString $ catMaybes lts++onlyStringTokens :: [Maybe IPv6AddrToken] -> [String]+onlyStringTokens x = filter (/=":") $ map ipv6TokenToString $ catMaybes x++replaceTheLongestZerosRun :: [Maybe IPv6AddrToken] -> IPv6Addr+replaceTheLongestZerosRun s' = zerosToDoubleColon (onlyStringTokens s') (zerosRunToReplace $ zerosRunsList s')++zerosRunToReplace :: [(Bool, Int)] -> (Int, Int)+zerosRunToReplace t =+    let l = longestLengthZerosRun t+    in (firstLongestZerosRunIndex t l,l)++zerosToDoubleColon :: [String] -> (Int,Int) -> IPv6Addr+-- No all zeros token, so no double colon replacement...+zerosToDoubleColon ls (_,0) = intercalate ":" ls+-- "The symbol '::' MUST NOT be used to shorten just one 16-bit 0 field" (RFC 4.2.2)+zerosToDoubleColon ls (_,1) = intercalate ":" ls+zerosToDoubleColon ls (i,l) =+    concat $ intersperse ":" (take i ls) ++ ["::"] ++ intersperse ":" (drop (i+l) ls)
− src/IsIPv6Addr.hs
@@ -1,111 +0,0 @@---   ip6addr filters parsed IPv6 Addresses against RFC 4291---   Copyright (c) 2009-2010, Michel Boucey---   All rights reserved.----   Redistribution and use in source and binary forms,---   with or without modification, are permitted provided that---   the following conditions are met:----   Redistributions of source code must retain the above copyright notice,---   this list of conditions and the following disclaimer. Redistributions in---   binary form must reproduce the above copyright notice, this list of---   conditions and the following disclaimer in the documentation and/or other---   materials provided with the distribution. The name of the author may not be---   used to endorse or promote products derived from this software without---   specific prior written permission.----   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"---   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,---   THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR---   PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR---   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,---   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,---   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;---   OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,---   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR---   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF---   ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.--module IsIPv6Addr where--import Data.Char (isDigit,isHexDigit)-import Data.List (groupBy)-import Data.Function (on)---- Parsing embedded IPv4 address--is8bitsToken :: String -> Bool-is8bitsToken s = if (not $ null s) && all isDigit s-                 then t >= 0 && t <= 255 else False-                 where t = read s::Int--isIPv4Token :: String -> Char-isIPv4Token s-              | s == "." = 'd'-              | is8bitsToken s == True = '8'-              | otherwise = '?'--internalIPv4Rep :: [String] -> String-internalIPv4Rep = map isIPv4Token--tokenizeIPv4AddrInput :: String -> [String]-tokenizeIPv4AddrInput = groupBy ((==) `on` (=='.'))--parseIPv4Tokens :: String -> Bool-parseIPv4Tokens s = s == "8d8d8d8"--embeddedIPv4Addr :: String -> Int-embeddedIPv4Addr s-                   | f == 0 = 0-                   | f == 1 = 1-                   | otherwise = -1-                   where f = length $ filter (=='4') s--isIPv4Addr :: String -> Bool-isIPv4Addr = parseIPv4Tokens . internalIPv4Rep . tokenizeIPv4AddrInput---- Parsing IPv6 Address--is16bitsToken :: String -> Bool-is16bitsToken s = l < 5 && l > 0 && all isHexDigit s where l = length s--tokenizeIPv6Input :: String -> [String]-tokenizeIPv6Input = groupBy ((==) `on` (==':'))--ipv6AddrToken :: String -> Char-ipv6AddrToken s-               | s ==":" = 'c'-               | s == "::" = 'd'-               | is16bitsToken s == True = '6'-               | isIPv4Addr s == True = '4'-               | otherwise = '?'--ipv6AddrInternalRep :: [String] -> String-ipv6AddrInternalRep = map ipv6AddrToken--isCompressed :: String -> Int-isCompressed s-              | c == 0 = 0-              | c == 1 = 1-              | otherwise = -1-              where c = length $ filter (=='d') s--ipv6AddrConstraints :: String -> Bool-ipv6AddrConstraints s = if '?' `notElem` s then-							let h = head s in-								if (h == '6' || h == 'd') then-									case embeddedIPv4Addr s of-										-1 -> False-										0 -> (e == '6' || e == 'd') && ((l == 15 && c <= 0) || (l < 15 && c == 1))-										1 -> (e == '4' && l == 13 && c <= 0) || (e == '4' && l < 13 && c == 1)-								else False-						else False-								where-									l = length s-									c = isCompressed s-									e = last s--isIPv6Addr :: String -> Bool-isIPv6Addr s-			| length s < 2 = False-			| otherwise = ipv6AddrConstraints $ ipv6AddrInternalRep $ tokenizeIPv6Input s
− test/inputs
@@ -1,30 +0,0 @@-:::!0-::4AF:!0-:!0-::!1-0:0:0:0:0:0:0:0!1-0:0:0:0:0:0:0:0:0!0-::1!1-0:0:0:0:0:0:0:1!1-ABCD:EF01:2345:6789:ABCD:EF01:2345:6789!1-0:ABCD:EF01:2345:6789:ABCD:EF01:2345:6789!0-ABCD:EF01:123.67.3.45:6789:ABCD:EF01:2345:78.123.23.79!0-ABCD:EF01:2345:6789:ABTD:EF01:2345:6789!0-ABCD::2345:6789:ABTD::2345:6789!0-:EF01:2345:6789:ABCD:EF01:2345:6789!0-2001:DB8:0:0:8:800:200C:417A!1-2001:DB8:0:0:8:8004:200CD:417A!0-FF01:0:0:0:0:0:0:101!1-FF01::101!1-0:0:0:0:0:0:13.1.68.3!1-::13.1.68.3!1-0:0:0:0:0:FFFF:129.144.52.38!1-0:0:0:0:0:FFFF:0:129.144.52.38!0-0:0:0:0:0:129.144.52.38:0!0-::FFFF:129.144.52.38!1-::FFFF:129.144.52.38:ADEF!0-129.144.52.38:ADEF!0-::1/129!0-::1:3ACF/124!1-A:123D//64!0-DF:87::4:34.1.34.56:/23!0
− test/test.pl
@@ -1,55 +0,0 @@-#!/usr/bin/perl -w--use Cwd 'abs_path';-use File::Basename;--chdir(dirname(abs_path($0)));--$ip6addrval = "../dist/build/ip6addrval/ip6addrval";-$ip6addrgen = "../dist/build/ip6addrgen/ip6addrgen";--if ((-e $ip6addrval) && (-e $ip6addrgen)) {--	print "'ip6addrval < a set of inputs'\n";--	@testList1 = `cat ./inputs`;-	$fcpt = 0;-	foreach (@testList1) {-		@test = split(/!/);-		$result = `$ip6addrval $test[0]`;-		chomp($result);-		if ($test[1] == "0") {print "Bad ";} else {print "Good";}	-		print " input >> '$test[0]' >> ";-		@s=split(/\//,$test[0]);-		if (($result eq "" && $test[1] == "0")||($result eq $s[0] && $test[1] == "1")) {-			print "PASSED\n";-		} else {-			print "FAILED !\n";-			$fcpt++;-		} -		$cpt++;-	}--	print "30 tests, $cpt passed.\n\n";--	print "'ip6addrgen -p 1234:abcd -n 5 | ip6addrval'\n";-	@testList2 = `$ip6addrgen -p 1234:abcd -n 5 | $ip6addrval`;-	foreach (@testList2) { print $_; $cpt++;$tcpt++}-	print "5 random addresses generated >> $tcpt outputted.\n\n";--	$tcpt = 0;-	print "\n'ip6addrgen -p ff00 -n 5 | ip6addrval'\n";-	@testList2 = `$ip6addrgen -p ff00 -n 5 | $ip6addrval`;-	foreach (@testList2) { print $_; $cpt++;$tcpt++}-	print "5 random addresses generated >> $tcpt outputted.\n\n";-	-	$tcpt = 0;-	print "\n'ip6addrgen -p a:b:c:d:e:f000 -n 5 | ip6addrval'\n";-	@testList2 = `$ip6addrgen -p a:b:c:d:e:f000 -n 5 | $ip6addrval`;-	foreach (@testList2) { print $_; $cpt++;$tcpt++}-	print "5 random addresses generated >> $tcpt outputted.\n";--	print "\nTests: $cpt\nFailed tests: ".(45 - $cpt)."\n\n";-} else {-	print "Run  a 'make build' before testing...\n"-}