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