packages feed

ip6addr-0.2: src/IsIPv6Addr.hs

--   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