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 +14/−3
- IsIPv6Addr.hs +0/−112
- LICENSE +2/−2
- Main.hs +0/−72
- Makefile +1/−2
- README +3/−5
- ip6addr.cabal +23/−19
- src/CidrSuffix.hs +48/−0
- src/IP6AddrGen.hs +135/−0
- src/IP6AddrVal.hs +78/−0
- src/IsIPv6Addr.hs +111/−0
- test/inputs +4/−0
- test/test.pl +35/−10
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" }