{-# LANGUAGE MultiParamTypeClasses, RecordWildCards, TypeOperators #-} module Network.Data.Ethernet.AddressResolutionProtocol ( ARPPacket (..) , ARPQueryPacket(..) , ARPReplyPacket(..) , arpOpCode , getARPPacket , putARPPacket ) where import Network.Data.Ethernet.EthernetAddress import Network.Data.IPv4.IPAddress import Data.Word import qualified Data.Binary.Get as Strict import qualified Data.Binary.Put as Strict data ARPPacket = ARPQuery ARPQueryPacket | ARPReply ARPReplyPacket deriving (Show, Eq) data ARPQueryPacket = ARPQueryPacket { querySenderEthernetAddress :: EthernetAddress , querySenderIPAddress :: IPAddress , queryTargetIPAddress :: IPAddress } deriving (Show,Eq) data ARPReplyPacket = ARPReplyPacket { replySenderEthernetAddress :: EthernetAddress , replySenderIPAddress :: IPAddress , replyTargetEthernetAddress :: EthernetAddress , replyTargetIPAddress :: IPAddress } deriving (Show, Eq) arpOpCode :: ARPPacket -> Word16 arpOpCode (ARPQuery _) = queryOpCode arpOpCode (ARPReply _) = replyOpCode queryOpCode, replyOpCode :: Word16 queryOpCode = 1 replyOpCode = 2 -- | Parser for ARP packets getARPPacket :: Strict.Get (Maybe ARPPacket) getARPPacket = do _ <- Strict.getWord16be _ <- Strict.getWord16be _ <- Strict.getWord8 _ <- Strict.getWord8 opCode <- Strict.getWord16be sha <- getEthernetAddress spa <- getIPAddress tha <- getEthernetAddress tpa <- getIPAddress body <- if opCode == queryOpCode then return ( Just (ARPQuery (ARPQueryPacket { querySenderEthernetAddress = sha , querySenderIPAddress = spa , queryTargetIPAddress = tpa } ) ) ) else if opCode == replyOpCode then return (Just (ARPReply (ARPReplyPacket { replySenderEthernetAddress = sha , replySenderIPAddress = spa , replyTargetEthernetAddress = tha , replyTargetIPAddress = tpa } ) ) ) else return Nothing return body putARPPacket :: ARPPacket -> Strict.Put putARPPacket body = case body of (ARPQuery (ARPQueryPacket {..})) -> Strict.putWord16be ethernetHardwareType >> Strict.putWord16be ipProtocolType >> Strict.putWord8 numberOctetsInEthernetAddress >> Strict.putWord8 numberOctetsInIPAddress >> Strict.putWord16be queryOpCode >> putEthernetAddress querySenderEthernetAddress >> putIPAddress querySenderIPAddress >> putEthernetAddress (ethernetAddress 0 0 0 0 0 0) >> putIPAddress queryTargetIPAddress (ARPReply (ARPReplyPacket {..})) -> Strict.putWord16be ethernetHardwareType >> Strict.putWord16be ipProtocolType >> Strict.putWord8 numberOctetsInEthernetAddress >> Strict.putWord8 numberOctetsInIPAddress >> Strict.putWord16be replyOpCode >> putEthernetAddress replySenderEthernetAddress >> putIPAddress replySenderIPAddress >> putEthernetAddress replyTargetEthernetAddress >> putIPAddress replyTargetIPAddress ethernetHardwareType :: Word16 ethernetHardwareType = 1 ipProtocolType :: Word16 ipProtocolType = 0x0800 numberOctetsInEthernetAddress :: Word8 numberOctetsInEthernetAddress = 6 numberOctetsInIPAddress :: Word8 numberOctetsInIPAddress = 4