all pollers converted to single thread pool
[public/netxms.git] / src / server / core / np.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2013 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 * Externals
27 */
28 extern Queue g_nodePollerQueue;
29
30 /**
31 * Discovery class
32 */
33 class NXSL_DiscoveryClass : public NXSL_Class
34 {
35 public:
36 NXSL_DiscoveryClass();
37
38 virtual NXSL_Value *getAttr(NXSL_Object *pObject, const TCHAR *pszAttr);
39 };
40
41 /**
42 * Implementation of discovery class
43 */
44 NXSL_DiscoveryClass::NXSL_DiscoveryClass() : NXSL_Class()
45 {
46 _tcscpy(m_name, _T("NewNode"));
47 }
48
49 NXSL_Value *NXSL_DiscoveryClass::getAttr(NXSL_Object *pObject, const TCHAR *pszAttr)
50 {
51 DISCOVERY_FILTER_DATA *pData;
52 NXSL_Value *pValue = NULL;
53 TCHAR szBuffer[256];
54
55 pData = (DISCOVERY_FILTER_DATA *)pObject->getData();
56 if (!_tcscmp(pszAttr, _T("ipAddr")))
57 {
58 pValue = new NXSL_Value(pData->ipAddr.toString(szBuffer));
59 }
60 else if (!_tcscmp(pszAttr, _T("netMask")))
61 {
62 pValue = new NXSL_Value(pData->ipAddr.getMaskBits());
63 }
64 else if (!_tcscmp(pszAttr, _T("subnet")))
65 {
66 pValue = new NXSL_Value(pData->ipAddr.getSubnetAddress().toString(szBuffer));
67 }
68 else if (!_tcscmp(pszAttr, _T("isAgent")))
69 {
70 pValue = new NXSL_Value((LONG)((pData->dwFlags & NNF_IS_AGENT) ? 1 : 0));
71 }
72 else if (!_tcscmp(pszAttr, _T("isSNMP")))
73 {
74 pValue = new NXSL_Value((LONG)((pData->dwFlags & NNF_IS_SNMP) ? 1 : 0));
75 }
76 else if (!_tcscmp(pszAttr, _T("isBridge")))
77 {
78 pValue = new NXSL_Value((LONG)((pData->dwFlags & NNF_IS_BRIDGE) ? 1 : 0));
79 }
80 else if (!_tcscmp(pszAttr, _T("isRouter")))
81 {
82 pValue = new NXSL_Value((LONG)((pData->dwFlags & NNF_IS_ROUTER) ? 1 : 0));
83 }
84 else if (!_tcscmp(pszAttr, _T("isPrinter")))
85 {
86 pValue = new NXSL_Value((LONG)((pData->dwFlags & NNF_IS_PRINTER) ? 1 : 0));
87 }
88 else if (!_tcscmp(pszAttr, _T("isCDP")))
89 {
90 pValue = new NXSL_Value((LONG)((pData->dwFlags & NNF_IS_CDP) ? 1 : 0));
91 }
92 else if (!_tcscmp(pszAttr, _T("isSONMP")))
93 {
94 pValue = new NXSL_Value((LONG)((pData->dwFlags & NNF_IS_SONMP) ? 1 : 0));
95 }
96 else if (!_tcscmp(pszAttr, _T("isLLDP")))
97 {
98 pValue = new NXSL_Value((LONG)((pData->dwFlags & NNF_IS_LLDP) ? 1 : 0));
99 }
100 else if (!_tcscmp(pszAttr, _T("snmpVersion")))
101 {
102 pValue = new NXSL_Value((LONG)pData->nSNMPVersion);
103 }
104 else if (!_tcscmp(pszAttr, _T("snmpOID")))
105 {
106 pValue = new NXSL_Value(pData->szObjectId);
107 }
108 else if (!_tcscmp(pszAttr, _T("agentVersion")))
109 {
110 pValue = new NXSL_Value(pData->szAgentVersion);
111 }
112 else if (!_tcscmp(pszAttr, _T("platformName")))
113 {
114 pValue = new NXSL_Value(pData->szPlatform);
115 }
116 return pValue;
117 }
118
119 /**
120 * Discovery class object
121 */
122 static NXSL_DiscoveryClass m_nxslDiscoveryClass;
123
124 /**
125 * Poll new node for configuration
126 * Returns pointer to new node object on success or NULL on failure
127 *
128 * @param ipAddr IP address of new node
129 * @param dwCreationFlags
130 * @param agentPort port number of NetXMS agent
131 * @param snmpPort port number of SNMP agent
132 * @param pszName name for new node, can be NULL
133 * @param dwProxyNode agent proxy node ID or 0 to use direct communications
134 * @param dwSNMPProxy SNMP proxy node ID or 0 to use direct communications
135 * @param pCluster pointer to parent cluster object or NULL
136 * @param zoneId zone ID
137 * @param doConfPoll if set to true, Node::configurationPoll will be called before exit
138 * @param discoveredNode must be set to true if node being added automatically by discovery thread
139 */
140 Node NXCORE_EXPORTABLE *PollNewNode(const InetAddress& ipAddr, UINT32 dwCreationFlags,
141 WORD agentPort, WORD snmpPort, const TCHAR *pszName, UINT32 dwProxyNode, UINT32 dwSNMPProxy,
142 Cluster *pCluster, UINT32 zoneId, bool doConfPoll, bool discoveredNode)
143 {
144 Node *pNode;
145 TCHAR szIpAddr[64];
146 UINT32 dwFlags = 0;
147
148 DbgPrintf(4, _T("PollNode(%s/%d) zone %d"), ipAddr.toString(szIpAddr), ipAddr.getMaskBits(), (int)zoneId);
149 // Check for node existence
150 if ((FindNodeByIP(zoneId, ipAddr) != NULL) ||
151 (FindSubnetByIP(zoneId, ipAddr) != NULL))
152 {
153 DbgPrintf(4, _T("PollNode: Node %s already exist in database"), szIpAddr);
154 return NULL;
155 }
156
157 if (dwCreationFlags & NXC_NCF_DISABLE_ICMP)
158 dwFlags |= NF_DISABLE_ICMP;
159 if (dwCreationFlags & NXC_NCF_DISABLE_SNMP)
160 dwFlags |= NF_DISABLE_SNMP;
161 if (dwCreationFlags & NXC_NCF_DISABLE_NXCP)
162 dwFlags |= NF_DISABLE_NXCP;
163 pNode = new Node(ipAddr, dwFlags, dwProxyNode, dwSNMPProxy, zoneId);
164 if (agentPort != 0)
165 pNode->setAgentPort(agentPort);
166 if (snmpPort != 0)
167 pNode->setSnmpPort(snmpPort);
168 NetObjInsert(pNode, TRUE);
169 if (pszName != NULL)
170 pNode->setName(pszName);
171
172 // Use DNS name as primary name if required
173 if (discoveredNode && ConfigReadInt(_T("UseDNSNameForDiscoveredNodes"), 0))
174 {
175 TCHAR dnsName[MAX_DNS_NAME];
176 if (ipAddr.getHostByAddr(dnsName, MAX_DNS_NAME) != NULL)
177 {
178 if (InetAddress::resolveHostName(dnsName).equals(ipAddr))
179 {
180 // We have valid DNS name which resolves back to node's IP address, use it as primary name
181 pNode->setPrimaryName(dnsName);
182 DbgPrintf(4, _T("PollNode: Using DNS name %s as primary name for node %s"), dnsName, szIpAddr);
183 }
184 }
185 }
186
187 // Bind node to cluster before first configuration poll
188 if (pCluster != NULL)
189 {
190 pCluster->applyToTarget(pNode);
191 }
192
193 if (dwCreationFlags & NXC_NCF_CREATE_UNMANAGED)
194 {
195 pNode->setMgmtStatus(FALSE);
196 pNode->checkSubnetBinding();
197 }
198
199 // Add default DCIs
200 pNode->addDCObject(new DCItem(CreateUniqueId(IDG_ITEM), _T("Status"), DS_INTERNAL, DCI_DT_INT,
201 ConfigReadInt(_T("DefaultDCIPollingInterval"), 60),
202 ConfigReadInt(_T("DefaultDCIRetentionTime"), 30), pNode));
203
204 if (doConfPoll)
205 {
206 PollerInfo *p = RegisterPoller(POLLER_TYPE_CONFIGURATION, pNode);
207 p->startExecution();
208 pNode->configurationPoll(NULL, 0, p, ipAddr.getMaskBits());
209 delete p;
210 }
211
212 pNode->unhide();
213 PostEvent(EVENT_NODE_ADDED, pNode->getId(), "d", (int)(discoveredNode ? 1 : 0));
214
215 return pNode;
216 }
217
218 /**
219 * Find existing node by MAC address to detect IP address change for already known node.
220 *
221 * @param ipAddr new (discovered) IP address
222 * @param dwZoneID zone ID
223 * @param bMacAddr MAC address of discovered node, or NULL if not known
224 *
225 * @return pointer to existing interface object with given MAC address or NULL if no such interface found
226 */
227 static Interface *GetOldNodeWithNewIP(const InetAddress& ipAddr, UINT32 dwZoneId, BYTE *bMacAddr)
228 {
229 Subnet *subnet;
230 BYTE nodeMacAddr[MAC_ADDR_LENGTH];
231 TCHAR szIpAddr[64], szMacAddr[20];
232
233 ipAddr.toString(szIpAddr);
234 MACToStr(bMacAddr, szMacAddr);
235 DbgPrintf(6, _T("GetOldNodeWithNewIP: ip=%s mac=%s"), szIpAddr, szMacAddr);
236
237 if (bMacAddr == NULL)
238 {
239 subnet = FindSubnetForNode(dwZoneId, ipAddr);
240 if (subnet != NULL)
241 {
242 BOOL found = subnet->findMacAddress(ipAddr, nodeMacAddr);
243 if (!found)
244 {
245 DbgPrintf(6, _T("GetOldNodeWithNewIP: MAC address not found"));
246 return NULL;
247 }
248 }
249 else
250 {
251 DbgPrintf(6, _T("GetOldNodeWithNewIP: subnet not found"));
252 return NULL;
253 }
254 }
255 else
256 {
257 memcpy(nodeMacAddr, bMacAddr, MAC_ADDR_LENGTH);
258 }
259
260 Interface *iface = FindInterfaceByMAC(nodeMacAddr);
261
262 if (iface == NULL)
263 DbgPrintf(6, _T("GetOldNodeWithNewIP: returning null (FindInterfaceByMAC!)"));
264
265 return iface;
266 }
267
268 /**
269 * Check if host at given IP address is reachable by NetXMS server
270 */
271 static bool HostIsReachable(const InetAddress& ipAddr, UINT32 zoneId, bool fullCheck, SNMP_Transport **transport, AgentConnection **agentConn)
272 {
273 bool reachable = false;
274
275 if (transport != NULL)
276 *transport = NULL;
277 if (agentConn != NULL)
278 *agentConn = NULL;
279
280 UINT32 agentProxy = 0;
281 UINT32 icmpProxy = 0;
282 UINT32 snmpProxy = 0;
283
284 if (IsZoningEnabled() && (zoneId != 0))
285 {
286 Zone *zone = (Zone *)g_idxZoneByGUID.get(zoneId);
287 if (zone != NULL)
288 {
289 agentProxy = zone->getAgentProxy();
290 icmpProxy = zone->getIcmpProxy();
291 snmpProxy = zone->getSnmpProxy();
292 }
293 }
294
295 // *** ICMP PING ***
296 if (icmpProxy != 0)
297 {
298 Node *proxyNode = (Node *)g_idxNodeById.get(icmpProxy);
299 if ((proxyNode != NULL) && proxyNode->isNativeAgent() && !proxyNode->isDown())
300 {
301 AgentConnection *conn = proxyNode->createAgentConnection();
302 if (conn != NULL)
303 {
304 TCHAR parameter[128], buffer[64];
305
306 _sntprintf(parameter, 128, _T("Icmp.Ping(%s)"), ipAddr.toString(buffer));
307 if (conn->getParameter(parameter, 64, buffer) == ERR_SUCCESS)
308 {
309 TCHAR *eptr;
310 long value = _tcstol(buffer, &eptr, 10);
311 if ((*eptr == 0) && (value >= 0))
312 {
313 if (value < 10000)
314 {
315 reachable = true;
316 }
317 }
318 }
319 conn->disconnect();
320 delete conn;
321 }
322 }
323 }
324 else // not using ICMP proxy
325 {
326 if (IcmpPing(ipAddr, 3, g_icmpPingTimeout, NULL, g_icmpPingSize) == ICMP_SUCCESS)
327 reachable = true;
328 }
329
330 if (reachable && !fullCheck)
331 return true;
332
333 // *** NetXMS agent ***
334 AgentConnection *pAgentConn = new AgentConnectionEx(0, ipAddr, AGENT_LISTEN_PORT, AUTH_NONE, _T(""));
335 if (agentProxy != 0)
336 {
337 Node *proxyNode = (Node *)g_idxNodeById.get(agentProxy);
338 if (proxyNode != NULL)
339 {
340 pAgentConn->setProxy(proxyNode->getIpAddress(), proxyNode->getAgentPort(),
341 proxyNode->getAgentAuthMethod(), proxyNode->getSharedSecret());
342 }
343 }
344 UINT32 rcc;
345 if (!pAgentConn->connect(g_pServerKey, FALSE, &rcc))
346 {
347 // If there are authentication problem, try default shared secret
348 if ((rcc == ERR_AUTH_REQUIRED) || (rcc == ERR_AUTH_FAILED))
349 {
350 TCHAR secret[MAX_SECRET_LENGTH];
351 ConfigReadStr(_T("AgentDefaultSharedSecret"), secret, MAX_SECRET_LENGTH, _T("netxms"));
352 pAgentConn->setAuthData(AUTH_SHA1_HASH, secret);
353 pAgentConn->connect(g_pServerKey, FALSE, &rcc);
354 }
355 }
356 if (rcc == ERR_SUCCESS)
357 {
358 if (agentConn != NULL)
359 {
360 *agentConn = pAgentConn;
361 pAgentConn = NULL; // prevent deletion
362 }
363 reachable = true;
364 }
365 delete pAgentConn;
366
367 if (reachable && !fullCheck)
368 return true;
369
370 // *** SNMP ***
371 SNMP_Transport *pTransport = NULL;
372 if (snmpProxy != 0)
373 {
374 Node *proxyNode = (Node *)g_idxNodeById.get(snmpProxy);
375 if (proxyNode != NULL)
376 {
377 AgentConnection *pConn;
378
379 pConn = proxyNode->createAgentConnection();
380 if (pConn != NULL)
381 {
382 pTransport = new SNMP_ProxyTransport(pConn, ipAddr, 161);
383 }
384 }
385 }
386 else
387 {
388 pTransport = new SNMP_UDPTransport;
389 ((SNMP_UDPTransport *)pTransport)->createUDPTransport(ipAddr, 161);
390 }
391 if (pTransport != NULL)
392 {
393 INT16 version;
394 StringList oids;
395 oids.add(_T(".1.3.6.1.2.1.1.2.0"));
396 oids.add(_T(".1.3.6.1.2.1.1.1.0"));
397 AddDriverSpecificOids(&oids);
398 SNMP_SecurityContext *ctx = SnmpCheckCommSettings(pTransport, &version, NULL, &oids);
399 if (ctx != NULL)
400 {
401 delete ctx;
402 if (transport != NULL)
403 {
404 pTransport->setSnmpVersion(version);
405 *transport = pTransport;
406 pTransport = NULL; // prevent deletion
407 }
408 reachable = true;
409 }
410 delete pTransport;
411 }
412
413 return reachable;
414 }
415
416 /**
417 * Check if newly discovered node should be added
418 */
419 static BOOL AcceptNewNode(const InetAddress& addr, UINT32 zoneId, BYTE *macAddr)
420 {
421 DISCOVERY_FILTER_DATA data;
422 TCHAR szFilter[MAX_DB_STRING], szBuffer[256], szIpAddr[64];
423 UINT32 dwTemp;
424 AgentConnection *pAgentConn;
425 BOOL bResult = FALSE;
426 SNMP_Transport *pTransport;
427
428 addr.toString(szIpAddr);
429 if ((FindNodeByIP(zoneId, addr) != NULL) ||
430 (FindSubnetByIP(zoneId, addr) != NULL))
431 {
432 DbgPrintf(4, _T("AcceptNewNode(%s): node already exist in database"), szIpAddr);
433 return FALSE; // Node already exist in database
434 }
435
436 if (!memcmp(macAddr, "\xFF\xFF\xFF\xFF\xFF\xFF", 6))
437 {
438 DbgPrintf(4, _T("AcceptNewNode(%s): broadcast MAC address"), szIpAddr);
439 return FALSE; // Broadcast MAC
440 }
441
442 NXSL_VM *hook = FindHookScript(_T("AcceptNewNode"));
443 if (hook != NULL)
444 {
445 bool stop = false;
446 hook->setGlobalVariable(_T("$ipAddr"), new NXSL_Value(szIpAddr));
447 hook->setGlobalVariable(_T("$ipNetMask"), new NXSL_Value(addr.getMaskBits()));
448 MACToStr(macAddr, szBuffer);
449 hook->setGlobalVariable(_T("$macAddr"), new NXSL_Value(szBuffer));
450 hook->setGlobalVariable(_T("$zoneId"), new NXSL_Value(zoneId));
451 if (hook->run())
452 {
453 NXSL_Value *result = hook->getResult();
454 if (result->isZero())
455 {
456 stop = true;
457 DbgPrintf(4, _T("AcceptNewNode(%s): rejected by hook script"), szIpAddr);
458 }
459 }
460 else
461 {
462 DbgPrintf(4, _T("AcceptNewNode(%s): hook script execution error: %s"), szIpAddr, hook->getErrorText());
463 }
464 delete hook;
465 if (stop)
466 return FALSE; // blocked by hook
467 }
468
469 Interface *iface = GetOldNodeWithNewIP(addr, zoneId, macAddr);
470 if (iface != NULL)
471 {
472 if (!HostIsReachable(addr, zoneId, false, NULL, NULL))
473 {
474 DbgPrintf(4, _T("AcceptNewNode(%s): found existing interface with same MAC address, but new IP is not reachable"), szIpAddr);
475 return FALSE;
476 }
477
478 Node *oldNode = iface->getParentNode();
479 if (iface->getIpAddressList()->hasAddress(oldNode->getIpAddress()))
480 {
481 // we should change node's primary IP only if old IP for this MAC was also node's primary IP
482 TCHAR szOldIpAddr[16];
483 oldNode->getIpAddress().toString(szOldIpAddr);
484 DbgPrintf(4, _T("AcceptNewNode(%s): node already exist in database with ip %s, will change to new"), szIpAddr, szOldIpAddr);
485 oldNode->changeIPAddress(addr);
486 }
487 return FALSE;
488 }
489
490 // Allow filtering by loaded modules
491 for(UINT32 i = 0; i < g_dwNumModules; i++)
492 {
493 if (g_pModuleList[i].pfAcceptNewNode != NULL)
494 {
495 if (!g_pModuleList[i].pfAcceptNewNode(addr, zoneId, macAddr))
496 return FALSE; // filtered out by module
497 }
498 }
499
500 // Read configuration
501 ConfigReadStr(_T("DiscoveryFilter"), szFilter, MAX_DB_STRING, _T(""));
502 StrStrip(szFilter);
503
504 // Check for filter script
505 if ((szFilter[0] == 0) || (!_tcsicmp(szFilter, _T("none"))))
506 {
507 if (!HostIsReachable(addr, zoneId, false, NULL, NULL))
508 {
509 DbgPrintf(4, _T("AcceptNewNode(%s): host is not reachable"), szIpAddr);
510 return FALSE;
511 }
512 DbgPrintf(4, _T("AcceptNewNode(%s): no filtering, node accepted"), szIpAddr);
513 return TRUE; // No filtering
514 }
515
516 // Initialize new node data
517 memset(&data, 0, sizeof(DISCOVERY_FILTER_DATA));
518 data.ipAddr = addr;
519
520 // Check for address range if we use simple filter instead of script
521 UINT32 autoFilterFlags;
522 if (!_tcsicmp(szFilter, _T("auto")))
523 {
524 autoFilterFlags = ConfigReadULong(_T("DiscoveryFilterFlags"), DFF_ALLOW_AGENT | DFF_ALLOW_SNMP);
525 DbgPrintf(4, _T("AcceptNewNode(%s): auto filter, flags=%04X"), szIpAddr, autoFilterFlags);
526
527 if (autoFilterFlags & DFF_ONLY_RANGE)
528 {
529 DbgPrintf(4, _T("AcceptNewNode(%s): auto filter - checking range"), szIpAddr);
530 DB_RESULT hResult = DBSelect(g_hCoreDB, _T("SELECT addr_type,addr1,addr2 FROM address_lists WHERE list_type=2"));
531 if (hResult != NULL)
532 {
533 int nRows = DBGetNumRows(hResult);
534 for(int i = 0; (i < nRows) && (!bResult); i++)
535 {
536 int nType = DBGetFieldLong(hResult, i, 0);
537 if (nType == 0)
538 {
539 // Subnet
540 InetAddress subnet = DBGetFieldInetAddr(hResult, i, 1);
541 subnet.setMaskBits(DBGetFieldLong(hResult, i, 2));
542 bResult = subnet.contain(data.ipAddr);
543 }
544 else
545 {
546 // Range
547 InetAddress addr1 = DBGetFieldInetAddr(hResult, i, 1);
548 InetAddress addr2 = DBGetFieldInetAddr(hResult, i, 2);
549 if ((addr1.getFamily() == data.ipAddr.getFamily()) && (addr2.getFamily() == data.ipAddr.getFamily()))
550 bResult = (addr1.compareTo(data.ipAddr) <= 0) && (addr2.compareTo(data.ipAddr) >= 0);
551 else
552 bResult = FALSE;
553 }
554 }
555 DBFreeResult(hResult);
556 }
557 DbgPrintf(4, _T("AcceptNewNode(%s): auto filter - range check result is %d"), szIpAddr, bResult);
558 if (!bResult)
559 return FALSE;
560 }
561 }
562
563 // Check if host is reachable
564 if (!HostIsReachable(addr, zoneId, true, &pTransport, &pAgentConn))
565 {
566 DbgPrintf(4, _T("AcceptNewNode(%s): host is not reachable"), szIpAddr);
567 return FALSE;
568 }
569 if (pTransport != NULL)
570 {
571 data.dwFlags |= NNF_IS_SNMP;
572 data.nSNMPVersion = pTransport->getSnmpVersion();
573 }
574 if (pAgentConn != NULL)
575 {
576 data.dwFlags |= NNF_IS_AGENT;
577 pAgentConn->getParameter(_T("Agent.Version"), MAX_AGENT_VERSION_LEN, data.szAgentVersion);
578 pAgentConn->getParameter(_T("System.PlatformName"), MAX_PLATFORM_NAME_LEN, data.szPlatform);
579 }
580
581 // Check if node is a router
582 if (data.dwFlags & NNF_IS_SNMP)
583 {
584 if (SnmpGet(data.nSNMPVersion, pTransport,
585 _T(".1.3.6.1.2.1.4.1.0"), NULL, 0, &dwTemp, sizeof(UINT32), 0) == SNMP_ERR_SUCCESS)
586 {
587 if (dwTemp == 1)
588 data.dwFlags |= NNF_IS_ROUTER;
589 }
590 }
591 else if (data.dwFlags & NNF_IS_AGENT)
592 {
593 // Check IP forwarding status
594 if (pAgentConn->getParameter(_T("Net.IP.Forwarding"), 16, szBuffer) == ERR_SUCCESS)
595 {
596 if (_tcstoul(szBuffer, NULL, 10) != 0)
597 data.dwFlags |= NNF_IS_ROUTER;
598 }
599 }
600
601 // Check various SNMP device capabilities
602 if (data.dwFlags & NNF_IS_SNMP)
603 {
604 // Get SNMP OID
605 SnmpGet(data.nSNMPVersion, pTransport,
606 _T(".1.3.6.1.2.1.1.2.0"), NULL, 0, data.szObjectId, MAX_OID_LEN * 4, 0);
607
608 // Check if node is a bridge
609 if (SnmpGet(data.nSNMPVersion, pTransport,
610 _T(".1.3.6.1.2.1.17.1.1.0"), NULL, 0, szBuffer, sizeof(szBuffer), 0) == SNMP_ERR_SUCCESS)
611 {
612 data.dwFlags |= NNF_IS_BRIDGE;
613 }
614
615 // Check for CDP (Cisco Discovery Protocol) support
616 if (SnmpGet(data.nSNMPVersion, pTransport,
617 _T(".1.3.6.1.4.1.9.9.23.1.3.1.0"), NULL, 0, &dwTemp, sizeof(UINT32), 0) == SNMP_ERR_SUCCESS)
618 {
619 if (dwTemp == 1)
620 data.dwFlags |= NNF_IS_CDP;
621 }
622
623 // Check for SONMP (Nortel topology discovery protocol) support
624 if (SnmpGet(data.nSNMPVersion, pTransport,
625 _T(".1.3.6.1.4.1.45.1.6.13.1.2.0"), NULL, 0, &dwTemp, sizeof(UINT32), 0) == SNMP_ERR_SUCCESS)
626 {
627 if (dwTemp == 1)
628 data.dwFlags |= NNF_IS_SONMP;
629 }
630
631 // Check for LLDP (Link Layer Discovery Protocol) support
632 if (SnmpGet(data.nSNMPVersion, pTransport,
633 _T(".1.0.8802.1.1.2.1.3.2.0"), NULL, 0, szBuffer, sizeof(szBuffer), 0) == SNMP_ERR_SUCCESS)
634 {
635 data.dwFlags |= NNF_IS_LLDP;
636 }
637 }
638
639 // Cleanup
640 delete pAgentConn;
641 delete pTransport;
642
643 // Check if we use simple filter instead of script
644 if (!_tcsicmp(szFilter, _T("auto")))
645 {
646 bResult = FALSE;
647 if ((autoFilterFlags & (DFF_ALLOW_AGENT | DFF_ALLOW_SNMP)) == 0)
648 {
649 bResult = TRUE;
650 }
651 else
652 {
653 if (autoFilterFlags & DFF_ALLOW_AGENT)
654 {
655 if (data.dwFlags & NNF_IS_AGENT)
656 bResult = TRUE;
657 }
658
659 if (autoFilterFlags & DFF_ALLOW_SNMP)
660 {
661 if (data.dwFlags & NNF_IS_SNMP)
662 bResult = TRUE;
663 }
664 }
665 DbgPrintf(4, _T("AcceptNewNode(%s): auto filter - bResult=%d"), szIpAddr, bResult);
666 }
667 else
668 {
669 NXSL_VM *vm = g_pScriptLibrary->createVM(szFilter, new NXSL_ServerEnv);
670 if (vm != NULL)
671 {
672 DbgPrintf(4, _T("AcceptNewNode(%s): Running filter script %s"), szIpAddr, szFilter);
673 NXSL_Value *pValue = new NXSL_Value(new NXSL_Object(&m_nxslDiscoveryClass, &data));
674 if (vm->run(1, &pValue))
675 {
676 bResult = (vm->getResult()->getValueAsInt32() != 0) ? TRUE : FALSE;
677 DbgPrintf(4, _T("AcceptNewNode(%s): Filter script result: %d"), szIpAddr, bResult);
678 }
679 else
680 {
681 DbgPrintf(4, _T("AcceptNewNode(%s): Filter script execution error: %s"),
682 szIpAddr, vm->getErrorText());
683 PostEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, "ssd", szFilter, vm->getErrorText(), 0);
684 }
685 delete vm;
686 }
687 else
688 {
689 DbgPrintf(4, _T("AcceptNewNode(%s): Cannot find filter script %s"), szIpAddr, szFilter);
690 }
691 }
692
693 return bResult;
694 }
695
696 /**
697 * Node poller thread (poll new nodes and put them into the database)
698 */
699 THREAD_RESULT THREAD_CALL NodePoller(void *arg)
700 {
701 NEW_NODE *pInfo;
702 TCHAR szIpAddr[64];
703
704 DbgPrintf(1, _T("Node poller started"));
705
706 while(!IsShutdownInProgress())
707 {
708 pInfo = (NEW_NODE *)g_nodePollerQueue.getOrBlock();
709 if (pInfo == INVALID_POINTER_VALUE)
710 break; // Shutdown indicator received
711
712 DbgPrintf(4, _T("NodePoller: processing node %s/%d in zone %d"),
713 pInfo->ipAddr.toString(szIpAddr), pInfo->ipAddr.getMaskBits(), (int)pInfo->zoneId);
714 if (pInfo->ignoreFilter || AcceptNewNode(pInfo->ipAddr, pInfo->zoneId, pInfo->bMacAddr))
715 {
716 ObjectTransactionStart();
717 PollNewNode(pInfo->ipAddr, 0, 0, 0, NULL, 0, 0, NULL, pInfo->zoneId, true, true);
718 ObjectTransactionEnd();
719 }
720 free(pInfo);
721 }
722 DbgPrintf(1, _T("Node poller thread terminated"));
723 return THREAD_OK;
724 }