Rollback from r3608 to r3606
[public/netxms.git] / src / server / core / np.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
3** Copyright (C) 2003, 2004, 2005, 2006 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: np.cpp
20**
21**/
22
23#include "nxcore.h"
24
25
26//
27// Externals
28//
29
30extern Queue g_nodePollerQueue;
31
32
33//
34// Discovery class
35//
36
37class NXSL_DiscoveryClass : public NXSL_Class
38{
39public:
40 NXSL_DiscoveryClass();
41
42 virtual NXSL_Value *GetAttr(NXSL_Object *pObject, char *pszAttr);
43};
44
45
46//
47// Implementation of discovery class
48//
49
50NXSL_DiscoveryClass::NXSL_DiscoveryClass()
51 :NXSL_Class()
52{
53 strcpy(m_szName, "NewNode");
54}
55
56NXSL_Value *NXSL_DiscoveryClass::GetAttr(NXSL_Object *pObject, char *pszAttr)
57{
58 DISCOVERY_FILTER_DATA *pData;
59 NXSL_Value *pValue = NULL;
60 char szBuffer[256];
61
62 pData = (DISCOVERY_FILTER_DATA *)pObject->Data();
63 if (!strcmp(pszAttr, "ipAddr"))
64 {
65 IpToStr(pData->dwIpAddr, szBuffer);
66 pValue = new NXSL_Value(szBuffer);
67 }
68 else if (!strcmp(pszAttr, "netMask"))
69 {
70 IpToStr(pData->dwNetMask, szBuffer);
71 pValue = new NXSL_Value(szBuffer);
72 }
73 else if (!strcmp(pszAttr, "subnet"))
74 {
75 IpToStr(pData->dwSubnetAddr, szBuffer);
76 pValue = new NXSL_Value(szBuffer);
77 }
78 else if (!strcmp(pszAttr, "isAgent"))
79 {
80 pValue = new NXSL_Value((LONG)((pData->dwFlags & NNF_IS_AGENT) ? 1 : 0));
81 }
82 else if (!strcmp(pszAttr, "isSNMP"))
83 {
84 pValue = new NXSL_Value((LONG)((pData->dwFlags & NNF_IS_SNMP) ? 1 : 0));
85 }
86 else if (!strcmp(pszAttr, "isBridge"))
87 {
88 pValue = new NXSL_Value((LONG)((pData->dwFlags & NNF_IS_BRIDGE) ? 1 : 0));
89 }
90 else if (!strcmp(pszAttr, "isRouter"))
91 {
92 pValue = new NXSL_Value((LONG)((pData->dwFlags & NNF_IS_ROUTER) ? 1 : 0));
93 }
94 else if (!strcmp(pszAttr, "isPrinter"))
95 {
96 pValue = new NXSL_Value((LONG)((pData->dwFlags & NNF_IS_PRINTER) ? 1 : 0));
97 }
98 else if (!strcmp(pszAttr, "isCDP"))
99 {
100 pValue = new NXSL_Value((LONG)((pData->dwFlags & NNF_IS_CDP) ? 1 : 0));
101 }
102 else if (!strcmp(pszAttr, "isSONMP"))
103 {
104 pValue = new NXSL_Value((LONG)((pData->dwFlags & NNF_IS_SONMP) ? 1 : 0));
105 }
106 else if (!strcmp(pszAttr, "isLLDP"))
107 {
108 pValue = new NXSL_Value((LONG)((pData->dwFlags & NNF_IS_LLDP) ? 1 : 0));
109 }
110 else if (!strcmp(pszAttr, "snmpVersion"))
111 {
112 pValue = new NXSL_Value((LONG)pData->nSNMPVersion);
113 }
114 else if (!strcmp(pszAttr, "snmpOID"))
115 {
116 pValue = new NXSL_Value(pData->szObjectId);
117 }
118 else if (!strcmp(pszAttr, "agentVersion"))
119 {
120 pValue = new NXSL_Value(pData->szAgentVersion);
121 }
122 else if (!strcmp(pszAttr, "platformName"))
123 {
124 pValue = new NXSL_Value(pData->szPlatform);
125 }
126 return pValue;
127}
128
129
130//
131// Discovery class object
132//
133
134static NXSL_DiscoveryClass m_nxslDiscoveryClass;
135
136
137//
138// Poll new node for configuration
139// Returns pointer to new node object on success or NULL on failure
140//
141
142NetObj *PollNewNode(DWORD dwIpAddr, DWORD dwNetMask, DWORD dwCreationFlags,
143 TCHAR *pszName, DWORD dwProxyNode, DWORD dwSNMPProxy,
144 Cluster *pCluster)
145{
146 Node *pNode;
147 char szIpAddr1[32], szIpAddr2[32];
148 DWORD dwFlags = 0;
149
150 DbgPrintf(4, "PollNode(%s,%s)",
151 IpToStr(dwIpAddr, szIpAddr1), IpToStr(dwNetMask, szIpAddr2));
152 // Check for node existence
153 if ((FindNodeByIP(dwIpAddr) != NULL) ||
154 (FindSubnetByIP(dwIpAddr) != NULL))
155 {
156 DbgPrintf(4, "PollNode: Node %s already exist in database",
157 IpToStr(dwIpAddr, szIpAddr1));
158 return NULL;
159 }
160
161 if (dwCreationFlags & NXC_NCF_DISABLE_ICMP)
162 dwFlags |= NF_DISABLE_ICMP;
163 if (dwCreationFlags & NXC_NCF_DISABLE_SNMP)
164 dwFlags |= NF_DISABLE_SNMP;
165 if (dwCreationFlags & NXC_NCF_DISABLE_NXCP)
166 dwFlags |= NF_DISABLE_NXCP;
167 pNode = new Node(dwIpAddr, dwFlags, dwProxyNode, dwSNMPProxy, 0);
168 NetObjInsert(pNode, TRUE);
169 if (pszName != NULL)
170 pNode->SetName(pszName);
171
172 // Bind node to cluster before first configuration poll
173 if (pCluster != NULL)
174 {
175 pCluster->AddChild(pNode);
176 pNode->AddParent(pCluster);
177 }
178
179 if (dwCreationFlags & NXC_NCF_CREATE_UNMANAGED)
180 {
181 pNode->SetMgmtStatus(FALSE);
182 }
183 else
184 {
185 pNode->ConfigurationPoll(NULL, 0, -1, dwNetMask);
186 }
187 pNode->Unhide();
188 PostEvent(EVENT_NODE_ADDED, pNode->Id(), NULL);
189
190 // Add default DCIs
191 pNode->AddItem(new DCItem(CreateUniqueId(IDG_ITEM), _T("Status"), DS_INTERNAL, DCI_DT_INT, 60, 30, pNode));
192 return pNode;
193}
194
195
196//
197// Check if newly discovered node should be added
198//
199
200static BOOL AcceptNewNode(DWORD dwIpAddr, DWORD dwNetMask)
201{
202 DISCOVERY_FILTER_DATA data;
203 char szCommunityString[MAX_DB_STRING], szFilter[MAX_DB_STRING], szBuffer[256], szIpAddr[16];
204 DWORD dwTemp;
205 AgentConnection *pAgentConn;
206 NXSL_Program *pScript;
207 NXSL_Value *pValue;
208 BOOL bResult = FALSE;
209 SNMP_UDPTransport *pTransport;
210
211 IpToStr(dwIpAddr, szIpAddr);
212 if ((FindNodeByIP(dwIpAddr) != NULL) ||
213 (FindSubnetByIP(dwIpAddr) != NULL))
214 {
215 DbgPrintf(4, "AcceptNewNode(%s): node already exist in database", szIpAddr);
216 return FALSE; // Node already exist in database
217 }
218
219 // Read configuration
220 ConfigReadStr("DiscoveryFilter", szFilter, MAX_DB_STRING, "");
221 StrStrip(szFilter);
222
223 // Run filter script
224 if ((szFilter[0] == 0) || (!_tcsicmp(szFilter, "none")))
225 {
226 DbgPrintf(4, "AcceptNewNode(%s): no filtering, node accepted", szIpAddr);
227 return TRUE; // No filtering
228 }
229
230 // Initialize new node data
231 memset(&data, 0, sizeof(DISCOVERY_FILTER_DATA));
232 data.dwIpAddr = dwIpAddr;
233 data.dwNetMask = dwNetMask;
234 data.dwSubnetAddr = dwIpAddr & dwNetMask;
235
236 // Check SNMP support
237 DbgPrintf(4, "AcceptNewNode(%s): checking SNMP support", szIpAddr);
238 pTransport = new SNMP_UDPTransport;
239 pTransport->CreateUDPTransport(NULL, htonl(dwIpAddr), 161);
240 if (SnmpCheckCommSettings(pTransport, NULL, &data.nSNMPVersion, szCommunityString))
241 {
242 data.dwFlags |= NNF_IS_SNMP;
243 }
244
245 // Check NetXMS agent support
246 DbgPrintf(4, "AcceptNewNode(%s): checking NetXMS agent", szIpAddr);
247 pAgentConn = new AgentConnection(htonl(dwIpAddr), AGENT_LISTEN_PORT,
248 AUTH_NONE, "");
249 if (pAgentConn->Connect(g_pServerKey))
250 {
251 data.dwFlags |= NNF_IS_AGENT;
252 pAgentConn->GetParameter("Agent.Version", MAX_AGENT_VERSION_LEN, data.szAgentVersion);
253 pAgentConn->GetParameter("System.PlatformName", MAX_PLATFORM_NAME_LEN, data.szPlatform);
254 }
255
256 // Check if node is a router
257 if (data.dwFlags & NNF_IS_SNMP)
258 {
259 if (SnmpGet(data.nSNMPVersion, pTransport, szCommunityString,
260 ".1.3.6.1.2.1.4.1.0", NULL, 0, &dwTemp, sizeof(DWORD),
261 FALSE, FALSE) == SNMP_ERR_SUCCESS)
262 {
263 if (dwTemp == 1)
264 data.dwFlags |= NNF_IS_ROUTER;
265 }
266 }
267 else if (data.dwFlags & NNF_IS_AGENT)
268 {
269 // Check IP forwarding status
270 if (pAgentConn->GetParameter("Net.IP.Forwarding", 16, szBuffer) == ERR_SUCCESS)
271 {
272 if (_tcstoul(szBuffer, NULL, 10) != 0)
273 data.dwFlags |= NNF_IS_ROUTER;
274 }
275 }
276
277 // Check various SNMP device capabilities
278 if (data.dwFlags & NNF_IS_SNMP)
279 {
280 // Get SNMP OID
281 SnmpGet(data.nSNMPVersion, pTransport, szCommunityString,
282 ".1.3.6.1.2.1.1.2.0", NULL, 0, data.szObjectId, MAX_OID_LEN * 4,
283 FALSE, FALSE);
284
285 // Check if node is a bridge
286 if (SnmpGet(data.nSNMPVersion, pTransport, szCommunityString,
287 ".1.3.6.1.2.1.17.1.1.0", NULL, 0, szBuffer, 256,
288 FALSE, FALSE) == SNMP_ERR_SUCCESS)
289 {
290 data.dwFlags |= NNF_IS_BRIDGE;
291 }
292
293 // Check for CDP (Cisco Discovery Protocol) support
294 if (SnmpGet(data.nSNMPVersion, pTransport, szCommunityString,
295 ".1.3.6.1.4.1.9.9.23.1.3.1.0", NULL, 0, &dwTemp, sizeof(DWORD),
296 FALSE, FALSE) == SNMP_ERR_SUCCESS)
297 {
298 if (dwTemp == 1)
299 data.dwFlags |= NNF_IS_CDP;
300 }
301
302 // Check for SONMP (Nortel topology discovery protocol) support
303 if (SnmpGet(data.nSNMPVersion, pTransport, szCommunityString,
304 ".1.3.6.1.4.1.45.1.6.13.1.2.0", NULL, 0, &dwTemp, sizeof(DWORD),
305 FALSE, FALSE) == SNMP_ERR_SUCCESS)
306 {
307 if (dwTemp == 1)
308 data.dwFlags |= NNF_IS_SONMP;
309 }
310
311 // Check for LLDP (Link Layer Discovery Protocol) support
312 if (SnmpGet(data.nSNMPVersion, pTransport, szCommunityString,
313 ".1.0.8802.1.1.2.1.3.2.0", NULL, 0, szBuffer, 256,
314 FALSE, FALSE) == SNMP_ERR_SUCCESS)
315 {
316 data.dwFlags |= NNF_IS_LLDP;
317 }
318 }
319
320 // Cleanup
321 delete pAgentConn;
322 delete pTransport;
323
324 // Check if we use simple filter instead of script
325 if (!_tcsicmp(szFilter, "auto"))
326 {
327 DWORD dwFlags;
328 DB_RESULT hResult;
329 int i, nRows, nType;
330
331 dwFlags = ConfigReadULong(_T("DiscoveryFilterFlags"), DFF_ALLOW_AGENT | DFF_ALLOW_SNMP);
332 DbgPrintf(4, "AcceptNewNode(%s): auto filter, dwFlags=%04X", szIpAddr, dwFlags);
333
334 if ((dwFlags & (DFF_ALLOW_AGENT | DFF_ALLOW_SNMP)) == 0)
335 {
336 bResult = TRUE;
337 }
338 else
339 {
340 if (dwFlags & DFF_ALLOW_AGENT)
341 {
342 if (data.dwFlags & NNF_IS_AGENT)
343 bResult = TRUE;
344 }
345
346 if (dwFlags & DFF_ALLOW_SNMP)
347 {
348 if (data.dwFlags & NNF_IS_SNMP)
349 bResult = TRUE;
350 }
351 }
352
353 // Check range
354 if ((dwFlags & DFF_ONLY_RANGE) && bResult)
355 {
356 DbgPrintf(4, "AcceptNewNode(%s): auto filter - checking range", szIpAddr);
357 hResult = DBSelect(g_hCoreDB, _T("SELECT addr_type,addr1,addr2 FROM address_lists WHERE list_type=2"));
358 if (hResult != NULL)
359 {
360 nRows = DBGetNumRows(hResult);
361 for(i = 0, bResult = FALSE; (i < nRows) && (!bResult); i++)
362 {
363 nType = DBGetFieldLong(hResult, i, 0);
364 if (nType == 0)
365 {
366 // Subnet
367 bResult = (data.dwIpAddr & DBGetFieldIPAddr(hResult, i, 2)) == DBGetFieldIPAddr(hResult, i, 1);
368 }
369 else
370 {
371 // Range
372 bResult = ((data.dwIpAddr >= DBGetFieldIPAddr(hResult, i, 1)) &&
373 (data.dwIpAddr <= DBGetFieldIPAddr(hResult, i, 2)));
374 }
375 }
376 DBFreeResult(hResult);
377 }
378 }
379 DbgPrintf(4, "AcceptNewNode(%s): auto filter - bResult=%d", szIpAddr, bResult);
380 }
381 else
382 {
383 g_pScriptLibrary->Lock();
384 pScript = g_pScriptLibrary->FindScript(szFilter);
385 if (pScript != NULL)
386 {
387 DbgPrintf(4, "AcceptNewNode(%s): Running filter script %s", szIpAddr, szFilter);
388 pValue = new NXSL_Value(new NXSL_Object(&m_nxslDiscoveryClass, &data));
389 if (pScript->Run(NULL, 1, &pValue) == 0)
390 {
391 bResult = (pScript->GetResult()->GetValueAsInt32() != 0) ? TRUE : FALSE;
392 DbgPrintf(4, "AcceptNewNode(%s): Filter script result: %d", szIpAddr, bResult);
393 }
394 else
395 {
396 DbgPrintf(4, "AcceptNewNode(%s): Filter script execution error: %s",
397 szIpAddr, pScript->GetErrorText());
398 PostEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, _T("ssd"), szFilter,
399 pScript->GetErrorText(), 0);
400 }
401 }
402 else
403 {
404 DbgPrintf(4, "AcceptNewNode(%s): Cannot find filter script %s", szIpAddr, szFilter);
405 }
406 g_pScriptLibrary->Unlock();
407 }
408
409 return bResult;
410}
411
412
413//
414// Node poller thread (poll new nodes and put them into the database)
415//
416
417THREAD_RESULT THREAD_CALL NodePoller(void *arg)
418{
419 NEW_NODE *pInfo;
420 TCHAR szIpAddr[16], szNetMask[16];
421
422 DbgPrintf(1, "Node poller started");
423
424 while(!ShutdownInProgress())
425 {
426 pInfo = (NEW_NODE *)g_nodePollerQueue.GetOrBlock();
427 if (pInfo == INVALID_POINTER_VALUE)
428 break; // Shutdown indicator received
429
430 DbgPrintf(4, "NodePoller: processing node %s/%s",
431 IpToStr(pInfo->dwIpAddr, szIpAddr),
432 IpToStr(pInfo->dwNetMask, szNetMask));
433 if (AcceptNewNode(pInfo->dwIpAddr, pInfo->dwNetMask))
434 PollNewNode(pInfo->dwIpAddr, pInfo->dwNetMask, 0, NULL, 0, 0, NULL);
435 free(pInfo);
436 }
437 DbgPrintf(1, "Node poller thread terminated");
438 return THREAD_OK;
439}