{-# language BangPatterns #-}
{-# language MultiWayIf #-}
{-# language ScopedTypeVariables #-}
{-# language TypeApplications #-}
import Panos.Syslog (Log(..),decode)
import Control.Exception (throwIO)
import Data.Primitive (ByteArray)
import Data.Word (Word8)
import Data.Char (ord,chr)
import Data.Bytes.Types (Bytes(Bytes))
import qualified Panos.Syslog.Traffic as Traffic
import qualified Panos.Syslog.Threat as Threat
import qualified Panos.Syslog.System as System
import qualified Data.Primitive as PM
import qualified GHC.Exts as Exts
import qualified Sample as S
main :: IO ()
main = do
putStrLn "Start"
putStrLn "8.1-Traffic-A"
testA
putStrLn "8.1-Traffic-B"
testTrafficB
putStrLn "8.1-Threat-A"
testB
putStrLn "8.1-Threat-B"
testC
putStrLn "8.1-Threat-C"
testD
putStrLn "8.1-Threat-D"
testThreatD
putStrLn "8.1-Threat-E"
testThreatE
putStrLn "8.1-Threat-F"
testThreatF
putStrLn "8.1-Threat-G"
testThreatG
putStrLn "8.1-Threat-H"
testThreatH
putStrLn "8.1-Threat-I"
testThreatI
putStrLn "8.1-System-A"
testSystemA
putStrLn "Finished"
testA :: IO ()
testA = case decode S.traffic_8_1_A of
Left err -> throwIO err
Right (LogTraffic t) ->
if | Traffic.deviceName t /= bytes "MY-DEVICE-NAME" ->
fail $
"wrong device name:\nexpected: " ++
show (bytes "MY-DEVICE-NAME") ++
"\nactually: " ++
show (Traffic.deviceName t)
| Traffic.packetsReceived t /= 0 ->
fail $
"wrong packets received: expected 0 but got " ++
show (Traffic.packetsReceived t)
| Traffic.bytesReceived t /= 34 ->
fail $
"wrong bytes received: expected 34 but got " ++
show (Traffic.bytesReceived t)
| otherwise -> pure ()
Right _ -> fail "wrong log type"
testB :: IO ()
testB = case decode S.threat_8_1_A of
Left err -> throwIO err
Right (LogThreat t) ->
if | Threat.contentVersion t /= bytes "AppThreat-1-6" -> fail $
"wrong content version:\nExpected: AppThreat-1-6\nActually: " ++
prettyBytes (Threat.contentVersion t)
| Threat.miscellaneous t /= bytes "www.example.com/string/\"hello\"" -> fail $
"wrong miscellaneous (URL):\nExpected: www.example.com\nActually: " ++
prettyBytes (Threat.miscellaneous t)
| otherwise -> pure ()
Right _ -> fail "wrong log type"
testTrafficB :: IO ()
testTrafficB = case decode S.traffic_8_1_B of
Left err -> throwIO err
Right (LogTraffic t) ->
if | Traffic.sourceUser t /= bytes "example\\jdoe" ->
fail $
"wrong source user:\nexpected: " ++
show (bytes "MY-DEVICE-NAME") ++
"\nactually: " ++
show (Traffic.deviceName t)
| otherwise -> pure ()
Right _ -> fail "wrong log type"
testC :: IO ()
testC = case decode S.threat_8_1_B of
Left err -> throwIO err
Right (LogThreat t) ->
if | Threat.miscellaneous t /= bytes "www.example.com/" -> fail $
"wrong miscellaneous (URL):\nExpected: www.example.com/\nActually: " ++
prettyBytes (Threat.miscellaneous t) ++ "\n"
| Threat.virtualSystemName t /= bytes "the-vsys-name" -> fail $
"wrong vsys name:\nExpected: the-vsys-name\nActually: " ++
prettyBytes (Threat.virtualSystemName t) ++ "\n"
| Threat.contentVersion t /= bytes "AppThreat-3-7" -> fail $
"wrong content version:\nExpected: AppThreat-3-7\nActually: " ++
prettyBytes (Threat.contentVersion t) ++ "\n"
| otherwise -> pure ()
Right _ -> fail "wrong log type"
testD :: IO ()
testD = case decode S.threat_8_1_C of
Left err -> throwIO err
Right (LogThreat t) ->
if | Threat.threatId t /= 30845 -> fail $
"wrong threat id:\nExpected: 30845\nActually: " ++
show (Threat.threatId t) ++ "\n"
| Threat.threatName t /= bytes "Microsoft RPC Endpoint Mapper Detection" -> fail $
"wrong threat name:\nExpected: Microsoft RPC Endpoint Mapper Detection\nActually: " ++
prettyBytes (Threat.threatName t) ++ "\n"
| otherwise -> pure ()
Right _ -> fail "wrong log type"
testThreatD :: IO ()
testThreatD = case decode S.threat_8_1_D of
Left err -> throwIO err
Right (LogThreat t) ->
if | Threat.threatName t /= bytes "Email Link" -> fail $
"wrong threat name:\nExpected: Email Link\nActually: " ++
prettyBytes (Threat.threatName t) ++ "\n"
| Threat.sender t /= bytes "From: \"John Doe\" <jdoe@example.com>" ->
fail $ "wrong sender"
| otherwise -> pure ()
Right _ -> fail "wrong log type"
testThreatE :: IO ()
testThreatE = case decode S.threat_8_1_E of
Left err -> throwIO err
Right (LogThreat t) ->
if | Threat.threatName t /= bytes "Windows Executable" -> fail $
"wrong threat name:\nExpected: Windows Executable\nActually: " ++
prettyBytes (Threat.threatName t) ++ "\n"
| otherwise -> pure ()
Right _ -> fail "wrong log type"
testThreatF :: IO ()
testThreatF = case decode S.threat_8_1_F of
Left err -> throwIO err
Right (LogThreat t) ->
if | Threat.threatName t /= bytes "Temporary TMP File" ->
fail "wrong threat name"
| otherwise -> pure ()
Right _ -> fail "wrong log type"
testThreatG :: IO ()
testThreatG = case decode S.threat_8_1_G of
Left err -> throwIO err
Right (LogThreat t) ->
if | Threat.threatName t /= bytes "Hypertext Preprocessor PHP File" ->
fail "wrong threat name"
| Threat.httpHeaders t /= bytes "contextual.media.net/" ->
fail "wrong http headers"
| otherwise -> pure ()
Right _ -> fail "wrong log type"
testThreatH :: IO ()
testThreatH = case decode S.threat_8_1_H of
Left err -> throwIO err
Right (LogThreat t) ->
if | Threat.threatId t /= 9999 ->
fail "wrong threat id"
| otherwise -> pure ()
Right _ -> fail "wrong log type"
testThreatI :: IO ()
testThreatI = case decode S.threat_8_1_I of
Left err -> throwIO err
Right (LogThreat t) ->
if | Threat.threatId t /= 320511141 ->
fail "wrong threat id"
| otherwise -> pure ()
Right _ -> fail "wrong log type"
testSystemA :: IO ()
testSystemA = case decode S.system_8_1_A of
Left err -> throwIO err
Right (LogSystem t) ->
if | System.deviceName t /= bytes "NY-DC-FW-2" -> fail $
"wrong device name:\nexpected: NY-DC-FW-2\nactually: " ++
show (System.deviceName t)
| System.description t /= bytes
( concat
[ "IKE protocol IPSec SA delete message "
, "sent to peer. SPI:0xA1CD910F."
]
) -> fail $
"wrong description:\nexpected something about IKE\nactually: " ++
show (System.description t)
| otherwise -> pure ()
Right _ -> fail "wrong log type"
bytes :: String -> Bytes
bytes s = let b = pack s in Bytes b 0 (PM.sizeofByteArray b)
pack :: String -> ByteArray
pack = Exts.fromList . map (fromIntegral @Int @Word8 . ord)
prettyBytes :: Bytes -> String
prettyBytes (Bytes arr off len) = if len > 0
then
let w = PM.indexByteArray arr off :: Word8
c = if w > 31 && w < 127
then chr (fromIntegral w)
else 'X'
in c : prettyBytes (Bytes arr (off + 1) (len - 1))
else []