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