{-# INCLUDE <pcap.h> #-} {-# INCLUDE <pcap-bpf.h> #-} {-# INCLUDE <netinet/in.h> #-} {-# INCLUDE <sys/socket.h> #-} {-# INCLUDE "config.h" #-} {-# LINE 1 "Network/Pcap.hsc" #-} ------------------------------------------------------------------------------ {-# LINE 2 "Network/Pcap.hsc" #-} -- | -- Module : Network.Pcap -- Copyright : (c) Antiope Associates LLC 2004 -- License : BSD-style (see the file libraries/network/license) -- -- Maintainer : nickburlett@mac.com, dominic.steinitz@blueyonder.co.uk -- Stability : experimental -- Portability : non-portable -- -- The "Pcap" modules is a binding to all of the functions in -- libpcap (See <http://www.tcpdump.org> for more information.) -- -- Only a minimum of mashalling is done; for light duty applications, -- the user can extract the length of the captured buffer -- from the packet header record and use 'peekArray' to convert the -- captured data to a list. For illustration: -- -- > import Pcap -- > import Foreign -- > -- > main = do -- > let -- > printIt :: PktHdr -> Ptr Word8 -> IO () -- > printIt ph bytep = do -- > a <- peekArray (fromIntegral (caplen ph)) bytep -- > print a -- > -- > p <- openLive "em0" 100 True 10000 -- > s <- withForeignPtr p $ \ptr -> do -- > dispatch ptr (-1) printIt -- > return () -- > -- -- Users requiring higher perfomance (such as O(1) access to any byte -- in a packet) should roll their own marshalling functions. -- -- Note that the SockAddr exported here is not the SockAddr from -- Network.Socket. The SockAddr from Network.Socket corresponds to -- @struct sockaddr_in@ in BSD terminology. The SockAddr record here -- is BDS's @struct sockaddr@. See W.R.Stevens, TCP Illustrated, volume 2, -- for further eluciadation. -- -- This binding should be portable for systems that can use the libpcap -- from tcpdump.org. It will not work with Winpcap, a similar library -- for Windows, although adapting it should not prove difficult. -- ------------------------------------------------------------------------------ module Network.Pcap ( -- * Types Pcap, Pdump, BpfProgram, Callback, Link(..), Interface(..), PcapAddr(..), SockAddr(..), Network(..), PktHdr(..), Statistics(..), -- * Device opening openOffline, -- :: String -> IO Pcap openLive, -- :: String -> Int -> Bool -> Int -> IO Pcap openDead, -- :: Int -> Int -> IO Pcap openDump, -- :: Ptr PcapTag -> String -> IO Pdump -- * Filter handling setFilter, -- :: Ptr PcapTag -> String -> Bool -> Word32 -> IO () compileFilter, -- :: Int -> Int -> String -> Bool -> Word32 -> IO BpfProgram -- * Device utilities lookupDev, -- :: IO String findAllDevs, -- :: IO [Interface] lookupNet, -- :: String -> IO Network -- * Interface control -- ** Blocking mode setNonBlock, -- :: Ptr PcapTag -> Bool -> IO () getNonBlock, -- :: Ptr PcapTag -> IO Bool -- ** Link layer utilities datalink, -- :: Ptr PcapTag -> IO Link setDatalink, -- :: Ptr PcapTag -> Link -> IO () listDatalinks, -- :: Ptr PcapTag -> IO [Link] -- * Packet processing dispatch, -- :: Ptr PcapTag -> Int -> Callback -> IO Int loop, -- :: Ptr PcapTag -> Int -> Callback -> IO Int next, -- :: Ptr PcapTag -> IO (PktHdr, Ptr Word8) dump, -- :: Ptr PcapDumpTag -> Ptr PktHdr -> Ptr Word8 -> IO () -- * Miscellaneous statistics, -- :: Ptr PcapTag -> IO Statistics majorVersion, -- :: Ptr PcapTag -> IO Int minorVersion, -- :: Ptr PcapTag -> IO Int isSwapped, -- :: Ptr PcapTag -> IO Bool snapshotLen, -- :: Ptr PcapTag -> IO Int ) where import Maybe (isNothing, fromJust ) import Data.Word ( Word8, Word32 ) import Foreign.Ptr ( Ptr, plusPtr, nullPtr, FunPtr, freeHaskellFunPtr ) import Foreign.C.String ( peekCString, withCString ) import Foreign.C.Types ( CInt, CUInt, CChar, CUChar, CLong ) import Foreign.ForeignPtr ( ForeignPtr, FinalizerPtr, newForeignPtr ) import Foreign.Marshal.Alloc ( alloca, allocaBytes, free ) import Foreign.Marshal.Array ( allocaArray, peekArray ) import Foreign.Marshal.Utils ( fromBool, toBool ) import Foreign.Storable ( Storable(..) ) import Network.Socket ( Family(..), unpackFamily) import System.IO.Error ( userError ) {-# LINE 119 "Network/Pcap.hsc" #-} {-# LINE 120 "Network/Pcap.hsc" #-} {-# LINE 121 "Network/Pcap.hsc" #-} {-# LINE 122 "Network/Pcap.hsc" #-} {-# LINE 124 "Network/Pcap.hsc" #-} data BpfProgramTag -- | Compiled Berkeley Packet Filter program type BpfProgram = ForeignPtr BpfProgramTag data PcapTag -- | packet capture descriptor type Pcap = ForeignPtr PcapTag data PcapDumpTag -- | savefile descriptor type Pdump = ForeignPtr PcapDumpTag data PktHdr = PktHdr { sec :: Word32, -- ^ timestamp (seconds) usec :: Word32, -- ^ timestamp (microseconds) caplen :: Word32, -- ^ number of bytes present in capture len :: Word32 -- ^ number of bytes on the wire } deriving (Show) data Statistics = Statistics { recv :: Word32, -- ^ packets received drop :: Word32, -- ^ packets dropped by libpcap ifdrop :: Word32 -- ^ packets dropped by the interface } deriving (Show) -- -- Data types for interface list -- -- | The interface structure data Interface = Interface { ifName :: String, -- ^ the interface name ifDescription :: String, -- ^ interface description string (if any) ifAddresses :: [PcapAddr], -- ^ address families supported by this interface ifFlags :: Word32 } deriving (Read, Show) -- | The address structure data PcapAddr = PcapAddr { ifAddr :: SockAddr, -- ^ interface address ifMask :: Maybe SockAddr, -- ^ network mask ifBcast :: Maybe SockAddr, -- ^ broadcast address ifPeer :: Maybe SockAddr -- ^ address of peer, of a point-to-point link } deriving (Read, Show) -- | -- The socket address record. Note that this is not the same as -- SockAddr from Network.Sockets. (That is a Haskell version of -- struct sockaddr_in. This is the real struct sockaddr from the BSD -- network stack.) -- data SockAddr = SockAddr { sockAddrFamily :: Family, -- ^ an address family exported by Network.Socket sockAddrAddr :: [Word8] } deriving (Read, Show) -- | The network address record. Both the address and mask are in -- network byte order. data Network = Network { netAddr :: Word32, -- ^ IPv4 network address netMask :: Word32 -- ^ IPv4 netmask } deriving (Read, Show) -- -- Open a device -- -- | -- openOffline opens a \"savefile\" for reading. The file foramt is the -- as used for tcpdump. The string \"-\" is a synonym for stdin. -- openOffline :: String -- ^ filename -> IO Pcap openOffline name = withCString name $ \namePtr -> allocaArray (256) $ \errPtr -> do {-# LINE 205 "Network/Pcap.hsc" #-} ptr <- pcap_open_offline namePtr errPtr if ptr == nullPtr then peekCString errPtr >>= ioError . userError else do final <- h2c pcap_close newForeignPtr final ptr -- | -- openLive is used to get a packet descriptor that can be used to -- look at packates on the network. The arguments are the device name, -- the snapshot legnth (in bytes), the promiscuity of the interface -- (True == promiscuous) and a timeout in milliseconds. -- -- Using \"any\" as the device name will capture packets from all interfaces. -- On some systems, reading from the \"any\" device is incompatible with -- setting the interfaces into promiscuous mode. In that case, only packets -- whose link layer addresses match those of the interfaces are captured. -- openLive :: String -- ^ device name -> Int -- ^ snapshot length -> Bool -- ^ set to promiscuous mode? -> Int -- ^ timeout in milliseconds -> IO Pcap openLive name snaplen promisc timeout = withCString name $ \namePtr -> allocaArray (256) $ \errPtr -> do {-# LINE 232 "Network/Pcap.hsc" #-} ptr <- pcap_open_live namePtr (fromIntegral snaplen) (fromBool promisc) (fromIntegral timeout) errPtr if ptr == nullPtr then peekCString errPtr >>= ioError . userError else do final <- h2c pcap_close newForeignPtr final ptr -- | -- openDead is used to get a packet capture descriptor without opening -- a file or device. It is typically used to test packet filter compilation -- by setFilter. The arguments are the linktype and the snapshot length. -- openDead :: Link -- ^ datalink type -> Int -- ^ snapshot length -> IO Pcap -- ^ packet capture descriptor openDead link snaplen = do ptr <- pcap_open_dead (packLink link) (fromIntegral snaplen) if ptr == nullPtr then ioError $ userError "Can't open dead pcap device" else do final <- h2c pcap_close newForeignPtr final ptr foreign import ccall unsafe pcap_open_offline :: Ptr CChar -> Ptr CChar -> IO (Ptr PcapTag) foreign import ccall unsafe pcap_close :: Ptr PcapTag -> IO () foreign import ccall unsafe pcap_open_live :: Ptr CChar -> CInt -> CInt -> CInt -> Ptr CChar -> IO (Ptr PcapTag) foreign import ccall unsafe pcap_open_dead :: CInt -> CInt -> IO (Ptr PcapTag) foreign import ccall "wrapper" h2c :: (Ptr PcapTag -> IO()) -> IO (FinalizerPtr a) -- -- Open a dump device -- -- | -- openDump opens a \"savefile\" for writing. This savefile is written to -- by the dump function. The arguments are a raw packet capture descriptor -- and the filename, with \"-\" as a synonym for stdout. -- openDump :: Ptr PcapTag -- ^ packet capture descriptor -> String -- ^ savefile name -> IO Pdump -- ^ davefile descriptor openDump hdl name = withCString name $ \namePtr -> do ptr <- pcap_dump_open hdl namePtr if (ptr == nullPtr) then throwPcapError hdl else do final <- h2c' pcap_dump_close newForeignPtr final ptr foreign import ccall unsafe pcap_dump_open :: Ptr PcapTag -> Ptr CChar -> IO (Ptr PcapDumpTag) foreign import ccall unsafe pcap_dump_close :: Ptr PcapDumpTag -> IO () foreign import ccall "wrapper" h2c' :: (Ptr PcapDumpTag -> IO()) -> IO (FinalizerPtr a) -- -- Set the filter -- -- | -- Set a filter on the specified packet capture descriptor. Valid filter -- strings are those accepted by tcpdump. -- setFilter :: Ptr PcapTag -- ^ packet capture descriptor -> String -- ^ filter string -> Bool -- ^ optimize? -> Word32 -- ^ IPv4 network mask -> IO () setFilter hdl filt opt mask = withCString filt $ \filter -> do allocaBytes ((8)) $ \bpfp -> do {-# LINE 317 "Network/Pcap.hsc" #-} ret <- pcap_compile hdl bpfp filter (fromBool opt) (fromIntegral mask) if ret == (-1) then throwPcapError hdl else do ret <- pcap_setfilter hdl bpfp if ret == (-1) then throwPcapError hdl else pcap_freecode bpfp -- | -- Compile a filter for use by another program using the Berkeley Packet -- Filter library. -- compileFilter :: Int -- ^ snapshot length -> Link -- ^ datalink type -> String -- ^ filter string -> Bool -- ^ optimize? -> Word32 -- ^ IPv4 network mask -> IO BpfProgram compileFilter snaplen link filt opt mask = withCString filt $ \filter -> allocaBytes ((8)) $ \bpfp -> do {-# LINE 345 "Network/Pcap.hsc" #-} ret <- pcap_compile_nopcap (fromIntegral snaplen) (packLink link) bpfp filter (fromBool opt) (fromIntegral mask) if ret == (-1) then ioError $ userError "Pcap.compileFilter error" else do final <- h2c'' pcap_freecode newForeignPtr final bpfp foreign import ccall pcap_compile :: Ptr PcapTag -> Ptr BpfProgramTag -> Ptr CChar -> CInt -> CInt -> IO CInt foreign import ccall pcap_compile_nopcap :: CInt -> CInt -> Ptr BpfProgramTag -> Ptr CChar -> CInt -> CInt -> IO CInt foreign import ccall pcap_setfilter :: Ptr PcapTag -> Ptr BpfProgramTag -> IO CInt foreign import ccall pcap_freecode :: Ptr BpfProgramTag -> IO () foreign import ccall "wrapper" h2c'' :: (Ptr BpfProgramTag -> IO ()) -> IO (FinalizerPtr a) -- -- Find devices -- data DevBuf data DevAddr -- | -- lookupDev returns the name of a device suitable for use with -- openLive and lookupNet. If you only have one interface, it is the -- function of choice. If not, see findAllDevs. -- lookupDev :: IO String lookupDev = allocaArray (256) $ \errPtr -> do {-# LINE 388 "Network/Pcap.hsc" #-} ptr <- pcap_lookupdev errPtr if ptr == nullPtr then peekCString errPtr >>= ioError . userError else peekCString ptr -- | -- findAllDevs returns a list of all the network devices that can -- be opened by openLive. It returns only those devices that the -- calling process has sufficient privileges to open, so it may not -- find every device on the system. -- findAllDevs :: IO [Interface] findAllDevs = alloca $ \dptr -> do allocaArray (256) $ \errPtr -> do {-# LINE 404 "Network/Pcap.hsc" #-} ret <- pcap_findalldevs dptr errPtr if (ret == -1) then peekCString errPtr >>= ioError . userError else do dbuf <- peek dptr dl <- devs2list dbuf pcap_freealldevs dbuf return dl devs2list :: Ptr DevBuf -> IO [Interface] devs2list dbuf | dbuf == nullPtr = do return [] | otherwise = do nextdev <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) dbuf {-# LINE 419 "Network/Pcap.hsc" #-} ds <- devs2list nextdev d <- oneDev dbuf return (d : ds) oneDev :: Ptr DevBuf -> IO Interface oneDev dbuf = do name <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) dbuf {-# LINE 428 "Network/Pcap.hsc" #-} desc <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) dbuf {-# LINE 429 "Network/Pcap.hsc" #-} addrs <- ((\hsc_ptr -> peekByteOff hsc_ptr 12)) dbuf {-# LINE 430 "Network/Pcap.hsc" #-} flags <- ((\hsc_ptr -> peekByteOff hsc_ptr 16)) dbuf {-# LINE 431 "Network/Pcap.hsc" #-} name' <- peekCString name desc' <- if desc /= nullPtr then peekCString desc else return "" addrs' <- addrs2list addrs return (Interface name' desc' addrs' (fromIntegral (flags :: CUInt))) addrs2list :: Ptr DevAddr -> IO [PcapAddr] addrs2list abuf | abuf == nullPtr = do return [] | otherwise = do nextaddr <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) abuf {-# LINE 448 "Network/Pcap.hsc" #-} as <- addrs2list nextaddr a <- oneAddr abuf return (a : as) oneAddr :: Ptr DevAddr -> IO PcapAddr oneAddr abuf = let socka :: Ptr a -> IO (Maybe SockAddr) socka sa = if sa /= nullPtr then do {-# LINE 463 "Network/Pcap.hsc" #-} l <- return ((16)) :: IO CUChar {-# LINE 464 "Network/Pcap.hsc" #-} {-# LINE 465 "Network/Pcap.hsc" #-} f <- (((\hsc_ptr -> peekByteOff hsc_ptr 0)) sa) :: IO CUChar {-# LINE 466 "Network/Pcap.hsc" #-} addr <- peekArray ((fromIntegral l) - ((2))) {-# LINE 468 "Network/Pcap.hsc" #-} ((plusPtr sa ((2))) :: Ptr Word8) {-# LINE 469 "Network/Pcap.hsc" #-} return (Just (SockAddr (unpackFamily (fromIntegral f)) addr)) else return Nothing in do addr <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) abuf >>= socka {-# LINE 476 "Network/Pcap.hsc" #-} mask <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) abuf >>= socka {-# LINE 477 "Network/Pcap.hsc" #-} bcast <- ((\hsc_ptr -> peekByteOff hsc_ptr 12)) abuf >>= socka {-# LINE 478 "Network/Pcap.hsc" #-} peer <- ((\hsc_ptr -> peekByteOff hsc_ptr 16)) abuf >>= socka {-# LINE 479 "Network/Pcap.hsc" #-} if isNothing addr then ioError $ userError "Pcap.oneAddr: null address" else return (PcapAddr (fromJust addr) mask bcast peer) -- | Return the network address and mask for the specified interface -- name. Only valid for IPv4. For other protocols, -- use findAllDevs and search the Address list for the associated -- network mask. -- lookupNet :: String -- ^ device name -> IO Network lookupNet dev = withCString dev $ \name -> alloca $ \netp -> alloca $ \maskp -> do allocaArray (256) $ \errPtr -> do {-# LINE 499 "Network/Pcap.hsc" #-} ret <- pcap_lookupnet name netp maskp errPtr if ret == (-1) then peekCString errPtr >>= ioError . userError else do net <- peek netp mask <- peek maskp return (Network (fromIntegral net) (fromIntegral mask) ) foreign import ccall unsafe pcap_lookupdev :: Ptr CChar -> IO (Ptr CChar) foreign import ccall unsafe pcap_findalldevs :: Ptr (Ptr DevBuf) -> Ptr CChar -> IO CInt foreign import ccall unsafe pcap_freealldevs :: Ptr DevBuf -> IO () foreign import ccall unsafe pcap_lookupnet :: Ptr CChar -> Ptr CUInt -> Ptr CUInt -> Ptr CChar -> IO CInt -- -- Set or read the device mode (blocking/nonblocking) -- -- | Set a packet capture descriptor into non-blocking mode, if the -- second argument is True, otherwise put it in blocking mode. Note -- that the packet capture descripto must have been obtaine from openLive. -- setNonBlock :: Ptr PcapTag -> Bool -> IO () setNonBlock ptr block = allocaArray (256) $ \errPtr -> do {-# LINE 528 "Network/Pcap.hsc" #-} ret <- pcap_setnonblock ptr (fromBool block) errPtr if ret == (-1) then peekCString errPtr >>= ioError . userError else return () -- -- | Return the blocking status of the packet capture descriptor. Ture -- indicates that the descriptor is non-blocking. Descriptors referring -- savefiles opened by openDump always reutre False. -- getNonBlock :: Ptr PcapTag -> IO Bool getNonBlock ptr = allocaArray (256) $ \errPtr -> do {-# LINE 541 "Network/Pcap.hsc" #-} ret <- pcap_getnonblock ptr errPtr if ret == (-1) then peekCString errPtr >>= ioError . userError else return (toBool ret) foreign import ccall unsafe pcap_setnonblock :: Ptr PcapTag -> CInt -> Ptr CChar -> IO CInt foreign import ccall unsafe pcap_getnonblock :: Ptr PcapTag -> Ptr CChar -> IO CInt -- -- Error handling -- throwPcapError :: Ptr PcapTag -> IO a throwPcapError hdl = do msg <- pcap_geterr hdl >>= peekCString ioError (userError msg) foreign import ccall unsafe pcap_geterr :: Ptr PcapTag -> IO (Ptr CChar) -- -- Reading packets -- -- | the type of the callback function passed to dispatch or loop. type Callback = PktHdr -> Ptr Word8 -> IO () type CCallback = Ptr Word8 -> Ptr PktHdr -> Ptr Word8 -> IO () exportCallback :: Callback -> IO (FunPtr CCallback) exportCallback f = exportCCallback $ \_user hdr ptr -> do let ts = ((\hsc_ptr -> hsc_ptr `plusPtr` 0)) hdr {-# LINE 578 "Network/Pcap.hsc" #-} s <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) ts {-# LINE 580 "Network/Pcap.hsc" #-} us <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) ts {-# LINE 581 "Network/Pcap.hsc" #-} caplen <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) hdr {-# LINE 582 "Network/Pcap.hsc" #-} len <- ((\hsc_ptr -> peekByteOff hsc_ptr 12)) hdr {-# LINE 583 "Network/Pcap.hsc" #-} f (PktHdr (fromIntegral (s :: CLong)) (fromIntegral (us :: CLong)) (fromIntegral (caplen :: CUInt)) (fromIntegral (len :: CUInt))) ptr -- | -- Collect and process packets. The arguments are the packet capture -- descriptor, the count and a callback function. -- -- The count is the maximum number of packets to process before returning. -- A count of -1 means process all of the packets received in one buffer -- (if a live capture) or all of the packets in a savefile (if offline). -- -- The callback function is passed two arguments, a packet header -- record and a pointer to the packet data (Ptr Word8). THe header -- record contains the number of bytes captured, whcih can be used -- to marshal the data into a list or array. -- dispatch :: Ptr PcapTag -- ^ packet capture descriptor -> Int -- ^ number of packets to process -> Callback -- ^ packet processing function -> IO Int -- ^ number of packets read dispatch hdl count f = do handler <- exportCallback f result <- pcap_dispatch hdl (fromIntegral count) handler nullPtr freeHaskellFunPtr handler if (result == -1) then throwPcapError hdl else return (fromIntegral result) -- | -- Similar to dispatch, but loop until the number of packets specified -- by the second argument are read. A negative value loops forever. -- -- It does not return when a live read tiemout occurs. Use dispatch instead -- if you wnat to specify a timeout. -- loop :: Ptr PcapTag -- ^ packet cpature descriptor -> Int -- ^ number of packet to read -> Callback -- ^ packet processing function -> IO Int -- ^ number of packets read loop hdl count f = do handler <- exportCallback f result <- pcap_loop hdl (fromIntegral count) handler nullPtr freeHaskellFunPtr handler if (result == -1) then throwPcapError hdl else return (fromIntegral result) -- | -- Read the next packet (by calling dispatch with a count of 1). -- next :: Ptr PcapTag -- ^ packet capture descriptor -> IO (PktHdr, Ptr Word8) -- ^ packet header and data of the next packet next hdl = allocaBytes ((16)) $ \hdr -> do {-# LINE 655 "Network/Pcap.hsc" #-} ptr <- pcap_next hdl hdr if (ptr == nullPtr) then return (PktHdr 0 0 0 0, ptr) else do let ts = ((\hsc_ptr -> hsc_ptr `plusPtr` 0)) hdr {-# LINE 660 "Network/Pcap.hsc" #-} s <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) ts {-# LINE 662 "Network/Pcap.hsc" #-} us <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) ts {-# LINE 663 "Network/Pcap.hsc" #-} caplen <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) hdr {-# LINE 664 "Network/Pcap.hsc" #-} len <- ((\hsc_ptr -> peekByteOff hsc_ptr 12)) hdr {-# LINE 665 "Network/Pcap.hsc" #-} return (PktHdr (fromIntegral (s :: CLong)) (fromIntegral (us :: CLong)) (fromIntegral (caplen :: CUInt)) (fromIntegral (len :: CUInt)), ptr) -- | -- Write the packet data given by the second and third arguments -- to a savefile opened by openDead. dump is designed so it can be -- easily used as a default callback function by dispatch or loop. -- dump :: Ptr PcapDumpTag -- ^ savefile descriptor -> Ptr PktHdr -- ^ packet header record -> Ptr Word8 -- ^ packet data -> IO () dump hdl hdr pkt = pcap_dump hdl hdr pkt foreign import ccall "wrapper" exportCCallback :: CCallback -> IO (FunPtr CCallback) foreign import ccall pcap_dispatch :: Ptr PcapTag -> CInt -> FunPtr CCallback -> Ptr Word8 -> IO CInt foreign import ccall pcap_loop :: Ptr PcapTag -> CInt -> FunPtr CCallback -> Ptr Word8 -> IO CInt foreign import ccall pcap_next :: Ptr PcapTag -> Ptr PktHdr -> IO (Ptr Word8) foreign import ccall pcap_dump :: Ptr PcapDumpTag -> Ptr PktHdr -> Ptr Word8 -> IO () -- -- Datalink manipulation -- -- | -- Returns the datalink type associated with the given pcap descriptor. -- datalink :: Ptr PcapTag -> IO Link datalink hdl = do ret <- pcap_datalink hdl return (unpackLink ret) -- | -- Sets the datalink type for a given pcap descriptor. -- setDatalink :: Ptr PcapTag -> Link -> IO () setDatalink hdl link = do ret <- pcap_set_datalink hdl (packLink link) if (ret == -1) then throwPcapError hdl else return () -- | -- List all the datalink types supported by a pcap descriptor. Entries -- from the resulting list are valid arguments to setDatalink. -- listDatalinks :: Ptr PcapTag -> IO [Link] listDatalinks hdl = alloca $ \lptr -> do ret <- pcap_list_datalinks hdl lptr if (ret == -1) then throwPcapError hdl else do dlbuf <- peek lptr dls <- peekArray (fromIntegral (ret :: CInt)) dlbuf free dlbuf return (map unpackLink dls) foreign import ccall unsafe pcap_datalink :: Ptr PcapTag -> IO CInt foreign import ccall unsafe pcap_set_datalink :: Ptr PcapTag -> CInt -> IO CInt foreign import ccall unsafe pcap_list_datalinks :: Ptr PcapTag -> Ptr (Ptr CInt) -> IO CInt -- -- Statistics -- data PcapStats = PcapStats -- | -- Returns the number of packets received, the number of packets -- dropped by the packet filter and the number of packets dropped -- by the interface (before processing by the packet filter). -- statistics :: Ptr PcapTag -> IO Statistics statistics hdl = allocaBytes ((12)) $ \stats -> do {-# LINE 762 "Network/Pcap.hsc" #-} ret <- pcap_stats hdl stats if (ret == -1) then throwPcapError hdl else do recv <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) stats {-# LINE 767 "Network/Pcap.hsc" #-} drop <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) stats {-# LINE 768 "Network/Pcap.hsc" #-} ifdrop <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) stats {-# LINE 769 "Network/Pcap.hsc" #-} return (Statistics (fromIntegral (recv :: CUInt)) (fromIntegral (drop :: CUInt)) (fromIntegral (ifdrop :: CUInt))) foreign import ccall unsafe pcap_stats :: Ptr PcapTag -> Ptr PcapStats -> IO Int -- -- Version information -- -- | -- Major version number of the library. -- majorVersion :: Ptr PcapTag -> IO Int majorVersion ptr = do v <- pcap_major_version ptr return (fromIntegral (v :: CInt)) -- | -- Minor version number of the library. -- minorVersion :: Ptr PcapTag -> IO Int minorVersion ptr = do v <- pcap_major_version ptr return (fromIntegral (v :: CInt)) -- | -- isSwapped is True if the current savefile uses a different -- byte order than the one native to the system. -- isSwapped :: Ptr PcapTag -> IO Bool isSwapped ptr = do sw <- pcap_is_swapped ptr return (toBool sw) -- | -- The snapshot length that was used in the call to openLive. -- snapshotLen :: Ptr PcapTag -> IO Int snapshotLen ptr = do l <- pcap_snapshot ptr return (fromIntegral (l :: CInt)) foreign import ccall pcap_major_version :: Ptr PcapTag -> IO CInt foreign import ccall pcap_minor_version :: Ptr PcapTag -> IO CInt foreign import ccall pcap_is_swapped :: Ptr PcapTag -> IO CInt foreign import ccall pcap_snapshot :: Ptr PcapTag -> IO CInt -- -- Utility functions for data link types -- -- | Datalink types. -- -- This covers all of the datalink types defined in bpf.h. -- Types defined on your system may vary. -- data Link = DLT_NULL -- ^ no link layer encapsulation {-# LINE 838 "Network/Pcap.hsc" #-} | DLT_EN10MB -- ^ 10 Mbit per second (or faster) ethernet {-# LINE 840 "Network/Pcap.hsc" #-} {-# LINE 841 "Network/Pcap.hsc" #-} | DLT_EN3MB -- ^ original 3 Mbit per second ethernet {-# LINE 843 "Network/Pcap.hsc" #-} {-# LINE 844 "Network/Pcap.hsc" #-} | DLT_AX25 -- ^ amateur radio AX.25 {-# LINE 846 "Network/Pcap.hsc" #-} {-# LINE 847 "Network/Pcap.hsc" #-} | DLT_PRONET -- ^ Proteon ProNET Token Ring {-# LINE 849 "Network/Pcap.hsc" #-} {-# LINE 850 "Network/Pcap.hsc" #-} | DLT_CHAOS -- ^ Chaos {-# LINE 852 "Network/Pcap.hsc" #-} {-# LINE 853 "Network/Pcap.hsc" #-} | DLT_IEEE802 -- ^ IEEE 802 networks {-# LINE 855 "Network/Pcap.hsc" #-} {-# LINE 856 "Network/Pcap.hsc" #-} | DLT_ARCNET -- ^ ARCNET {-# LINE 858 "Network/Pcap.hsc" #-} {-# LINE 859 "Network/Pcap.hsc" #-} | DLT_SLIP -- ^ Serial line IP {-# LINE 861 "Network/Pcap.hsc" #-} {-# LINE 862 "Network/Pcap.hsc" #-} | DLT_PPP -- ^ Point-to-point protocol {-# LINE 864 "Network/Pcap.hsc" #-} {-# LINE 865 "Network/Pcap.hsc" #-} | DLT_FDDI -- ^ FDDI {-# LINE 867 "Network/Pcap.hsc" #-} {-# LINE 868 "Network/Pcap.hsc" #-} | DLT_ATM_RFC1483 -- ^ LLC SNAP encapsulated ATM {-# LINE 870 "Network/Pcap.hsc" #-} {-# LINE 871 "Network/Pcap.hsc" #-} | DLT_RAW -- ^ raw IP {-# LINE 873 "Network/Pcap.hsc" #-} {-# LINE 874 "Network/Pcap.hsc" #-} | DLT_SLIP_BSDOS -- ^ BSD OS serial line IP {-# LINE 876 "Network/Pcap.hsc" #-} {-# LINE 877 "Network/Pcap.hsc" #-} | DLT_PPP_BSDOS -- ^ BSD OS point-to-point protocol {-# LINE 879 "Network/Pcap.hsc" #-} {-# LINE 880 "Network/Pcap.hsc" #-} | DLT_ATM_CLIP -- ^ Linux classical IP over ATM {-# LINE 882 "Network/Pcap.hsc" #-} {-# LINE 883 "Network/Pcap.hsc" #-} | DLT_PPP_SERIAL -- ^ PPP over serial with HDLC encapsulation {-# LINE 885 "Network/Pcap.hsc" #-} {-# LINE 886 "Network/Pcap.hsc" #-} | DLT_PPP_ETHER -- ^ PPP over ethernet {-# LINE 888 "Network/Pcap.hsc" #-} {-# LINE 889 "Network/Pcap.hsc" #-} | DLT_C_HDLC -- ^ Cisco HDLC {-# LINE 891 "Network/Pcap.hsc" #-} {-# LINE 892 "Network/Pcap.hsc" #-} | DLT_IEEE802_11 -- ^ IEEE 802.11 wireless {-# LINE 894 "Network/Pcap.hsc" #-} {-# LINE 895 "Network/Pcap.hsc" #-} | DLT_LOOP -- ^ OpenBSD loopback device {-# LINE 897 "Network/Pcap.hsc" #-} {-# LINE 898 "Network/Pcap.hsc" #-} | DLT_LINUX_SLL -- ^ Linux cooked sockets {-# LINE 900 "Network/Pcap.hsc" #-} {-# LINE 901 "Network/Pcap.hsc" #-} | DLT_LTALK -- ^ Apple LocalTalk {-# LINE 903 "Network/Pcap.hsc" #-} {-# LINE 904 "Network/Pcap.hsc" #-} | DLT_ECONET -- ^ Acorn Econet {-# LINE 906 "Network/Pcap.hsc" #-} {-# LINE 907 "Network/Pcap.hsc" #-} | DLT_IPFILTER -- ^ OpenBSD's old ipfilter {-# LINE 909 "Network/Pcap.hsc" #-} {-# LINE 910 "Network/Pcap.hsc" #-} | DLT_PFLOG -- ^ OpenBSD's pflog {-# LINE 912 "Network/Pcap.hsc" #-} {-# LINE 913 "Network/Pcap.hsc" #-} | DLT_CISCO_IOS -- ^ Cisco IOS {-# LINE 915 "Network/Pcap.hsc" #-} {-# LINE 916 "Network/Pcap.hsc" #-} | DLT_PRISM_HEADER -- ^ Intersil Prism II wireless chips {-# LINE 918 "Network/Pcap.hsc" #-} {-# LINE 919 "Network/Pcap.hsc" #-} | DLT_AIRONET_HEADER -- ^ Aironet (Cisco) 802.11 wireless {-# LINE 921 "Network/Pcap.hsc" #-} deriving (Eq, Ord, Read, Show) packLink :: Link -> CInt packLink l = case l of DLT_NULL -> 0 {-# LINE 927 "Network/Pcap.hsc" #-} {-# LINE 928 "Network/Pcap.hsc" #-} DLT_EN10MB -> 1 {-# LINE 929 "Network/Pcap.hsc" #-} {-# LINE 930 "Network/Pcap.hsc" #-} {-# LINE 931 "Network/Pcap.hsc" #-} DLT_EN3MB -> 2 {-# LINE 932 "Network/Pcap.hsc" #-} {-# LINE 933 "Network/Pcap.hsc" #-} {-# LINE 934 "Network/Pcap.hsc" #-} DLT_AX25 -> 3 {-# LINE 935 "Network/Pcap.hsc" #-} {-# LINE 936 "Network/Pcap.hsc" #-} {-# LINE 937 "Network/Pcap.hsc" #-} DLT_PRONET -> 4 {-# LINE 938 "Network/Pcap.hsc" #-} {-# LINE 939 "Network/Pcap.hsc" #-} {-# LINE 940 "Network/Pcap.hsc" #-} DLT_CHAOS -> 5 {-# LINE 941 "Network/Pcap.hsc" #-} {-# LINE 942 "Network/Pcap.hsc" #-} {-# LINE 943 "Network/Pcap.hsc" #-} DLT_IEEE802 -> 6 {-# LINE 944 "Network/Pcap.hsc" #-} {-# LINE 945 "Network/Pcap.hsc" #-} {-# LINE 946 "Network/Pcap.hsc" #-} DLT_ARCNET -> 7 {-# LINE 947 "Network/Pcap.hsc" #-} {-# LINE 948 "Network/Pcap.hsc" #-} {-# LINE 949 "Network/Pcap.hsc" #-} DLT_SLIP -> 8 {-# LINE 950 "Network/Pcap.hsc" #-} {-# LINE 951 "Network/Pcap.hsc" #-} {-# LINE 952 "Network/Pcap.hsc" #-} DLT_PPP -> 9 {-# LINE 953 "Network/Pcap.hsc" #-} {-# LINE 954 "Network/Pcap.hsc" #-} {-# LINE 955 "Network/Pcap.hsc" #-} DLT_FDDI -> 10 {-# LINE 956 "Network/Pcap.hsc" #-} {-# LINE 957 "Network/Pcap.hsc" #-} {-# LINE 958 "Network/Pcap.hsc" #-} DLT_ATM_RFC1483 -> 11 {-# LINE 959 "Network/Pcap.hsc" #-} {-# LINE 960 "Network/Pcap.hsc" #-} {-# LINE 961 "Network/Pcap.hsc" #-} DLT_RAW -> 12 {-# LINE 962 "Network/Pcap.hsc" #-} {-# LINE 963 "Network/Pcap.hsc" #-} {-# LINE 964 "Network/Pcap.hsc" #-} DLT_SLIP_BSDOS -> 15 {-# LINE 965 "Network/Pcap.hsc" #-} {-# LINE 966 "Network/Pcap.hsc" #-} {-# LINE 967 "Network/Pcap.hsc" #-} DLT_PPP_BSDOS -> 16 {-# LINE 968 "Network/Pcap.hsc" #-} {-# LINE 969 "Network/Pcap.hsc" #-} {-# LINE 970 "Network/Pcap.hsc" #-} DLT_ATM_CLIP -> 19 {-# LINE 971 "Network/Pcap.hsc" #-} {-# LINE 972 "Network/Pcap.hsc" #-} {-# LINE 973 "Network/Pcap.hsc" #-} DLT_PPP_SERIAL -> 50 {-# LINE 974 "Network/Pcap.hsc" #-} {-# LINE 975 "Network/Pcap.hsc" #-} {-# LINE 976 "Network/Pcap.hsc" #-} DLT_PPP_ETHER -> 51 {-# LINE 977 "Network/Pcap.hsc" #-} {-# LINE 978 "Network/Pcap.hsc" #-} {-# LINE 979 "Network/Pcap.hsc" #-} DLT_C_HDLC -> 104 {-# LINE 980 "Network/Pcap.hsc" #-} {-# LINE 981 "Network/Pcap.hsc" #-} {-# LINE 982 "Network/Pcap.hsc" #-} DLT_IEEE802_11 -> 105 {-# LINE 983 "Network/Pcap.hsc" #-} {-# LINE 984 "Network/Pcap.hsc" #-} {-# LINE 985 "Network/Pcap.hsc" #-} DLT_LOOP -> 108 {-# LINE 986 "Network/Pcap.hsc" #-} {-# LINE 987 "Network/Pcap.hsc" #-} {-# LINE 988 "Network/Pcap.hsc" #-} DLT_LINUX_SLL -> 113 {-# LINE 989 "Network/Pcap.hsc" #-} {-# LINE 990 "Network/Pcap.hsc" #-} {-# LINE 991 "Network/Pcap.hsc" #-} DLT_LTALK -> 114 {-# LINE 992 "Network/Pcap.hsc" #-} {-# LINE 993 "Network/Pcap.hsc" #-} {-# LINE 994 "Network/Pcap.hsc" #-} DLT_ECONET -> 115 {-# LINE 995 "Network/Pcap.hsc" #-} {-# LINE 996 "Network/Pcap.hsc" #-} {-# LINE 997 "Network/Pcap.hsc" #-} DLT_IPFILTER -> 116 {-# LINE 998 "Network/Pcap.hsc" #-} {-# LINE 999 "Network/Pcap.hsc" #-} {-# LINE 1000 "Network/Pcap.hsc" #-} DLT_PFLOG -> 117 {-# LINE 1001 "Network/Pcap.hsc" #-} {-# LINE 1002 "Network/Pcap.hsc" #-} {-# LINE 1003 "Network/Pcap.hsc" #-} DLT_CISCO_IOS -> 118 {-# LINE 1004 "Network/Pcap.hsc" #-} {-# LINE 1005 "Network/Pcap.hsc" #-} {-# LINE 1006 "Network/Pcap.hsc" #-} DLT_PRISM_HEADER -> 119 {-# LINE 1007 "Network/Pcap.hsc" #-} {-# LINE 1008 "Network/Pcap.hsc" #-} {-# LINE 1009 "Network/Pcap.hsc" #-} DLT_AIRONET_HEADER -> 120 {-# LINE 1010 "Network/Pcap.hsc" #-} {-# LINE 1011 "Network/Pcap.hsc" #-} unpackLink :: CInt -> Link unpackLink l = case l of (0) -> DLT_NULL {-# LINE 1017 "Network/Pcap.hsc" #-} {-# LINE 1018 "Network/Pcap.hsc" #-} (1) -> DLT_EN10MB {-# LINE 1019 "Network/Pcap.hsc" #-} {-# LINE 1020 "Network/Pcap.hsc" #-} {-# LINE 1021 "Network/Pcap.hsc" #-} (2) -> DLT_EN3MB {-# LINE 1022 "Network/Pcap.hsc" #-} {-# LINE 1023 "Network/Pcap.hsc" #-} {-# LINE 1024 "Network/Pcap.hsc" #-} (3) -> DLT_AX25 {-# LINE 1025 "Network/Pcap.hsc" #-} {-# LINE 1026 "Network/Pcap.hsc" #-} {-# LINE 1027 "Network/Pcap.hsc" #-} (4) -> DLT_PRONET {-# LINE 1028 "Network/Pcap.hsc" #-} {-# LINE 1029 "Network/Pcap.hsc" #-} {-# LINE 1030 "Network/Pcap.hsc" #-} (5) -> DLT_CHAOS {-# LINE 1031 "Network/Pcap.hsc" #-} {-# LINE 1032 "Network/Pcap.hsc" #-} {-# LINE 1033 "Network/Pcap.hsc" #-} (6) -> DLT_IEEE802 {-# LINE 1034 "Network/Pcap.hsc" #-} {-# LINE 1035 "Network/Pcap.hsc" #-} {-# LINE 1036 "Network/Pcap.hsc" #-} (7) -> DLT_ARCNET {-# LINE 1037 "Network/Pcap.hsc" #-} {-# LINE 1038 "Network/Pcap.hsc" #-} {-# LINE 1039 "Network/Pcap.hsc" #-} (8) -> DLT_SLIP {-# LINE 1040 "Network/Pcap.hsc" #-} {-# LINE 1041 "Network/Pcap.hsc" #-} {-# LINE 1042 "Network/Pcap.hsc" #-} (9) -> DLT_PPP {-# LINE 1043 "Network/Pcap.hsc" #-} {-# LINE 1044 "Network/Pcap.hsc" #-} {-# LINE 1045 "Network/Pcap.hsc" #-} (10) -> DLT_FDDI {-# LINE 1046 "Network/Pcap.hsc" #-} {-# LINE 1047 "Network/Pcap.hsc" #-} {-# LINE 1048 "Network/Pcap.hsc" #-} (11) -> DLT_ATM_RFC1483 {-# LINE 1049 "Network/Pcap.hsc" #-} {-# LINE 1050 "Network/Pcap.hsc" #-} {-# LINE 1051 "Network/Pcap.hsc" #-} (12) -> DLT_RAW {-# LINE 1052 "Network/Pcap.hsc" #-} {-# LINE 1053 "Network/Pcap.hsc" #-} {-# LINE 1054 "Network/Pcap.hsc" #-} (15) -> DLT_SLIP_BSDOS {-# LINE 1055 "Network/Pcap.hsc" #-} {-# LINE 1056 "Network/Pcap.hsc" #-} {-# LINE 1057 "Network/Pcap.hsc" #-} (16) -> DLT_PPP_BSDOS {-# LINE 1058 "Network/Pcap.hsc" #-} {-# LINE 1059 "Network/Pcap.hsc" #-} {-# LINE 1060 "Network/Pcap.hsc" #-} (19) -> DLT_ATM_CLIP {-# LINE 1061 "Network/Pcap.hsc" #-} {-# LINE 1062 "Network/Pcap.hsc" #-} {-# LINE 1063 "Network/Pcap.hsc" #-} (50) -> DLT_PPP_SERIAL {-# LINE 1064 "Network/Pcap.hsc" #-} {-# LINE 1065 "Network/Pcap.hsc" #-} {-# LINE 1066 "Network/Pcap.hsc" #-} (51) -> DLT_PPP_ETHER {-# LINE 1067 "Network/Pcap.hsc" #-} {-# LINE 1068 "Network/Pcap.hsc" #-} {-# LINE 1069 "Network/Pcap.hsc" #-} (104) -> DLT_C_HDLC {-# LINE 1070 "Network/Pcap.hsc" #-} {-# LINE 1071 "Network/Pcap.hsc" #-} {-# LINE 1072 "Network/Pcap.hsc" #-} (105) -> DLT_IEEE802_11 {-# LINE 1073 "Network/Pcap.hsc" #-} {-# LINE 1074 "Network/Pcap.hsc" #-} {-# LINE 1075 "Network/Pcap.hsc" #-} (108) -> DLT_LOOP {-# LINE 1076 "Network/Pcap.hsc" #-} {-# LINE 1077 "Network/Pcap.hsc" #-} {-# LINE 1078 "Network/Pcap.hsc" #-} (113) -> DLT_LINUX_SLL {-# LINE 1079 "Network/Pcap.hsc" #-} {-# LINE 1080 "Network/Pcap.hsc" #-} {-# LINE 1081 "Network/Pcap.hsc" #-} (114) -> DLT_LTALK {-# LINE 1082 "Network/Pcap.hsc" #-} {-# LINE 1083 "Network/Pcap.hsc" #-} {-# LINE 1084 "Network/Pcap.hsc" #-} (115) -> DLT_ECONET {-# LINE 1085 "Network/Pcap.hsc" #-} {-# LINE 1086 "Network/Pcap.hsc" #-} {-# LINE 1087 "Network/Pcap.hsc" #-} (116) -> DLT_IPFILTER {-# LINE 1088 "Network/Pcap.hsc" #-} {-# LINE 1089 "Network/Pcap.hsc" #-} {-# LINE 1090 "Network/Pcap.hsc" #-} (117) -> DLT_PFLOG {-# LINE 1091 "Network/Pcap.hsc" #-} {-# LINE 1092 "Network/Pcap.hsc" #-} {-# LINE 1093 "Network/Pcap.hsc" #-} (118) -> DLT_CISCO_IOS {-# LINE 1094 "Network/Pcap.hsc" #-} {-# LINE 1095 "Network/Pcap.hsc" #-} {-# LINE 1096 "Network/Pcap.hsc" #-} (119) -> DLT_PRISM_HEADER {-# LINE 1097 "Network/Pcap.hsc" #-} {-# LINE 1098 "Network/Pcap.hsc" #-} {-# LINE 1099 "Network/Pcap.hsc" #-} (120) -> DLT_AIRONET_HEADER {-# LINE 1100 "Network/Pcap.hsc" #-} {-# LINE 1101 "Network/Pcap.hsc" #-}