packages feed

ip6addr 0.1.1 → 0.2

raw patch · 13 files changed

+454/−225 lines, 13 filesdep +randomdep ~basenew-component:exe:ip6addrgennew-component:exe:ip6addrval

Dependencies added: random

Dependency ranges changed: base

Files

ChangeLog view
@@ -1,9 +1,20 @@-2009-06-26	Michel Boucey <michel.boucey@gmail.com>--	- Version 0.1 released.+2010-08-09	Michel Boucey <michel.boucey@gmail.com> +	- Version 0.2 released.+	- 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.+	 2009-09-11	Michel Boucey <michel.boucey@gmail.com>  	- Version 0.1.1 released. 	- Fixed three bugs in IPv6 address validation. 	- Added a test written in Perl.++2009-06-26	Michel Boucey <michel.boucey@gmail.com>++	- Version 0.1 released.
− IsIPv6Addr.hs
@@ -1,112 +0,0 @@---   ip6addr filters parsed IPv6 Addresses against RFC 4291
---   Copyright (c) 2009, 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 (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 = '?'
-               
-internalIPv6Rep :: [String] -> String
-internalIPv6Rep = map ipv6AddrToken
-
-parseInternalRep :: String -> Bool
-parseInternalRep s = '?' `notElem` s
-
-isCompressed :: String -> Int
-isCompressed s
-              | c == 0 = 0
-              | c == 1 = 1
-              | otherwise = -1
-              where c = length $ filter (=='d') s
-
-lengthConstraints :: String -> Bool
-lengthConstraints s = case embeddedIPv4Addr s of
-			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)
-                        -1 -> False
-			where l = length s
-			      c = isCompressed s
-			      e = last s
-
-validFirstToken :: String -> Bool
-validFirstToken s = h == '6' || h == 'd' where h = head s 
-
-testsIPv6Addr :: String -> Bool
-testsIPv6Addr s = lengthConstraints s && parseInternalRep s && validFirstToken s
-   
-isIPv6Addr :: String -> Bool
-isIPv6Addr = testsIPv6Addr . internalIPv6Rep . tokenizeIPv6Input            
LICENSE view
@@ -1,6 +1,6 @@-ip6addr filters parsed IPv6 Addresses against RFC 4291
+ip6addr provides command-line tools to filters parsed IPv6 Addresses against RFC 4291 and to generate random IPv6 addresses
 
-Copyright (c) 2009, Michel Boucey All rights reserved.
+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:
 
− Main.hs
@@ -1,72 +0,0 @@---   ip6addr filters parsed IPv6 Addresses against RFC 4291
---   Copyright (c) 2009, 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
-
-data Flag = Help | Version | Stderr
-            deriving (Show,Eq)
-
-options :: [OptDescr Flag]
-options =
-          [Option ['v'] ["version"] (NoArg Version) "show version number"
-          ,Option ['e'] ["errors"]  (NoArg Stderr)  "throw out discarded inputs to stderr"
-          ,Option ['h'] ["help"]    (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 (a:as) = if isIPv6Addr a
-                    then hPutStrLn stdout a >> evalInputs as
-                    else hPutStr stderr ""  >> evalInputs as
-
-evalInputsErr :: [String] -> IO ()
-evalInputsErr [] = exit
-evalInputsErr (a:as) = if isIPv6Addr a
-                       then hPutStrLn stdout a >> evalInputsErr as
-                       else hPutStrLn stderr a >> evalInputsErr as
-
-version = "ip6addr Version 0.1.1"
-help   = "Usage: ip6addr [-v|-h] | [-e] [address ...]\n"
-exit    = exitWith ExitSuccess
-
-main = getArgs >>= parseArgs
Makefile view
@@ -11,10 +11,9 @@ build: clean configure 	$(RHS) build - .PHONY: test test:-	./test/test.pl+	perl ./test/test.pl  install: clean configure build 	$(RHS) install
README view
@@ -1,6 +1,4 @@-ip6addr is a command line tool written in Haskell for filtering
-IPv6 addresses parsed against RFC 4291. By default, ip6addr outputs
-only validated inputs, i.e. IPv6 addresses. Option -e throws out
-discarded inputs to stderr, that have to be redirected.
+ip6addr provides command-line tools written in Haskell for filtering
+IPv6 addresses parsed against RFC 4291 and generating random IPv6 addresses
 
-Copyright (c) 2009, Michel Boucey All rights reserved.
+Copyright (c) 2009-2010, Michel Boucey All rights reserved.
ip6addr.cabal view
@@ -1,19 +1,23 @@-Name:		ip6addr
-Version:	0.1.1
-Author:         Michel Boucey <michel.boucey@gmail.com>
-Maintainer:     Michel Boucey <michel.boucey@gmail.com>
-Homepage:       http://www.cybervisible.fr/ip6addr
-Category:	Console,Network
-Synopsis:	Command line tool that filters parsed IPv6 Addresses against RFC 4291
-Description:	ip6addr is a command line tool for filtering IPv6 addresses parsed against RFC 4291. By default, ip6addr outputs only validated inputs, i.e. IPv6 addresses. Option -e throws out discarded inputs to stderr, that have to be redirected.
-License:        BSD3
-License-File:   LICENSE
-Build-Type:	Simple
-Cabal-Version:	>= 1.2
-Extra-Source-Files: IsIPv6Addr.hs
-Extra-Source-Files: README
-Extra-Source-Files: Makefile
-
-Executable ip6addr
-    Main-Is:  Main.hs
-    Build-Depends:	base <= 4 && < 5
+Name:           ip6addr+Version:        0.2+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.+License:        BSD3+License-File:   LICENSE+Build-Type:     Simple+Cabal-Version:  >= 1.2++Executable ip6addrval+    Hs-Source-Dirs: src +    Main-Is:  IP6AddrVal.hs+    Build-Depends:  base >4 && <5++Executable ip6addrgen+    Hs-Source-Dirs: src+    Main-Is:  IP6AddrGen.hs+    Build-Depends:  base >4 && <5,+                    random
+ src/CidrSuffix.hs view
@@ -0,0 +1,48 @@+--   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
+
+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
+
+removeCidrSuffix :: String -> String
+removeCidrSuffix [] = []
+removeCidrSuffix s
+		  | l == 1 = s
+		  | l == 3 = if g !! 1 == "/" && (isCidrSuffix $ last g) then head g else []
+		  | otherwise = []
+		  where
+			g = groupBy ((==) `on` (=='/')) s
+			l = length g
+ src/IP6AddrGen.hs view
@@ -0,0 +1,135 @@+--   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 System.Random (randomRIO)+import Data.Char (isDigit,intToDigit,toUpper)++-- local import+import IsIPv6Addr++-- IPv6 address prefix validation and random rewrite of trailing zero(s)+	+ipv6PrefixToken :: String -> Char+ipv6PrefixToken s+                 | s ==":" = 'c'+                 | is16bitsToken s == True = '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))++prefixRewrite :: String -> IO ()							+prefixRewrite s =  do+			t <- readLast16bitsTokenOfPrefix s+			putStr $ map toUpper $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)			+					+genNhex :: Int -> IO String+genNhex n = replicateM n genRandomHex++n16bitsToken :: Int -> IO ()+n16bitsToken n = replicateM n (genNhex 4) >>= putStr . intercalate ":"++count16bitsToken :: String -> Int+count16bitsToken = foldl (\x y -> if y == '6' then x+1 else x) 0++mkRandomIPv6Addr :: IO ()+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++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"+			+-- GetOpt stuff++data Flag = Help | Version | Count String | Prefix String deriving (Show)++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"]++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++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)++version = "0.1"++help = "Usage: ip6addrgen [-v|-h] | [-n] [-p]\n"++exit = exitWith ExitSuccess++main :: IO ()+main = getArgs >>= parseArgs
+ src/IP6AddrVal.hs view
@@ -0,0 +1,78 @@+--   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/IsIPv6Addr.hs view
@@ -0,0 +1,111 @@+--   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 view
@@ -24,3 +24,7 @@ ::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 view
@@ -4,19 +4,24 @@ use File::Basename;  chdir(dirname(abs_path($0)));-$ip6addr = "../dist/build/ip6addr/ip6addr"; -if (-e $ip6addr) {-	@testList = `cat ./inputs`;+$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;-	print "\n";-	foreach (@testList) {+	foreach (@testList1) { 		@test = split(/!/);-		$result = `$ip6addr $test[0]`;+		$result = `$ip6addrval $test[0]`; 		chomp($result);-		if ($test[1] == "0") {print "Bad";} else {print "Good";}	-		print " input \"$test[0]\" - ";-		if (($result eq "" && $test[1] == "0")||($result eq $test[0] && $test[1] == "1")) {+		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";@@ -24,7 +29,27 @@ 		}  		$cpt++; 	}-	print "\nTests: $cpt\nFailed tests: $fcpt\n\n";++	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" }