module Net.ICMP where -- Internet Control Message Protocol -- http://rfc.net/rfc792.html import Net.Bits import Net.Utils import Net.Packet import Net.PacketParsing data Packet = EchoRequest EchoMsg | EchoReply EchoMsg | Other { type_ :: !MessageType, code :: !Word8, chksum :: !Word16, content :: UArray Int Word8 } deriving Show data EchoMsg = Echo { ident :: !Word16 , seqNum :: !Word16 , echoData :: UArray Int Word8 } deriving Show instance Parse Packet where parse = do (t,c,s) <- parse case t of Echo_Request -> EchoRequest # parse Echo_Reply -> EchoReply # parse _ -> Other t c s # parse instance Parse EchoMsg where parse = Echo # parse <# parse <# parse {- -- XXX: Assuming only Echo messages icmpParse :: InPacket -> EchoMsg icmpParse p = Echo { reply = (p `byteAt` 0) == 0 , ident = p `wordAt` 4 , seqNum = fromIntegral (p `wordAt` 6) , echoData = toUArray (p { from = from p + 8, len = len p - 8 }) } -} instance Unparse Packet where unparse = unparse . icmpUnparse icmpUnparse (EchoRequest m) = echoUnparse False m icmpUnparse (EchoReply m) = echoUnparse True m --icmpUnparse (Other ...) = echoUnparse :: Bool -> EchoMsg -> OutPacket echoUnparse reply m = addChunk (array (0,7) (zip [0..] [a1,a2,a3,a4,b1,b2,b3,b4])) $ addChunk (echoData m) $ emptyOutPack where a1 = if reply then 0 else 8 a2 = 0 (a3,a4) = (check .!. 1, check .!. 0) (b1,b2) = (ident m .!. 1, ident m .!. 0) (b3,b4) = (seqNum m .!. 1, seqNum m .!. 0) check = checksum $ bytes_to_words_big ([a1,a2,0,0,b1,b2,b3,b4] ++ elems (echoData m)) data MessageType = Echo_Reply | Unknown1 | Unknown2 | Destination_Unreachable | Source_Quench | Redirect | Unknown6 | Unknown7 | Echo_Request | Unknown9 | Unknown10 | Time_Exceeded | Parameter_Problem | Timestamp | Timestamp_Reply | Information_Request | Information_Reply | UnknownOther deriving (Eq,Enum,Bounded,Show) instance Parse MessageType where parse = toEnum' # word8 where toEnum' w = if nfromEnum hi then UnknownOther else toEnum (fromEnum n) where n=fromEnum w lo,hi::MessageType lo=minBound hi=maxBound {- -- dependent type, the type determines the shape of -- code & content data Header = Header { msgType :: !MessageType , msgCode :: !Word8 , msgChecksum :: !Word16 , msgContent :: ![Word8] } -------------------------------------------------------------------------------- -- Destination unreachable -------------------------------------------------------------------------------- data Dest = Net_unreachable | Host_unreachable | Protocol_unreachable | Port_unreachable | Fragmentation_needed_and_DF_set | Source_route_failed deriving (Show,Enum) -------------------------------------------------------------------------------- -- Time exceeded -------------------------------------------------------------------------------- data TimeExceeded = Time_to_live_exceeded_in_transit | Fragment_reassembly_time_exceeded deriving (Show,Enum) -------------------------------------------------------------------------------- -- Parameter problem -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- -- Source quench -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- -- Redirect message -------------------------------------------------------------------------------- data RedirectMsg = Netwrok | Host | ToS_Network | ToS_Host -------------------------------------------------------------------------------- -- Echo & echo reply messages -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- -- Time stamp & time stamp reply reply messages -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- -- Information request & information reply message -------------------------------------------------------------------------------- -}