rws-0.1.1.2: src/Icmp.hs
{-# LANGUAGE CPP #-}
module Icmp where
import Data.Binary.Put
import qualified Data.ByteString.Lazy as B
import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Perm
import Util
import Packet
import Lexer
#ifdef HRWS_TEST
import Debug.Trace
import Test.QuickCheck hiding ((.&.))
import Test.Framework (Test)
import Test.Framework.Providers.QuickCheck2 (testProperty)
import Text.Printf
#endif
parseIcmpPkt :: Parser Packet -> Parser IcmpPkt
parseIcmpPkt f = permute
(tuple <$?> (8, parseIntAttribute "type")
<|?> (0, try (parseIntAttribute "code"))
<|?> (0, try (parseIntAttribute "csum"))
<|?> (0xcafe, parseIntAttribute "id")
<|?> (0x1, parseIntAttribute "seq")
<|?> (True, parseBoolAttribute "fixcsum")
<|?> ([PPayload defaultPayload], parsePayload f))
where
tuple t c cs i s fc = IcmpPkt (Icmp t c cs i s fc)
icmpDecl :: Parser Packet -> Parser Packet
icmpDecl f = do
symbol "icmp"
g <- parseIcmpPkt f
return (PIcmp g)
icmpWriteHdr :: Icmp -> Put
icmpWriteHdr p = do
putWord8 $ icmpType p
putWord8 $ icmpCode p
putWord16be $ icmpCsum p
putWord16be $ icmpId p
putWord16be $ icmpSeq p
icmpWrite :: Icmp -> Maybe Packet -> B.ByteString -> Put
icmpWrite h _ bs = do
icmpWriteHdr h
putLazyByteString bs
instance PacketWriteable IcmpPkt where packetWrite p = icmpWrite (icmpPktHeader p)
#ifdef HRWS_TEST
{- Unit Tests -}
instance Arbitrary Icmp where
arbitrary = do
t <- arbitrary
c <- arbitrary
cs <- arbitrary
i <- arbitrary
s <- arbitrary
return (Icmp t c cs i s True)
testValidParse :: String -> (Icmp -> Bool) -> Bool
testValidParse str fn =
case parse (dummyParsePacket icmpDecl) "packet parse" str of
Left err -> trace (show err) False
Right val -> fn $ testIcmpPkt val
testIcmpPkt :: Packet -> Icmp
testIcmpPkt (PIcmp p) = icmpPktHeader p
testIcmpPkt _ = error "Unexpected packet type"
testIcmpDefault :: () -> Bool
testIcmpDefault _ =
let cmp p = defaultIcmp == p in
testValidParse "(icmp)" cmp
testIcmpPacket :: Icmp -> Bool
testIcmpPacket pkt =
let cmp p = pkt == p in
testValidParse (printf "(icmp type=%d code=%d csum=%d id=%d seq=%d fixcsum=true)" (icmpType pkt)
(icmpCode pkt) (icmpCsum pkt) (icmpId pkt) (icmpSeq pkt)) cmp
testIcmpWrite :: () -> Bool
testIcmpWrite _ =
let expPkt = B.pack [0x08, 0x00, 0xab, 0xcd, 0x04, 0xd2, 0x16, 0x2e] in
let cmp p = runPut (icmpWrite p Nothing B.empty) == expPkt in
testValidParse "(icmp id=1234 seq=5678 csum=0xabcd)" cmp
icmpTests :: [Test]
icmpTests = [
testProperty "ICMP: Default" testIcmpDefault,
testProperty "ICMP: Packet" testIcmpPacket,
testProperty "ICMP: Write" testIcmpWrite
]
#endif