"Fossies" - the Fresh Open Source Software Archive 
Member "netxms-3.8.166/src/server/core/snmptrap.cpp" (23 Feb 2021, 42330 Bytes) of package /linux/misc/netxms-3.8.166.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "snmptrap.cpp" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
3.7.95_vs_3.7.116.
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2020 Raden Solutions
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: snmptrap.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24
25 #define DEBUG_TAG _T("snmp.trap")
26
27 #define BY_OBJECT_ID 0
28 #define BY_POSITION 1
29
30 /**
31 * Total number of received SNMP traps
32 */
33 VolatileCounter64 g_snmpTrapsReceived = 0;
34
35 /**
36 * Max SNMP packet length
37 */
38 #define MAX_PACKET_LENGTH 65536
39
40 /**
41 * Static data
42 */
43 static Mutex s_trapCfgLock;
44 static ObjectArray<SNMPTrapConfiguration> m_trapCfgList(16, 4, Ownership::True);
45 static VolatileCounter64 s_trapId = 0; // Last used trap ID
46 static uint16_t s_trapListenerPort = 162;
47
48 /**
49 * Create new SNMP trap configuration object
50 */
51 SNMPTrapConfiguration::SNMPTrapConfiguration() : m_objectId(), m_mappings(8, 8, Ownership::True)
52 {
53 m_guid = uuid::generate();
54 m_id = CreateUniqueId(IDG_SNMP_TRAP);
55 m_eventCode = EVENT_SNMP_UNMATCHED_TRAP;
56 m_eventTag = nullptr;
57 m_description = nullptr;
58 m_scriptSource = nullptr;
59 m_script = nullptr;
60 }
61
62 /**
63 * Create SNMP trap configuration object from database
64 */
65 SNMPTrapConfiguration::SNMPTrapConfiguration(DB_RESULT trapResult, DB_HANDLE hdb, DB_STATEMENT stmt, int row) : m_mappings(8, 8, Ownership::True)
66 {
67 m_id = DBGetFieldULong(trapResult, row, 0);
68 TCHAR buffer[MAX_OID_LENGTH];
69 m_objectId = SNMP_ObjectId::parse(DBGetField(trapResult, row, 1, buffer, MAX_OID_LENGTH));
70 m_eventCode = DBGetFieldULong(trapResult, row, 2);
71 m_description = DBGetField(trapResult, row, 3, nullptr, 0);
72 m_eventTag = DBGetField(trapResult, row, 4, nullptr, 0);
73 m_guid = DBGetFieldGUID(trapResult, row, 5);
74 m_scriptSource = DBGetField(trapResult, row, 6, nullptr, 0);
75 m_script = nullptr;
76
77 DB_RESULT mapResult;
78 if (stmt != nullptr)
79 {
80 DBBind(stmt, 1, DB_SQLTYPE_INTEGER, m_id);
81 mapResult = DBSelectPrepared(stmt);
82 }
83 else
84 {
85 TCHAR query[256];
86 _sntprintf(query, 256, _T("SELECT snmp_oid,description,flags FROM snmp_trap_pmap WHERE trap_id=%u ORDER BY parameter"), m_id);
87 mapResult = DBSelect(hdb, query);
88 }
89 if (mapResult != nullptr)
90 {
91 int mapCount = DBGetNumRows(mapResult);
92 for(int i = 0; i < mapCount; i++)
93 {
94 SNMPTrapParameterMapping *param = new SNMPTrapParameterMapping(mapResult, i);
95 if (!param->isPositional() && !param->getOid()->isValid())
96 nxlog_write(NXLOG_WARNING, _T("Invalid trap parameter OID %s for trap %u in trap configuration table"), (const TCHAR *)param->getOid()->toString(), m_id);
97 m_mappings.add(param);
98 }
99 DBFreeResult(mapResult);
100 }
101
102 compileScript();
103 }
104
105 /**
106 * Create SNMP trap configuration object from config entry
107 */
108 SNMPTrapConfiguration::SNMPTrapConfiguration(const ConfigEntry& entry, const uuid& guid, uint32_t id, uint32_t eventCode) : m_mappings(8, 8, Ownership::True)
109 {
110 if (id == 0)
111 m_id = CreateUniqueId(IDG_SNMP_TRAP);
112 else
113 m_id = id;
114
115 m_guid = guid;
116 m_objectId = SNMP_ObjectId::parse(entry.getSubEntryValue(_T("oid"), 0, _T("")));
117 m_eventCode = eventCode;
118 m_description = MemCopyString(entry.getSubEntryValue(_T("description")));
119 m_eventTag = MemCopyString(entry.getSubEntryValue(_T("eventTag"), 0, entry.getSubEntryValue(_T("userTag"))));
120 m_scriptSource = MemCopyString(entry.getSubEntryValue(_T("transformationScript")));
121 m_script = nullptr;
122
123 const ConfigEntry *parametersRoot = entry.findEntry(_T("parameters"));
124 if (parametersRoot != nullptr)
125 {
126 ObjectArray<ConfigEntry> *parameters = parametersRoot->getOrderedSubEntries(_T("parameter#*"));
127 if (parameters->size() > 0)
128 {
129 for(int i = 0; i < parameters->size(); i++)
130 {
131 SNMPTrapParameterMapping *param = new SNMPTrapParameterMapping(parameters->get(i));
132 if (!param->isPositional() && !param->getOid()->isValid())
133 nxlog_write(NXLOG_WARNING, _T("Invalid trap parameter OID %s for trap %u in trap configuration table"), param->getOid()->toString().cstr(), m_id);
134 m_mappings.add(param);
135 }
136 }
137 delete parameters;
138 }
139
140 compileScript();
141 }
142
143 /**
144 * Create SNMP trap configuration object from NXCPMessage
145 */
146 SNMPTrapConfiguration::SNMPTrapConfiguration(NXCPMessage *msg) : m_mappings(8, 8, Ownership::True)
147 {
148 UINT32 buffer[MAX_OID_LENGTH];
149
150 m_id = msg->getFieldAsUInt32(VID_TRAP_ID);
151 msg->getFieldAsInt32Array(VID_TRAP_OID, msg->getFieldAsUInt32(VID_TRAP_OID_LEN), buffer);
152 m_objectId = SNMP_ObjectId(buffer, msg->getFieldAsUInt32(VID_TRAP_OID_LEN));
153 m_eventCode = msg->getFieldAsUInt32(VID_EVENT_CODE);
154 m_description = msg->getFieldAsString(VID_DESCRIPTION);
155 m_eventTag = msg->getFieldAsString(VID_USER_TAG);
156 m_scriptSource = msg->getFieldAsString(VID_TRANSFORMATION_SCRIPT);
157 m_script = nullptr;
158
159 // Read new mappings from message
160 int count = msg->getFieldAsInt32(VID_TRAP_NUM_MAPS);
161 UINT32 base = VID_TRAP_PBASE;
162 for(int i = 0; i < count; i++, base += 10)
163 {
164 m_mappings.add(new SNMPTrapParameterMapping(msg, base));
165 }
166
167 compileScript();
168 }
169
170 /**
171 * Destructor for SNMP trap configuration object
172 */
173 SNMPTrapConfiguration::~SNMPTrapConfiguration()
174 {
175 MemFree(m_description);
176 MemFree(m_eventTag);
177 MemFree(m_scriptSource);
178 delete m_script;
179 }
180
181 /**
182 * Compile transformation script
183 */
184 void SNMPTrapConfiguration::compileScript()
185 {
186 delete m_script;
187 if ((m_scriptSource != nullptr) && (*m_scriptSource != 0))
188 {
189 TCHAR errorMessage[1024];
190 m_script = NXSLCompile(m_scriptSource, errorMessage, 1024, nullptr);
191 if (m_script == nullptr)
192 {
193 TCHAR buffer[1024];
194 _sntprintf(buffer, 1024, _T("SNMPTrap::%d"), m_id);
195 PostSystemEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, "ssd", buffer, errorMessage, m_id);
196 nxlog_write_tag(NXLOG_WARNING, DEBUG_TAG, _T("Failed to compile SNMP trap transformation script for trap mapping [%u] (%s)"), m_id, errorMessage);
197 }
198 }
199 else
200 {
201 m_script = nullptr;
202 }
203 }
204
205 /**
206 * Fill NXCP message with trap configuration data
207 */
208 void SNMPTrapConfiguration::fillMessage(NXCPMessage *msg) const
209 {
210 msg->setField(VID_TRAP_ID, m_id);
211 msg->setField(VID_TRAP_OID_LEN, (UINT32)m_objectId.length());
212 msg->setFieldFromInt32Array(VID_TRAP_OID, m_objectId.length(), m_objectId.value());
213 msg->setField(VID_EVENT_CODE, m_eventCode);
214 msg->setField(VID_DESCRIPTION, CHECK_NULL_EX(m_description));
215 msg->setField(VID_USER_TAG, CHECK_NULL_EX(m_eventTag));
216 msg->setField(VID_TRANSFORMATION_SCRIPT, CHECK_NULL_EX(m_scriptSource));
217
218 msg->setField(VID_TRAP_NUM_MAPS, (UINT32)m_mappings.size());
219 UINT32 base = VID_TRAP_PBASE;
220 for(int i = 0; i < m_mappings.size(); i++, base += 10)
221 {
222 m_mappings.get(i)->fillMessage(msg, base);
223 }
224 }
225
226 /**
227 * Fill NXCP message with trap configuration for list
228 */
229 void SNMPTrapConfiguration::fillMessage(NXCPMessage *msg, UINT32 base) const
230 {
231 msg->setField(base, m_id);
232 msg->setField(base + 1, CHECK_NULL_EX(m_description));
233 msg->setFieldFromInt32Array(base + 2, m_objectId.length(), m_objectId.value());
234 msg->setField(base + 3, m_eventCode);
235 }
236
237 /**
238 * Notify clients about trap configuration change
239 */
240 void NotifyOnTrapCfgChangeCB(ClientSession *session, NXCPMessage *msg)
241 {
242 if (session->isAuthenticated())
243 session->postMessage(msg);
244 }
245
246 /**
247 * Notify clients of trap cfg change
248 */
249 void SNMPTrapConfiguration::notifyOnTrapCfgChange(UINT32 code)
250 {
251 NXCPMessage msg;
252 msg.setCode(CMD_TRAP_CFG_UPDATE);
253 msg.setField(VID_NOTIFICATION_CODE, code);
254 fillMessage(&msg);
255 EnumerateClientSessions(NotifyOnTrapCfgChangeCB, &msg);
256 }
257
258 /**
259 * SNMP trap parameter map default constructor
260 */
261 SNMPTrapParameterMapping::SNMPTrapParameterMapping()
262 {
263 m_objectId = new SNMP_ObjectId();
264 m_position = 0;
265 m_flags = 0;
266 m_description = nullptr;
267 }
268
269 /**
270 * Create SNMP trap parameter map object from database
271 */
272 SNMPTrapParameterMapping::SNMPTrapParameterMapping(DB_RESULT mapResult, int row)
273 {
274 TCHAR oid[MAX_DB_STRING];
275 DBGetField(mapResult, row, 0, oid, MAX_DB_STRING);
276
277 if (!_tcsncmp(oid, _T("POS:"), 4))
278 {
279 m_objectId = nullptr;
280 m_position = _tcstoul(&oid[4], nullptr, 10);
281 }
282 else
283 {
284 m_objectId = new SNMP_ObjectId(SNMP_ObjectId::parse(oid));
285 m_position = 0;
286 }
287
288 m_description = DBGetField(mapResult, row, 1, nullptr, 0);
289 m_flags = DBGetFieldULong(mapResult, row, 2);
290 }
291
292 /**
293 * Create SNMP trap parameter map object from config entry
294 */
295 SNMPTrapParameterMapping::SNMPTrapParameterMapping(ConfigEntry *entry)
296 {
297 int position = entry->getSubEntryValueAsInt(_T("position"), 0, -1);
298 if (position > 0)
299 {
300 m_objectId = nullptr;
301 m_position = position; // Positional parameter
302 }
303 else
304 {
305 m_objectId = new SNMP_ObjectId(SNMP_ObjectId::parse(entry->getSubEntryValue(_T("oid"), 0, _T("")))); // OID parameter
306 m_position = 0;
307 }
308
309 m_description = MemCopyString(entry->getSubEntryValue(_T("description")));
310 m_flags = entry->getSubEntryValueAsUInt(_T("flags"), 0, 0);
311 }
312
313 /**
314 * Create SNMP trap parameter map object from NXCPMessage
315 */
316 SNMPTrapParameterMapping::SNMPTrapParameterMapping(NXCPMessage *msg, UINT32 base)
317 {
318 m_flags = msg->getFieldAsUInt32(base);
319 m_description = msg->getFieldAsString(base + 1);
320 if (msg->getFieldAsUInt32(base + 2) == BY_POSITION)
321 {
322 m_objectId = nullptr;
323 m_position = msg->getFieldAsUInt32(base + 3);
324 }
325 else
326 {
327 UINT32 buffer[MAX_OID_LENGTH];
328 msg->getFieldAsInt32Array(base + 3, msg->getFieldAsUInt32(base + 4), buffer);
329 m_objectId = new SNMP_ObjectId(buffer, msg->getFieldAsUInt32(base + 4));
330 }
331 }
332
333 /**
334 * Destructor for SNMP trap parameter map object
335 */
336 SNMPTrapParameterMapping::~SNMPTrapParameterMapping()
337 {
338 delete m_objectId;
339 MemFree(m_description);
340 }
341
342 /**
343 * Fill NXCP message with trap parameter map configuration data
344 */
345 void SNMPTrapParameterMapping::fillMessage(NXCPMessage *msg, UINT32 base) const
346 {
347 msg->setField(base, isPositional());
348 if (isPositional())
349 msg->setField(base + 1, m_position);
350 else
351 msg->setFieldFromInt32Array(base + 1, m_objectId->length(), m_objectId->value());
352 msg->setField(base + 2, CHECK_NULL_EX(m_description));
353 msg->setField(base + 3, m_flags);
354
355 }
356
357 /**
358 * Load trap configuration from database
359 */
360 void LoadTrapCfg()
361 {
362 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
363
364 // Load traps
365 DB_RESULT hResult = DBSelect(hdb, _T("SELECT trap_id,snmp_oid,event_code,description,user_tag,guid,transformation_script FROM snmp_trap_cfg"));
366 if (hResult != nullptr)
367 {
368 DB_STATEMENT hStmt = (g_dbSyntax == DB_SYNTAX_ORACLE) ?
369 DBPrepare(hdb, _T("SELECT snmp_oid,description,flags FROM snmp_trap_pmap WHERE trap_id=? ORDER BY parameter"), true)
370 : nullptr;
371 if ((g_dbSyntax != DB_SYNTAX_ORACLE) || (hStmt != nullptr))
372 {
373 int numRows = DBGetNumRows(hResult);
374 for(int i = 0; i < numRows; i++)
375 {
376 SNMPTrapConfiguration *trapCfg = new SNMPTrapConfiguration(hResult, hdb, hStmt, i);
377 if (!trapCfg->getOid().isValid())
378 {
379 TCHAR buffer[MAX_DB_STRING];
380 nxlog_write(NXLOG_ERROR, _T("Invalid trap enterprise ID %s in trap configuration table"),
381 DBGetField(hResult, i, 1, buffer, MAX_DB_STRING));
382 }
383 m_trapCfgList.add(trapCfg);
384 }
385 if (hStmt != nullptr)
386 DBFreeStatement(hStmt);
387 }
388 DBFreeResult(hResult);
389 }
390
391 DBConnectionPoolReleaseConnection(hdb);
392 }
393
394 /**
395 * Get last SNMP Trap id
396 */
397 int64_t GetLastSnmpTrapId()
398 {
399 return s_trapId;
400 }
401
402 /**
403 * Initialize trap handling
404 */
405 void InitTraps()
406 {
407 LoadTrapCfg();
408
409 int64_t id = ConfigReadInt64(_T("LastSNMPTrapId"), 0);
410 if (id > s_trapId)
411 s_trapId = id;
412 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
413 DB_RESULT hResult = DBSelect(hdb, _T("SELECT max(trap_id) FROM snmp_trap_log"));
414 if (hResult != nullptr)
415 {
416 if (DBGetNumRows(hResult) > 0)
417 s_trapId = std::max(DBGetFieldInt64(hResult, 0, 0), static_cast<int64_t>(s_trapId));
418 DBFreeResult(hResult);
419 }
420 DBConnectionPoolReleaseConnection(hdb);
421
422 s_trapListenerPort = static_cast<uint16_t>(ConfigReadULong(_T("SNMP.Traps.ListenerPort"), s_trapListenerPort)); // 162 by default;
423 }
424
425 /**
426 * Generate event for matched trap
427 */
428 static void GenerateTrapEvent(const shared_ptr<Node>& node, UINT32 dwIndex, SNMP_PDU *pdu, int sourcePort)
429 {
430 SNMPTrapConfiguration *trapCfg = m_trapCfgList.get(dwIndex);
431
432 StringMap parameters;
433 parameters.set(_T("oid"), pdu->getTrapId()->toString());
434
435 // Extract varbinds from trap and add them as event's parameters
436 int numMaps = trapCfg->getParameterMappingCount();
437 for(int i = 0; i < numMaps; i++)
438 {
439 const SNMPTrapParameterMapping *pm = trapCfg->getParameterMapping(i);
440 if (pm->isPositional())
441 {
442 // Extract by varbind position
443 // Position numbering in mapping starts from 1,
444 // SNMP v2/v3 trap contains uptime and trap OID at positions 0 and 1,
445 // so map first mapping position to index 2 and so on
446 int index = (pdu->getVersion() == SNMP_VERSION_1) ? pm->getPosition() - 1 : pm->getPosition() + 1;
447 SNMP_Variable *varbind = pdu->getVariable(index);
448 if (varbind != nullptr)
449 {
450 bool convertToHex = true;
451 TCHAR name[64], buffer[3072];
452 _sntprintf(name, 64, _T("%d"), pm->getPosition());
453 parameters.set(name,
454 ((g_flags & AF_ALLOW_TRAP_VARBIND_CONVERSION) && !(pm->getFlags() & TRAP_VARBIND_FORCE_TEXT)) ?
455 varbind->getValueAsPrintableString(buffer, 3072, &convertToHex) :
456 varbind->getValueAsString(buffer, 3072));
457 }
458 }
459 else
460 {
461 // Extract by varbind OID
462 for(int j = 0; j < pdu->getNumVariables(); j++)
463 {
464 SNMP_Variable *varbind = pdu->getVariable(j);
465 int result = varbind->getName().compare(*(pm->getOid()));
466 if ((result == OID_EQUAL) || (result == OID_LONGER))
467 {
468 bool convertToHex = true;
469 TCHAR buffer[3072];
470 parameters.set(varbind->getName().toString(),
471 ((g_flags & AF_ALLOW_TRAP_VARBIND_CONVERSION) && !(pm->getFlags() & TRAP_VARBIND_FORCE_TEXT)) ?
472 varbind->getValueAsPrintableString(buffer, 3072, &convertToHex) :
473 varbind->getValueAsString(buffer, 3072));
474 break;
475 }
476 }
477 }
478 }
479
480 parameters.set(_T("sourcePort"), sourcePort);
481
482 NXSL_VM *vm;
483 if ((trapCfg->getScript() != nullptr) && !trapCfg->getScript()->isEmpty())
484 {
485 vm = CreateServerScriptVM(trapCfg->getScript(), node);
486 if (vm != nullptr)
487 {
488 vm->setGlobalVariable("$trap", vm->createValue(pdu->getTrapId()->toString()));
489 NXSL_Array *varbinds = new NXSL_Array(vm);
490 for(int i = (pdu->getVersion() == SNMP_VERSION_1) ? 0 : 2; i < pdu->getNumVariables(); i++)
491 {
492 varbinds->append(vm->createValue(new NXSL_Object(vm, &g_nxslSnmpVarBindClass, new SNMP_Variable(pdu->getVariable(i)))));
493 }
494 vm->setGlobalVariable("$varbinds", vm->createValue(varbinds));
495 }
496 else
497 {
498 nxlog_debug_tag(DEBUG_TAG, 6, _T("GenerateTrapEvent: cannot load transformation script for trap mapping [%u]"), trapCfg->getId());
499 }
500 }
501 else
502 {
503 vm = nullptr;
504 }
505 TransformAndPostEvent(trapCfg->getEventCode(), EventOrigin::SNMP, 0, node->getId(), trapCfg->getEventTag(), ¶meters, vm);
506 delete vm;
507 }
508
509 /**
510 * Handler for EnumerateSessions()
511 */
512 static void BroadcastNewTrap(ClientSession *pSession, NXCPMessage *msg)
513 {
514 pSession->onNewSNMPTrap(msg);
515 }
516
517 /**
518 * Build trap varbind list
519 */
520 static StringBuffer BuildVarbindList(SNMP_PDU *pdu)
521 {
522 StringBuffer out;
523 TCHAR oidText[1024], data[4096];
524
525 for(int i = (pdu->getVersion() == SNMP_VERSION_1) ? 0 : 2; i < pdu->getNumVariables(); i++)
526 {
527 SNMP_Variable *v = pdu->getVariable(i);
528 if (!out.isEmpty())
529 out.append(_T("; "));
530
531 v->getName().toString(oidText, 1024);
532
533 bool convertToHex = true;
534 if (g_flags & AF_ALLOW_TRAP_VARBIND_CONVERSION)
535 v->getValueAsPrintableString(data, 4096, &convertToHex);
536 else
537 v->getValueAsString(data, 4096);
538
539 nxlog_debug_tag(DEBUG_TAG, 5, _T(" %s == '%s'"), oidText, data);
540
541 out.append(oidText);
542 out.append(_T(" == '"));
543 out.append(data);
544 out.append(_T('\''));
545 }
546
547 return out;
548 }
549
550 /**
551 * Process trap
552 */
553 void ProcessTrap(SNMP_PDU *pdu, const InetAddress& srcAddr, int32_t zoneUIN, int srcPort, SNMP_Transport *snmpTransport, SNMP_Engine *localEngine, bool isInformRq)
554 {
555 StringBuffer varbinds;
556 TCHAR buffer[4096];
557 bool processedByModule = false;
558 int iResult;
559
560 InterlockedIncrement64(&g_snmpTrapsReceived);
561 nxlog_debug_tag(DEBUG_TAG, 4, _T("Received SNMP %s %s from %s"), isInformRq ? _T("INFORM-REQUEST") : _T("TRAP"),
562 pdu->getTrapId()->toString(&buffer[96], 4000), srcAddr.toString(buffer));
563
564 if (isInformRq)
565 {
566 SNMP_PDU response(SNMP_RESPONSE, pdu->getRequestId(), pdu->getVersion());
567 if (snmpTransport->getSecurityContext() == nullptr)
568 {
569 snmpTransport->setSecurityContext(new SNMP_SecurityContext(pdu->getCommunity()));
570 }
571 response.setMessageId(pdu->getMessageId());
572 response.setContextEngineId(localEngine->getId(), localEngine->getIdLen());
573 snmpTransport->sendMessage(&response, 0);
574 }
575
576 // Match IP address to object
577 shared_ptr<Node> node = FindNodeByIP(zoneUIN, (g_flags & AF_TRAP_SOURCES_IN_ALL_ZONES) != 0, srcAddr);
578
579 // Write trap to log if required
580 if ((node != nullptr) || (g_flags & AF_LOG_ALL_SNMP_TRAPS))
581 {
582 time_t timestamp = time(nullptr);
583
584 nxlog_debug_tag(DEBUG_TAG, 5, _T("Varbinds for %s %s from %s:"), isInformRq ? _T("INFORM-REQUEST") : _T("TRAP"), &buffer[96], buffer);
585 varbinds = BuildVarbindList(pdu);
586
587 // Write new trap to database
588 uint64_t trapId = InterlockedIncrement64(&s_trapId);
589 TCHAR query[8192], oidText[1024];
590 _sntprintf(query, 8192, _T("INSERT INTO snmp_trap_log (trap_id,trap_timestamp,")
591 _T("ip_addr,object_id,zone_uin,trap_oid,trap_varlist) VALUES ")
592 _T("(") UINT64_FMT _T(",%s") INT64_FMT _T("%s,'%s',%d,%d,'%s',%s)"),
593 trapId, (g_dbSyntax == DB_SYNTAX_TSDB) ? _T("to_timestamp(") : _T(""), static_cast<int64_t>(timestamp),
594 (g_dbSyntax == DB_SYNTAX_TSDB) ? _T(")") : _T(""), srcAddr.toString(buffer),
595 (node != nullptr) ? node->getId() : (UINT32)0, (node != nullptr) ? node->getZoneUIN() : zoneUIN,
596 pdu->getTrapId()->toString(oidText, 1024),
597 (const TCHAR *)DBPrepareString(g_dbDriver, varbinds));
598 QueueSQLRequest(query);
599
600 // Notify connected clients
601 NXCPMessage msg;
602 msg.setCode(CMD_TRAP_LOG_RECORDS);
603 msg.setField(VID_NUM_RECORDS, (UINT32)1);
604 msg.setField(VID_RECORDS_ORDER, (WORD)RECORD_ORDER_NORMAL);
605 msg.setField(VID_TRAP_LOG_MSG_BASE, trapId);
606 msg.setFieldFromTime(VID_TRAP_LOG_MSG_BASE + 1, timestamp);
607 msg.setField(VID_TRAP_LOG_MSG_BASE + 2, srcAddr);
608 msg.setField(VID_TRAP_LOG_MSG_BASE + 3, (node != nullptr) ? node->getId() : (UINT32)0);
609 msg.setField(VID_TRAP_LOG_MSG_BASE + 4, pdu->getTrapId()->toString(oidText, 1024));
610 msg.setField(VID_TRAP_LOG_MSG_BASE + 5, varbinds);
611 EnumerateClientSessions(BroadcastNewTrap, &msg);
612 }
613 else if (nxlog_get_debug_level_tag(DEBUG_TAG) >= 5)
614 {
615 nxlog_debug_tag(DEBUG_TAG, 5, _T("Varbinds for %s %s:"), isInformRq ? _T("INFORM-REQUEST") : _T("TRAP"), &buffer[96]);
616 BuildVarbindList(pdu);
617 }
618
619 // Process trap if it is coming from host registered in database
620 if (node != nullptr)
621 {
622 nxlog_debug_tag(DEBUG_TAG, 4, _T("ProcessTrap: trap matched to node %s [%d]"), node->getName(), node->getId());
623 node->incSnmpTrapCount();
624 if (node->checkTrapShouldBeProcessed())
625 {
626 if ((node->getStatus() != STATUS_UNMANAGED) || (g_flags & AF_TRAPS_FROM_UNMANAGED_NODES))
627 {
628 // Pass trap to loaded modules
629 ENUMERATE_MODULES(pfTrapHandler)
630 {
631 if (CURRENT_MODULE.pfTrapHandler(pdu, node))
632 {
633 processedByModule = true;
634 break; // Trap was processed by the module
635 }
636 }
637
638 // Find if we have this trap in our list
639 s_trapCfgLock.lock();
640
641 // Try to find closest match
642 size_t matchLen = 0;
643 int matchIndex;
644 for(int i = 0; i < m_trapCfgList.size(); i++)
645 {
646 const SNMPTrapConfiguration *trapCfg = m_trapCfgList.get(i);
647 if (trapCfg->getOid().length() > 0)
648 {
649 iResult = pdu->getTrapId()->compare(trapCfg->getOid());
650 if (iResult == OID_EQUAL)
651 {
652 matchLen = trapCfg->getOid().length();
653 matchIndex = i;
654 break; // Find exact match
655 }
656 else if (iResult == OID_LONGER)
657 {
658 if (trapCfg->getOid().length() > matchLen)
659 {
660 matchLen = trapCfg->getOid().length();
661 matchIndex = i;
662 }
663 }
664 }
665 }
666
667 if (matchLen > 0)
668 {
669 GenerateTrapEvent(node, matchIndex, pdu, srcPort);
670 }
671 else if (!processedByModule) // Process unmatched traps not processed by module
672 {
673 // Generate default event for unmatched traps
674 const TCHAR *names[3] = { _T("oid"), nullptr, _T("sourcePort") };
675 TCHAR oidText[1024];
676 PostEventWithNames(EVENT_SNMP_UNMATCHED_TRAP, EventOrigin::SNMP, 0, node->getId(), "ssd", names,
677 pdu->getTrapId()->toString(oidText, 1024), (const TCHAR *)varbinds, srcPort);
678 }
679 s_trapCfgLock.unlock();
680 }
681 else
682 {
683 nxlog_debug_tag(DEBUG_TAG, 4, _T("ProcessTrap: Node %s [%d] is in UNMANAGED state, trap ignored"), node->getName(), node->getId());
684 }
685 }
686 else
687 {
688 nxlog_debug_tag(DEBUG_TAG, 4, _T("ProcessTrap: Node %s [%d] is in trap flood state, trap is dropped"), node->getName(), node->getId());
689 }
690 }
691 else if (g_flags & AF_SNMP_TRAP_DISCOVERY) // unknown node, discovery enabled
692 {
693 nxlog_debug_tag(DEBUG_TAG, 4, _T("ProcessTrap: trap not matched to node, adding new IP address %s for discovery"), srcAddr.toString(buffer));
694 CheckPotentialNode(srcAddr, zoneUIN, DA_SRC_SNMP_TRAP, 0);
695 }
696 else // unknown node, discovery disabled
697 {
698 nxlog_debug_tag(DEBUG_TAG, 4, _T("ProcessTrap: trap not matched to any node"));
699 }
700 }
701
702 /**
703 * Context finder - tries to find SNMPv3 security context by IP address
704 */
705 static SNMP_SecurityContext *ContextFinder(struct sockaddr *addr, socklen_t addrLen)
706 {
707 InetAddress ipAddr = InetAddress::createFromSockaddr(addr);
708 shared_ptr<Node> node = FindNodeByIP((g_flags & AF_TRAP_SOURCES_IN_ALL_ZONES) ? ALL_ZONES : 0, ipAddr);
709 TCHAR buffer[64];
710 nxlog_debug_tag(DEBUG_TAG, 6, _T("SNMPTrapReceiver: looking for SNMP security context for node %s %s"),
711 ipAddr.toString(buffer), (node != nullptr) ? node->getName() : _T("<unknown>"));
712 return (node != nullptr) ? node->getSnmpSecurityContext() : nullptr;
713 }
714
715 /**
716 * Create SNMP transport for receiver
717 */
718 static SNMP_Transport *CreateTransport(SOCKET hSocket)
719 {
720 if (hSocket == INVALID_SOCKET)
721 return nullptr;
722
723 SNMP_Transport *t = new SNMP_UDPTransport(hSocket);
724 t->enableEngineIdAutoupdate(true);
725 t->setPeerUpdatedOnRecv(true);
726 return t;
727 }
728
729 /**
730 * SNMP trap receiver thread
731 */
732 void SNMPTrapReceiver()
733 {
734 static BYTE engineId[] = { 0x80, 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00 };
735 SNMP_Engine localEngine(engineId, 12);
736
737 ThreadSetName("SNMPTrapRecv");
738
739 SOCKET hSocket = CreateSocket(AF_INET, SOCK_DGRAM, 0);
740 #ifdef WITH_IPV6
741 SOCKET hSocket6 = CreateSocket(AF_INET6, SOCK_DGRAM, 0);
742 #endif
743
744 #ifdef WITH_IPV6
745 if ((hSocket == INVALID_SOCKET) && (hSocket6 == INVALID_SOCKET))
746 #else
747 if (hSocket == INVALID_SOCKET)
748 #endif
749 {
750 TCHAR buffer[1024];
751 nxlog_write(NXLOG_ERROR, _T("Unable to create socket for SNMP trap receiver (%s)"), GetLastSocketErrorText(buffer, 1024));
752 return;
753 }
754
755 SetSocketExclusiveAddrUse(hSocket);
756 SetSocketReuseFlag(hSocket);
757 #ifndef _WIN32
758 fcntl(hSocket, F_SETFD, fcntl(hSocket, F_GETFD) | FD_CLOEXEC);
759 #endif
760
761 #ifdef WITH_IPV6
762 SetSocketExclusiveAddrUse(hSocket6);
763 SetSocketReuseFlag(hSocket6);
764 #ifndef _WIN32
765 fcntl(hSocket6, F_SETFD, fcntl(hSocket6, F_GETFD) | FD_CLOEXEC);
766 #endif
767 #ifdef IPV6_V6ONLY
768 int on = 1;
769 setsockopt(hSocket6, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(int));
770 #endif
771 #endif
772
773 // Fill in local address structure
774 struct sockaddr_in servAddr;
775 memset(&servAddr, 0, sizeof(struct sockaddr_in));
776 servAddr.sin_family = AF_INET;
777
778 #ifdef WITH_IPV6
779 struct sockaddr_in6 servAddr6;
780 memset(&servAddr6, 0, sizeof(struct sockaddr_in6));
781 servAddr6.sin6_family = AF_INET6;
782 #endif
783 if (!_tcscmp(g_szListenAddress, _T("*")))
784 {
785 servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
786 #ifdef WITH_IPV6
787 memset(servAddr6.sin6_addr.s6_addr, 0, 16);
788 #endif
789 }
790 else
791 {
792 InetAddress bindAddress = InetAddress::resolveHostName(g_szListenAddress, AF_INET);
793 if (bindAddress.isValid() && (bindAddress.getFamily() == AF_INET))
794 {
795 servAddr.sin_addr.s_addr = htonl(bindAddress.getAddressV4());
796 }
797 else
798 {
799 servAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
800 }
801 #ifdef WITH_IPV6
802 bindAddress = InetAddress::resolveHostName(g_szListenAddress, AF_INET6);
803 if (bindAddress.isValid() && (bindAddress.getFamily() == AF_INET6))
804 {
805 memcpy(servAddr6.sin6_addr.s6_addr, bindAddress.getAddressV6(), 16);
806 }
807 else
808 {
809 memset(servAddr6.sin6_addr.s6_addr, 0, 15);
810 servAddr6.sin6_addr.s6_addr[15] = 1;
811 }
812 #endif
813 }
814 servAddr.sin_port = htons(s_trapListenerPort);
815 #ifdef WITH_IPV6
816 servAddr6.sin6_port = htons(s_trapListenerPort);
817 #endif
818
819 // Bind socket
820 TCHAR buffer[64];
821 int bindFailures = 0;
822 nxlog_debug_tag(DEBUG_TAG, 5, _T("Trying to bind on UDP %s:%d"), SockaddrToStr((struct sockaddr *)&servAddr, buffer), ntohs(servAddr.sin_port));
823 if (bind(hSocket, (struct sockaddr *)&servAddr, sizeof(struct sockaddr_in)) != 0)
824 {
825 TCHAR buffer[1024];
826 nxlog_write(NXLOG_ERROR, _T("Unable to bind IPv4 socket for SNMP trap receiver (%s)"), GetLastSocketErrorText(buffer, 1024));
827 bindFailures++;
828 closesocket(hSocket);
829 hSocket = INVALID_SOCKET;
830 }
831
832 #ifdef WITH_IPV6
833 nxlog_debug_tag(DEBUG_TAG, 5, _T("Trying to bind on UDP [%s]:%d"), SockaddrToStr((struct sockaddr *)&servAddr6, buffer), ntohs(servAddr6.sin6_port));
834 if (bind(hSocket6, (struct sockaddr *)&servAddr6, sizeof(struct sockaddr_in6)) != 0)
835 {
836 TCHAR buffer[1024];
837 nxlog_write(NXLOG_ERROR, _T("Unable to bind IPv6 socket for SNMP trap receiver (%s)"), GetLastSocketErrorText(buffer, 1024));
838 bindFailures++;
839 closesocket(hSocket6);
840 hSocket6 = INVALID_SOCKET;
841 }
842 #else
843 bindFailures++;
844 #endif
845
846 // Abort if cannot bind to at least one socket
847 if (bindFailures == 2)
848 {
849 nxlog_debug_tag(DEBUG_TAG, 1, _T("SNMP trap receiver aborted - cannot bind at least one socket"));
850 return;
851 }
852
853 if (hSocket != INVALID_SOCKET)
854 {
855 TCHAR ipAddrText[64];
856 nxlog_write(NXLOG_INFO, _T("Listening for SNMP traps on UDP socket %s:%u"), InetAddress(ntohl(servAddr.sin_addr.s_addr)).toString(ipAddrText), s_trapListenerPort);
857 }
858 #ifdef WITH_IPV6
859 if (hSocket6 != INVALID_SOCKET)
860 {
861 TCHAR ipAddrText[64];
862 nxlog_write(NXLOG_INFO, _T("Listening for SNMP traps on UDP socket %s:%u"), InetAddress(servAddr6.sin6_addr.s6_addr).toString(ipAddrText), s_trapListenerPort);
863 }
864 #endif
865
866 SNMP_Transport *snmp = CreateTransport(hSocket);
867 #ifdef WITH_IPV6
868 SNMP_Transport *snmp6 = CreateTransport(hSocket6);
869 #endif
870
871 SocketPoller sp;
872
873 nxlog_debug_tag(DEBUG_TAG, 1, _T("SNMP Trap Receiver started on port %u"), s_trapListenerPort);
874
875 // Wait for packets
876 while(!IsShutdownInProgress())
877 {
878 sp.reset();
879 if (hSocket != INVALID_SOCKET)
880 sp.add(hSocket);
881 #ifdef WITH_IPV6
882 if (hSocket6 != INVALID_SOCKET)
883 sp.add(hSocket6);
884 #endif
885
886 int rc = sp.poll(1000);
887 if ((rc > 0) && !IsShutdownInProgress())
888 {
889 SockAddrBuffer addr;
890 socklen_t addrLen = sizeof(SockAddrBuffer);
891 SNMP_PDU *pdu;
892 #ifdef WITH_IPV6
893 SNMP_Transport *transport = sp.isSet(hSocket) ? snmp : snmp6;
894 #else
895 SNMP_Transport *transport = snmp;
896 #endif
897 int bytes = transport->readMessage(&pdu, 2000, (struct sockaddr *)&addr, &addrLen, ContextFinder);
898 if ((bytes > 0) && (pdu != nullptr))
899 {
900 InetAddress sourceAddr = InetAddress::createFromSockaddr((struct sockaddr *)&addr);
901 nxlog_debug_tag(DEBUG_TAG, 6, _T("SNMPTrapReceiver: received PDU of type %d from %s"), pdu->getCommand(), (const TCHAR *)sourceAddr.toString());
902 if ((pdu->getCommand() == SNMP_TRAP) || (pdu->getCommand() == SNMP_INFORM_REQUEST))
903 {
904 if ((pdu->getVersion() == SNMP_VERSION_3) && (pdu->getCommand() == SNMP_INFORM_REQUEST))
905 {
906 SNMP_SecurityContext *context = transport->getSecurityContext();
907 context->setAuthoritativeEngine(localEngine);
908 }
909 ProcessTrap(pdu, sourceAddr, 0, ntohs(SA_PORT(&addr)), transport, &localEngine, pdu->getCommand() == SNMP_INFORM_REQUEST);
910 }
911 else if ((pdu->getVersion() == SNMP_VERSION_3) && (pdu->getCommand() == SNMP_GET_REQUEST) && (pdu->getAuthoritativeEngine().getIdLen() == 0))
912 {
913 // Engine ID discovery
914 nxlog_debug_tag(DEBUG_TAG, 6, _T("SNMPTrapReceiver: EngineId discovery"));
915
916 SNMP_PDU *response = new SNMP_PDU(SNMP_REPORT, pdu->getRequestId(), pdu->getVersion());
917 response->setReportable(false);
918 response->setMessageId(pdu->getMessageId());
919 response->setContextEngineId(localEngine.getId(), localEngine.getIdLen());
920
921 SNMP_Variable *var = new SNMP_Variable(_T(".1.3.6.1.6.3.15.1.1.4.0"));
922 var->setValueFromString(ASN_INTEGER, _T("2"));
923 response->bindVariable(var);
924
925 SNMP_SecurityContext *context = new SNMP_SecurityContext();
926 localEngine.setTime((int)time(nullptr));
927 context->setAuthoritativeEngine(localEngine);
928 context->setSecurityModel(SNMP_SECURITY_MODEL_USM);
929 context->setAuthMethod(SNMP_AUTH_NONE);
930 context->setPrivMethod(SNMP_ENCRYPT_NONE);
931 transport->setSecurityContext(context);
932
933 transport->sendMessage(response, 0);
934 delete response;
935 }
936 else if (pdu->getCommand() == SNMP_REPORT)
937 {
938 nxlog_debug_tag(DEBUG_TAG, 6, _T("SNMPTrapReceiver: REPORT PDU with error %s"), (const TCHAR *)pdu->getVariable(0)->getName().toString());
939 }
940 delete pdu;
941 }
942 else
943 {
944 // Sleep on error
945 ThreadSleepMs(100);
946 }
947 }
948 }
949
950 delete snmp;
951 #ifdef WITH_IPV6
952 delete snmp6;
953 #endif
954 nxlog_debug_tag(DEBUG_TAG, 1, _T("SNMP Trap Receiver terminated"));
955 }
956
957 /**
958 * Send all trap configuration records to client
959 */
960 void SendTrapsToClient(ClientSession *pSession, UINT32 dwRqId)
961 {
962 NXCPMessage msg;
963
964 // Prepare message
965 msg.setCode(CMD_TRAP_CFG_RECORD);
966 msg.setId(dwRqId);
967
968 s_trapCfgLock.lock();
969 for(int i = 0; i < m_trapCfgList.size(); i++)
970 {
971 m_trapCfgList.get(i)->fillMessage(&msg);
972 pSession->sendMessage(&msg);
973 msg.deleteAllFields();
974 }
975 s_trapCfgLock.unlock();
976
977 msg.setField(VID_TRAP_ID, (UINT32)0);
978 pSession->sendMessage(&msg);
979 }
980
981 /**
982 * Prepare single message with all trap configuration records
983 */
984 void CreateTrapCfgMessage(NXCPMessage *msg)
985 {
986 s_trapCfgLock.lock();
987 msg->setField(VID_NUM_TRAPS, m_trapCfgList.size());
988 for(int i = 0, id = VID_TRAP_INFO_BASE; i < m_trapCfgList.size(); i++, id += 10)
989 m_trapCfgList.get(i)->fillMessage(msg, id);
990 s_trapCfgLock.unlock();
991 }
992
993 static void NotifyOnTrapCfgDelete(UINT32 id)
994 {
995 NXCPMessage msg;
996
997 msg.setCode(CMD_TRAP_CFG_UPDATE);
998 msg.setField(VID_NOTIFICATION_CODE, (UINT32)NX_NOTIFY_TRAPCFG_DELETED);
999 msg.setField(VID_TRAP_ID, id);
1000 EnumerateClientSessions(NotifyOnTrapCfgChangeCB, &msg);
1001 }
1002
1003 /**
1004 * Delete trap configuration record
1005 */
1006 UINT32 DeleteTrap(UINT32 id)
1007 {
1008 UINT32 dwResult = RCC_INVALID_TRAP_ID;
1009
1010 s_trapCfgLock.lock();
1011
1012 for(int i = 0; i < m_trapCfgList.size(); i++)
1013 {
1014 if (m_trapCfgList.get(i)->getId() == id)
1015 {
1016 // Remove trap entry from database
1017 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
1018 DB_STATEMENT hStmtCfg = DBPrepare(hdb, _T("DELETE FROM snmp_trap_cfg WHERE trap_id=?"));
1019 DB_STATEMENT hStmtMap = DBPrepare(hdb, _T("DELETE FROM snmp_trap_pmap WHERE trap_id=?"));
1020
1021 if (hStmtCfg != nullptr && hStmtMap != nullptr)
1022 {
1023 DBBind(hStmtCfg, 1, DB_SQLTYPE_INTEGER, id);
1024 DBBind(hStmtMap, 1, DB_SQLTYPE_INTEGER, id);
1025
1026 if (DBBegin(hdb))
1027 {
1028 if (DBExecute(hStmtCfg) && DBExecute(hStmtMap))
1029 {
1030 m_trapCfgList.remove(i);
1031 NotifyOnTrapCfgDelete(id);
1032 dwResult = RCC_SUCCESS;
1033 DBCommit(hdb);
1034 }
1035 else
1036 DBRollback(hdb);
1037
1038 DBFreeStatement(hStmtCfg);
1039 DBFreeStatement(hStmtMap);
1040 }
1041 }
1042 DBConnectionPoolReleaseConnection(hdb);
1043 break;
1044 }
1045 }
1046
1047 s_trapCfgLock.unlock();
1048 return dwResult;
1049 }
1050
1051 /**
1052 * Save parameter mapping to database
1053 */
1054 bool SNMPTrapConfiguration::saveParameterMapping(DB_HANDLE hdb)
1055 {
1056 if (!ExecuteQueryOnObject(hdb, m_id, _T("DELETE FROM snmp_trap_pmap WHERE trap_id=?")))
1057 return false;
1058
1059 if (m_mappings.isEmpty())
1060 return true;
1061
1062 DB_STATEMENT hStmt = DBPrepare(hdb, _T("INSERT INTO snmp_trap_pmap (trap_id,parameter,snmp_oid,description,flags) VALUES (?,?,?,?,?)"), true);
1063 if (hStmt == nullptr)
1064 return false;
1065
1066 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
1067
1068 bool success = true;
1069 TCHAR oid[1024];
1070 for(int i = 0; (i < m_mappings.size()) && success; i++)
1071 {
1072 const SNMPTrapParameterMapping *pm = m_mappings.get(i);
1073 if (!pm->isPositional())
1074 pm->getOid()->toString(oid, 1024);
1075 else
1076 _sntprintf(oid, 1024, _T("POS:%d"), pm->getPosition());
1077
1078 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, i + 1);
1079 DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, oid, DB_BIND_STATIC);
1080 DBBind(hStmt, 4, DB_SQLTYPE_VARCHAR, pm->getDescription(), DB_BIND_STATIC);
1081 DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, pm->getFlags());
1082
1083 success = DBExecute(hStmt);
1084 }
1085 DBFreeStatement(hStmt);
1086 return success;
1087 }
1088
1089 /**
1090 * Create new trap configuration record
1091 */
1092 UINT32 CreateNewTrap(UINT32 *pdwTrapId)
1093 {
1094 UINT32 rcc = RCC_DB_FAILURE;
1095
1096 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
1097 DB_STATEMENT hStmt = DBPrepare(hdb, _T("INSERT INTO snmp_trap_cfg (guid,trap_id,snmp_oid,event_code,description,user_tag) VALUES (?,?,'',?,'','')"));
1098 if (hStmt != nullptr)
1099 {
1100 SNMPTrapConfiguration *trapCfg = new SNMPTrapConfiguration();
1101 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, trapCfg->getGuid());
1102 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, trapCfg->getId());
1103 DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, trapCfg->getEventCode());
1104
1105 if (DBExecute(hStmt))
1106 {
1107 AddTrapCfgToList(trapCfg);
1108 trapCfg->notifyOnTrapCfgChange(NX_NOTIFY_TRAPCFG_CREATED);
1109 *pdwTrapId = trapCfg->getId();
1110 rcc = RCC_SUCCESS;
1111 }
1112 else
1113 {
1114 delete trapCfg;
1115 }
1116
1117 DBFreeStatement(hStmt);
1118 }
1119 DBConnectionPoolReleaseConnection(hdb);
1120 return rcc;
1121 }
1122
1123 /**
1124 * Update trap configuration record from message
1125 */
1126 UINT32 UpdateTrapFromMsg(NXCPMessage *pMsg)
1127 {
1128 UINT32 rcc = RCC_INVALID_TRAP_ID;
1129 TCHAR oid[1024];
1130
1131 UINT32 id = pMsg->getFieldAsUInt32(VID_TRAP_ID);
1132 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
1133
1134 for(int i = 0; i < m_trapCfgList.size(); i++)
1135 {
1136 if (m_trapCfgList.get(i)->getId() == id)
1137 {
1138 DB_STATEMENT hStmt = DBPrepare(hdb, _T("UPDATE snmp_trap_cfg SET snmp_oid=?,event_code=?,description=?,user_tag=?,transformation_script=? WHERE trap_id=?"));
1139 if (hStmt != nullptr)
1140 {
1141 SNMPTrapConfiguration *trapCfg = new SNMPTrapConfiguration(pMsg);
1142 trapCfg->getOid().toString(oid, 1024);
1143 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, oid, DB_BIND_STATIC);
1144 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, trapCfg->getEventCode());
1145 DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, trapCfg->getDescription(), DB_BIND_STATIC);
1146 DBBind(hStmt, 4, DB_SQLTYPE_VARCHAR, trapCfg->getEventTag(), DB_BIND_STATIC);
1147 DBBind(hStmt, 5, DB_SQLTYPE_TEXT, trapCfg->getScriptSource(), DB_BIND_STATIC);
1148 DBBind(hStmt, 6, DB_SQLTYPE_INTEGER, trapCfg->getId());
1149
1150 if (DBBegin(hdb))
1151 {
1152 if (DBExecute(hStmt) && trapCfg->saveParameterMapping(hdb))
1153 {
1154 AddTrapCfgToList(trapCfg);
1155 trapCfg->notifyOnTrapCfgChange(NX_NOTIFY_TRAPCFG_MODIFIED);
1156 rcc = RCC_SUCCESS;
1157 DBCommit(hdb);
1158 }
1159 else
1160 {
1161 DBRollback(hdb);
1162 rcc = RCC_DB_FAILURE;
1163 }
1164 }
1165 else
1166 {
1167 rcc = RCC_DB_FAILURE;
1168 }
1169 DBFreeStatement(hStmt);
1170
1171 if (rcc != RCC_SUCCESS)
1172 delete trapCfg;
1173 }
1174
1175 DBConnectionPoolReleaseConnection(hdb);
1176 break;
1177 }
1178 }
1179
1180 return rcc;
1181 }
1182
1183 /**
1184 * Create trap record in NXMP file
1185 */
1186 void CreateTrapExportRecord(StringBuffer &xml, UINT32 id)
1187 {
1188 TCHAR szBuffer[1024];
1189 SNMPTrapConfiguration *trapCfg;
1190
1191 s_trapCfgLock.lock();
1192 for(int i = 0; i < m_trapCfgList.size(); i++)
1193 {
1194 trapCfg = m_trapCfgList.get(i);
1195 if (trapCfg->getId() == id)
1196 {
1197 xml.append(_T("\t\t<trap id=\""));
1198 xml.append(id);
1199 xml.append(_T("\">\n\t\t\t<guid>"));
1200 xml.append(trapCfg->getGuid());
1201 xml.append(_T("</guid>\n\t\t\t<oid>"));
1202 xml.append(trapCfg->getOid().toString());
1203 xml.append(_T("</oid>\n\t\t\t<description>"));
1204 xml.append(EscapeStringForXML2(trapCfg->getDescription()));
1205 xml.append(_T("</description>\n\t\t\t<eventTag>"));
1206 xml.append(EscapeStringForXML2(trapCfg->getEventTag()));
1207 xml.append(_T("</eventTag>\n\t\t\t<event>"));
1208 EventNameFromCode(trapCfg->getEventCode(), szBuffer);
1209 xml.append(EscapeStringForXML2(szBuffer));
1210 xml.append(_T("</event>\n\t\t\t<transformationScript>"));
1211 xml.append(EscapeStringForXML2(trapCfg->getScriptSource()));
1212 xml.append(_T("</transformationScript>\n"));
1213 if (trapCfg->getParameterMappingCount() > 0)
1214 {
1215 xml.append(_T("\t\t\t<parameters>\n"));
1216 for(int j = 0; j < trapCfg->getParameterMappingCount(); j++)
1217 {
1218 const SNMPTrapParameterMapping *pm = trapCfg->getParameterMapping(j);
1219 xml.appendFormattedString(_T("\t\t\t\t<parameter id=\"%d\">\n")
1220 _T("\t\t\t\t\t<flags>%d</flags>\n")
1221 _T("\t\t\t\t\t<description>%s</description>\n"),
1222 j + 1, pm->getFlags(),
1223 (const TCHAR *)EscapeStringForXML2(pm->getDescription()));
1224 if (!pm->isPositional())
1225 {
1226 xml.appendFormattedString(_T("\t\t\t\t\t<oid>%s</oid>\n"), pm->getOid()->toString(szBuffer, 1024));
1227 }
1228 else
1229 {
1230 xml.appendFormattedString(_T("\t\t\t\t\t<position>%d</position>\n"), pm->getPosition());
1231 }
1232 xml.append(_T("\t\t\t\t</parameter>\n"));
1233 }
1234 xml.append(_T("\t\t\t</parameters>\n"));
1235 }
1236 xml.append(_T("\t\t</trap>\n"));
1237 break;
1238 }
1239 }
1240 s_trapCfgLock.unlock();
1241 }
1242
1243 /**
1244 * Find if trap with guid already exists
1245 */
1246 UINT32 ResolveTrapGuid(const uuid& guid)
1247 {
1248 UINT32 id = 0;
1249
1250 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
1251
1252 DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT trap_id FROM snmp_trap_cfg WHERE guid=?"));
1253 if (hStmt != nullptr)
1254 {
1255 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, guid);
1256 DB_RESULT hResult = DBSelectPrepared(hStmt);
1257 if (hResult != nullptr)
1258 {
1259 if (DBGetNumRows(hResult) > 0)
1260 id = DBGetFieldULong(hResult, 0, 0);
1261 DBFreeResult(hResult);
1262 }
1263 DBFreeStatement(hStmt);
1264 }
1265
1266 DBConnectionPoolReleaseConnection(hdb);
1267 return id;
1268 }
1269
1270 /**
1271 * Add SNMP trap configuration to local list
1272 */
1273 void AddTrapCfgToList(SNMPTrapConfiguration *trapCfg)
1274 {
1275 s_trapCfgLock.lock();
1276
1277 for(int i = 0; i < m_trapCfgList.size(); i++)
1278 {
1279 if (m_trapCfgList.get(i)->getId() == trapCfg->getId())
1280 {
1281 m_trapCfgList.remove(i);
1282 }
1283 }
1284 m_trapCfgList.add(trapCfg);
1285
1286 s_trapCfgLock.unlock();
1287 }