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