diff --git a/ChangeLog b/ChangeLog
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/IsIPv6Addr.hs b/IsIPv6Addr.hs
deleted file mode 100644
--- a/IsIPv6Addr.hs
+++ /dev/null
@@ -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            
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -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:
 
diff --git a/Main.hs b/Main.hs
deleted file mode 100644
--- a/Main.hs
+++ /dev/null
@@ -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
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/README b/README
--- a/README
+++ b/README
@@ -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.
diff --git a/ip6addr.cabal b/ip6addr.cabal
--- a/ip6addr.cabal
+++ b/ip6addr.cabal
@@ -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
diff --git a/src/CidrSuffix.hs b/src/CidrSuffix.hs
new file mode 100644
--- /dev/null
+++ b/src/CidrSuffix.hs
@@ -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
diff --git a/src/IP6AddrGen.hs b/src/IP6AddrGen.hs
new file mode 100644
--- /dev/null
+++ b/src/IP6AddrGen.hs
@@ -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
diff --git a/src/IP6AddrVal.hs b/src/IP6AddrVal.hs
new file mode 100644
--- /dev/null
+++ b/src/IP6AddrVal.hs
@@ -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
diff --git a/src/IsIPv6Addr.hs b/src/IsIPv6Addr.hs
new file mode 100644
--- /dev/null
+++ b/src/IsIPv6Addr.hs
@@ -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
diff --git a/test/inputs b/test/inputs
--- a/test/inputs
+++ b/test/inputs
@@ -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
diff --git a/test/test.pl b/test/test.pl
--- a/test/test.pl
+++ b/test/test.pl
@@ -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"
 }
