snmp_agent_trap.c
Go to the documentation of this file.
1 /**
2  * @file snmp_agent_trap.c
3  * @brief SNMP trap notifications
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL SNMP_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "snmp/snmp_agent.h"
37 #include "snmp/snmp_agent_misc.h"
38 #include "snmp/snmp_agent_trap.h"
39 #include "mibs/mib2_module.h"
40 #include "debug.h"
41 
42 //Check TCP/IP stack configuration
43 #if (SNMP_AGENT_SUPPORT == ENABLED && SNMP_AGENT_TRAP_SUPPORT == ENABLED)
44 
45 
46 /**
47  * @brief Format SNMP Trap message
48  * @param[in] context Pointer to the SNMP agent context
49  * @param[in] version SNMP version identifier
50  * @param[in] userName User name or community name
51  * @param[in] genericTrapType Generic trap type
52  * @param[in] specificTrapCode Specific code
53  * @param[in] objectList List of object names
54  * @param[in] objectListSize Number of entries in the list
55  * @return Error code
56  **/
57 
59  const char_t *userName, uint_t genericTrapType, uint_t specificTrapCode,
60  const SnmpTrapObject *objectList, uint_t objectListSize)
61 {
62  error_t error;
63 
64 #if (SNMP_V1_SUPPORT == ENABLED)
65  //SNMPv1 version?
66  if(version == SNMP_VERSION_1)
67  {
68  //Format Trap-PDU
69  error = snmpFormatTrapPdu(context, version, userName,
70  genericTrapType, specificTrapCode, objectList, objectListSize);
71  //Any error to report?
72  if(error)
73  return error;
74 
75  //Format SMNP message header
76  error = snmpWriteMessageHeader(&context->response);
77  //Any error to report?
78  if(error)
79  return error;
80  }
81  else
82 #endif
83 #if (SNMP_V2C_SUPPORT == ENABLED)
84  //SNMPv2c version?
86  {
87  //Format SNMPv2-Trap-PDU
88  error = snmpFormatTrapPdu(context, version, userName,
89  genericTrapType, specificTrapCode, objectList, objectListSize);
90  //Any error to report?
91  if(error)
92  return error;
93 
94  //Format SMNP message header
95  error = snmpWriteMessageHeader(&context->response);
96  //Any error to report?
97  if(error)
98  return error;
99  }
100  else
101 #endif
102 #if (SNMP_V3_SUPPORT == ENABLED)
103  //SNMPv3 version?
104  if(version == SNMP_VERSION_3)
105  {
106  SnmpUserEntry *user;
107 
108  //Information about the user name is extracted from the local
109  //configuration datastore
110  user = snmpFindUserEntry(context, userName, osStrlen(userName));
111 
112  //Invalid user name?
113  if(user == NULL || user->status != MIB_ROW_STATUS_ACTIVE)
115 
116  //Save the security profile associated with the current user
117  context->user = *user;
118 
119  //Format SNMPv2-Trap-PDU
120  error = snmpFormatTrapPdu(context, version, userName,
121  genericTrapType, specificTrapCode, objectList, objectListSize);
122  //Any error to report?
123  if(error)
124  return error;
125 
126  //Format scopedPDU
127  error = snmpWriteScopedPdu(&context->response);
128  //Any error to report?
129  if(error)
130  return error;
131 
132  //Check whether the privFlag is set
133  if((context->response.msgFlags & SNMP_MSG_FLAG_PRIV) != 0)
134  {
135  //Encrypt data
136  error = snmpEncryptData(&context->user, &context->response,
137  &context->salt);
138  //Any error to report?
139  if(error)
140  return error;
141  }
142 
143  //Format SMNP message header
144  error = snmpWriteMessageHeader(&context->response);
145  //Any error to report?
146  if(error)
147  return error;
148 
149  //Check whether the authFlag is set
150  if((context->response.msgFlags & SNMP_MSG_FLAG_AUTH) != 0)
151  {
152  //Authenticate outgoing SNMP message
153  error = snmpAuthOutgoingMessage(&context->user, &context->response);
154  //Any error to report?
155  if(error)
156  return error;
157  }
158  }
159  else
160 #endif
161  //Invalid SNMP version?
162  {
163  //Debug message
164  TRACE_WARNING(" Invalid SNMP version!\r\n");
165  //Report an error
166  return ERROR_INVALID_VERSION;
167  }
168 
169  //Successful processing
170  return NO_ERROR;
171 }
172 
173 
174 /**
175  * @brief Format Trap-PDU or SNMPv2-Trap-PDU
176  * @param[in] context Pointer to the SNMP agent context
177  * @param[in] version SNMP version identifier
178  * @param[in] userName User name or community name
179  * @param[in] genericTrapType Generic trap type
180  * @param[in] specificTrapCode Specific code
181  * @param[in] objectList List of object names
182  * @param[in] objectListSize Number of entries in the list
183  * @return Error code
184  **/
185 
187  const char_t *userName, uint_t genericTrapType, uint_t specificTrapCode,
188  const SnmpTrapObject *objectList, uint_t objectListSize)
189 {
190  error_t error;
192 
193  //Point to the SNMP message
194  message = &context->response;
195  //Initialize SNMP message
197 
198  //SNMP version identifier
199  message->version = version;
200 
201 #if (SNMP_V1_SUPPORT == ENABLED)
202  //SNMPv1 version?
203  if(version == SNMP_VERSION_1)
204  {
205 #if (IPV4_SUPPORT == ENABLED)
206  NetInterface *interface;
207 
208  //Point to the underlying network interface
209  interface = context->settings.interface;
210 #endif
211 
212  //Community name
213  message->community = userName;
214  message->communityLen = osStrlen(userName);
215 
216  //Prepare to send a Trap-PDU
217  message->pduType = SNMP_PDU_TRAP;
218  //Type of object generating trap
219  message->enterpriseOid = context->enterpriseOid;
220  message->enterpriseOidLen = context->enterpriseOidLen;
221 
222 #if (IPV4_SUPPORT == ENABLED)
223  //Address of object generating trap
224  if(interface != NULL)
225  message->agentAddr = interface->ipv4Context.addrList[0].addr;
226 #endif
227 
228  //Generic trap type
229  message->genericTrapType = genericTrapType;
230  //Specific trap code
231  message->specificTrapCode = specificTrapCode;
232  //Timestamp
233  message->timestamp = osGetSystemTime64() / 10;
234  }
235  else
236 #endif
237 #if (SNMP_V2C_SUPPORT == ENABLED)
238  //SNMPv2c version?
239  if(version == SNMP_VERSION_2C)
240  {
241  //Community name
242  message->community = userName;
243  message->communityLen = osStrlen(userName);
244 
245  //Prepare to send a SNMPv2-Trap-PDU
246  message->pduType = SNMP_PDU_TRAP_V2;
247  }
248  else
249 #endif
250 #if (SNMP_V3_SUPPORT == ENABLED)
251  //SNMPv3 version?
252  if(version == SNMP_VERSION_3)
253  {
254  //Increment message identifier
255  message->msgId = context->msgId++;
256  //Wrap around if necessary
257  if(context->msgId < 0)
258  context->msgId = 0;
259 
260  //Maximum message size supported by the sender
261  message->msgMaxSize = SNMP_MAX_MSG_SIZE;
262 
263  //Bit fields which control processing of the message
264  if(context->user.authProtocol != SNMP_AUTH_PROTOCOL_NONE)
265  message->msgFlags |= SNMP_MSG_FLAG_AUTH;
266  if(context->user.privProtocol != SNMP_PRIV_PROTOCOL_NONE)
267  message->msgFlags |= SNMP_MSG_FLAG_PRIV;
268 
269  //Security model used by the sender
270  message->msgSecurityModel = SNMP_SECURITY_MODEL_USM;
271 
272  //Authoritative engine identifier
273  message->msgAuthEngineId = context->contextEngine;
274  message->msgAuthEngineIdLen = context->contextEngineLen;
275  //Number of times the SNMP engine has rebooted
276  message->msgAuthEngineBoots = context->engineBoots;
277  //Number of seconds since last reboot
278  message->msgAuthEngineTime = context->engineTime;
279  //User name
280  message->msgUserName = userName;
281  message->msgUserNameLen = osStrlen(userName);
282  //Authentication parameters
283  message->msgAuthParameters = NULL;
284  //Length of the authentication parameters
285  message->msgAuthParametersLen = snmpGetMacLength(context->user.authProtocol);
286  //Privacy parameters
287  message->msgPrivParameters = context->privParameters;
288 
289  //Length of the privacy parameters
290  if(context->user.privProtocol == SNMP_PRIV_PROTOCOL_DES)
291  {
292  message->msgPrivParametersLen = 8;
293  }
294  else if(context->user.privProtocol == SNMP_PRIV_PROTOCOL_AES)
295  {
296  message->msgPrivParametersLen = 8;
297  }
298  else
299  {
300  message->msgPrivParametersLen = 0;
301  }
302 
303  //Context engine identifier
304  message->contextEngineId = context->contextEngine;
305  message->contextEngineIdLen = context->contextEngineLen;
306  //Context name
307  message->contextName = context->contextName;
308  message->contextNameLen = osStrlen(context->contextName);
309 
310  //Prepare to send a SNMPv2-Trap-PDU
311  message->pduType = SNMP_PDU_TRAP_V2;
312  }
313  else
314 #endif
315  //Invalid SNMP version?
316  {
317  //Report an error
318  return ERROR_INVALID_VERSION;
319  }
320 
321  //Increment request identifier
322  message->requestId = context->requestId++;
323  //Wrap around if necessary
324  if(context->requestId < 0)
325  context->requestId = 0;
326 
327  //Make room for the message header at the beginning of the buffer
328  error = snmpComputeMessageOverhead(&context->response);
329  //Any error to report?
330  if(error)
331  return error;
332 
333  //Format the list of variable bindings
334  error = snmpWriteTrapVarBindingList(context, genericTrapType,
335  specificTrapCode, objectList, objectListSize);
336  //Any error to report?
337  if(error)
338  return error;
339 
340  //Total number of SNMP Trap PDUs which have been generated by
341  //the SNMP protocol entity
342  MIB2_SNMP_INC_COUNTER32(snmpOutTraps, 1);
343 
344  //Format PDU header
345  error = snmpWritePduHeader(&context->response);
346  //Return status code
347  return error;
348 }
349 
350 #endif
error_t snmpEncryptData(const SnmpUserEntry *user, SnmpMessage *message, uint64_t *salt)
Data encryption.
error_t snmpFormatTrapPdu(SnmpAgentContext *context, SnmpVersion version, const char_t *userName, uint_t genericTrapType, uint_t specificTrapCode, const SnmpTrapObject *objectList, uint_t objectListSize)
Format Trap-PDU or SNMPv2-Trap-PDU.
MIB-II module.
@ SNMP_PDU_TRAP
Definition: snmp_common.h:154
@ ERROR_UNKNOWN_USER_NAME
Definition: error.h:262
@ SNMP_PDU_TRAP_V2
Definition: snmp_common.h:157
uint8_t message[]
Definition: chap.h:154
error_t snmpWriteScopedPdu(SnmpMessage *message)
Format scopedPDU.
Object descriptor for trap notifications.
@ SNMP_SECURITY_MODEL_USM
User-based security model.
#define osStrlen(s)
Definition: os_port.h:165
SNMP trap notifications.
uint8_t version
Definition: coap_common.h:177
User table entry.
@ SNMP_VERSION_2C
Definition: snmp_common.h:139
@ ERROR_INVALID_VERSION
Definition: error.h:118
SNMP agent (Simple Network Management Protocol)
SnmpVersion
SNMP version identifiers.
Definition: snmp_common.h:137
@ SNMP_MSG_FLAG_PRIV
@ SNMP_PRIV_PROTOCOL_NONE
No privacy.
error_t
Error codes.
Definition: error.h:43
#define MIB2_SNMP_INC_COUNTER32(name, value)
Definition: mib2_module.h:192
SnmpUserEntry * snmpFindUserEntry(SnmpAgentContext *context, const char_t *name, size_t length)
Search the user table for a given user name.
#define NetInterface
Definition: net.h:36
Helper functions for SNMP agent.
@ SNMP_MSG_FLAG_AUTH
MibRowStatus status
Status of the user.
@ SNMP_VERSION_3
Definition: snmp_common.h:140
size_t snmpGetMacLength(SnmpAuthProtocol authProtocol)
Get the length of the truncated MAC for a given authentication protocol.
#define TRACE_WARNING(...)
Definition: debug.h:85
char char_t
Definition: compiler_port.h:48
@ MIB_ROW_STATUS_ACTIVE
Definition: mib_common.h:103
#define SNMP_MAX_MSG_SIZE
Definition: snmp_common.h:60
error_t snmpWritePduHeader(SnmpMessage *message)
Format PDU header.
error_t snmpFormatTrapMessage(SnmpAgentContext *context, SnmpVersion version, const char_t *userName, uint_t genericTrapType, uint_t specificTrapCode, const SnmpTrapObject *objectList, uint_t objectListSize)
Format SNMP Trap message.
#define osGetSystemTime64()
SNMP message.
@ SNMP_VERSION_1
Definition: snmp_common.h:138
#define SnmpAgentContext
Definition: snmp_agent.h:36
error_t snmpComputeMessageOverhead(SnmpMessage *message)
Compute SNMP message overhead.
error_t snmpAuthOutgoingMessage(const SnmpUserEntry *user, SnmpMessage *message)
Authenticate outgoing SNMP message.
@ SNMP_PRIV_PROTOCOL_AES
AES-128-CFB.
unsigned int uint_t
Definition: compiler_port.h:50
TCP/IP stack core.
@ SNMP_AUTH_PROTOCOL_NONE
No authentication.
@ SNMP_PRIV_PROTOCOL_DES
DES-CBC.
error_t snmpWriteTrapVarBindingList(SnmpAgentContext *context, uint_t genericTrapType, uint_t specificTrapCode, const SnmpTrapObject *objectList, uint_t objectListSize)
Format the variable binding list for Trap-PDU or SNMPv2-Trap-PDU.
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
void snmpInitMessage(SnmpMessage *message)
Initialize a SNMP message.
error_t snmpWriteMessageHeader(SnmpMessage *message)
Format SNMP message header.