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