{-# language BangPatterns #-}
{-# language LambdaCase #-}
{-# language OverloadedStrings #-}
module Snmp.Decoding where
import Data.Bifunctor (first)
import Data.Coerce (coerce)
import Language.Asn.Decoding
import Language.Asn.Types
import Snmp.Types
import qualified Data.Vector as Vector
import qualified Language.Asn.Decoding as AsnDecoding
import Prelude hiding (sequence,null)
trapPdu :: AsnDecoding TrapPdu
trapPdu = sequence $ TrapPdu
<$> required "enterprise" objectIdentifier
<*> required "agent-addr"
( choice
[ option "internet" $ tag Application 0 Implicit octetStringWord32
]
)
<*> required "generic-trap" genericTrap
<*> required "specific-trap" integer
<*> required "time-stamp" (tag Application 3 Implicit integer)
<*> required "variable-bindings" (sequenceOf varBind)
genericTrap :: AsnDecoding GenericTrap
genericTrap = flip mapFailable integer $ \case
0 -> Right GenericTrapColdStart
1 -> Right GenericTrapWarmStart
2 -> Right GenericTrapLinkDown
3 -> Right GenericTrapLinkUp
4 -> Right GenericTrapAuthenticationFailure
5 -> Right GenericTrapEgpNeighborLoss
6 -> Right GenericTrapEnterpriseSpecific
_ -> Left "unrecognized generic-trap number"
messageV2 :: AsnDecoding MessageV2
messageV2 = sequence $ MessageV2
<$ required "version" integer
<*> required "community" octetString
<*> required "data" pdus
simpleSyntax :: AsnDecoding SimpleSyntax
simpleSyntax = choice
[ fmap SimpleSyntaxInteger $ option "integer-value" int32
, fmap SimpleSyntaxString $ option "string-value" octetString
, fmap SimpleSyntaxObjectId $ option "objectID-value" objectIdentifier
]
applicationSyntax :: AsnDecoding ApplicationSyntax
applicationSyntax = choice
[ fmap ApplicationSyntaxIpAddress
$ option "ipAddress-value" $ tag Application 0 Implicit octetStringWord32
, fmap ApplicationSyntaxCounter
$ option "counter-value" $ tag Application 1 Implicit word32
, fmap ApplicationSyntaxTimeTicks
$ option "timeticks-value" $ tag Application 3 Implicit word32
, fmap ApplicationSyntaxArbitrary
$ option "arbitrary-value" $ tag Application 4 Implicit octetString
, fmap ApplicationSyntaxBigCounter
$ option "big-counter-value" $ tag Application 6 Implicit word64
, fmap ApplicationSyntaxUnsignedInteger
$ option "unsigned-integer-value" $ tag Application 2 Implicit word32
]
objectSyntax :: AsnDecoding ObjectSyntax
objectSyntax = choice
[ fmap ObjectSyntaxSimple $ option "simple" simpleSyntax
, fmap ObjectSyntaxApplication $ option "application-wide" applicationSyntax
]
bindingResult :: AsnDecoding BindingResult
bindingResult = choice
[ BindingResultValue <$> option "value" objectSyntax
, BindingResultUnspecified <$ option "unSpecified" null
, BindingResultNoSuchObject <$ option "noSuchObject" (tag ContextSpecific 0 Implicit null)
, BindingResultNoSuchInstance <$ option "noSuchInstance" (tag ContextSpecific 1 Implicit null)
, BindingResultEndOfMibView <$ option "endOfMibView" (tag ContextSpecific 2 Implicit null)
]
varBind :: AsnDecoding VarBind
varBind = sequence $ VarBind
<$> required "name" objectIdentifier
<*> required "result" bindingResult
pdu :: AsnDecoding Pdu
pdu = sequence $ Pdu
<$> required "request-id" (coerce int)
<*> required "error-status" (coerce integer)
<*> required "error-index" (coerce int32)
<*> required "variable-bindings" (fmap Vector.fromList $ sequenceOf varBind)
bulkPdu :: AsnDecoding BulkPdu
bulkPdu = sequence $ BulkPdu
<$> required "request-id" (coerce int)
<*> required "non-repeaters" int32
<*> required "max-repetitions" int32
<*> required "variable-bindings" (fmap Vector.fromList $ sequenceOf varBind)
pdus :: AsnDecoding Pdus
pdus = choice
[ PdusGetRequest <$> option "get-request" (tag ContextSpecific 0 Implicit pdu)
, PdusGetNextRequest <$> option "get-next-request" (tag ContextSpecific 1 Implicit pdu)
, PdusGetBulkRequest <$> option "get-bulk-request" (tag ContextSpecific 5 Implicit bulkPdu)
, PdusResponse <$> option "response" (tag ContextSpecific 2 Implicit pdu)
, PdusSetRequest <$> option "set-request" (tag ContextSpecific 3 Implicit pdu)
, PdusInformRequest <$> option "inform-request" (tag ContextSpecific 6 Implicit pdu)
, PdusSnmpTrap <$> option "snmpV2-trap" (tag ContextSpecific 4 Implicit trapPdu)
, PdusReport <$> option "report" (tag ContextSpecific 8 Implicit pdu)
]
messageV3 :: AsnDecoding MessageV3
messageV3 = sequence $ MessageV3
<$ required "msgVersion" integer
<*> required "msgGlobalData" headerData
<*> required "msgSecurityParameters"
(mapFailable (first ("while decoding security params" ++) . AsnDecoding.ber usm) octetString)
<*> required "msgData" scopedPduDataDecoding
headerData :: AsnDecoding HeaderData
headerData = sequence $ HeaderData
<$> required "msgID" (coerce int)
<*> required "msgMaxSize" int32
<*> required "msgFlags" octetStringWord8
<* required "msgSecurityModel" integer
scopedPduDataDecoding :: AsnDecoding ScopedPduData
scopedPduDataDecoding = choice
[ fmap ScopedPduDataPlaintext $ option "plaintext" scopedPdu
, fmap ScopedPduDataEncrypted $ option "encryptedPDU" octetString
]
scopedPdu :: AsnDecoding ScopedPdu
scopedPdu = sequence $ ScopedPdu
<$> required "contextEngineID" (coerce octetString)
<*> required "contextName" octetString
<*> required "data" pdus
usm :: AsnDecoding Usm
usm = sequence $ Usm
<$> required "msgAuthoritativeEngineID" (coerce octetString)
<*> required "msgAuthoritativeEngineBoots" int32
<*> required "msgAuthoritativeEngineTime" int32
<*> required "msgUserName" octetString
<*> required "msgAuthenticationParameters" octetString
<*> required "msgPrivacyParameters" octetString