1
votes

I am trying to decode a pcap file and its working fine except couple of things.

import Network.Pcap
import System.IO
import Control.Monad

callfun f = do
    ( p , q ) <- next f 
    print $ hdrSeconds p  
    print $ hdrCaptureLength p
    print $ hdrWireLength p
    print q 
    when ( hdrWireLength p /= 0 ) $ callfun f    

main = do
    f <- openOffline "udp_lite_full_coverage_0.pcap"
    callfun f 

I want the time return by hdrSeconds p [ time to capture ] in same format as in wireshark [ Date : Month : Year Hour : Min : Sec ] and data return by variable q in Ascii format.Kindly tell me how to do this.
Actually i was trying to parse pcap file to display its content in almost similar manner to wireshark without libpcap library [ purely in haskell by opening the pcap file in binary format and read byte by byte ] but i could not get any further. Could some please put the guide map for this project like what to read , how to approach , any thing which you feel would be helpful .

Edit: I started writing this application but there is some thing missing. I read this file http://www.viste.com/Linux/Server/WireShark/libpcapformat.pdf and it say that first 24 bytes are global headers , after that every packet contains pcap local header . What i am trying to do is , first trying to get the bytes of data in each packet by reading the third field incl_len in local header but my code is not behaving as it suppose . My test libcap file.

--http://www.viste.com/Linux/Server/WireShark/libpcapformat.pdf  
import Data.List 
import qualified Data.ByteString.Lazy as BS 
import qualified Data.ByteString.Lazy.Char8 as B 
import Control.Monad 
import Text.Printf 
import Data.Word 
import Data.Char 
import System.Time 
import Numeric 
import System.Environment 
hexTodec :: BS.ByteString ->  Integer 
hexTodec lst = read $   "0x" ++  (  concatMap ( \x -> showHex x "" ) $ BS.unpack lst  ) 
parseFile :: BS.ByteString -> Bool -> IO [ BS.ByteString ] 
parseFile xs revflag 
  | BS.null xs = return [] 
  | otherwise =   do 
    let ind =if revflag then   hexTodec . BS.reverse . BS.take 4 . BS.drop 8 $ xs 
              else hexTodec  . BS.take 4 . BS.drop 8 $ xs 
    print ind 
    let ( x , ys ) = BS.splitAt  ( fromIntegral ind  )  xs 
    --BS.putStrLn $ x 
    tmp <- parseFile ys revflag 
    return $ x : tmp 
main = do 
    [ file ]  <- getArgs 
    contents  <- BS.readFile file 
    let ( a , rest ) =  BS.splitAt 24  contents  --strip global header 
    let revflag = case BS.unpack $ BS.take 4  a of 
                    [ 0xd4 , 0xc3 , 0xb2 , 0xa1 ] -> True 
                    _ -> False 
    p <-   parseFile  rest  revflag 
    print $ p !! 0 
    BS.putStr $  p !! 0 


Regards
Mukesh Tiwari

3

3 Answers

2
votes

I want the time return by hdrSeconds p [ time to capture ] in same format as in wireshark [ Date : Month : Year Hour : Min : Sec ]

Well you can use the time package and convert this to a UTCTime. This makes it trivial to extract month, day, year, etc. Look at the time package's haddock for more.

let epoch = pcapEpochTimeThatYouFindInOnlineDocumentation
diff <- hdrDiffTime p
let date = addUTCTime (realToFrac diff) epoch

From what I can tell the Haskell bindings don't provide the epoch, but once you find that this should be fine. I'd e-mail in a patch to the maintainer to add a converstion directly to UTCTime.

and data return by variable q in Ascii format

Well q is just an intergral and you can get Chars from Ints using toEnum:

print (toEnum (fromIntegral q) :: Char)

As for doing this in pure Haskell, I think you need to step back a bit and learn more about Haskell as a language, perhaps from a tutuorial such as learnyouahaskell. If you are determined to forge ahead then read up on the binary package, which was mentioned on the mailing list as the library of choice for their non-public pcap Haskell library.

2
votes

You can use the Data.Time module to convert the UNIX epoch-based time returned by hdrSeconds to a LocalTime object that can then be formatted into a string with formatTime.

import Data.Time.Clock.POSIX
import Data.Time.Format
import Data.Time.LocalTime
import System.Locale
import Data.Word (Word32)

data MockPCap = MockPCap { hdrSeconds :: Word32 }

toPosixTime :: Word32 -> POSIXTime
toPosixTime = fromIntegral

localHdrTime p = do tz <- getCurrentTimeZone
                    return $ utcToLocalTime tz $ posixSecondsToUTCTime $ toPosixTime $ hdrSeconds p

main = let p = MockPCap 1318464165  {-- Mock a PCap object --}
       in do hTime <- localHdrTime p
             print $ formatTime defaultTimeLocale "%c" hTime
0
votes

There's a Haskell library for reading pcap files, which does the work of parsing the file header and packet record headers, so you don't have to do that on your own. You're still on your own parsing the packet data, however.