RFC 3412

Message Processing and Dispatching for the Simple Network Management Protocol (SNMP)

๐Ÿ“… published December 2002, from ietf

RFC 3412: Message Processing and Dispatching for the SNMP ๐ŸŽ€

okay bestie, this one is the RFC that tells SNMP engines how to handle their messages, which versions go where, and how PDUs get passed up to the apps ๐Ÿ’…โœจ it's Standards Track (so it's an actual Internet standard, not just a suggestion) and it's part of STD 62 ๐Ÿ”ฅ

the authors are J. Case (SNMP Research, Inc.), D. Harrington (Enterasys Networks), R. Presuhn (BMC Software, Inc.), and B. Wijnen (Lucent Technologies) ๐Ÿซถ it came out in December 2002, and it obsoletes RFC 2572 ๐Ÿฆ‹ so if you're still reading the old one, it's time to upgrade bestie ๐ŸŒธ


Status of this Memo ๐Ÿ“œ

okay so this part is the legal-ish intro ๐Ÿ™ˆ it says this document specifies an Internet standards track protocol for the Internet community, and it's asking for discussion and suggestions for improvements ๐Ÿ’œ if you want to know where this protocol stands, check the current edition of "Internet Official Protocol Standards" (STD 1) ๐Ÿงš and yes, distribution of this memo is unlimited, so it's all open ๐ŸŒˆ

Copyright (C) The Internet Society (2002). All Rights Reserved. ๐ŸŒธ

Abstract ๐Ÿฆ‹

so this doc is all about Message Processing and Dispatching for SNMP messages inside the SNMP architecture ๐Ÿซถ it sets out the procedures for sending potentially multiple versions of SNMP messages to the right Message Processing Models, and for dispatching PDUs to SNMP applications ๐Ÿ’– it also describes one Message Processing Model, the SNMPv3 Message Processing Model ๐Ÿ‘‘ and yeah, it obsoletes RFC 2572 ๐Ÿ’…

Table of Contents ๐Ÿ“š

   1. Introduction ................................................    3
   2. Overview ....................................................    4
   2.1. The Dispatcher ............................................    5
   2.2. Message Processing Subsystem ..............................    5
   3. Elements of Message Processing and Dispatching ..............    6
   3.1. messageProcessingModel ....................................    6
   3.2. pduVersion ................................................    6
   3.3. pduType ...................................................    7
   3.4. sendPduHandle .............................................    7
   4. Dispatcher Elements of Procedure ............................    7
   4.1. Sending an SNMP Message to the Network ....................    7
   4.1.1. Sending a Request or Notification .......................    8
   4.1.2. Sending a Response to the Network .......................    9
   4.2. Receiving an SNMP Message from the Network ................   11
   4.2.1. Message Dispatching of received SNMP Messages ...........   11
   4.2.2. PDU Dispatching for Incoming Messages ...................   12
   4.2.2.1. Incoming Requests and Notifications ...................   13
   4.2.2.2. Incoming Responses ....................................   14
   4.3. Application Registration for Handling PDU types ...........   15
   4.4. Application Unregistration for Handling PDU Types .........   16
   5. Definitions .................................................   16
   5.1. Definitions for SNMP Message Processing and Dispatching ...   16
   6. The SNMPv3 Message Format ...................................   19
   6.1. msgVersion ................................................   20
   6.2. msgID .....................................................   20
   6.3. msgMaxSize ................................................   21
   6.4. msgFlags ..................................................   21
   6.5. msgSecurityModel ..........................................   24
   6.6. msgSecurityParameters .....................................   24
   6.7. scopedPduData .............................................   24
   6.8. scopedPDU .................................................   24
   6.8.1. contextEngineID .........................................   24
   6.8.2. contextName .............................................   25
   6.8.3. data ....................................................   25
   7. Elements of Procedure for v3MP ..............................   25
   7.1. Prepare an Outgoing SNMP Message ..........................   26
   7.2. Prepare Data Elements from an Incoming SNMP Message .......   32
   8. Intellectual Property .......................................   37
   9. Acknowledgements ............................................   38
   10. Security Considerations ....................................   39
   11. References .................................................   40
   11.1. Normative References .....................................   40
   11.2. Informative References ...................................   41
   12. Editors' Addresses .........................................   42
   13. Full Copyright Statement ...................................   43

1. Introduction ๐Ÿงš

okay so the Architecture for describing Internet Management Frameworks [RFC3411] says an SNMP engine is made of four pieces ๐Ÿ’–

   1) a Dispatcher
   2) a Message Processing Subsystem,
   3) a Security Subsystem, and
   4) an Access Control Subsystem.

and applications use the services of these subsystems ๐Ÿซถ

it's really important to get the SNMP architecture and its terminology down first, so you know where the Message Processing Subsystem and Dispatcher from this doc fit in and how they talk to everything else โœจ you're expected to have read and understood the architecture description in [RFC3411] ๐Ÿ“š

the Dispatcher in the SNMP engine sends and receives SNMP messages ๐Ÿฆ‹ it also dispatches SNMP PDUs to SNMP applications ๐Ÿ’… when a message needs to be prepared, or data needs to be pulled out of one, the Dispatcher hands that job off to a message version-specific Message Processing Model inside the Message Processing Subsystem ๐ŸŒธ

a Message Processing Model is in charge of processing a version-specific SNMP message ๐Ÿ”ฅ it also coordinates with the Security Subsystem so the right security gets applied to the message being handled ๐Ÿ‘‘

the interactions between the Dispatcher, the Message Processing Subsystem, and applications are modeled with abstract data elements and abstract service interface primitives from the SNMP architecture ๐ŸŒˆ

same vibe for the Message Processing Subsystem and the Security Subsystem: they're also modeled with abstract data elements and abstract service interface primitives from the SNMP architecture ๐Ÿ’œ

the key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14, RFC 2119 ๐ŸŽ€

2. Overview ๐ŸŒธ

this illustration shows how Message Processing lines up with SNMP applications, the Security Subsystem, and Transport Mappings ๐Ÿฆ‹

   +-------------------------------------------------------------------+
   | SNMP Entity                                                       |
   |                                                                   |
   | +---------------------------------------------------------------+ |
   | | Applications                                                  | |
   | | +-----------+  +--------------+                               | |
   | | | Command   |  | Notification |                               | |
   | | | Generator |  | Originator   | +-----------+ +--------------+| |
   | | +-----------+  +--------------+ | Proxy     | | Other        || |
   | | +-----------+  +--------------+ | Forwarder | |Application(s)|| |
   | | | Command   |  | Notification | +-----------+ +--------------+| |
   | | | Responder |  | Receiver     |                               | |
   | | +-----------+  +--------------+                               | |
   | +---------------------------------------------------------------+ |
   |        ^                ^               ^           ^             |
   |        |                |               |           |             |
   |        v                v               v           v             |
   |        +--------+-------+---------------+-----------+             |
   |                 ^                                                 |
   |                 |    +---------------------+  +-----------------+ |
   |                 |    | Message Processing  |  | Security        | |
   | Dispatcher      v    | Subsystem           |  | Subsystem       | |
   | +------------------+ |     +------------+  |  |                 | |
   | | PDU Dispatcher   | |  +->| v1MP     * |<--->| +-------------+ | |
   | |                  | |  |  +------------+  |  | | Other       | | |
   | |                  | |  |  +------------+  |  | | Security    | | |
   | |                  | |  +->| v2cMP    * |<--->| | Model       | | |
   | | Message          | |  |  +------------+  |  | +-------------+ | |
   | | Dispatcher  <-------->+                  |  |                 | |
   | |                  | |  |  +------------+  |  | +-------------+ | |
   | |                  | |  +->| v3MP     * |<--->| | User-based  | | |
   | | Transport        | |  |  +------------+  |  | | Security    | | |
   | | Mapping          | |  |  +------------+  |  | | Model       | | |
   | | (e.g., RFC 3417) | |  +->| otherMP  * |<--->| +-------------+ | |
   | +------------------+ |     +------------+  |  |                 | |
   |          ^           +---------------------+  +-----------------+ |
   |          |                                                        |
   +----------|--------------------------------------------------------+
              v
     +------------------+
     |   Network        |           * One or more models may be present.
     +------------------+

2.1. The Dispatcher ๐ŸŽ€

the Dispatcher is a key piece of an SNMP engine ๐Ÿ’– there's only one in each SNMP engine, and its job is to dispatch tasks to the multiple version-specific Message Processing Models and to dispatch PDUs to the various applications ๐Ÿ‘‘

for outgoing messages, an application hands over a PDU to be sent, plus the data needed to prepare and send the message ๐Ÿฆ‹ the application also says which version-specific Message Processing Model should prepare the message, with the desired security processing ๐ŸŒˆ once the message is prepared, the Dispatcher sends it ๐Ÿซถ

for incoming messages, the Dispatcher figures out the SNMP version of the message and passes it to the matching version-specific Message Processing Model ๐Ÿ’… that model pulls out the components of the message and coordinates the security services for it ๐Ÿ”ฅ after that version-specific processing, the PDU Dispatcher decides which application, if any, should get the PDU, and forwards it there โœจ

while it's sending and receiving SNMP messages, the Dispatcher collects statistics about the messages and how the SNMP engine is behaving ๐ŸŒธ those statistics go into managed objects so remote SNMP entities can access them ๐Ÿ’œ this document defines those managed objects, the MIB module that contains them, and how they might be used to provide useful management ๐Ÿงš

2.2. Message Processing Subsystem โœจ

okay so the Message Processing Subsystem is the bit of an SNMP engine that talks to the Dispatcher to handle the version-specific SNMP messages ๐Ÿ’… and it holds one or more Message Processing Models ๐ŸŽ€

this document describes one Message Processing Model, the SNMPv3 Message Processing Model, in Section 6 ๐Ÿฆ‹ it gets its own section so everyone can see that multiple (independent) Message Processing Models can exist at the same time and be described in different documents ๐Ÿ’– the SNMPv3 one can be replaced or supplemented with other Models later on ๐ŸŒˆ two that are expected to show up are the SNMPv1 message format [RFC1157] and the SNMPv2c message format [RFC1901] ๐Ÿงš and others may be developed as needed ๐Ÿ’œ


3. Elements of Message Processing and Dispatching ๐ŸŒธ

see [RFC3411] for the definitions of:

   contextEngineID
   contextName
   scopedPDU
   maxSizeResponseScopedPDU
   securityModel
   securityName
   securityLevel
   messageProcessingModel

for incoming messages, a version-specific message processing module hands these values to the Dispatcher ๐Ÿ“ฅ for outgoing messages, an application hands them over instead ๐Ÿ“ค

for some version-specific processing the values may be extracted from received messages, and for other versions they may be determined by algorithm or by an implementation-defined mechanism ๐Ÿคทโ€โ™€๏ธ the way the value gets figured out is totally irrelevant to the Dispatcher ๐Ÿ’…

the following additional or expanded definitions are for use within the Dispatcher ๐Ÿซถ

3.1. messageProcessingModel ๐ŸŽ€

the value of messageProcessingModel identifies a Message Processing Model ๐Ÿช„ a Message Processing Model describes the version-specific procedures for extracting data from messages, generating messages, and calling upon a securityModel to apply its security services to messages ๐Ÿ” it also handles converting data from a version-specific message format into a generic format the Dispatcher can use, and converting data from Dispatcher format back into a version-specific message format ๐Ÿ”

3.2. pduVersion ๐Ÿฆ‹

the value of pduVersion represents a specific version of protocol operation and its associated PDU formats, such as SNMPv1 or SNMPv2 [RFC3416] โœจ the values are specific to the version of the PDU in a message and to the PDUs processed by applications ๐Ÿง the Dispatcher doesn't use the value of pduVersion directly, so it's not its problem ๐Ÿ˜Œ

an application specifies the pduVersion when it asks the PDU Dispatcher to send a PDU to another SNMP engine ๐Ÿ“จ the Dispatcher then passes the pduVersion along to a Message Processing Model, so it knows how to handle the PDU properly ๐Ÿ™Œ

for incoming messages, the pduVersion is provided to the Dispatcher by a version-specific Message Processing module ๐Ÿ“ฌ the PDU Dispatcher passes it on to the application so the app knows how to handle the PDU properly ๐Ÿ’• for example, a command responder application needs to know whether to use [RFC3416] elements of procedure and syntax instead of the ones specified for SNMPv1 ๐Ÿง

3.3. pduType ๐ŸŒท

a value of the pduType represents a specific type of protocol operation ๐Ÿ“ the values are specific to the version of the PDU in a message ๐ŸŽฏ

applications register to support particular pduTypes for particular contextEngineIDs ๐Ÿ“

for incoming messages, pduType is provided to the Dispatcher by a version-specific Message Processing module ๐Ÿ“ฆ it's then used to dispatch the PDU to the application that registered for that pduType and the contextEngineID of the associated scopedPDU ๐Ÿš€

3.4. sendPduHandle ๐Ÿซง

this handle is generated to coordinate the processing of requests and responses between the SNMP engine and an application ๐Ÿค the handle must be unique across all version-specific Message Processing Models, and it's of local significance only ๐Ÿ 


4. Dispatcher Elements of Procedure ๐Ÿ”ฅ

this section describes the procedures the Dispatcher follows when it generates and processes SNMP messages ๐Ÿง 

4.1. Sending an SNMP Message to the Network ๐Ÿ“ค

this section describes the procedure an SNMP engine follows whenever it sends an SNMP message ๐Ÿ’Œ

4.1.1. Sending a Request or Notification ๐Ÿ’–

the Dispatcher follows these procedures when an application wants to send an SNMP PDU to another (remote) application ๐ŸŒ that means starting a communication by originating a message, like one containing a request or a notification ๐Ÿ””

  1. the application asks for this using the abstract service primitive:
statusInformation =              -- sendPduHandle if success
                                 -- errorIndication if failure
  sendPdu(
  IN   transportDomain           -- transport domain to be used
  IN   transportAddress          -- destination network address
  IN   messageProcessingModel    -- typically, SNMP version
  IN   securityModel             -- Security Model to use
  IN   securityName              -- on behalf of this principal
  IN   securityLevel             -- Level of Security requested
  IN   contextEngineID           -- data from/at this entity
  IN   contextName               -- data from/in this context
  IN   pduVersion                -- the version of the PDU
  IN   PDU                       -- SNMP Protocol Data Unit
  IN   expectResponse            -- TRUE or FALSE
       )
  1. if the messageProcessingModel value doesn't represent a Message Processing Model the Dispatcher knows about, then an errorIndication (implementation-dependent) gets returned to the calling application ๐Ÿ™…โ€โ™€๏ธ no further processing happens after that
  2. the Dispatcher generates a sendPduHandle to coordinate the subsequent processing ๐ŸŽŸ๏ธ
  3. the Message Dispatcher sends the request to the version-specific Message Processing module identified by messageProcessingModel using the abstract service primitive:
statusInformation =              -- success or error indication
  prepareOutgoingMessage(
  IN   transportDomain           -- as specified by application
  IN   transportAddress          -- as specified by application
  IN   messageProcessingModel    -- as specified by application
  IN   securityModel             -- as specified by application
  IN   securityName              -- as specified by application
  IN   securityLevel             -- as specified by application
  IN   contextEngineID           -- as specified by application
  IN   contextName               -- as specified by application
  IN   pduVersion                -- as specified by application
  IN   PDU                       -- as specified by application
  IN   expectResponse            -- as specified by application
  IN   sendPduHandle             -- as determined in step 3.
  OUT  destTransportDomain       -- destination transport domain
  OUT  destTransportAddress      -- destination transport address
  OUT  outgoingMessage           -- the message to send
  OUT  outgoingMessageLength     -- the message length
       )
  1. if the statusInformation shows an error, the errorIndication gets returned to the calling application ๐Ÿšซ and no further processing happens
  2. if the statusInformation shows success, the sendPduHandle is returned to the application and the outgoingMessage is sent ๐ŸŽ‰ the transport used to send it comes back via destTransportDomain, and the address it was sent to comes back via destTransportAddress ๐Ÿ“

outgoing Message Processing is complete โœ…

4.1.2. Sending a Response to the Network ๐Ÿ“ฌ

this procedure is followed when an application wants to send a response back to the originator of an SNMP Request ๐Ÿ’ฌ

  1. an application can ask for this using the abstract service primitive:
result =
returnResponsePdu(
 IN   messageProcessingModel   -- typically, SNMP version
 IN   securityModel            -- Security Model in use
 IN   securityName             -- on behalf of this principal
 IN   securityLevel            -- same as on incoming request
 IN   contextEngineID          -- data from/at this SNMP entity
 IN   contextName              -- data from/in this context
 IN   pduVersion               -- the version of the PDU
 IN   PDU                      -- SNMP Protocol Data Unit
 IN   maxSizeResponseScopedPDU -- maximum size of Response PDU
 IN   stateReference           -- reference to state information
                               -- as presented with the request
 IN   statusInformation        -- success or errorIndication
 )                             -- (error counter OID and value
                               -- when errorIndication)
  1. the Message Dispatcher sends the request to the appropriate Message Processing Model indicated by the received value of messageProcessingModel, using the abstract service primitive:
result =                       -- SUCCESS or errorIndication
 prepareResponseMessage(
 IN   messageProcessingModel   -- specified by application
 IN   securityModel            -- specified by application
 IN   securityName             -- specified by application
 IN   securityLevel            -- specified by application
 IN   contextEngineID          -- specified by application
 IN   contextName              -- specified by application
 IN   pduVersion               -- specified by application
 IN   PDU                      -- specified by application
 IN   maxSizeResponseScopedPDU -- specified by application
 IN   stateReference           -- specified by application
 IN   statusInformation        -- specified by application
 OUT  destTransportDomain      -- destination transport domain
 OUT  destTransportAddress     -- destination transport address
 OUT  outgoingMessage          -- the message to send
 OUT  outgoingMessageLength    -- the message length
      )
  1. if the result is an errorIndication, it gets returned to the calling application ๐Ÿ™…โ€โ™€๏ธ no further processing happens
  2. if the result is success, the outgoingMessage is sent ๐Ÿ’Œ the transport used comes back via destTransportDomain, and the address it went to comes back via destTransportAddress ๐Ÿ—บ๏ธ

Message Processing is complete ๐Ÿ

4.2. Receiving an SNMP Message from the Network ๐Ÿ“ฅ

this section describes the procedure an SNMP engine follows whenever it receives an SNMP message ๐Ÿ‘‚

ok bestie, quick heads up: for the sake of clarity (and so the text doesn't get even longer and more complicated ๐Ÿ˜ญ), some details were left out of the steps below. in particular, the elements of procedure don't always explicitly say when state information needs to be released. the general rule is that if state information is available when a message is to be "discarded without further processing", then the state information must also be released at that same time ๐Ÿซถ

4.2.1. Message Dispatching of received SNMP Messages โœจ

  1. okay so the snmpInPkts counter [RFC3418] gets incremented first ๐Ÿ”ข every packet counts, bestie!
  2. the version of the SNMP message is figured out in an implementation-dependent manner ๐Ÿงฉ. if the packet can't be parsed well enough to tell the version, the snmpInASNParseErrs [RFC3418] counter goes up and the message gets discarded with no further processing ๐Ÿ—‘๏ธ. if the version isn't supported, the snmpInBadVersions [RFC3418] counter goes up and the message gets discarded with no further processing too ๐Ÿ’€.
  3. the origin transportDomain and origin transportAddress get determined ๐Ÿ“.
  4. the message is handed to the version-specific Message Processing Model, which gives back the abstract data elements the Dispatcher needs ๐ŸŽ€. this happens with the abstract service primitive below:
result =                        -- SUCCESS or errorIndication
  prepareDataElements(
  IN   transportDomain          -- origin as determined in step 3.
  IN   transportAddress         -- origin as determined in step 3.
  IN   wholeMsg                 -- as received from the network
  IN   wholeMsgLength           -- as received from the network
  OUT  messageProcessingModel   -- typically, SNMP version
  OUT  securityModel            -- Security Model specified
  OUT  securityName             -- on behalf of this principal
  OUT  securityLevel            -- Level of Security specified
  OUT  contextEngineID          -- data from/at this entity
  OUT  contextName              -- data from/in this context
  OUT  pduVersion               -- the version of the PDU
  OUT  PDU                      -- SNMP Protocol Data Unit
  OUT  pduType                  -- SNMP PDU type
  OUT  sendPduHandle            -- handle for a matched request
  OUT  maxSizeResponseScopedPDU -- maximum size of Response PDU
  OUT  statusInformation        -- success or errorIndication
                                -- (error counter OID and value
                                -- when errorIndication)
  OUT  stateReference           -- reference to state information
                                -- to be used for a possible
       )                        -- Response
  1. if the result is a FAILURE errorIndication, the message is discarded with no further processing ๐Ÿšซ.
  2. at this point the abstract data elements are all prepped ๐Ÿ’…, and processing carries on as described in Section 4.2.2, PDU Dispatching for Incoming Messages ๐Ÿฆ‹.

4.2.2. PDU Dispatching for Incoming Messages ๐ŸŒธ

the way the PDU gets dispatched depends on the value of sendPduHandle ๐Ÿง . if sendPduHandle is <none>, then it's a request or notification, and the procedures in Section 4.2.2.1 apply. if the value of snmpPduHandle is not <none>, then it's a response, and the procedures in Section 4.2.2.2 apply.

4.2.2.1. Incoming Requests and Notifications ๐Ÿ“จ

these are the procedures for dispatching PDUs when sendPduHandle is <none>, which means it's a request or notification ๐Ÿ’Œ.

  1. the combination of contextEngineID and pduType is used to figure out which application registered for this request or notification ๐Ÿ‘‘.
  2. if no application has registered for that combination, then:
    • a) the snmpUnknownPDUHandlers counter gets incremented ๐Ÿ“ˆ.
    • b) a Response message gets generated using this abstract service primitive:
result =                       -- SUCCESS or FAILURE
prepareResponseMessage(
IN   messageProcessingModel    -- as provided by MP module
IN   securityModel             -- as provided by MP module
IN   securityName              -- as provided by MP module
IN   securityLevel             -- as provided by MP module
IN   contextEngineID           -- as provided by MP module
IN   contextName               -- as provided by MP module
IN   pduVersion                -- as provided by MP module
IN   PDU                       -- as provided by MP module
IN   maxSizeResponseScopedPDU  -- as provided by MP module
IN   stateReference            -- as provided by MP module
IN   statusInformation         -- errorIndication plus
                               -- snmpUnknownPDUHandlers OID
                               -- value pair.
OUT  destTransportDomain       -- destination transportDomain
OUT  destTransportAddress      -- destination transportAddress
OUT  outgoingMessage           -- the message to send
OUT  outgoingMessageLength     -- its length
)
  • c) if the result is SUCCESS, the prepared message gets sent to the originator of the request, as identified by the transportDomain and transportAddress ๐Ÿš€. the transport used to send the outgoingMessage comes back via destTransportDomain, and the address it was sent to comes back via destTransportAddress ๐Ÿ“ฌ.
  • d) the incoming message is discarded with no further processing ๐Ÿซก. Message Processing for this message is complete โœ….
  1. the PDU gets dispatched to the application with this abstract service primitive ๐ŸŽ:
processPdu(                     -- process Request/Notification
  IN   messageProcessingModel   -- as provided by MP module
  IN   securityModel            -- as provided by MP module
  IN   securityName             -- as provided by MP module
  IN   securityLevel            -- as provided by MP module
  IN   contextEngineID          -- as provided by MP module
  IN   contextName              -- as provided by MP module
  IN   pduVersion               -- as provided by MP module
  IN   PDU                      -- as provided by MP module
  IN   maxSizeResponseScopedPDU -- as provided by MP module
  IN   stateReference           -- as provided by MP module
                                -- needed when sending response
       )

Message processing for this message is complete ๐ŸŽ‰.

4.2.2.2. Incoming Responses ๐Ÿ’œ

these are the procedures for dispatching PDUs when sendPduHandle is not <none>, which means it's a response ๐Ÿ’ซ.

  1. the value of sendPduHandle is used to figure out, in an implementation-defined manner, which application is waiting for a response tied to this sendPduHandle ๐Ÿ”.
  2. if no waiting application is found, the message gets discarded with no further processing, and the stateReference is released ๐Ÿซ . the snmpUnknownPDUHandlers counter gets incremented. Message Processing is complete for this message.
  3. any cached information about the message, including stateReference, gets discarded ๐Ÿงน.
  4. the response gets dispatched to the application using this abstract service primitive ๐ŸŒˆ:
processResponsePdu(              -- process Response PDU
  IN   messageProcessingModel    -- provided by the MP module
  IN   securityModel             -- provided by the MP module
  IN   securityName              -- provided by the MP module
  IN   securityLevel             -- provided by the MP module
  IN   contextEngineID           -- provided by the MP module
  IN   contextName               -- provided by the MP module
  IN   pduVersion                -- provided by the MP module
  IN   PDU                       -- provided by the MP module
  IN   statusInformation         -- provided by the MP module
  IN   sendPduHandle             -- provided by the MP module
)

Message Processing is complete for this message ๐Ÿฉท.

4.3. Application Registration for Handling PDU types ๐ŸŽ€

okay so applications that want to process certain PDUs have to register with the PDU Dispatcher ๐Ÿ™Œ. they tell it which combination of contextEngineID and pduType(s) they want to take responsibility for ๐Ÿซถ.

  1. an application registers using this abstract interface primitive:
statusInformation =           -- success or errorIndication
  registerContextEngineID(
  IN   contextEngineID        -- take responsibility for this one
  IN   pduType                -- the pduType(s) to be registered
       )

Note: implementations may provide a way to request registration for multiple contextEngineID values at once (like all of them ๐Ÿ‘€), and they may also provide a way to request registration for multiple values of pduType at once.

  1. the parameters may be checked for validity ๐Ÿ”Ž. if they aren't valid, an errorIndication (invalidParameter) is returned to the application ๐Ÿ™….
  2. each combination of contextEngineID and pduType can only be registered once ๐Ÿšซ. if another application has already registered for the specified combination, then an errorIndication (alreadyRegistered) is returned to the application ๐Ÿ˜ญ.
  3. otherwise, the registration is saved so SNMP PDUs can be dispatched to this application ๐Ÿ’–.

4.4. Application Unregistration for Handling PDU Types ๐Ÿฅ€

applications that no longer want to process certain PDUs have to unregister with the PDU Dispatcher ๐Ÿ‘‹.

  1. an application unregisters using this abstract service primitive:
unregisterContextEngineID(
 IN   contextEngineID        -- give up responsibility for this
 IN   pduType                -- the pduType(s) to be unregistered
      )

Note: implementations may provide a way to request unregistration for multiple contextEngineID values at once, like all of them, and they may also provide a way to request unregistration for multiple values of pduType at once.

  1. if the contextEngineID and pduType combination has been registered, then the registration is deleted ๐Ÿ—‘๏ธ. if no such registration exists, the request is ignored ๐Ÿ™ƒ.

5. Definitions ๐Ÿงš

5.1. Definitions for SNMP Message Processing and Dispatching ๐Ÿ’–

okay so this is the MIB module, the official little dictionary for the SNMP-MPD-MIB. it's giving admin paperwork, but it's how the engine tells everyone what it's been up to ๐Ÿ“‹โœจ

SNMP-MPD-MIB DEFINITIONS ::= BEGIN

IMPORTS
    MODULE-COMPLIANCE, OBJECT-GROUP         FROM SNMPv2-CONF
    MODULE-IDENTITY, OBJECT-TYPE,
    snmpModules, Counter32                  FROM SNMPv2-SMI;

snmpMPDMIB MODULE-IDENTITY
    LAST-UPDATED "200210140000Z"
    ORGANIZATION "SNMPv3 Working Group"
    CONTACT-INFO "WG-EMail:   snmpv3@lists.tislabs.com
                  Subscribe:  snmpv3-request@lists.tislabs.com

                  Co-Chair:   Russ Mundy
                              Network Associates Laboratories
                  postal:     15204 Omega Drive, Suite 300
                              Rockville, MD 20850-4601
                              USA

                  EMail:      mundy@tislabs.com
                  phone:      +1 301-947-7107

                  Co-Chair &
                  Co-editor:  David Harrington
                              Enterasys Networks
                  postal:     35 Industrial Way
                              P. O. Box 5005
                              Rochester NH 03866-5005
                              USA
                  EMail:      dbh@enterasys.com
                  phone:      +1 603-337-2614

                  Co-editor:  Jeffrey Case
                              SNMP Research, Inc.
                  postal:     3001 Kimberlin Heights Road
                              Knoxville, TN 37920-9716
                              USA
                  EMail:      case@snmp.com
                  phone:      +1 423-573-1434

                  Co-editor:  Randy Presuhn
                              BMC Software, Inc.
                  postal:     2141 North First Street
                              San Jose, CA 95131
                              USA
                  EMail:      randy_presuhn@bmc.com
                  phone:      +1 408-546-1006

                  Co-editor:  Bert Wijnen
                              Lucent Technologies
                  postal:     Schagen 33
                              3461 GL Linschoten
                              Netherlands
                  EMail:      bwijnen@lucent.com
                  phone:      +31 348-680-485
                 "
    DESCRIPTION  "The MIB for Message Processing and Dispatching

                  Copyright (C) The Internet Society (2002). This
                  version of this MIB module is part of RFC 3412;
                  see the RFC itself for full legal notices.
                 "
    REVISION     "200210140000Z"            -- 14 October 2002
    DESCRIPTION  "Updated addresses, published as RFC 3412."
    REVISION     "199905041636Z"            -- 4 May 1999
    DESCRIPTION  "Updated addresses, published as RFC 2572."
    REVISION     "199709300000Z"            -- 30 September 1997
    DESCRIPTION  "Original version, published as RFC 2272."
    ::= { snmpModules 11 }

-- Administrative assignments ***************************************

snmpMPDAdmin           OBJECT IDENTIFIER ::= { snmpMPDMIB 1 }
snmpMPDMIBObjects      OBJECT IDENTIFIER ::= { snmpMPDMIB 2 }
snmpMPDMIBConformance  OBJECT IDENTIFIER ::= { snmpMPDMIB 3 }

-- Statistics for SNMP Messages *************************************

snmpMPDStats           OBJECT IDENTIFIER ::= { snmpMPDMIBObjects 1 }

snmpUnknownSecurityModels OBJECT-TYPE
    SYNTAX       Counter32
    MAX-ACCESS   read-only
    STATUS       current
    DESCRIPTION "The total number of packets received by the SNMP
                 engine which were dropped because they referenced a
                 securityModel that was not known to or supported by
                 the SNMP engine.
                "
    ::= { snmpMPDStats 1 }

snmpInvalidMsgs OBJECT-TYPE
    SYNTAX       Counter32
    MAX-ACCESS   read-only
    STATUS       current
    DESCRIPTION "The total number of packets received by the SNMP
                 engine which were dropped because there were invalid
                 or inconsistent components in the SNMP message.
                "
    ::= { snmpMPDStats 2 }

snmpUnknownPDUHandlers OBJECT-TYPE
    SYNTAX       Counter32
    MAX-ACCESS   read-only
    STATUS       current
    DESCRIPTION "The total number of packets received by the SNMP
                 engine which were dropped because the PDU contained
                 in the packet could not be passed to an application
                 responsible for handling the pduType, e.g. no SNMP
                 application had registered for the proper
                 combination of the contextEngineID and the pduType.
                "
    ::= { snmpMPDStats 3 }

-- Conformance information ******************************************

snmpMPDMIBCompliances OBJECT IDENTIFIER ::= {snmpMPDMIBConformance 1}
snmpMPDMIBGroups      OBJECT IDENTIFIER ::= {snmpMPDMIBConformance 2}

-- Compliance statements

snmpMPDCompliance MODULE-COMPLIANCE
    STATUS       current
    DESCRIPTION "The compliance statement for SNMP entities which
                 implement the SNMP-MPD-MIB.
                "
    MODULE    -- this module
        MANDATORY-GROUPS { snmpMPDGroup }
    ::= { snmpMPDMIBCompliances 1 }

snmpMPDGroup OBJECT-GROUP
    OBJECTS {
              snmpUnknownSecurityModels,
              snmpInvalidMsgs,
              snmpUnknownPDUHandlers
            }
    STATUS       current
    DESCRIPTION "A collection of objects providing for remote
                 monitoring of the SNMP Message Processing and
                 Dispatching process.
                "
    ::= { snmpMPDMIBGroups 1 }

END

6. The SNMPv3 Message Format โœจ

okay this section is where the actual message layout lives, so pay attention bestie ๐Ÿงš it defines the SNMPv3 message format and the SNMP version 3 Message Processing Model (v3MP) ๐Ÿ’…

SNMPv3MessageSyntax DEFINITIONS IMPLICIT TAGS ::= BEGIN

    SNMPv3Message ::= SEQUENCE {
        -- identify the layout of the SNMPv3Message
        -- this element is in same position as in SNMPv1
        -- and SNMPv2c, allowing recognition
        -- the value 3 is used for snmpv3
        msgVersion INTEGER ( 0 .. 2147483647 ),
        -- administrative parameters
        msgGlobalData HeaderData,
        -- security model-specific parameters
        -- format defined by Security Model
        msgSecurityParameters OCTET STRING,
        msgData  ScopedPduData
    }

    HeaderData ::= SEQUENCE {
        msgID      INTEGER (0..2147483647),
        msgMaxSize INTEGER (484..2147483647),

        msgFlags   OCTET STRING (SIZE(1)),
                   --  .... ...1   authFlag
                   --  .... ..1.   privFlag
                   --  .... .1..   reportableFlag
                   --              Please observe:
                   --  .... ..00   is OK, means noAuthNoPriv
                   --  .... ..01   is OK, means authNoPriv
                   --  .... ..10   reserved, MUST NOT be used.
                   --  .... ..11   is OK, means authPriv

        msgSecurityModel INTEGER (1..2147483647)
    }

    ScopedPduData ::= CHOICE {
        plaintext    ScopedPDU,
        encryptedPDU OCTET STRING  -- encrypted scopedPDU value
    }

    ScopedPDU ::= SEQUENCE {
        contextEngineID  OCTET STRING,
        contextName      OCTET STRING,
        data             ANY -- e.g., PDUs as defined in [RFC3416]
    }
END

6.1. msgVersion ๐ŸŒธ

this one's simple, no cap. the msgVersion field gets set to snmpv3(3), and that's how you know it's an SNMP version 3 Message ๐Ÿฆ‹

6.2. msgID ๐Ÿ’œ

the msgID is the thing two SNMP entities use to keep track of requests and responses, and the v3MP uses it to keep the different subsystem models in sync while they process the message ๐Ÿซถ

values for msgID SHOULD be generated so they don't re-use anything still outstanding. this is lowkey important because it helps protect against some replay attacks ๐Ÿ”ฅ one possible way to do it is to use the low-order bits of snmpEngineBoots [RFC3411] as the high-order part of the msgID, and then a monotonically increasing integer for the low-order part โœจ

ngl this next bit is so iconic ๐Ÿ‘‘ the request-id in a PDU can be used by SNMP applications to identify the PDU, but the msgID is what the engine uses to identify the message that carries the PDU. the engine needs to identify the message even if decrypting the PDU (and request-id) fails ๐Ÿ˜ญ so don't assume the msgID and the request-id are the same thing, bestie ๐Ÿ™ˆ

the msgID of a response takes the msgID from the message it's responding to. this is how an engine keeps track of its (potentially many) outstanding requests and matches incoming responses to them ๐Ÿ’… and if you're using an unreliable datagram service, the msgID also gives you a simple way to spot messages the network duplicated ๐ŸŒˆ if a request gets retransmitted, a new msgID SHOULD be used for each retransmission ๐Ÿ“

6.3. msgMaxSize ๐ŸŽ€

the msgMaxSize field tells you the biggest message the sender can handle. so it's the max size that sender can accept when another SNMP engine sends them an SNMP message (a response or anything else) over the transport in use for that message ๐Ÿงš

when an SNMP message is being generated, the SNMP engine that makes it is the one who provides the msgMaxSize โœจ and at the receiving engine, msgMaxSize is what tells you how big a message the sender can accommodate ๐Ÿ’–

6.4. msgFlags ๐ŸŽ€

okay so msgFlags is basically a bundle of bit fields ๐Ÿ’… and each one controls how the message gets processed. let's go through them bestie ๐Ÿซถ

The reportableFlag is a secondary aid for deciding whether a Report PDU MUST be sent ๐Ÿ‘€ It only gets used when the PDU part of a message can't be decoded, like if the encryption key is wrong ๐Ÿ” If the PDU can be decoded, the PDU type is what drives the decisions about Report PDUs. no cap, that's the main character ๐Ÿ‘‘

When the reportableFlag is used, a value of one means a Report PDU MUST be returned to the sender under the conditions that can trigger Report PDUs โœจ And a value of zero means a Report PDU MUST NOT be sent ๐Ÿ™…โ€โ™€๏ธ The reportableFlag MUST always be zero for PDUs from the Unconfirmed Class, like a Report PDU, a response-type PDU (such as a Response PDU), or an unacknowledged notification-type PDU (such as an SNMPv2-trap PDU) ๐Ÿฆ‹ It MUST always be one for PDUs from the Confirmed Class, including request-type PDUs (such as a Get PDU) and acknowledged notification-type PDUs (such as an Inform PDU) ๐Ÿ”ฅ

Now the receiver side, which is so iconic ๐Ÿ˜ญ If the reportableFlag is one on a message carrying an Unconfirmed Class PDU (like a Report PDU, a Response PDU, or an SNMPv2-trap PDU), the receiver MUST process it as though the reportableFlag were zero ๐ŸŒธ And if the reportableFlag is zero on a message carrying a request-type PDU (like a Get PDU) or an acknowledged notification-type PDU (like an Inform PDU), the receiver MUST process it as though the reportableFlag were one ๐Ÿ’œ

Report PDUs are generated directly by the SNMPv3 Message Processing Model ๐Ÿงš They're how engines talk to each other, but they can also be handed up to applications for processing ๐Ÿ“

An SNMP engine that receives a reportPDU can use it to figure out what kind of problem the remote SNMP engine ran into ๐Ÿ•ต๏ธโ€โ™€๏ธ It does that by reading the error counter in the first (and only) varBind of the reportPDU โœจ Based on that error, the engine may try to send a corrected SNMP message ๐Ÿ” If that isn't possible, it may pass an indication of the error up to the application that originally issued the failed SNMP request ๐Ÿ’–

The authFlag and privFlag parts of msgFlags are set by the sender to say which securityLevel was applied before the message went out on the wire ๐Ÿ“ก The receiver MUST apply that same securityLevel when it receives the message and processes the contents ๐Ÿซถ

There are three securityLevels: noAuthNoPriv, which is less than authNoPriv, which is less than authPriv ๐ŸŒˆ For more on securityLevel, check the SNMP architecture document [RFC3411] ๐Ÿ“š

a) authFlag

If the authFlag is set to one, the securityModel used by the SNMP engine that sent the message MUST identify the securityName the message was generated on behalf of, and MUST provide, in a securityModel-specific manner, enough data for the receiver to authenticate that identification ๐Ÿ” Generally, this authentication lets the receiver determine, with reasonable certainty, that the message:

  • was sent on behalf of the principal associated with the securityName,
  • was not redirected,
  • was not modified in transit, and
  • was not replayed.

If the authFlag is zero, the securityModel used by the sending engine MUST still identify the securityName the message was generated on behalf of ๐Ÿ™ƒ but it does not need to provide enough data for the receiver to authenticate that identification, since there's no need to authenticate the message in this case ๐ŸŒธ

b) privFlag

If the privFlag is set, the securityModel used by the sending SNMP engine MUST also protect the scopedPDU in an SNMP message from disclosure, meaning it MUST encrypt/decrypt the scopedPDU ๐Ÿ”’ If the privFlag is zero, the securityModel in use doesn't need to protect the data from disclosure ๐Ÿฆ‹

It's an explicit requirement of the SNMP architecture that if privacy is selected, authentication is also required ๐Ÿซข So if the privFlag is set, the authFlag MUST also be set to one ๐Ÿ’…

The combination of authFlag and privFlag makes up the Level of Security like this:

authFlag zero, privFlag zero -> securityLevel is noAuthNoPriv
authFlag zero, privFlag one  -> invalid combination, see below
authFlag one,  privFlag zero -> securityLevel is authNoPriv
authFlag one,  privFlag one  -> securityLevel is authPriv

The elements of procedure (further down) describe what to do when you hit that invalid combination, where authFlag is zero and privFlag is one ๐Ÿ™ˆ

The remaining bits in msgFlags are reserved ๐Ÿงฉ They MUST be set to zero when sending a message, and they SHOULD be ignored when receiving one โœจ


6.5. msgSecurityModel ๐Ÿ”

The v3MP supports multiple Security Models existing at the same time to provide security services for SNMPv3 messages ๐ŸŒˆ The msgSecurityModel field in an SNMPv3 Message says which Security Model the sender used to generate the message ๐Ÿ’œ That tells the receiver which securityModel MUST be used to do the security processing for that message ๐ŸŽฏ How that gets mapped to the right securityModel implementation inside an SNMP engine is up to each implementation ๐Ÿ› ๏ธ

6.6. msgSecurityParameters ๐Ÿง

The msgSecurityParameters field of the SNMPv3 Message is for communication between the Security Model modules on the sending and receiving engines ๐Ÿค Only the Security Model uses that data, and the Security Model defines both its contents and format ๐Ÿ“‹ This OCTET STRING isn't interpreted by the v3MP at all. It just gets passed along to the local implementation of whichever Security Model msgSecurityModel points to ๐Ÿฆ‹

6.7. scopedPduData ๐ŸŽ

The scopedPduData field holds either the plain text scopedPDU, if the privFlag in msgFlags is zero, or an encryptedPDU (encoded as an OCTET STRING) ๐Ÿ”“ That encryptedPDU MUST be decrypted by the securityModel in use to produce a plaintext scopedPDU ๐Ÿ—๏ธ

6.8. scopedPDU ๐ŸŒธ

The scopedPDU holds the info that identifies an administratively unique context and a PDU ๐Ÿ’– The object identifiers in the PDU refer to managed objects that are (expected to be) accessible within that context โœจ

6.8.1. contextEngineID ๐Ÿงš

The contextEngineID in the SNMPv3 message uniquely identifies, within an administrative domain, an SNMP entity that may realize an instance of a context with a particular contextName ๐ŸŒ

For incoming messages, the contextEngineID is used together with the pduType to decide which application the scopedPDU gets sent to for processing ๐Ÿ“ฌ

For outgoing messages, the v3MP sets the contextEngineID to the value the application gave in its request to send a message ๐Ÿ“ค

6.8.2. contextName ๐Ÿท๏ธ

The contextName field in an SNMPv3 message, together with the contextEngineID field, identifies the particular context linked to the management information in the PDU portion of the message ๐Ÿ’… The contextName is unique within the SNMP entity named by the contextEngineID, which may realize the managed objects the PDU references ๐Ÿฆ‹ The application that originates a message provides the contextName value, and the application on the receiving SNMP Engine may use that value during its processing ๐Ÿซถ

6.8.3. data ๐Ÿ“ฆ

The data field of the SNMPv3 Message contains the PDU ๐ŸŽ€ Among other things, the PDU carries the PDU type, which the v3MP uses to determine the type of the incoming SNMP message ๐Ÿ” The v3MP specifies that the PDU MUST be one of those specified in [RFC3416] ๐Ÿ‘‘


7. Elements of Procedure for v3MP ๐Ÿ“œ

This section describes the steps an SNMP engine follows when it generates and processes SNMP messages under the SNMPv3 Message Processing Model ๐Ÿ› ๏ธ

Quick heads up: to keep things clear and stop the text from getting even longer and messier, some details were left out of the steps below ๐Ÿ™ˆ

a) Some steps say that when certain error conditions come up while processing a received message, a message containing a Report PDU is generated and the received message is discarded without further processing ๐Ÿ—‘๏ธ However, a Report-PDU MUST NOT be generated unless the PDU that caused it can be determined to be a member of the Confirmed Class, or the reportableFlag is set to one and the PDU class can't be determined ๐Ÿšซ

b) The elements of procedure don't always explicitly say when state information needs to be released ๐Ÿง  The general rule is that if state information is available when a message is to be "discarded without further processing", the state information should also be released at that same time โœจ

7.1. Prepare an Outgoing SNMP Message โœจ

okay bestie, this section is the recipe for building an SNMPv3 message out of the ingredients the Message Dispatcher hands over ๐ŸŽ€

1) The Message Dispatcher can ask for an SNMPv3 message carrying a Read Class, Write Class, or Notification Class PDU to be prepared for sending ๐Ÿ’Œ

a) It asks using this abstract service primitive:

statusInformation =           -- success or errorIndication
  prepareOutgoingMessage(
  IN   transportDomain        -- requested transport domain
  IN   transportAddress       -- requested destination address
  IN   messageProcessingModel -- typically, SNMP version
  IN   securityModel          -- Security Model to use
  IN   securityName           -- on behalf of this principal
  IN   securityLevel          -- Level of Security requested
  IN   contextEngineID        -- data from/at this entity
  IN   contextName            -- data from/in this context
  IN   pduVersion             -- version of the PDU *
  IN   PDU                    -- SNMP Protocol Data Unit
  IN   expectResponse         -- TRUE or FALSE *
  IN   sendPduHandle          -- the handle for matching
                              -- incoming responses
  OUT  destTransportDomain    -- destination transport domain
  OUT  destTransportAddress   -- destination transport address
  OUT  outgoingMessage        -- the message to send
  OUT  outgoingMessageLength  -- the length of the message
  )

* The SNMPv3 Message Processing Model does not use the values of expectResponse or pduVersion. ๐Ÿ™ˆ

b) A unique msgID gets generated. The number used for msgID should not have been used recently, and it MUST NOT be the same as the one used for any outstanding request ๐Ÿ”ฅ

2) The Message Dispatcher can also ask for an SNMPv3 message carrying a Response Class or Internal Class PDU to be prepared for sending ๐Ÿฆ‹

a) It asks using this abstract service primitive:

result =                        -- SUCCESS or FAILURE
prepareResponseMessage(
  IN   messageProcessingModel   -- typically, SNMP version
  IN   securityModel            -- same as on incoming request
  IN   securityName             -- same as on incoming request
  IN   securityLevel            -- same as on incoming request
  IN   contextEngineID          -- data from/at this SNMP entity
  IN   contextName              -- data from/in this context
  IN   pduVersion               -- version of the PDU
  IN   PDU                      -- SNMP Protocol Data Unit
  IN   maxSizeResponseScopedPDU -- maximum size sender can
                                -- accept
  IN   stateReference           -- reference to state
                                -- information presented with
                                -- the request
  IN   statusInformation        -- success or errorIndication
                                -- error counter OID and value
                                -- when errorIndication
  OUT  destTransportDomain      -- destination transport domain
  OUT  destTransportAddress     -- destination transport address
  OUT  outgoingMessage          -- the message to send
  OUT  outgoingMessageLength    -- the length of the message
  )

b) The cached info for the original request gets pulled back out using the stateReference. That includes:

- msgID,
- contextEngineID,
- contextName,
- securityModel,
- securityName,
- securityLevel,
- securityStateReference,
- reportableFlag,
- transportDomain, and
- transportAddress.

The SNMPv3 Message Processing Model does not allow cached data to be overridden, except by error indications as detailed in (3) below. Hard rule, no cap, no exceptions except that one ๐Ÿซถ

3) If statusInformation contains values for an OID/value combination (it might also contain a securityLevel value, contextEngineID value, or contextName value), then:

a) If a PDU is provided, it is the PDU from the original request. If possible, extract the request-id and pduType ๐Ÿงš

b) If the pduType is determined to not be a member of the Confirmed Class, or if the reportableFlag is zero and the pduType cannot be determined, then the original message is discarded and no further processing happens. A result of FAILURE is returned, and SNMPv3 Message Processing is complete ๐Ÿ’€

c) A Report PDU gets prepared:

  1. the varBindList is set to contain the OID and value from the statusInformation.
  2. error-status is set to 0.
  3. error-index is set to 0.
  4. request-id is set to the value extracted in step b). Otherwise, request-id is set to 0.

d) The errorIndication in statusInformation may come with a securityLevel value, a contextEngineID value, or a contextName value.

  1. If statusInformation contains a value for securityLevel, then securityLevel is set to that value. Otherwise it is set to noAuthNoPriv.
  2. If statusInformation contains a value for contextEngineID, then contextEngineID is set to that value. Otherwise it is set to the value of this entity's snmpEngineID.
  3. If statusInformation contains a value for contextName, then contextName is set to that value. Otherwise it is set to the default context of "" (zero-length string).

e) PDU is set to refer to the new Report-PDU. The old PDU is discarded ๐Ÿ—‘๏ธ

f) Processing continues with step 6) below โœจ

4) If the contextEngineID is not yet determined, then it gets determined in an implementation-dependent manner, possibly using the transportDomain and transportAddress ๐ŸŒธ

5) If the contextName is not yet determined, it is set to the default context ๐Ÿ“

6) A scopedPDU is prepared from the contextEngineID, contextName, and PDU ๐Ÿ’œ

7) msgGlobalData is constructed as follows:

a) The msgVersion field is set to snmpv3(3).

b) msgID is set as determined in step 1 or 2 above.

c) msgMaxSize is set to an implementation-dependent value.

d) msgFlags are set as follows:

  • If securityLevel specifies noAuthNoPriv, then authFlag and privFlag are both set to zero.
  • If securityLevel specifies authNoPriv, then authFlag is set to one and privFlag is set to zero.
  • If securityLevel specifies authPriv, then authFlag is set to one and privFlag is set to one.
  • If the PDU is from the Unconfirmed Class, then the reportableFlag is set to zero.
  • If the PDU is from the Confirmed Class, then the reportableFlag is set to one.
  • All other msgFlags bits are set to zero.

e) msgSecurityModel is set to the value of securityModel ๐Ÿ”

8) If the PDU is from the Response Class or the Internal Class, then:

a) The specified Security Model is called to generate the message, using this primitive:

statusInformation =
  generateResponseMsg(
  IN   messageProcessingModel -- SNMPv3 Message Processing
                              -- Model
  IN   globalData             -- msgGlobalData from step 7
  IN   maxMessageSize         -- from msgMaxSize (step 7c)
  IN   securityModel          -- as determined in step 7e
  IN   securityEngineID       -- the value of snmpEngineID
  IN   securityName           -- on behalf of this principal
  IN   securityLevel          -- for the outgoing message
  IN   scopedPDU              -- as prepared in step 6)
  IN   securityStateReference -- as determined in step 2
  OUT  securityParameters     -- filled in by Security Module
  OUT  wholeMsg               -- complete generated message
  OUT  wholeMsgLength         -- length of generated message
  )

If, when the Security Model returns, the statusInformation includes an errorIndication, then any cached info about the outstanding request message is discarded, and an errorIndication is returned so it can go back to the calling application. SNMPv3 Message Processing is complete ๐Ÿ’…

b) A SUCCESS result is returned. SNMPv3 Message Processing is complete ๐ŸŽ€

9) If the PDU is from the Confirmed Class or the Notification Class, then:

a) If the PDU is from the Unconfirmed Class, then securityEngineID is set to the value of this entity's snmpEngineID.

Otherwise, the snmpEngineID of the target entity is determined in an implementation-dependent manner, possibly using transportDomain and transportAddress. The value of securityEngineID is then set to the value of the target entity's snmpEngineID ๐ŸŒˆ

b) The specified Security Model is called to generate the message, using this primitive:

statusInformation =
  generateRequestMsg(
  IN  messageProcessingModel -- SNMPv3 Message Processing Model
  IN  globalData             -- msgGlobalData, from step 7
  IN  maxMessageSize         -- from msgMaxSize in step 7 c)
  IN  securityModel          -- as provided by caller
  IN  securityEngineID       -- authoritative SNMP entity
                             -- from step 9 a)
  IN  securityName           -- as provided by caller
  IN  securityLevel          -- as provided by caller
  IN  scopedPDU              -- as prepared in step 6
  OUT securityParameters     -- filled in by Security Module
  OUT wholeMsg               -- complete generated message
  OUT wholeMsgLength         -- length of the generated message
  )

If, when the Security Model returns, the statusInformation includes an errorIndication, then the message is discarded and the errorIndication is returned so it can go back to the calling application. No further processing is done. SNMPv3 Message Processing is complete ๐Ÿ™…โ€โ™€๏ธ

c) If the PDU is from the Confirmed Class, information about the outgoing message gets cached, and an implementation-specific stateReference is created. The info to cache includes the values of:

  • sendPduHandle
  • msgID
  • snmpEngineID
  • securityModel
  • securityName
  • securityLevel
  • contextEngineID
  • contextName

d) A SUCCESS result is returned. SNMPv3 Message Processing is complete ๐Ÿ‘‘


7.2. Prepare Data Elements from an Incoming SNMP Message ๐Ÿฆ‹

okay so this part is the flip side, where we take an SNMPv3 message apart and pull out the data elements the Message Dispatcher needs for the next steps ๐Ÿ’– It's giving unpacking day โœจ

This section describes the procedure followed to extract data from an SNMPv3 message, and to prepare the data elements required for further processing of the message by the Message Dispatcher.

1) The message is passed in from the Message Dispatcher, using the abstract service primitive:

       result =                       -- SUCCESS or errorIndication
         prepareDataElements(
         IN  transportDomain          -- origin transport domain
         IN  transportAddress         -- origin transport address
         IN  wholeMsg                 -- as received from the network
         IN  wholeMsgLength           -- as received from the network
         OUT messageProcessingModel   -- typically, SNMP version
         OUT securityModel            -- Security Model to use
         OUT securityName             -- on behalf of this principal
         OUT securityLevel            -- Level of Security requested
         OUT contextEngineID          -- data from/at this entity
         OUT contextName              -- data from/in this context
         OUT pduVersion               -- version of the PDU
         OUT PDU                      -- SNMP Protocol Data Unit
         OUT pduType                  -- SNMP PDU type
         OUT sendPduHandle            -- handle for matched request
         OUT maxSizeResponseScopedPDU -- maximum size sender can accept
         OUT statusInformation        -- success or errorIndication
                                      -- error counter OID and value
                                      -- when errorIndication
         OUT stateReference           -- reference to state information
                                      -- to be used for a possible
         )                            -- Response
  1. Okay, bestie, if the received message isn't a proper serialization (following the rules in [RFC3417]) of an SNMPv3Message value, then the snmpInASNParseErrs counter [RFC3418] gets incremented ๐Ÿ“ˆ, the message gets discarded without any further processing ๐Ÿ—‘๏ธ, and a FAILURE result comes back. SNMPv3 Message Processing is complete. Done and dusted ๐Ÿ’….
  2. The values for msgVersion, msgID, msgMaxSize, msgFlags, msgSecurityModel, msgSecurityParameters, and msgData get pulled out of the message ๐ŸŽ€.
  3. If the msgSecurityModel component doesn't match a supported securityModel, then the snmpUnknownSecurityModels counter gets incremented, the message is discarded without further processing, and a FAILURE result is returned. SNMPv3 Message Processing is complete. Not the vibe ๐Ÿ™…โ€โ™€๏ธ.
  4. The securityLevel is figured out from the authFlag and the privFlag bits of the msgFlags component, like this ๐Ÿ”‘:

a) If the authFlag is not set and the privFlag is not set, then securityLevel is set to noAuthNoPriv.

b) If the authFlag is set and the privFlag is not set, then securityLevel is set to authNoPriv.

c) If the authFlag is set and the privFlag is set, then securityLevel is set to authPriv.

d) If the authFlag is not set and privFlag is set, then the snmpInvalidMsgs counter is incremented, the message is discarded without further processing, and a FAILURE result is returned. SNMPv3 Message Processing is complete. That combo is a no-go ๐Ÿšซ.

e) Any other bits in the msgFlags are ignored ๐Ÿคทโ€โ™€๏ธ.

  1. The security module that implements the Security Model named by the securityModel component gets called for authentication and privacy services ๐Ÿ›ก๏ธ. This happens through the abstract service primitive below:
       statusInformation =            -- errorIndication or success
                                      -- error counter OID and
                                      -- value if error
         processIncomingMsg(
         IN  messageProcessingModel   -- SNMPv3 Message Processing Model
         IN  maxMessageSize           -- of the sending SNMP entity
         IN  securityParameters       -- for the received message
         IN  securityModel            -- for the received message
         IN  securityLevel            -- Level of Security
         IN  wholeMsg                 -- as received on the wire
         IN  wholeMsgLength           -- length as received on the wire
         OUT securityEngineID         -- authoritative SNMP entity
         OUT securityName             -- identification of the principal
         OUT scopedPDU,               -- message (plaintext) payload
         OUT maxSizeResponseScopedPDU -- maximum size sender can accept
         OUT securityStateReference   -- reference to security state
         )                            -- information, needed for
                                      -- response

If the security module returns an errorIndication, then:

a) If statusInformation contains values for an OID/value pair, then generating a Report PDU is attempted (see step 3 in section 7.1) ๐Ÿ“จ.

  1. If the scopedPDU has come back from processIncomingMsg, then contextEngineID, contextName, and PDU get determined ๐Ÿ”.
  2. Info about the message gets cached and a stateReference gets created (this part is implementation-specific ๐Ÿงฉ). The stuff to cache includes the values of:
    • msgVersion,
    • msgID,
    • securityLevel,
    • msgFlags,
    • msgMaxSize,
    • securityModel,
    • maxSizeResponseScopedPDU,
    • securityStateReference
  3. A Report-PDU gets requested to be prepared and sent, following this abstract service primitive:
             result =                     -- SUCCESS or FAILURE
             returnResponsePdu(
             IN  messageProcessingModel   -- SNMPv3(3)
             IN  securityModel            -- same as on incoming request
             IN  securityName             -- from processIncomingMsg
             IN  securityLevel            -- same as on incoming request
             IN  contextEngineID          -- from step 6 a) 1)
             IN  contextName              -- from step 6 a) 1)
             IN  pduVersion               -- SNMPv2-PDU
             IN  PDU                      -- from step 6 a) 1)
             IN  maxSizeResponseScopedPDU -- from processIncomingMsg
             IN  stateReference           -- from step 6 a) 2)
             IN  statusInformation        -- from processIncomingMsg
             )

b) The incoming message gets discarded without further processing, and a FAILURE result is returned. SNMPv3 Message Processing is complete ๐Ÿซ .

  1. The scopedPDU gets parsed to pull out the contextEngineID, the contextName and the PDU ๐Ÿง. If any parse error happens, then the snmpInASNParseErrs counter [RFC3418] gets incremented, the security state information is discarded, the message is discarded without further processing, and a FAILURE result is returned. SNMPv3 Message Processing is complete. Treating an unknown PDU type as a parse error is an implementation option, so it's up to you, boo ๐Ÿค“.
  2. The pduVersion is determined in an implementation-dependent manner. For SNMPv3, the pduVersion would be an SNMPv2-PDU ๐Ÿ“ฆ.
  3. The pduType is determined, also in an implementation-dependent manner. For [RFC3416], the pduTypes include:
    • GetRequest-PDU,
    • GetNextRequest-PDU,
    • GetBulkRequest-PDU,
    • SetRequest-PDU,
    • InformRequest-PDU,
    • SNMPv2-Trap-PDU,
    • Response-PDU,
    • Report-PDU.
  4. If the pduType is from the Response Class or the Internal Class, then:

a) The value of the msgID component is used to find the cached info for a matching outstanding Request message ๐Ÿ”Ž. If no such outstanding Request message is found, then the security state information is discarded, the message is discarded without further processing, and a FAILURE result is returned. SNMPv3 Message Processing is complete. Ghosted ๐Ÿ‘ป.

b) sendPduHandle is retrieved from the cached info.

Otherwise, sendPduHandle is set to <none>, which is an implementation defined value.

  1. If the pduType is from the Internal Class, then:

a) statusInformation is created from the contents of the Report-PDU, in an implementation-dependent manner ๐Ÿง . This statusInformation gets forwarded to the application associated with the sendPduHandle.

b) The cached data for the outstanding message, referred to by stateReference, gets retrieved. If the securityModel or securityLevel values differ from the cached ones, it's important to know that Internal Class PDUs delivered at the security level of noAuthNoPriv open a window of opportunity for spoofing or replay attacks ๐Ÿšจ. If the receiver of such messages knows about these risks, then using these unauthenticated messages is acceptable, and they may provide a useful function for discovering engine IDs or for detecting misconfiguration at remote nodes ๐Ÿ”.

When the securityModel or securityLevel values differ from the cached ones, an implementation may keep the cached info about the outstanding Request message, just in case the Internal Class PDU that came in turns out to be illegitimate ๐Ÿง. Otherwise, any cached info about the outstanding Request message is discarded.

c) The security state information for this incoming message is discarded ๐Ÿงน.

d) stateReference is set to <none>.

e) A SUCCESS result is returned. SNMPv3 Message Processing is complete ๐ŸŽ‰.

  1. If the pduType is from the Response Class, then:

a) The cached data for the outstanding request, referred to by stateReference, gets retrieved, including:

  • snmpEngineID
  • securityModel
  • securityName
  • securityLevel
  • contextEngineID
  • contextName

b) If the values pulled from the incoming message differ from the cached data, then any cached info about the outstanding Request message is discarded, the incoming message is discarded without further processing, and a FAILURE result is returned. SNMPv3 Message Processing is complete ๐Ÿšซ.

When the securityModel or securityLevel values differ from the cached ones, an implementation may keep the cached info about the outstanding Request message, just in case the Response Class PDU that came in turns out to be illegitimate ๐Ÿ•ต๏ธโ€โ™€๏ธ.

c) Otherwise, any cached info about the outstanding Request message is discarded, and stateReference is set to <none> ๐Ÿซง.

d) A SUCCESS result is returned. SNMPv3 Message Processing is complete โœจ.

  1. If the pduType is from the Confirmed Class, then:

a) If the value of securityEngineID is not equal to the value of snmpEngineID, then the security state information is discarded, any cached info about this message is discarded, the incoming message is discarded without further processing, and a FAILURE result is returned. SNMPv3 Message Processing is complete. Wrong engine, wrong vibes ๐Ÿ™…โ€โ™€๏ธ.

b) Info about the message gets cached and a stateReference gets created (implementation-specific ๐Ÿงฉ). The stuff to cache includes the values of:

  • msgVersion,
  • msgID,
  • securityLevel,
  • msgFlags,
  • msgMaxSize,
  • securityModel,
  • maxSizeResponseScopedPDU,
  • securityStateReference

c) A SUCCESS result is returned. SNMPv3 Message Processing is complete ๐Ÿ’–.

  1. If the pduType is from the Unconfirmed Class, then a SUCCESS result gets returned. SNMPv3 Message Processing is complete. ๐ŸŽ‰โœจ

8. Intellectual Property โœจ

okay so the IETF doesn't take a side on whether any IP rights floating around could be claimed over the tech in this doc, or whether you'd be able to get a license for them. ๐Ÿ’… It also doesn't say it has checked for any such rights. If you want the IETF's rules on rights for standards-track and standards-related docs, those live in BCP-11. Any claims of rights that were filed for publication, any license assurances, or the results of someone trying to get a general license or permission for implementers or users are available from the IETF Secretariat. ๐Ÿงš

The IETF also invites anyone to tell it about any copyrights, patents, patent applications, or other proprietary rights that might cover tech you'd need to practice this standard. ๐Ÿฆ‹ Send that info to the IETF Executive Director. ๐Ÿ’œ

9. Acknowledgements ๐Ÿซถ

This document is the result of the efforts of the SNMPv3 Working Group. ๐ŸŒธ Some special thanks to these SNMPv3 WG members:

  • Harald Tveit Alvestrand (Maxware)
  • Dave Battle (SNMP Research, Inc.)
  • Alan Beard (Disney Worldwide Services)
  • Paul Berrevoets (SWI Systemware/Halcyon Inc.)
  • Martin Bjorklund (Ericsson)
  • Uri Blumenthal (IBM T. J. Watson Research Center)
  • Jeff Case (SNMP Research, Inc.)
  • John Curran (BBN)
  • Mike Daniele (Compaq Computer Corporation)
  • T. Max Devlin (Eltrax Systems)
  • John Flick (Hewlett Packard)
  • Rob Frye (MCI)
  • Wes Hardaker (U.C.Davis, Information Technology - D.C.A.S.)
  • David Harrington (Cabletron Systems Inc.)
  • Lauren Heintz (BMC Software, Inc.)
  • N.C. Hien (IBM T. J. Watson Research Center)
  • Michael Kirkham (InterWorking Labs, Inc.)
  • Dave Levi (SNMP Research, Inc.)
  • Louis A Mamakos (UUNET Technologies Inc.)
  • Joe Marzot (Nortel Networks)
  • Paul Meyer (Secure Computing Corporation)
  • Keith McCloghrie (Cisco Systems)
  • Bob Moore (IBM)
  • Russ Mundy (TIS Labs at Network Associates)
  • Bob Natale (ACE*COMM Corporation)
  • Mike O'Dell (UUNET Technologies Inc.)
  • Dave Perkins (DeskTalk)
  • Peter Polkinghorne (Brunel University)
  • Randy Presuhn (BMC Software, Inc.)
  • David Reeder (TIS Labs at Network Associates)
  • David Reid (SNMP Research, Inc.)
  • Aleksey Romanov (Quality Quorum)
  • Shawn Routhier (Epilogue)
  • Juergen Schoenwaelder (TU Braunschweig)
  • Bob Stewart (Cisco Systems)
  • Mike Thatcher (Independent Consultant)
  • Bert Wijnen (IBM T. J. Watson Research Center)

The document is based on recommendations from the IETF Security and Administrative Framework Evolution for SNMP Advisory Team. ๐Ÿ”ฅ The members of that Advisory Team were:

  • David Harrington (Cabletron Systems Inc.)
  • Jeff Johnson (Cisco Systems)
  • David Levi (SNMP Research Inc.)
  • John Linn (Openvision)
  • Russ Mundy (Trusted Information Systems) chair
  • Shawn Routhier (Epilogue)
  • Glenn Waters (Nortel)
  • Bert Wijnen (IBM T. J. Watson Research Center)

As the Advisory Team and the SNMPv3 Working Group Charter recommended, the design pulls in as much as is practical from previous RFCs and drafts. ๐Ÿ‘‘ So special thanks go to the authors of the earlier designs known as SNMPv2u and SNMPv2*:

  • Jeff Case (SNMP Research, Inc.)
  • David Harrington (Cabletron Systems Inc.)
  • David Levi (SNMP Research, Inc.)
  • Keith McCloghrie (Cisco Systems)
  • Brian O'Keefe (Hewlett Packard)
  • Marshall T. Rose (Dover Beach Consulting)
  • Jon Saperia (BGS Systems Inc.)
  • Steve Waldbusser (International Network Services)
  • Glenn W. Waters (Bell-Northern Research Ltd.)

10. Security Considerations ๐Ÿ”

okay this part is serious bestie, so pay attention ๐Ÿ™ˆ The Dispatcher coordinates how messages get processed. It gives management messages a level of security and sends the SNMP PDUs to the right SNMP application(s). ๐Ÿ’–

A Message Processing Model, and especially the v3MP defined in this document, plays with Security Models in the Security Subsystem during Message Processing. It does this through the abstract service interface primitives defined in [RFC3411] and explained above. ๐Ÿฆ‹

How much security you actually get mostly depends on which Security Model implementation(s) and which SNMP application implementation(s) are plugged into this framework. ๐ŸŒˆ Applications can reach data that isn't secured. So applications should take reasonable steps to protect that data from getting disclosed. And when they send data over the network, they should obey the securityLevel and call on an Access Control Model for access control. ๐Ÿ’…

The values for the msgID element used between SNMP entities MUST be chosen to avoid replay attacks. โš ๏ธ They don't need to be unpredictable, it's enough that they never repeat.

Now, when exchanges happen over an insecure network, a third party has an open chance to spoof or replay messages if any message in the exchange is at the security level of noAuthNoPriv. ๐Ÿ˜ญ For most exchanges, every message is at the same security level. But if the final message is an Internal Class PDU, that one can be delivered at noAuthNoPriv or authNoPriv, no matter what level the earlier messages used. Internal Class PDUs delivered at authNoPriv are not considered a security hazard. โœจ Internal Class PDUs delivered at noAuthNoPriv do open a window for spoofing or replay attacks. If the receiver knows about these risks, using unauthenticated messages like that is acceptable and may be a useful way to discover engine IDs or spot misconfiguration at remote nodes. ๐Ÿงš

This document also has a MIB definition module. None of the objects defined are writable, and the info they represent isn't considered especially sensitive. ๐Ÿ“ Still, if they are considered sensitive in a particular environment, you should restrict access to them using appropriately configured Security and Access Control models. ๐Ÿ”’

11. References ๐Ÿ“š

11.1. Normative References

  • [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.
  • [RFC2578] McCloghrie, K., Perkins, D., Schoenwaelder, J., Case, J., Rose, M. and S. Waldbusser, "Structure of Management Information Version 2 (SMIv2)", STD 58, RFC 2578, April 1999.
  • [RFC2580] McCloghrie, K., Perkins, D., Schoenwaelder, J., Case, J., Rose, M. and S. Waldbusser, "Conformance Statements for SMIv2", STD 58, RFC 2580, April 1999.
  • [RFC3411] Harrington, D., Presuhn, R. and B. Wijnen, "An Architecture for Describing Simple Network Management Protocol (SNMP) Management Frameworks", STD 62, RFC 3411, December 2002.
  • [RFC3413] Levi, D., Meyer, P. and B. Stewart, "Simple Network Management Protocol (SNMP) Applications", STD 62, RFC 3413, December 2002.
  • [RFC3414] Blumenthal, U. and B. Wijnen, "The User-Based Security Model (USM) for Version 3 of the Simple Network Management Protocol (SNMPv3)", STD 62, RFC 3414, December 2002.
  • [RFC3415] Wijnen, B., Presuhn, R. and K. McCloghrie, "View-based Access Control Model (VACM) for the Simple Network Management Protocol (SNMP)", STD 62, RFC 3415, December 2002.
  • [RFC3416] Presuhn, R., Case, J., McCloghrie, K., Rose, M. and S. Waldbusser, "Version 2 of the Protocol Operations for the Simple Network Management Protocol (SNMP)", STD 62, RFC 3416, December 2002.
  • [RFC3417] Presuhn, R., Case, J., McCloghrie, K., Rose, M. and S. Waldbusser, "Transport Mappings for the Simple Network Management Protocol (SNMP)", STD 62, RFC 3417, December 2002.
  • [RFC3418] Presuhn, R., Case, J., McCloghrie, K., Rose, M. and S. Waldbusser, "Management Information Base (MIB) for the Simple Network Management Protocol (SNMP)", STD 62, RFC 3418, December 2002.

11.2. Informative References

  • [RFC1901] Case, J., McCloghrie, K., Rose, M. and S. Waldbusser, "Introduction to Community-based SNMPv2", RFC 1901, January 1996.
  • [RFC2028] Hovey, R. and S. Bradner, "The Organizations Involved in the IETF Standards Process", BCP 11, RFC 2028, October 1996.
  • [RFC2576] Frye, R., Levi, D., Routhier, S. and B. Wijnen, "Coexistence between Version 1, Version 2, and Version 3 of the Internet-Standard Network Management Framework", RFC 2576, March 2000.
  • [RFC3410] Case, J., Mundy, R., Partain, D. and B. Stewart, "Introduction and Applicability Statements for Internet-Standard Management Framework", RFC 3410, December 2002.

12. Editors' Addresses ๐Ÿ“ฎ

Jeffrey Case
SNMP Research, Inc.
3001 Kimberlin Heights Road
Knoxville, TN 37920-9716
USA

Phone: +1 423-573-1434
EMail: case@snmp.com


David Harrington
Enterasys Networks
35 Industrial Way
Post Office Box 5005
Rochester, NH 03866-5005
USA

Phone: +1 603-337-2614
EMail: dbh@enterasys.com


Randy Presuhn
BMC Software, Inc.
2141 North First Street
San Jose, CA 95131
USA

Phone: +1 408-546-1006
EMail: randy_presuhn@bmc.com


Bert Wijnen
Lucent Technologies
Schagen 33
3461 GL Linschoten
Netherlands

Phone: +31 348-680-485
EMail: bwijnen@lucent.com

Copyright (C) The Internet Society (2002). All Rights Reserved. ๐ŸŒˆ

Okay so this document and translations of it can be copied and handed out to others. Derivative works that comment on or explain it, or help with implementing it, can be made, copied, published, and distributed, in whole or in part, with no restrictions of any kind. That's only if the above copyright notice and this paragraph are included on all those copies and derivative works. ๐Ÿ’œ However, this document itself may not be modified in any way, like removing the copyright notice or the references to the Internet Society or other Internet organizations. The exceptions are when it's needed for developing Internet standards, in which case the Internet Standards process copyright procedures must be followed, or when it's needed to translate it into languages other than English. ๐Ÿฆ‹

The limited permissions above are perpetual and won't be revoked by the Internet Society or its successors or assigns. โœจ

This document and the information in it are provided on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. ๐Ÿ™ˆ

Acknowledgement โœจ

okay bestie, the RFC Editor function is the crew that keeps all these documents organised and published ๐Ÿงš and right now, its funding is coming from the Internet Society ๐Ÿ’– so big shoutout to them fr fr ๐Ÿซถ

๐Ÿ“ฆ where this page comes from