Декодирование файла Pcap в Haskell

#networking #haskell #libpcap

#сеть #haskell #libpcap

Вопрос:

Я пытаюсь декодировать файл pcap, и он работает нормально, за исключением нескольких вещей.

 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 
  

Я хочу, чтобы время возвращалось в hdrсекундах p [время для захвата] в том же формате, что и в wireshark [Дата: месяц: год, час: минута: Сек], и данные возвращались переменной q в формате Ascii.Пожалуйста, скажите мне, как это сделать.

На самом деле я пытался проанализировать файл pcap, чтобы отобразить его содержимое почти аналогично wireshark без библиотеки libpcap [чисто в haskell, открыв файл pcap в двоичном формате и прочитав байт за байтом], но я не смог продвинуться дальше. Не могли бы некоторые, пожалуйста, поместить карту руководства для этого проекта, например, что читать, как подойти, что угодно, что, по вашему мнению, было бы полезно.

Редактировать: я начал писать это приложение, но чего-то не хватает. Я прочитал этот файл http://www.viste.com/Linux/Server/WireShark/libpcapformat.pdf и в нем говорится , что первые 24 байта являются глобальными заголовками , после чего каждый пакет содержит локальный заголовок pcap . Что я пытаюсь сделать, так это сначала попытаться получить байты данных в каждом пакете, прочитав третье поле incl_len в локальном заголовке, но мой код ведет себя не так, как он предполагает. Мой тестовый файл libcap.

 --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 
  

С уважением

Мукеш Тивари

Ответ №1:

Я хочу, чтобы время возвращалось на hdrСекунды p [время для захвата] в том же формате, что и в wireshark [ Дата: месяц: год Час: Мин: Сек]

Ну, вы можете использовать time пакет и преобразовать это в UTCTime . Это делает тривиальным извлечение месяца, дня, года и т. Д. Посмотрите на haddock пакета time для получения дополнительной информации.

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

Из того, что я могу сказать, привязки Haskell не предоставляют эпоху, но как только вы обнаружите, что это должно быть хорошо. Я бы отправил по электронной почте исправление сопровождающему, чтобы добавить диалог непосредственно в UTCTime.

и возврат данных переменной q в формате Ascii

Ну, q — это просто промежуточное значение, и вы можете получить Char s из Int s, используя toEnum :

 print (toEnum (fromIntegral q) :: Char)
  

Что касается выполнения этого в чистом Haskell, я думаю, вам нужно немного отступить назад и узнать больше о Haskell как языке, возможно, из учебника, такого как learnyouahaskell. Если вы полны решимости продвигаться вперед, ознакомьтесь с бинарным пакетом, который был упомянут в списке рассылки как библиотека выбора для их непубличной библиотеки pcap Haskell.

Ответ №2:

Вы можете использовать Data.Time модуль для преобразования времени на основе эпохи UNIX, возвращаемого by hdrSeconds , в LocalTime объект, который затем может быть отформатирован в строку 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
  

Ответ №3:

Существует библиотека Haskell для чтения файлов pcap, которая выполняет синтаксический анализ заголовка файла и заголовков записей пакетов, поэтому вам не нужно делать это самостоятельно. Однако вы все еще самостоятельно анализируете пакетные данные.