------------------------------------------------------------------------------
-- |
--  Module      : Network.Pcap
--  Copyright   : Bryan O'Sullivan 2007, Antiope Associates LLC 2004
--  License     : BSD-style
--  Maintainer  : bos@serpentine.com
--  Stability   : experimental
--  Portability : non-portable
--
-- The 'Network.Pcap' module is a high(ish) level binding to all of
-- the functions in @libpcap@.  See <http://www.tcpdump.org> for more
-- information.
--
-- This module is built on the lower-level 'Network.Pcap.Base' module,
-- which is slightly more efficient.  Don\'t use 'Network.Pcap.Base'
-- unless profiling data indicates that you need to.
--
-- Only a minimum of marshaling is done on received packets.  To
-- convert captured packet data to a 'B.ByteString' (space efficient,
-- and with /O(1)/ access to every byte in a captured packet), use
-- 'toBS'.
--
-- 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 BSD's @struct sockaddr@. See W.R.Stevens, TCP Illustrated,
-- volume 2, for further elucidation.
--
-- This binding should be portable across systems that can use the
-- @libpcap@ from @tcpdump.org@. It does not yet work with Winpcap, a
-- similar library for Windows, although adapting it should not prove
-- difficult.
--
------------------------------------------------------------------------------

module Network.Pcap
    (
      -- * Types
      PcapHandle
    , DumpHandle
    , BpfProgram
    , Callback
    , CallbackBS
    , Direction(..)
    , Link(..)
    , Interface(..)
    , PcapAddr(..)
    , SockAddr(..)
    , Network(..)
    , PktHdr(..)
    , Statistics(..)

    -- * Device opening
    , openOffline               -- :: FilePath -> IO Pcap
    , openLive                  -- :: String -> Int -> Bool -> Int -> IO Pcap
    , openDead                  -- :: Int -> Int -> IO Pcap
    , openDump                  -- :: PcapHandle -> FilePath -> IO Pdump

    -- * Filter handling
    , setFilter                 -- :: PcapHandle -> 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

    , setNonBlock               -- :: PcapHandle -> Bool -> IO ()
    , getNonBlock               -- :: PcapHandle -> IO Bool
    , setDirection

    -- * Link layer utilities
    , datalink                  -- :: PcapHandle -> IO Link
    , setDatalink               -- :: PcapHandle -> Link -> IO ()
    , listDatalinks             -- :: PcapHandle -> IO [Link]

    -- * Packet processing
    , dispatch                  -- :: PcapHandle -> Int -> Callback -> IO Int
    , loop                      -- :: PcapHandle -> Int -> Callback -> IO Int
    , next                      -- :: PcapHandle -> IO (PktHdr, Ptr Word8)
    , dump                      -- :: Ptr PcapDumpTag -> Ptr PktHdr -> Ptr Word8 -> IO ()

    -- ** 'B.ByteString' variants
    , dispatchBS                -- :: PcapHandle -> Int -> CallbackBS -> IO Int
    , loopBS                    -- :: PcapHandle -> Int -> CallbackBS -> IO Int
    , nextBS                    -- :: PcapHandle -> IO (PktHdr, B.ByteStringa)
    , dumpBS                    -- :: Ptr PcapDumpTag -> Ptr PktHdr -> B.ByteString -> IO ()

    -- * Sending packets
    , sendPacket
    , sendPacketBS

    -- * Conversion
    , toBS
    , hdrTime
    , hdrDiffTime

    -- * Miscellaneous
    , statistics                -- :: PcapHandle -> IO Statistics
    , version                   -- :: PcapHandle -> IO (Int, Int)
    , isSwapped                 -- :: PcapHandle -> IO Bool
    , snapshotLen               -- :: PcapHandle -> IO Int
    ) where

#ifdef BYTESTRING_IN_BASE
import qualified Data.ByteString.Base as B
import qualified Data.ByteString.Base as BU
#else
import qualified Data.ByteString.Internal as B
import qualified Data.ByteString.Unsafe as BU
#endif
import Data.Int (Int64)
import Data.Time.Clock (DiffTime, picosecondsToDiffTime)
import Data.Word (Word8, Word32)
import Foreign.Ptr (Ptr, castPtr)
import Foreign.ForeignPtr (ForeignPtr, withForeignPtr)
import qualified Network.Pcap.Base as P
import Network.Pcap.Base (BpfProgram, Callback, Interface(..), Link(..),
                          Network(..), Direction(..),
                          PcapAddr(..), PktHdr(..), SockAddr(..), Statistics,
                          compileFilter, findAllDevs, lookupDev, lookupNet)

-- | Packet capture handle.
newtype PcapHandle = PcapHandle (ForeignPtr P.PcapTag)

-- | Dump file handle.
newtype DumpHandle = DumpHandle (ForeignPtr P.PcapDumpTag)

-- | Callback using 'B.ByteString' for packet body.
type CallbackBS = PktHdr -> B.ByteString -> IO ()

--
-- Open a device
--

-- | 'openOffline' opens a dump file for reading. The file format is
-- the same as used by @tcpdump@ and Wireshark. The string @\"-\"@ is
-- a synonym for @stdin@.
--
openOffline :: FilePath -- ^ name of dump file to read
            -> IO PcapHandle
openOffline :: FilePath -> IO PcapHandle
openOffline = (ForeignPtr PcapTag -> PcapHandle)
-> IO (ForeignPtr PcapTag) -> IO PcapHandle
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ForeignPtr PcapTag -> PcapHandle
PcapHandle (IO (ForeignPtr PcapTag) -> IO PcapHandle)
-> (FilePath -> IO (ForeignPtr PcapTag))
-> FilePath
-> IO PcapHandle
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> IO (ForeignPtr PcapTag)
P.openOffline

-- | 'openLive' is used to get a 'PcapHandle' that can be used to look
-- at packets on the network. The arguments are the device name, the
-- snapshot length (in bytes), the promiscuity of the interface
-- ('True' == promiscuous) and a timeout in microseconds.
--
-- The timeout allows the packet filter to delay while accumulating
-- multiple packets, which is more efficient than reading packets one
-- by one.  A timeout of zero will wait indefinitely for \"enough\"
-- packets to arrive.
--
-- 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 interface to promiscuous mode?
         -> Int64               -- ^ timeout in microseconds
         -> IO PcapHandle
openLive :: FilePath -> Int -> Bool -> Int64 -> IO PcapHandle
openLive FilePath
name Int
snaplen Bool
promisc Int64
timeout =
    let timeout' :: Int
timeout' | Int64
timeout Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Int64
0 = Int
0
                 | Bool
otherwise = Int64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int64
timeout Int64 -> Int64 -> Int64
forall a. Integral a => a -> a -> a
`div` Int64
1000)
    in ForeignPtr PcapTag -> PcapHandle
PcapHandle (ForeignPtr PcapTag -> PcapHandle)
-> IO (ForeignPtr PcapTag) -> IO PcapHandle
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` FilePath -> Int -> Bool -> Int -> IO (ForeignPtr PcapTag)
P.openLive FilePath
name Int
snaplen Bool
promisc Int
timeout'

-- | 'openDead' is used to get a 'PcapHandle' without opening a file
-- or device. It is typically used to test packet filter compilation
-- by 'setFilter'. The arguments are the link type and the snapshot
-- length.
--
openDead :: Link                -- ^ datalink type
         -> Int                 -- ^ snapshot length
         -> IO PcapHandle
openDead :: Link -> Int -> IO PcapHandle
openDead Link
link Int
snaplen = ForeignPtr PcapTag -> PcapHandle
PcapHandle (ForeignPtr PcapTag -> PcapHandle)
-> IO (ForeignPtr PcapTag) -> IO PcapHandle
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Link -> Int -> IO (ForeignPtr PcapTag)
P.openDead Link
link Int
snaplen

{-# INLINE withPcap #-}
withPcap :: PcapHandle -> (Ptr P.PcapTag -> IO a) -> IO a
withPcap :: forall a. PcapHandle -> (Ptr PcapTag -> IO a) -> IO a
withPcap (PcapHandle ForeignPtr PcapTag
hdl) = ForeignPtr PcapTag -> (Ptr PcapTag -> IO a) -> IO a
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr PcapTag
hdl

{-# INLINE withDump #-}
withDump :: DumpHandle -> (Ptr P.PcapDumpTag -> IO a) -> IO a
withDump :: forall a. DumpHandle -> (Ptr PcapDumpTag -> IO a) -> IO a
withDump (DumpHandle ForeignPtr PcapDumpTag
hdl) = ForeignPtr PcapDumpTag -> (Ptr PcapDumpTag -> IO a) -> IO a
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr PcapDumpTag
hdl

--
-- Open a dump device
--

-- | 'openDump' opens a dump file for writing. This dump file is
-- written to by the 'dump' function.
openDump :: PcapHandle          -- ^ packet capture handle
         -> FilePath            -- ^ name of dump file to write to
         -> IO DumpHandle
openDump :: PcapHandle -> FilePath -> IO DumpHandle
openDump PcapHandle
pch FilePath
name = PcapHandle -> (Ptr PcapTag -> IO DumpHandle) -> IO DumpHandle
forall a. PcapHandle -> (Ptr PcapTag -> IO a) -> IO a
withPcap PcapHandle
pch ((Ptr PcapTag -> IO DumpHandle) -> IO DumpHandle)
-> (Ptr PcapTag -> IO DumpHandle) -> IO DumpHandle
forall a b. (a -> b) -> a -> b
$ \Ptr PcapTag
hdl ->
    ForeignPtr PcapDumpTag -> DumpHandle
DumpHandle (ForeignPtr PcapDumpTag -> DumpHandle)
-> IO (ForeignPtr PcapDumpTag) -> IO DumpHandle
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Ptr PcapTag -> FilePath -> IO (ForeignPtr PcapDumpTag)
P.openDump Ptr PcapTag
hdl FilePath
name

--
-- Set the filter
--

-- | Set a filter on the specified packet capture handle. Valid filter
-- strings are those accepted by @tcpdump@.
setFilter :: PcapHandle         -- ^ handle on which to set filter
          -> String             -- ^ filter string
          -> Bool               -- ^ optimize?
          -> Word32             -- ^ IPv4 network mask
          -> IO ()
setFilter :: PcapHandle -> FilePath -> Bool -> Word32 -> IO ()
setFilter PcapHandle
pch FilePath
filt Bool
opt Word32
mask = PcapHandle -> (Ptr PcapTag -> IO ()) -> IO ()
forall a. PcapHandle -> (Ptr PcapTag -> IO a) -> IO a
withPcap PcapHandle
pch ((Ptr PcapTag -> IO ()) -> IO ())
-> (Ptr PcapTag -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr PcapTag
hdl ->
    Ptr PcapTag -> FilePath -> Bool -> Word32 -> IO ()
P.setFilter Ptr PcapTag
hdl FilePath
filt Bool
opt Word32
mask

--
-- Set or read the device mode (blocking/nonblocking)
--

-- | Set the given 'PcapHandle' into non-blocking mode if the second
-- argument is 'True', otherwise put it in blocking mode. Note that
-- the 'PcapHandle' must have been obtained from 'openLive'.
--
setNonBlock :: PcapHandle       -- ^ must have been obtained from 'openLive'
            -> Bool             -- ^ set\/unset blocking mode
            -> IO ()
setNonBlock :: PcapHandle -> Bool -> IO ()
setNonBlock PcapHandle
pch Bool
block = PcapHandle -> (Ptr PcapTag -> IO ()) -> IO ()
forall a. PcapHandle -> (Ptr PcapTag -> IO a) -> IO a
withPcap PcapHandle
pch ((Ptr PcapTag -> IO ()) -> IO ())
-> (Ptr PcapTag -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr PcapTag
hdl -> Ptr PcapTag -> Bool -> IO ()
P.setNonBlock Ptr PcapTag
hdl Bool
block

-- | Return the blocking status of the 'PcapHandle'. 'True' indicates
-- that the handle is non-blocking. Handles referring to dump files
-- opened by 'openDump' always return 'False'.
getNonBlock :: PcapHandle -> IO Bool
getNonBlock :: PcapHandle -> IO Bool
getNonBlock PcapHandle
pch = PcapHandle -> (Ptr PcapTag -> IO Bool) -> IO Bool
forall a. PcapHandle -> (Ptr PcapTag -> IO a) -> IO a
withPcap PcapHandle
pch Ptr PcapTag -> IO Bool
P.getNonBlock

-- | Specify the direction in which packets are to be captured.
-- Complete functionality is not necessarily available on all
-- platforms.
setDirection :: PcapHandle -> Direction -> IO ()
setDirection :: PcapHandle -> Direction -> IO ()
setDirection PcapHandle
pch Direction
dir = PcapHandle -> (Ptr PcapTag -> IO ()) -> IO ()
forall a. PcapHandle -> (Ptr PcapTag -> IO a) -> IO a
withPcap PcapHandle
pch ((Ptr PcapTag -> IO ()) -> IO ())
-> (Ptr PcapTag -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr PcapTag
hdl -> Ptr PcapTag -> Direction -> IO ()
P.setDirection Ptr PcapTag
hdl Direction
dir

{-# INLINE hdrTime #-}
-- | Get the timestamp of a packet as a single quantity, in
-- microseconds.
hdrTime :: PktHdr -> Int64
hdrTime :: PktHdr -> Int64
hdrTime PktHdr
pkt = Word32 -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (PktHdr -> Word32
hdrSeconds PktHdr
pkt) Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
* Int64
1000000 Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
+
              Word32 -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (PktHdr -> Word32
hdrUseconds PktHdr
pkt)

-- | Get the timestamp of a packet as a 'DiffTime'.
hdrDiffTime :: PktHdr -> DiffTime
hdrDiffTime :: PktHdr -> DiffTime
hdrDiffTime PktHdr
pkt = Integer -> DiffTime
picosecondsToDiffTime (Int64 -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (PktHdr -> Int64
hdrTime PktHdr
pkt) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
1000000)

--
-- Reading packets
--

-- | Wrap a callback that expects a 'B.ByteString' so that it is
-- usable as a regular 'Callback'.
wrapBS :: CallbackBS -> Callback
wrapBS :: CallbackBS -> Callback
wrapBS CallbackBS
f PktHdr
hdr Ptr Word8
ptr = do
  let len :: Word32
len = PktHdr -> Word32
hdrCaptureLength PktHdr
hdr
  ByteString
bs <- Int -> (Ptr Word8 -> IO ()) -> IO ByteString
B.create (Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
len) ((Ptr Word8 -> IO ()) -> IO ByteString)
-> (Ptr Word8 -> IO ()) -> IO ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
B.memcpy Ptr Word8
p Ptr Word8
ptr (Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
len)
  CallbackBS
f PktHdr
hdr ByteString
bs

-- | Collect and process packets.
--
-- 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 dump
-- file (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, which can be used to
-- marshal the data into a list, array, or 'B.ByteString' (using
-- 'toBS').
--
dispatch :: PcapHandle
         -> Int                 -- ^ number of packets to process
         -> Callback            -- ^ packet processing function
         -> IO Int              -- ^ number of packets read
dispatch :: PcapHandle -> Int -> Callback -> IO Int
dispatch PcapHandle
pch Int
count Callback
f = PcapHandle -> (Ptr PcapTag -> IO Int) -> IO Int
forall a. PcapHandle -> (Ptr PcapTag -> IO a) -> IO a
withPcap PcapHandle
pch ((Ptr PcapTag -> IO Int) -> IO Int)
-> (Ptr PcapTag -> IO Int) -> IO Int
forall a b. (a -> b) -> a -> b
$ \Ptr PcapTag
hdl -> Ptr PcapTag -> Int -> Callback -> IO Int
P.dispatch Ptr PcapTag
hdl Int
count Callback
f

-- | Variant of 'dispatch' for use with 'B.ByteString'.
dispatchBS :: PcapHandle
           -> Int               -- ^ number of packets to process
           -> CallbackBS        -- ^ packet processing function
           -> IO Int            -- ^ number of packets read
dispatchBS :: PcapHandle -> Int -> CallbackBS -> IO Int
dispatchBS PcapHandle
pch Int
count CallbackBS
f = PcapHandle -> (Ptr PcapTag -> IO Int) -> IO Int
forall a. PcapHandle -> (Ptr PcapTag -> IO a) -> IO a
withPcap PcapHandle
pch ((Ptr PcapTag -> IO Int) -> IO Int)
-> (Ptr PcapTag -> IO Int) -> IO Int
forall a b. (a -> b) -> a -> b
$ \Ptr PcapTag
hdl -> Ptr PcapTag -> Int -> Callback -> IO Int
P.dispatch Ptr PcapTag
hdl Int
count (CallbackBS -> Callback
wrapBS CallbackBS
f)

-- | Similar to 'dispatch', but loop until the number of packets
-- specified by the second argument are read. A negative value loops
-- forever.
--
-- This function does not return when a live read timeout occurs. Use
-- 'dispatch' instead if you want to specify a timeout.
loop :: PcapHandle
     -> Int                     -- ^ number of packets to read (-1 == loop forever)
     -> Callback                -- ^ packet processing function
     -> IO Int                  -- ^ number of packets read
loop :: PcapHandle -> Int -> Callback -> IO Int
loop PcapHandle
pch Int
count Callback
f = PcapHandle -> (Ptr PcapTag -> IO Int) -> IO Int
forall a. PcapHandle -> (Ptr PcapTag -> IO a) -> IO a
withPcap PcapHandle
pch ((Ptr PcapTag -> IO Int) -> IO Int)
-> (Ptr PcapTag -> IO Int) -> IO Int
forall a b. (a -> b) -> a -> b
$ \Ptr PcapTag
hdl -> Ptr PcapTag -> Int -> Callback -> IO Int
P.loop Ptr PcapTag
hdl Int
count Callback
f

-- | Variant of 'loop' for use with 'B.ByteString'.
loopBS :: PcapHandle
       -> Int                   -- ^ number of packets to read (-1 == loop forever)
       -> CallbackBS            -- ^ packet processing function
       -> IO Int                -- ^ number of packets read
loopBS :: PcapHandle -> Int -> CallbackBS -> IO Int
loopBS PcapHandle
pch Int
count CallbackBS
f = PcapHandle -> (Ptr PcapTag -> IO Int) -> IO Int
forall a. PcapHandle -> (Ptr PcapTag -> IO a) -> IO a
withPcap PcapHandle
pch ((Ptr PcapTag -> IO Int) -> IO Int)
-> (Ptr PcapTag -> IO Int) -> IO Int
forall a b. (a -> b) -> a -> b
$ \Ptr PcapTag
hdl -> Ptr PcapTag -> Int -> Callback -> IO Int
P.loop Ptr PcapTag
hdl Int
count (CallbackBS -> Callback
wrapBS CallbackBS
f)

-- | Send a raw packet through the network interface.
sendPacket :: PcapHandle
           -> Ptr Word8         -- ^ packet data (including link-level header)
           -> Int               -- ^ packet size
           -> IO ()
sendPacket :: PcapHandle -> Ptr Word8 -> Int -> IO ()
sendPacket PcapHandle
pch Ptr Word8
buf Int
size = PcapHandle -> (Ptr PcapTag -> IO ()) -> IO ()
forall a. PcapHandle -> (Ptr PcapTag -> IO a) -> IO a
withPcap PcapHandle
pch ((Ptr PcapTag -> IO ()) -> IO ())
-> (Ptr PcapTag -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr PcapTag
hdl -> Ptr PcapTag -> Ptr Word8 -> Int -> IO ()
P.sendPacket Ptr PcapTag
hdl Ptr Word8
buf Int
size

-- | Variant of 'sendPacket' for use with 'B.ByteString'.
sendPacketBS :: PcapHandle
             -> B.ByteString    -- ^ packet data (including link-level header)
             -> IO ()
sendPacketBS :: PcapHandle -> ByteString -> IO ()
sendPacketBS PcapHandle
pch ByteString
s = ByteString -> (CStringLen -> IO ()) -> IO ()
forall a. ByteString -> (CStringLen -> IO a) -> IO a
BU.unsafeUseAsCStringLen ByteString
s ((CStringLen -> IO ()) -> IO ()) -> (CStringLen -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \(Ptr CChar
buf, Int
len) ->
    PcapHandle -> Ptr Word8 -> Int -> IO ()
sendPacket PcapHandle
pch (Ptr CChar -> Ptr Word8
forall a b. Ptr a -> Ptr b
castPtr Ptr CChar
buf) Int
len

-- | Represent a captured packet as a 'B.ByteString'.  Suitable for
-- use as is with the result of 'next', or use @'curry' 'toBS'@ inside
-- a 'Callback' with 'dispatch'.
toBS :: (PktHdr, Ptr Word8) -> IO (PktHdr, B.ByteString)
toBS :: (PktHdr, Ptr Word8) -> IO (PktHdr, ByteString)
toBS (PktHdr
hdr, Ptr Word8
ptr) = do
    let len :: Word32
len = PktHdr -> Word32
hdrCaptureLength PktHdr
hdr
    ByteString
s <- Int -> (Ptr Word8 -> IO ()) -> IO ByteString
B.create (Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
len) ((Ptr Word8 -> IO ()) -> IO ByteString)
-> (Ptr Word8 -> IO ()) -> IO ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
B.memcpy Ptr Word8
p Ptr Word8
ptr (Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
len)
    (PktHdr, ByteString) -> IO (PktHdr, ByteString)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (PktHdr
hdr, ByteString
s)

-- | Read the next packet (equivalent to calling 'dispatch' with a
-- count of 1).
next :: PcapHandle -> IO (PktHdr, Ptr Word8)
next :: PcapHandle -> IO (PktHdr, Ptr Word8)
next PcapHandle
pch = PcapHandle
-> (Ptr PcapTag -> IO (PktHdr, Ptr Word8))
-> IO (PktHdr, Ptr Word8)
forall a. PcapHandle -> (Ptr PcapTag -> IO a) -> IO a
withPcap PcapHandle
pch Ptr PcapTag -> IO (PktHdr, Ptr Word8)
P.next

nextBS :: PcapHandle -> IO (PktHdr, B.ByteString)
nextBS :: PcapHandle -> IO (PktHdr, ByteString)
nextBS PcapHandle
pch = PcapHandle
-> (Ptr PcapTag -> IO (PktHdr, Ptr Word8))
-> IO (PktHdr, Ptr Word8)
forall a. PcapHandle -> (Ptr PcapTag -> IO a) -> IO a
withPcap PcapHandle
pch Ptr PcapTag -> IO (PktHdr, Ptr Word8)
P.next IO (PktHdr, Ptr Word8)
-> ((PktHdr, Ptr Word8) -> IO (PktHdr, ByteString))
-> IO (PktHdr, ByteString)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (PktHdr, Ptr Word8) -> IO (PktHdr, ByteString)
toBS

-- | Write the packet data given by the second and third arguments to
-- a dump file opened by 'openDead'. 'dump' is designed so it can be
-- easily used as a default callback function by 'dispatch' or 'loop'.
dump :: DumpHandle
     -> Ptr PktHdr              -- ^ packet header record
     -> Ptr Word8               -- ^ packet data
     -> IO ()
dump :: DumpHandle -> Ptr PktHdr -> Ptr Word8 -> IO ()
dump DumpHandle
dh Ptr PktHdr
hdr Ptr Word8
pkt = DumpHandle -> (Ptr PcapDumpTag -> IO ()) -> IO ()
forall a. DumpHandle -> (Ptr PcapDumpTag -> IO a) -> IO a
withDump DumpHandle
dh ((Ptr PcapDumpTag -> IO ()) -> IO ())
-> (Ptr PcapDumpTag -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr PcapDumpTag
hdl -> Ptr PcapDumpTag -> Ptr PktHdr -> Ptr Word8 -> IO ()
P.dump Ptr PcapDumpTag
hdl Ptr PktHdr
hdr Ptr Word8
pkt

dumpBS :: DumpHandle
       -> Ptr PktHdr            -- ^ packet header record
       -> B.ByteString          -- ^ packet data
       -> IO ()
dumpBS :: DumpHandle -> Ptr PktHdr -> ByteString -> IO ()
dumpBS DumpHandle
dh Ptr PktHdr
hdr ByteString
s =
    DumpHandle -> (Ptr PcapDumpTag -> IO ()) -> IO ()
forall a. DumpHandle -> (Ptr PcapDumpTag -> IO a) -> IO a
withDump DumpHandle
dh ((Ptr PcapDumpTag -> IO ()) -> IO ())
-> (Ptr PcapDumpTag -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr PcapDumpTag
hdl ->
        ByteString -> (Ptr CChar -> IO ()) -> IO ()
forall a. ByteString -> (Ptr CChar -> IO a) -> IO a
BU.unsafeUseAsCString ByteString
s ((Ptr CChar -> IO ()) -> IO ()) -> (Ptr CChar -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ Ptr PcapDumpTag -> Ptr PktHdr -> Ptr Word8 -> IO ()
P.dump Ptr PcapDumpTag
hdl Ptr PktHdr
hdr (Ptr Word8 -> IO ())
-> (Ptr CChar -> Ptr Word8) -> Ptr CChar -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ptr CChar -> Ptr Word8
forall a b. Ptr a -> Ptr b
castPtr

--
-- Datalink manipulation
--

-- | Returns the datalink type associated with the given handle.
datalink :: PcapHandle -> IO Link
datalink :: PcapHandle -> IO Link
datalink PcapHandle
pch = PcapHandle -> (Ptr PcapTag -> IO Link) -> IO Link
forall a. PcapHandle -> (Ptr PcapTag -> IO a) -> IO a
withPcap PcapHandle
pch Ptr PcapTag -> IO Link
P.datalink

-- | Sets the datalink type for the given handle.
setDatalink :: PcapHandle -> Link -> IO ()
setDatalink :: PcapHandle -> Link -> IO ()
setDatalink PcapHandle
pch Link
link = PcapHandle -> (Ptr PcapTag -> IO ()) -> IO ()
forall a. PcapHandle -> (Ptr PcapTag -> IO a) -> IO a
withPcap PcapHandle
pch ((Ptr PcapTag -> IO ()) -> IO ())
-> (Ptr PcapTag -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr PcapTag
hdl -> Ptr PcapTag -> Link -> IO ()
P.setDatalink Ptr PcapTag
hdl Link
link

-- | List all the datalink types supported by the given
-- handle. Entries from the resulting list are valid arguments to
-- 'setDatalink'.
listDatalinks :: PcapHandle -> IO [Link]
listDatalinks :: PcapHandle -> IO [Link]
listDatalinks PcapHandle
pch = PcapHandle -> (Ptr PcapTag -> IO [Link]) -> IO [Link]
forall a. PcapHandle -> (Ptr PcapTag -> IO a) -> IO a
withPcap PcapHandle
pch Ptr PcapTag -> IO [Link]
P.listDatalinks

-- | 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 :: PcapHandle -> IO Statistics
statistics :: PcapHandle -> IO Statistics
statistics PcapHandle
pch = PcapHandle -> (Ptr PcapTag -> IO Statistics) -> IO Statistics
forall a. PcapHandle -> (Ptr PcapTag -> IO a) -> IO a
withPcap PcapHandle
pch Ptr PcapTag -> IO Statistics
P.statistics

-- | Version of the library.  The returned pair consists of the major
-- and minor version numbers.
version :: PcapHandle -> IO (Int, Int)
version :: PcapHandle -> IO (Int, Int)
version PcapHandle
pch = PcapHandle -> (Ptr PcapTag -> IO (Int, Int)) -> IO (Int, Int)
forall a. PcapHandle -> (Ptr PcapTag -> IO a) -> IO a
withPcap PcapHandle
pch Ptr PcapTag -> IO (Int, Int)
P.version

-- | 'isSwapped' returns 'True' if the current dump file uses a
-- different byte order than the one native to the system.
isSwapped :: PcapHandle -> IO Bool
isSwapped :: PcapHandle -> IO Bool
isSwapped PcapHandle
pch = PcapHandle -> (Ptr PcapTag -> IO Bool) -> IO Bool
forall a. PcapHandle -> (Ptr PcapTag -> IO a) -> IO a
withPcap PcapHandle
pch Ptr PcapTag -> IO Bool
P.isSwapped

-- | The snapshot length that was used in the call to 'openLive'.
snapshotLen :: PcapHandle -> IO Int
snapshotLen :: PcapHandle -> IO Int
snapshotLen PcapHandle
pch = PcapHandle -> (Ptr PcapTag -> IO Int) -> IO Int
forall a. PcapHandle -> (Ptr PcapTag -> IO a) -> IO a
withPcap PcapHandle
pch Ptr PcapTag -> IO Int
P.snapshotLen