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