511109e6b497a32140f58fcda8811c2df11252ee
[public/netxms.git] / src / server / core / snmp.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003, 2004, 2005 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 ** $module: snmp.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24
25
26 //
27 // OID translation structure
28 //
29
30 struct OID_TABLE
31 {
32 TCHAR *pszOid;
33 DWORD dwNodeType;
34 DWORD dwNodeFlags;
35 };
36
37
38 //
39 // Static data
40 //
41
42 static OID_TABLE *m_pOidTable = NULL;
43 static DWORD m_dwOidTableSize = 0;
44 static DWORD m_dwRequestId = 1;
45
46
47 //
48 // Initialize SNMP subsystem
49 //
50
51 void SnmpInit(void)
52 {
53 DB_RESULT hResult;
54 DWORD i;
55
56 // Load OID to type translation table
57 hResult = DBSelect(g_hCoreDB, _T("SELECT snmp_oid,node_type,node_flags FROM oid_to_type ORDER BY pair_id"));
58 if (hResult != NULL)
59 {
60 m_dwOidTableSize = DBGetNumRows(hResult);
61 m_pOidTable = (OID_TABLE *)malloc(sizeof(OID_TABLE) * m_dwOidTableSize);
62 for(i = 0; i < m_dwOidTableSize; i++)
63 {
64 m_pOidTable[i].pszOid = _tcsdup(DBGetField(hResult, i, 0));
65 m_pOidTable[i].dwNodeType = DBGetFieldULong(hResult, i, 1);
66 m_pOidTable[i].dwNodeFlags = DBGetFieldULong(hResult, i, 2);
67 }
68 DBFreeResult(hResult);
69 }
70 }
71
72
73 //
74 // Determine node type by OID
75 //
76
77 DWORD OidToType(TCHAR *pszOid, DWORD *pdwFlags)
78 {
79 DWORD i;
80
81 for(i = 0; i < m_dwOidTableSize; i++)
82 if (MatchString(m_pOidTable[i].pszOid, pszOid, TRUE))
83 {
84 if (pdwFlags != NULL)
85 *pdwFlags = m_pOidTable[i].dwNodeFlags;
86 return m_pOidTable[i].dwNodeType;
87 }
88
89 *pdwFlags = 0;
90 return NODE_TYPE_GENERIC;
91 }
92
93
94 //
95 // Get value for SNMP variable
96 // If szOidStr is not NULL, string representation of OID is used, otherwise -
97 // binary representation from oidBinary and dwOidLen
98 //
99
100 DWORD SnmpGet(DWORD dwVersion, DWORD dwAddr, WORD wPort, const char *szCommunity,
101 const char *szOidStr, const DWORD *oidBinary, DWORD dwOidLen, void *pValue,
102 DWORD dwBufferSize, BOOL bVerbose, BOOL bStringResult)
103 {
104 SNMP_Transport *pTransport;
105 SNMP_PDU *pRqPDU, *pRespPDU;
106 DWORD dwNameLen, pdwVarName[MAX_OID_LEN], dwResult;
107
108 // Open SNMP session
109 pTransport = new SNMP_Transport;
110 dwResult = pTransport->CreateUDPTransport(NULL, htonl(dwAddr), wPort);
111 if (dwResult != SNMP_ERR_SUCCESS)
112 {
113 WriteLog(MSG_SNMP_TRANSPORT_FAILED, EVENTLOG_ERROR_TYPE, NULL);
114 }
115 else
116 {
117 // Create PDU and send request
118 pRqPDU = new SNMP_PDU(SNMP_GET_REQUEST, (char *)szCommunity, m_dwRequestId++, dwVersion);
119 if (szOidStr != NULL)
120 {
121 dwNameLen = SNMPParseOID(szOidStr, pdwVarName, MAX_OID_LEN);
122 if (dwNameLen == 0)
123 {
124 WriteLog(MSG_OID_PARSE_ERROR, EVENTLOG_ERROR_TYPE, "s", szOidStr);
125 dwResult = SNMP_ERR_BAD_OID;
126 }
127 }
128 else
129 {
130 memcpy(pdwVarName, oidBinary, dwOidLen * sizeof(DWORD));
131 dwNameLen = dwOidLen;
132 }
133
134 if (dwResult == SNMP_ERR_SUCCESS) // Still no errors
135 {
136 pRqPDU->BindVariable(new SNMP_Variable(pdwVarName, dwNameLen));
137 dwResult = pTransport->DoRequest(pRqPDU, &pRespPDU, 1000, 3);
138
139 // Analyze response
140 if (dwResult == SNMP_ERR_SUCCESS)
141 {
142 if ((pRespPDU->GetNumVariables() > 0) &&
143 (pRespPDU->GetErrorCode() == SNMP_PDU_ERR_SUCCESS))
144 {
145 SNMP_Variable *pVar = pRespPDU->GetVariable(0);
146
147 if ((pVar->GetType() != ASN_NO_SUCH_OBJECT) &&
148 (pVar->GetType() != ASN_NO_SUCH_INSTANCE))
149 {
150 if (bStringResult)
151 {
152 pVar->GetValueAsString((TCHAR *)pValue, dwBufferSize);
153 }
154 else
155 {
156 switch(pVar->GetType())
157 {
158 case ASN_INTEGER:
159 case ASN_UINTEGER32:
160 case ASN_COUNTER32:
161 case ASN_GAUGE32:
162 case ASN_TIMETICKS:
163 *((long *)pValue) = pVar->GetValueAsInt();
164 break;
165 case ASN_IP_ADDR:
166 *((long *)pValue) = ntohl(pVar->GetValueAsUInt());
167 break;
168 case ASN_OCTET_STRING:
169 pVar->GetValueAsString((TCHAR *)pValue, dwBufferSize);
170 break;
171 case ASN_OBJECT_ID:
172 pVar->GetValueAsString((TCHAR *)pValue, dwBufferSize);
173 break;
174 default:
175 WriteLog(MSG_SNMP_UNKNOWN_TYPE, EVENTLOG_ERROR_TYPE, "x", pVar->GetType());
176 dwResult = SNMP_ERR_BAD_TYPE;
177 break;
178 }
179 }
180 }
181 else
182 {
183 dwResult = SNMP_ERR_NO_OBJECT;
184 }
185 }
186 else
187 {
188 if (pRespPDU->GetErrorCode() == SNMP_PDU_ERR_NO_SUCH_NAME)
189 dwResult = SNMP_ERR_NO_OBJECT;
190 else
191 dwResult = SNMP_ERR_AGENT;
192 }
193 delete pRespPDU;
194 }
195 else
196 {
197 if (bVerbose)
198 WriteLog(MSG_SNMP_GET_ERROR, EVENTLOG_ERROR_TYPE, "d", dwResult);
199 }
200 }
201
202 delete pRqPDU;
203 }
204
205 delete pTransport;
206 return dwResult;
207 }
208
209
210 //
211 // Enumerate multiple values by walking throgh MIB, starting at given root
212 //
213
214 DWORD SnmpEnumerate(DWORD dwVersion, DWORD dwAddr, WORD wPort, const char *szCommunity,
215 const char *szRootOid,
216 void (* pHandler)(DWORD, DWORD, WORD, const char *, SNMP_Variable *, void *),
217 void *pUserArg, BOOL bVerbose)
218 {
219 DWORD pdwRootName[MAX_OID_LEN], dwRootLen, pdwName[MAX_OID_LEN], dwNameLen, dwResult;
220 SNMP_PDU *pRqPDU, *pRespPDU;
221 SNMP_Transport *pTransport;
222 BOOL bRunning = TRUE;
223
224 // Open SNMP session
225 pTransport = new SNMP_Transport;
226 dwResult = pTransport->CreateUDPTransport(NULL, htonl(dwAddr), wPort);
227 if (dwResult != SNMP_ERR_SUCCESS)
228 {
229 WriteLog(MSG_SNMP_TRANSPORT_FAILED, EVENTLOG_ERROR_TYPE, NULL);
230 }
231 else
232 {
233 // Get root
234 dwRootLen = SNMPParseOID(szRootOid, pdwRootName, MAX_OID_LEN);
235 if (dwRootLen == 0)
236 {
237 WriteLog(MSG_OID_PARSE_ERROR, EVENTLOG_ERROR_TYPE, "s", szRootOid);
238 dwResult = SNMP_ERR_BAD_OID;
239 }
240 else
241 {
242 memcpy(pdwName, pdwRootName, dwRootLen * sizeof(DWORD));
243 dwNameLen = dwRootLen;
244
245 // Walk the MIB
246 while(bRunning)
247 {
248 pRqPDU = new SNMP_PDU(SNMP_GET_NEXT_REQUEST, (char *)szCommunity, m_dwRequestId++, dwVersion);
249 pRqPDU->BindVariable(new SNMP_Variable(pdwName, dwNameLen));
250 dwResult = pTransport->DoRequest(pRqPDU, &pRespPDU, 1000, 3);
251
252 // Analyze response
253 if (dwResult == SNMP_ERR_SUCCESS)
254 {
255 if ((pRespPDU->GetNumVariables() > 0) &&
256 (pRespPDU->GetErrorCode() == SNMP_PDU_ERR_SUCCESS))
257 {
258 SNMP_Variable *pVar = pRespPDU->GetVariable(0);
259
260 if ((pVar->GetType() != ASN_NO_SUCH_OBJECT) &&
261 (pVar->GetType() != ASN_NO_SUCH_INSTANCE))
262 {
263 // Should we stop walking?
264 if ((pVar->GetName()->Length() < dwRootLen) ||
265 (memcmp(pdwRootName, pVar->GetName()->GetValue(), dwRootLen * sizeof(DWORD))))
266 {
267 bRunning = FALSE;
268 delete pRespPDU;
269 delete pRqPDU;
270 break;
271 }
272 memcpy(pdwName, pVar->GetName()->GetValue(),
273 pVar->GetName()->Length() * sizeof(DWORD));
274 dwNameLen = pVar->GetName()->Length();
275
276 // Call user's callback function for processing
277 pHandler(dwVersion, dwAddr, wPort, szCommunity, pVar, pUserArg);
278 }
279 else
280 {
281 dwResult = SNMP_ERR_NO_OBJECT;
282 bRunning = FALSE;
283 }
284 }
285 else
286 {
287 if (pRespPDU->GetErrorCode() == SNMP_PDU_ERR_NO_SUCH_NAME)
288 dwResult = SNMP_ERR_NO_OBJECT;
289 else
290 dwResult = SNMP_ERR_AGENT;
291 bRunning = FALSE;
292 }
293 delete pRespPDU;
294 }
295 else
296 {
297 if (bVerbose)
298 WriteLog(MSG_SNMP_GET_ERROR, EVENTLOG_ERROR_TYPE, "d", dwResult);
299 bRunning = FALSE;
300 }
301 delete pRqPDU;
302 }
303 }
304 }
305
306 delete pTransport;
307 return dwResult;
308 }
309
310
311 //
312 // Handler for enumerating indexes
313 //
314
315 static void HandlerIndex(DWORD dwVersion, DWORD dwAddr, WORD wPort, const char *szCommunity,
316 SNMP_Variable *pVar, void *pArg)
317 {
318 if (((INTERFACE_LIST *)pArg)->iEnumPos < ((INTERFACE_LIST *)pArg)->iNumEntries)
319 ((INTERFACE_LIST *)pArg)->pInterfaces[((INTERFACE_LIST *)pArg)->iEnumPos].dwIndex = pVar->GetValueAsUInt();
320 ((INTERFACE_LIST *)pArg)->iEnumPos++;
321 }
322
323
324 //
325 // Handler for enumerating IP addresses
326 //
327
328 static void HandlerIpAddr(DWORD dwVersion, DWORD dwAddr, WORD wPort,
329 const char *szCommunity, SNMP_Variable *pVar, void *pArg)
330 {
331 DWORD dwIndex, dwNetMask, dwNameLen;
332 DWORD oidName[MAX_OID_LEN];
333
334 dwNameLen = pVar->GetName()->Length();
335 memcpy(oidName, pVar->GetName()->GetValue(), dwNameLen * sizeof(DWORD));
336 oidName[dwNameLen - 5] = 3; // Retrieve network mask for this IP
337 if (SnmpGet(dwVersion, dwAddr, wPort, szCommunity, NULL, oidName, dwNameLen,
338 &dwNetMask, sizeof(DWORD), FALSE, FALSE) != SNMP_ERR_SUCCESS)
339 return;
340
341 oidName[dwNameLen - 5] = 2; // Retrieve interface index for this IP
342 if (SnmpGet(dwVersion, dwAddr, wPort, szCommunity, NULL, oidName, dwNameLen,
343 &dwIndex, sizeof(DWORD), FALSE, FALSE) == SNMP_ERR_SUCCESS)
344 {
345 int i;
346
347 for(i = 0; i < ((INTERFACE_LIST *)pArg)->iNumEntries; i++)
348 if (((INTERFACE_LIST *)pArg)->pInterfaces[i].dwIndex == dwIndex)
349 {
350 if (((INTERFACE_LIST *)pArg)->pInterfaces[i].dwIpAddr != 0)
351 {
352 // This interface entry already filled, so we have additional IP addresses
353 // on a single interface
354 ((INTERFACE_LIST *)pArg)->iNumEntries++;
355 ((INTERFACE_LIST *)pArg)->pInterfaces = (INTERFACE_INFO *)realloc(((INTERFACE_LIST *)pArg)->pInterfaces,
356 sizeof(INTERFACE_INFO) * ((INTERFACE_LIST *)pArg)->iNumEntries);
357 memcpy(&(((INTERFACE_LIST *)pArg)->pInterfaces[((INTERFACE_LIST *)pArg)->iNumEntries - 1]),
358 &(((INTERFACE_LIST *)pArg)->pInterfaces[i]), sizeof(INTERFACE_INFO));
359 if (strlen(((INTERFACE_LIST *)pArg)->pInterfaces[i].szName) < MAX_OBJECT_NAME - 4)
360 {
361 char szBuffer[8];
362
363 sprintf(szBuffer,":%d", ((INTERFACE_LIST *)pArg)->pInterfaces[i].iNumSecondary++);
364 strcat(((INTERFACE_LIST *)pArg)->pInterfaces[((INTERFACE_LIST *)pArg)->iNumEntries - 1].szName, szBuffer);
365 }
366 i = ((INTERFACE_LIST *)pArg)->iNumEntries - 1;
367 }
368 ((INTERFACE_LIST *)pArg)->pInterfaces[i].dwIpAddr = ntohl(pVar->GetValueAsUInt());
369 ((INTERFACE_LIST *)pArg)->pInterfaces[i].dwIpNetMask = dwNetMask;
370 break;
371 }
372 }
373 }
374
375
376 //
377 // Get interface list via SNMP
378 //
379
380 INTERFACE_LIST *SnmpGetInterfaceList(DWORD dwVersion, DWORD dwAddr, WORD wPort,
381 const char *szCommunity, DWORD dwNodeType)
382 {
383 long i, iNumIf;
384 char szOid[128], szBuffer[256];
385 INTERFACE_LIST *pIfList = NULL;
386 BOOL bSuccess = FALSE;
387
388 // Get number of interfaces
389 if (SnmpGet(dwVersion, dwAddr, wPort, szCommunity, ".1.3.6.1.2.1.2.1.0", NULL, 0,
390 &iNumIf, sizeof(long), FALSE, FALSE) != SNMP_ERR_SUCCESS)
391 return NULL;
392
393 // Create empty list
394 pIfList = (INTERFACE_LIST *)malloc(sizeof(INTERFACE_LIST));
395 pIfList->iNumEntries = iNumIf;
396 pIfList->iEnumPos = 0;
397 pIfList->pInterfaces = (INTERFACE_INFO *)malloc(sizeof(INTERFACE_INFO) * iNumIf);
398 memset(pIfList->pInterfaces, 0, sizeof(INTERFACE_INFO) * pIfList->iNumEntries);
399
400 // Gather interface indexes
401 if (SnmpEnumerate(dwVersion, dwAddr, wPort, szCommunity, ".1.3.6.1.2.1.2.2.1.1",
402 HandlerIndex, pIfList, FALSE) == SNMP_ERR_SUCCESS)
403 {
404 // Enumerate interfaces
405 for(i = 0; i < iNumIf; i++)
406 {
407 // Interface name
408 sprintf(szOid, ".1.3.6.1.2.1.2.2.1.2.%d", pIfList->pInterfaces[i].dwIndex);
409 if (SnmpGet(dwVersion, dwAddr, wPort, szCommunity, szOid, NULL, 0,
410 pIfList->pInterfaces[i].szName, MAX_OBJECT_NAME,
411 FALSE, FALSE) != SNMP_ERR_SUCCESS)
412 break;
413
414 // Interface type
415 sprintf(szOid, ".1.3.6.1.2.1.2.2.1.3.%d", pIfList->pInterfaces[i].dwIndex);
416 if (SnmpGet(dwVersion, dwAddr, wPort, szCommunity, szOid, NULL, 0,
417 &pIfList->pInterfaces[i].dwType, sizeof(DWORD),
418 FALSE, FALSE) != SNMP_ERR_SUCCESS)
419 break;
420
421 // MAC address
422 sprintf(szOid, ".1.3.6.1.2.1.2.2.1.6.%d", pIfList->pInterfaces[i].dwIndex);
423 memset(szBuffer, 0, MAC_ADDR_LENGTH);
424 if (SnmpGet(dwVersion, dwAddr, wPort, szCommunity, szOid, NULL, 0,
425 szBuffer, 256, FALSE, TRUE) != SNMP_ERR_SUCCESS)
426 break;
427 memcpy(pIfList->pInterfaces[i].bMacAddr, szBuffer, MAC_ADDR_LENGTH);
428 }
429
430 if (i == iNumIf)
431 {
432 // Interface IP address'es and netmasks
433 if (SnmpEnumerate(dwVersion, dwAddr, wPort, szCommunity, ".1.3.6.1.2.1.4.20.1.1",
434 HandlerIpAddr, pIfList, FALSE) == SNMP_ERR_SUCCESS)
435 {
436 // Handle special cases
437 if (dwNodeType == NODE_TYPE_NORTEL_ACCELAR)
438 GetAccelarVLANIfList(dwVersion, dwAddr, wPort, szCommunity, pIfList);
439 bSuccess = TRUE;
440 }
441 }
442 }
443
444 if (bSuccess)
445 {
446 CleanInterfaceList(pIfList);
447 }
448 else
449 {
450 DestroyInterfaceList(pIfList);
451 pIfList = NULL;
452 }
453
454 return pIfList;
455 }
456
457
458 //
459 // Handler for ARP enumeration
460 //
461
462 static void HandlerArp(DWORD dwVersion, DWORD dwAddr, WORD wPort, const char *szCommunity,
463 SNMP_Variable *pVar, void *pArg)
464 {
465 DWORD oidName[MAX_OID_LEN], dwNameLen, dwIndex = 0;
466 BYTE bMac[64];
467
468 dwNameLen = pVar->GetName()->Length();
469 memcpy(oidName, pVar->GetName()->GetValue(), dwNameLen * sizeof(DWORD));
470
471 oidName[dwNameLen - 6] = 1; // Retrieve interface index
472 SnmpGet(dwVersion, dwAddr, wPort, szCommunity, NULL, oidName, dwNameLen, &dwIndex,
473 sizeof(DWORD), FALSE, FALSE);
474
475 oidName[dwNameLen - 6] = 2; // Retrieve MAC address for this IP
476 if (SnmpGet(dwVersion, dwAddr, wPort, szCommunity, NULL, oidName, dwNameLen, bMac,
477 64, FALSE, FALSE) == SNMP_ERR_SUCCESS)
478 {
479 ((ARP_CACHE *)pArg)->dwNumEntries++;
480 ((ARP_CACHE *)pArg)->pEntries = (ARP_ENTRY *)realloc(((ARP_CACHE *)pArg)->pEntries,
481 sizeof(ARP_ENTRY) * ((ARP_CACHE *)pArg)->dwNumEntries);
482 ((ARP_CACHE *)pArg)->pEntries[((ARP_CACHE *)pArg)->dwNumEntries - 1].dwIpAddr = ntohl(pVar->GetValueAsUInt());
483 memcpy(((ARP_CACHE *)pArg)->pEntries[((ARP_CACHE *)pArg)->dwNumEntries - 1].bMacAddr, bMac, 6);
484 ((ARP_CACHE *)pArg)->pEntries[((ARP_CACHE *)pArg)->dwNumEntries - 1].dwIndex = dwIndex;
485 }
486 }
487
488
489 //
490 // Get ARP cache via SNMP
491 //
492
493 ARP_CACHE *SnmpGetArpCache(DWORD dwVersion, DWORD dwAddr, WORD wPort, const char *szCommunity)
494 {
495 ARP_CACHE *pArpCache;
496
497 pArpCache = (ARP_CACHE *)malloc(sizeof(ARP_CACHE));
498 if (pArpCache == NULL)
499 return NULL;
500
501 pArpCache->dwNumEntries = 0;
502 pArpCache->pEntries = NULL;
503
504 if (SnmpEnumerate(dwVersion, dwAddr, wPort, szCommunity, ".1.3.6.1.2.1.4.22.1.3",
505 HandlerArp, pArpCache, FALSE) != SNMP_ERR_SUCCESS)
506 {
507 DestroyArpCache(pArpCache);
508 pArpCache = NULL;
509 }
510 return pArpCache;
511 }
512
513
514 //
515 // Get interface status via SNMP
516 // Possible return values can be NORMAL, CRITICAL, DISABLED, TESTING and UNKNOWN
517 //
518
519 int SnmpGetInterfaceStatus(DWORD dwVersion, DWORD dwNodeAddr, WORD wPort,
520 char *pszCommunity, DWORD dwIfIndex)
521 {
522 DWORD dwAdminStatus = 0, dwOperStatus = 0;
523 int iStatus;
524 char szOid[256];
525
526 // Interface administrative status
527 sprintf(szOid, ".1.3.6.1.2.1.2.2.1.7.%ld", dwIfIndex);
528 SnmpGet(dwVersion, dwNodeAddr, wPort, pszCommunity, szOid, NULL, 0,
529 &dwAdminStatus, sizeof(DWORD), FALSE, FALSE);
530
531 switch(dwAdminStatus)
532 {
533 case 3:
534 iStatus = STATUS_TESTING;
535 break;
536 case 2:
537 iStatus = STATUS_DISABLED;
538 break;
539 case 1: // Interface administratively up, check operational status
540 // Get interface operational status
541 sprintf(szOid, ".1.3.6.1.2.1.2.2.1.8.%ld", dwIfIndex);
542 SnmpGet(dwVersion, dwNodeAddr, wPort, pszCommunity, szOid, NULL, 0,
543 &dwOperStatus, sizeof(DWORD), FALSE, FALSE);
544 switch(dwOperStatus)
545 {
546 case 3:
547 iStatus = STATUS_TESTING;
548 break;
549 case 2: // Interface is down
550 iStatus = STATUS_CRITICAL;
551 break;
552 case 1:
553 iStatus = STATUS_NORMAL;
554 break;
555 default:
556 iStatus = STATUS_UNKNOWN;
557 break;
558 }
559 break;
560 default:
561 iStatus = STATUS_UNKNOWN;
562 break;
563 }
564 return iStatus;
565 }
566
567
568 //
569 // Handler for route enumeration
570 //
571
572 static void HandlerRoute(DWORD dwVersion, DWORD dwAddr, WORD wPort,
573 const char *szCommunity, SNMP_Variable *pVar, void *pArg)
574 {
575 DWORD oidName[MAX_OID_LEN], dwNameLen;
576 ROUTE route;
577
578 dwNameLen = pVar->GetName()->Length();
579 memcpy(oidName, pVar->GetName()->GetValue(), dwNameLen * sizeof(DWORD));
580 route.dwDestAddr = ntohl(pVar->GetValueAsUInt());
581
582 oidName[dwNameLen - 5] = 2; // Interface index
583 if (SnmpGet(dwVersion, dwAddr, wPort, szCommunity, NULL, oidName, dwNameLen,
584 &route.dwIfIndex, sizeof(DWORD), FALSE, FALSE) != SNMP_ERR_SUCCESS)
585 return;
586
587 oidName[dwNameLen - 5] = 7; // Next hop
588 if (SnmpGet(dwVersion, dwAddr, wPort, szCommunity, NULL, oidName, dwNameLen,
589 &route.dwNextHop, sizeof(DWORD), FALSE, FALSE) != SNMP_ERR_SUCCESS)
590 return;
591
592 oidName[dwNameLen - 5] = 8; // Route type
593 if (SnmpGet(dwVersion, dwAddr, wPort, szCommunity, NULL, oidName, dwNameLen,
594 &route.dwRouteType, sizeof(DWORD), FALSE, FALSE) != SNMP_ERR_SUCCESS)
595 return;
596
597 oidName[dwNameLen - 5] = 11; // Destination mask
598 if (SnmpGet(dwVersion, dwAddr, wPort, szCommunity, NULL, oidName, dwNameLen,
599 &route.dwDestMask, sizeof(DWORD), FALSE, FALSE) != SNMP_ERR_SUCCESS)
600 return;
601
602 ((ROUTING_TABLE *)pArg)->iNumEntries++;
603 ((ROUTING_TABLE *)pArg)->pRoutes =
604 (ROUTE *)realloc(((ROUTING_TABLE *)pArg)->pRoutes,
605 sizeof(ROUTE) * ((ROUTING_TABLE *)pArg)->iNumEntries);
606 memcpy(&((ROUTING_TABLE *)pArg)->pRoutes[((ROUTING_TABLE *)pArg)->iNumEntries - 1],
607 &route, sizeof(ROUTE));
608 }
609
610
611 //
612 // Get routing table via SNMP
613 //
614
615 ROUTING_TABLE *SnmpGetRoutingTable(DWORD dwVersion, DWORD dwAddr, WORD wPort,
616 const char *szCommunity)
617 {
618 ROUTING_TABLE *pRT;
619
620 pRT = (ROUTING_TABLE *)malloc(sizeof(ROUTING_TABLE));
621 if (pRT == NULL)
622 return NULL;
623
624 pRT->iNumEntries = 0;
625 pRT->pRoutes = NULL;
626
627 if (SnmpEnumerate(dwVersion, dwAddr, wPort, szCommunity, ".1.3.6.1.2.1.4.21.1.1",
628 HandlerRoute, pRT, FALSE) != SNMP_ERR_SUCCESS)
629 {
630 DestroyRoutingTable(pRT);
631 pRT = NULL;
632 }
633 return pRT;
634 }