ip6addr-0.2: src/IP6AddrGen.hs
-- 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