rws-0.1.1.2: src/IcmpV6.hs
{-# LANGUAGE CPP #-}
module IcmpV6 where
import Control.Monad
import Data.Binary.Put
import qualified Data.ByteString.Lazy as B
import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Perm
import Lexer
import Packet
import PseudoSum
import Util
#ifdef HRWS_TEST
import Debug.Trace
import Test.QuickCheck hiding ((.&.))
import Test.Framework (Test)
import Test.Framework.Providers.QuickCheck2 (testProperty)
import Text.Printf
#endif
parseIcmpV6Pkt :: Parser Packet -> Parser IcmpV6Pkt
parseIcmpV6Pkt f = permute
(tuple <$?> (8, parseIntAttribute "type")
<|?> (0, try (parseIntAttribute "code"))
<|?> (0, try (parseIntAttribute "csum"))
<|?> (0xffffffff, try (parseIntAttribute "pad"))
<|?> (True, parseBoolAttribute "fixcsum")
<|?> ([PPayload defaultPayload], parsePayload f))
where
tuple t c cs pad fc = IcmpV6Pkt (IcmpV6 t c cs pad fc)
icmpV6Decl :: Parser Packet -> Parser Packet
icmpV6Decl f = do
symbol "icmpv6"
g <- parseIcmpV6Pkt f
return (PIcmpV6 g)
icmpV6WriteHdr :: IcmpV6 -> Put
icmpV6WriteHdr p = do
putWord8 $ icmpV6Type p
putWord8 $ icmpV6Code p
putWord16be $ icmpV6Csum p
when (icmpV6Pad p /= 0xffffffff) $ putWord32be $ icmpV6Pad p
icmpV6Write :: IcmpV6 -> Maybe Packet -> B.ByteString -> Put
icmpV6Write h mp bs = do
let hdrLen = if icmpV6Pad h /= 0xffffffff
then 8
else 4
let len = hdrLen + fromIntegral (B.length bs)
let csum = if icmpV6CorrectCsum h
then let sum32 = csumAdd (B.unpack $ runPut $ icmpV6WriteHdr h) $ genPseudoSum mp len in
csumFin $ csumAdd (B.unpack bs) sum32
else icmpV6Csum h
icmpV6WriteHdr h {icmpV6Csum = csum}
putLazyByteString bs
instance PacketWriteable IcmpV6Pkt where packetWrite p = icmpV6Write $ icmpV6PktHeader p
#ifdef HRWS_TEST
{- Unit Tests -}
instance Arbitrary IcmpV6 where
arbitrary = do
t <- arbitrary
c <- arbitrary
cs <- arbitrary
pad <- arbitrary
return (IcmpV6 t c cs pad True)
testValidParse :: String -> (IcmpV6 -> Bool) -> Bool
testValidParse str fn =
case parse (dummyParsePacket icmpV6Decl) "packet parse" str of
Left err -> trace (show err) False
Right val -> fn $ testIcmpV6Pkt val
testIcmpV6Pkt :: Packet -> IcmpV6
testIcmpV6Pkt (PIcmpV6 p) = icmpV6PktHeader p
testIcmpV6Pkt _ = error "Unexpected packet type"
testIcmpV6Default :: () -> Bool
testIcmpV6Default _ =
let cmp p = defaultIcmpV6 == p in
testValidParse "(icmpv6)" cmp
testIcmpV6Packet :: IcmpV6 -> Bool
testIcmpV6Packet pkt =
let cmp p = pkt == p in
testValidParse (printf "(icmpv6 type=%d code=%d csum=%d pad=%d)" (icmpV6Type pkt)
(icmpV6Code pkt) (icmpV6Csum pkt) (icmpV6Pad pkt)) cmp
testIcmpV6Write :: () -> Bool
testIcmpV6Write _ =
let expPkt = B.pack [0x80, 0x00, 0xb1, 0x4c, 0xca, 0xfe, 0xba, 0xbe] in
let cmp p = runPut (icmpV6Write p Nothing B.empty) == expPkt in
testValidParse "(icmpv6 type=128 code=0 pad=0xcafebabe csum=0xb14c fixcsum=false)" cmp
icmpV6Tests :: [Test]
icmpV6Tests = [
testProperty "ICMPv6: Default" testIcmpV6Default,
testProperty "ICMPv6: Packet" testIcmpV6Packet,
testProperty "ICMPv6: Write" testIcmpV6Write
]
#endif