intermediate commit
[public/netxms.git] / src / server / libnxsrv / ndd.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2011 Victor Kirhenshtein
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU Lesser General Public License as published by
7 ** the Free Software Foundation; either version 3 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 Lesser 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: ndd.cpp
20 **/
21
22 #include "libnxsrv.h"
23 #include <nddrv.h>
24
25
26 /**
27 * Constructor
28 */
29 NetworkDeviceDriver::NetworkDeviceDriver()
30 {
31 }
32
33 /**
34 * Destructor
35 */
36 NetworkDeviceDriver::~NetworkDeviceDriver()
37 {
38 }
39
40 /**
41 * Get driver name
42 */
43 const TCHAR *NetworkDeviceDriver::getName()
44 {
45 return _T("GENERIC");
46 }
47
48 /**
49 * Get driver version
50 */
51 const TCHAR *NetworkDeviceDriver::getVersion()
52 {
53 return NETXMS_VERSION_STRING;
54 }
55
56 /**
57 * Check if given device can be potentially supported by driver
58 *
59 * @param oid Device OID
60 */
61 int NetworkDeviceDriver::isPotentialDevice(const TCHAR *oid)
62 {
63 return 1;
64 }
65
66 /**
67 * Check if given device is supported by driver
68 *
69 * @param snmp SNMP transport
70 * @param oid Device OID
71 */
72 bool NetworkDeviceDriver::isDeviceSupported(SNMP_Transport *snmp, const TCHAR *oid)
73 {
74 return true;
75 }
76
77 /**
78 * Do additional checks on the device required by driver.
79 * Driver can set device's custom attributes from within
80 * this function.
81 *
82 * @param snmp SNMP transport
83 * @param attributes Node's custom attributes
84 */
85 void NetworkDeviceDriver::analyzeDevice(SNMP_Transport *snmp, const TCHAR *oid, StringMap *attributes)
86 {
87 }
88
89 //
90 // Handler for enumerating indexes
91 //
92
93 static DWORD HandlerIndex(DWORD dwVersion, SNMP_Variable *pVar, SNMP_Transport *pTransport, void *pArg)
94 {
95 NX_INTERFACE_INFO info;
96 memset(&info, 0, sizeof(NX_INTERFACE_INFO));
97 info.dwIndex = pVar->GetValueAsUInt();
98 ((InterfaceList *)pArg)->add(&info);
99 return SNMP_ERR_SUCCESS;
100 }
101
102
103 //
104 // Handler for enumerating IP addresses
105 //
106
107 static DWORD HandlerIpAddr(DWORD dwVersion, SNMP_Variable *pVar, SNMP_Transport *pTransport, void *pArg)
108 {
109 DWORD dwIndex, dwNetMask, dwNameLen, dwResult;
110 DWORD oidName[MAX_OID_LEN];
111
112 dwNameLen = pVar->GetName()->getLength();
113 memcpy(oidName, pVar->GetName()->getValue(), dwNameLen * sizeof(DWORD));
114 oidName[dwNameLen - 5] = 3; // Retrieve network mask for this IP
115 dwResult = SnmpGet(dwVersion, pTransport, NULL, oidName, dwNameLen, &dwNetMask, sizeof(DWORD), 0);
116 if (dwResult != SNMP_ERR_SUCCESS)
117 {
118 TCHAR buffer[1024];
119 DbgPrintf(6, _T("NetworkDeviceDriver::getInterfaces(%p): SNMP GET %s failed (error %d)"),
120 pTransport, SNMPConvertOIDToText(dwNameLen, oidName, buffer, 1024), (int)dwResult);
121 // Continue walk even if we get error for some IP address
122 // For example, some Cisco ASA versions reports IP when walking, but does not
123 // allow to SNMP GET appropriate entry
124 return SNMP_ERR_SUCCESS;
125 }
126
127 oidName[dwNameLen - 5] = 2; // Retrieve interface index for this IP
128 dwResult = SnmpGet(dwVersion, pTransport, NULL, oidName, dwNameLen, &dwIndex, sizeof(DWORD), 0);
129 if (dwResult == SNMP_ERR_SUCCESS)
130 {
131 InterfaceList *ifList = (InterfaceList *)pArg;
132
133 for(int i = 0; i < ifList->getSize(); i++)
134 {
135 if (ifList->get(i)->dwIndex == dwIndex)
136 {
137 if (ifList->get(i)->dwIpAddr != 0)
138 {
139 // This interface entry already filled, so we have additional IP addresses
140 // on a single interface
141 NX_INTERFACE_INFO iface;
142 memcpy(&iface, ifList->get(i), sizeof(NX_INTERFACE_INFO));
143 iface.dwIpAddr = ntohl(pVar->GetValueAsUInt());
144 iface.dwIpNetMask = dwNetMask;
145 ifList->add(&iface);
146 }
147 else
148 {
149 ifList->get(i)->dwIpAddr = ntohl(pVar->GetValueAsUInt());
150 ifList->get(i)->dwIpNetMask = dwNetMask;
151 }
152 break;
153 }
154 }
155 }
156 else
157 {
158 TCHAR buffer[1024];
159 DbgPrintf(6, _T("NetworkDeviceDriver::getInterfaces(%p): SNMP GET %s failed (error %d)"),
160 pTransport, SNMPConvertOIDToText(dwNameLen, oidName, buffer, 1024), (int)dwResult);
161 dwResult = SNMP_ERR_SUCCESS; // continue walk
162 }
163 return dwResult;
164 }
165
166 /**
167 * Get list of interfaces for given node
168 *
169 * @param snmp SNMP transport
170 * @param attributes Node's custom attributes
171 * @param useAliases policy for interface alias usage
172 * @param useIfXTable if true, usage of ifXTable is allowed
173 */
174 InterfaceList *NetworkDeviceDriver::getInterfaces(SNMP_Transport *snmp, StringMap *attributes, int useAliases, bool useIfXTable)
175 {
176 LONG i, iNumIf;
177 TCHAR szOid[128], szBuffer[256];
178 InterfaceList *pIfList = NULL;
179 BOOL bSuccess = FALSE;
180
181 DbgPrintf(6, _T("NetworkDeviceDriver::getInterfaces(%p,%d,%s)"), snmp, useAliases, useIfXTable ? _T("true") : _T("false"));
182
183 // Get number of interfaces
184 if (SnmpGet(snmp->getSnmpVersion(), snmp, _T(".1.3.6.1.2.1.2.1.0"), NULL, 0,
185 &iNumIf, sizeof(LONG), 0) != SNMP_ERR_SUCCESS)
186 {
187 DbgPrintf(6, _T("NetworkDeviceDriver::getInterfaces(%p): SNMP GET .1.3.6.1.2.1.2.1.0 failed"), snmp);
188 return NULL;
189 }
190
191 // Some devices may return completely insane values here
192 // (for example, DLink DGS-3612 can return negative value)
193 // Anyway it's just a hint for initial array size
194 if ((iNumIf <= 0) || (iNumIf > 4096))
195 iNumIf = 64;
196
197 // Create empty list
198 pIfList = new InterfaceList(iNumIf);
199
200 // Gather interface indexes
201 if (SnmpEnumerate(snmp->getSnmpVersion(), snmp, _T(".1.3.6.1.2.1.2.2.1.1"), HandlerIndex, pIfList, FALSE) == SNMP_ERR_SUCCESS)
202 {
203 // Enumerate interfaces
204 for(i = 0; i < pIfList->getSize(); i++)
205 {
206 NX_INTERFACE_INFO *iface = pIfList->get(i);
207
208 // Get interface description
209 _sntprintf(szOid, 128, _T(".1.3.6.1.2.1.2.2.1.2.%d"), iface->dwIndex);
210 if (SnmpGet(snmp->getSnmpVersion(), snmp, szOid, NULL, 0, iface->szDescription, MAX_DB_STRING, 0) != SNMP_ERR_SUCCESS)
211 break;
212
213 // Get interface alias if needed
214 if (useAliases > 0)
215 {
216 _sntprintf(szOid, 128, _T(".1.3.6.1.2.1.31.1.1.1.18.%d"), iface->dwIndex);
217 if (SnmpGet(snmp->getSnmpVersion(), snmp, szOid, NULL, 0,
218 iface->szName, MAX_DB_STRING, 0) != SNMP_ERR_SUCCESS)
219 {
220 iface->szName[0] = 0; // It's not an error if we cannot get interface alias
221 }
222 else
223 {
224 StrStrip(iface->szName);
225 }
226 }
227
228 // Try to get interface name from ifXTable, if unsuccessful or disabled, use ifDescr from ifTable
229 _sntprintf(szOid, 128, _T(".1.3.6.1.2.1.31.1.1.1.1.%d"), iface->dwIndex);
230 if (!useIfXTable ||
231 (SnmpGet(snmp->getSnmpVersion(), snmp, szOid, NULL, 0, szBuffer, 256, 0) != SNMP_ERR_SUCCESS))
232 {
233 nx_strncpy(szBuffer, iface->szDescription, 256);
234 }
235
236 // Build full interface object name
237 switch(useAliases)
238 {
239 case 1: // Use only alias if available, otherwise name
240 if (iface->szName[0] == 0)
241 nx_strncpy(iface->szName, szBuffer, MAX_DB_STRING); // Alias is empty or not available
242 break;
243 case 2: // Concatenate alias with name
244 case 3: // Concatenate name with alias
245 if (iface->szName[0] != 0)
246 {
247 if (useAliases == 2)
248 {
249 if (_tcslen(iface->szName) < (MAX_DB_STRING - 3))
250 {
251 _sntprintf(&iface->szName[_tcslen(iface->szName)], MAX_DB_STRING - _tcslen(iface->szName), _T(" (%s)"), szBuffer);
252 iface->szName[MAX_DB_STRING - 1] = 0;
253 }
254 }
255 else
256 {
257 TCHAR temp[MAX_DB_STRING];
258
259 _tcscpy(temp, iface->szName);
260 nx_strncpy(iface->szName, szBuffer, MAX_DB_STRING);
261 if (_tcslen(iface->szName) < (MAX_DB_STRING - 3))
262 {
263 _sntprintf(&iface->szName[_tcslen(iface->szName)], MAX_DB_STRING - _tcslen(iface->szName), _T(" (%s)"), temp);
264 iface->szName[MAX_DB_STRING - 1] = 0;
265 }
266 }
267 }
268 else
269 {
270 nx_strncpy(iface->szName, szBuffer, MAX_DB_STRING); // Alias is empty or not available
271 }
272 break;
273 default: // Use only name
274 nx_strncpy(iface->szName, szBuffer, MAX_DB_STRING);
275 break;
276 }
277
278 // Interface type
279 _sntprintf(szOid, 128, _T(".1.3.6.1.2.1.2.2.1.3.%d"), iface->dwIndex);
280 if (SnmpGet(snmp->getSnmpVersion(), snmp, szOid, NULL, 0,
281 &iface->dwType, sizeof(DWORD), 0) != SNMP_ERR_SUCCESS)
282 {
283 iface->dwType = IFTYPE_OTHER;
284 }
285
286 // MAC address
287 _sntprintf(szOid, 128, _T(".1.3.6.1.2.1.2.2.1.6.%d"), iface->dwIndex);
288 memset(szBuffer, 0, MAC_ADDR_LENGTH);
289 if (SnmpGet(snmp->getSnmpVersion(), snmp, szOid, NULL, 0, szBuffer, 256, SG_RAW_RESULT) == SNMP_ERR_SUCCESS)
290 {
291 memcpy(iface->bMacAddr, szBuffer, MAC_ADDR_LENGTH);
292 }
293 else
294 {
295 // Unable to get MAC address
296 memset(iface->bMacAddr, 0, MAC_ADDR_LENGTH);
297 }
298 }
299
300 // Interface IP address'es and netmasks
301 if (SnmpEnumerate(snmp->getSnmpVersion(), snmp, _T(".1.3.6.1.2.1.4.20.1.1"),
302 HandlerIpAddr, pIfList, FALSE) == SNMP_ERR_SUCCESS)
303 {
304 bSuccess = TRUE;
305 }
306 else
307 {
308 DbgPrintf(6, _T("NetworkDeviceDriver::getInterfaces(%p): SNMP WALK .1.3.6.1.2.1.4.20.1.1 failed"), snmp);
309 }
310 }
311 else
312 {
313 DbgPrintf(6, _T("NetworkDeviceDriver::getInterfaces(%p): SNMP WALK .1.3.6.1.2.1.2.2.1.1 failed"), snmp);
314 }
315
316 if (!bSuccess)
317 {
318 delete_and_null(pIfList);
319 }
320
321 DbgPrintf(6, _T("NetworkDeviceDriver::getInterfaces(%p): completed, ifList=%p"), snmp, pIfList);
322 return pIfList;
323 }
324
325 /**
326 * Get list of VLANs on given node
327 *
328 * @param snmp SNMP transport
329 * @param attributes Node's custom attributes
330 * @return VLAN list or NULL
331 */
332 VlanList *NetworkDeviceDriver::getVlans(SNMP_Transport *snmp, StringMap *attributes)
333 {
334 return NULL;
335 }