{-# 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 Data.Primitive as PM
import qualified GHC.Exts as Exts
import qualified Panos.Syslog.Correlation as Correlation
import qualified Panos.Syslog.System as System
import qualified Panos.Syslog.Threat as Threat
import qualified Panos.Syslog.Traffic as Traffic
import qualified Panos.Syslog.User as User
import qualified Sample as S
main :: IO ()
main = do
putStrLn "Start"
putStrLn "8.1-Traffic-A"
testA
putStrLn "8.1-Traffic-B"
testTrafficB
putStrLn "9.0-Traffic-A"
testTraffic_9_0_A
putStrLn "Prisma-Traffic-A"
testPrismaTrafficA
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 "9.0-Threat-A"
testThreat_9_0_A
putStrLn "9.1-Threat-A"
testThreat_9_1_A
putStrLn "9.1-Threat-B"
testThreat_9_1_B
putStrLn "Prisma-Threat-A"
testPrismaThreatA
putStrLn "Prisma-Threat-B"
testPrismaThreatB
putStrLn "Prisma-Threat-C"
testPrismaThreatC
putStrLn "8.1-System-A"
testSystemA
putStrLn "User-A"
testUserA
putStrLn "Correlation-A"
testCorrelationA
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"
testTraffic_9_0_A :: IO ()
testTraffic_9_0_A = case decode S.traffic_9_0_A of
Left err -> throwIO err
Right (LogTraffic t) ->
if | Traffic.deviceName t /= bytes "NY-PAN-FW-5" ->
fail $
"wrong device name:\nexpected: " ++
show (bytes "NY-PAN-FW-5") ++
"\nactually: " ++
show (Traffic.deviceName t)
| Traffic.actionSource t /= bytes "my-policy" ->
fail $
"wrong action source:\nexpected: " ++
show (bytes "my-policy") ++
"\nactually: " ++
prettyBytes (Traffic.actionSource t)
| otherwise -> pure ()
Right _ -> fail "wrong log type"
testPrismaTrafficA :: IO ()
testPrismaTrafficA = case decode S.traffic_prisma_A of
Left err -> throwIO err
Right (LogTraffic t) ->
if | Traffic.deviceName t /= bytes "The-Device-Name" ->
fail $
"wrong device name:\nexpected: " ++
show (bytes "NY-PAN-FW-5") ++
"\nactually: " ++
show (Traffic.deviceName 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"
testThreat_9_0_A :: IO ()
testThreat_9_0_A = case decode S.threat_9_0_A of
Left err -> throwIO err
Right (LogThreat t) ->
if | Threat.miscellaneous t /= bytes "dt.adsafeprotected.com/" -> fail $
"wrong miscellaneous (URL):\nExpected: dt.adsafeprotected.com/\nActually: " ++
prettyBytes (Threat.miscellaneous t) ++ "\n"
| otherwise -> pure ()
Right _ -> fail "wrong log type"
testThreat_9_1_A :: IO ()
testThreat_9_1_A = case decode S.threat_9_1_A of
Left err -> throwIO err
Right (LogThreat t) ->
if | Threat.miscellaneous t /= bytes "192.0.2.17_solarwinds_zero_configuration:5986/" -> fail $
"wrong miscellaneous (URL):\nExpected: " ++
"192.0.2.17_solarwinds_zero_configuration:5986/\nActually: " ++
prettyBytes (Threat.miscellaneous t) ++ "\n"
| otherwise -> pure ()
Right _ -> fail "wrong log type"
testThreat_9_1_B :: IO ()
testThreat_9_1_B = case decode S.threat_9_1_B of
Left err -> throwIO err
Right (LogThreat t) ->
if | Threat.urlCategoryList t /= Just (bytes "social-networking,low-risk") ->
fail $
"wrong url category list\nExpected:\n"
++
"social-networking,low-risk"
++
"\nActually:\n"
++
maybe "(empty)" prettyBytes (Threat.urlCategoryList t)
++
"\n"
| otherwise -> pure ()
Right _ -> fail "wrong log type"
testPrismaThreatA :: IO ()
testPrismaThreatA = case decode S.threat_prisma_A of
Left err -> throwIO err
Right (LogThreat t) ->
if | Threat.miscellaneous t /= bytes "play.google.com/" -> fail $
"wrong miscellaneous (URL):\nExpected: " ++
"play.google.com/\nActually: " ++
prettyBytes (Threat.miscellaneous t) ++ "\n"
| otherwise -> pure ()
Right _ -> fail "wrong log type"
testPrismaThreatB :: IO ()
testPrismaThreatB = case decode S.threat_prisma_B of
Left err -> throwIO err
Right (LogThreat t) ->
if | Threat.miscellaneous t /= bytes "example.com" -> fail $
"wrong miscellaneous (domain name):\nExpected: " ++
"example.com\nActually: " ++
prettyBytes (Threat.miscellaneous t) ++ "\n"
| otherwise -> pure ()
Right _ -> fail "wrong log type"
testPrismaThreatC :: IO ()
testPrismaThreatC = case decode S.threat_prisma_C of
Left err -> throwIO err
Right (LogThreat t) ->
if | Threat.subtype t /= bytes "wildfire" -> fail "wrong subtype"
| Threat.miscellaneous t /= bytes "Exchange.asmx" -> fail $
"wrong miscellaneous:\nExpected: " ++
"Exchange.asmx\nActually: " ++
prettyBytes (Threat.miscellaneous 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"
testUserA :: IO ()
testUserA = case decode S.user_A of
Left err -> throwIO err
Right (LogUser t) ->
if | User.subtype t /= bytes "login" -> fail $
"wrong subtype name:\nexpected: login\nactually: " ++
show (User.subtype t)
| User.user t /= bytes "BIGDAWG10$@EXAMPLE.COM" -> fail "wrong user"
| otherwise -> pure ()
Right _ -> fail "wrong log type"
testCorrelationA :: IO ()
testCorrelationA = case decode S.correlation_A of
Left err -> throwIO err
Right (LogCorrelation t) ->
if | Correlation.objectId t /= 6005 -> fail "wrong object id"
| 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 []