Implemented seperate access rights for reading Agent data, SNMP data and taking scree...
[public/netxms.git] / src / server / core / node.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2017 Raden Solutions
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: node.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24 #include <agent_tunnel.h>
25
26 /**
27 * Externals
28 */
29 extern UINT64 g_syslogMessagesReceived;
30 extern UINT64 g_snmpTrapsReceived;
31
32 /**
33 * Node class default constructor
34 */
35 Node::Node() : DataCollectionTarget()
36 {
37 m_primaryName[0] = 0;
38 m_status = STATUS_UNKNOWN;
39 m_type = NODE_TYPE_UNKNOWN;
40 m_subType[0] = 0;
41 m_capabilities = 0;
42 m_zoneUIN = 0;
43 m_agentPort = AGENT_LISTEN_PORT;
44 m_agentAuthMethod = AUTH_NONE;
45 m_agentCacheMode = AGENT_CACHE_DEFAULT;
46 m_szSharedSecret[0] = 0;
47 m_iStatusPollType = POLL_ICMP_PING;
48 m_snmpVersion = SNMP_VERSION_1;
49 m_snmpPort = SNMP_DEFAULT_PORT;
50 m_snmpSecurity = new SNMP_SecurityContext("public");
51 m_snmpObjectId[0] = 0;
52 m_lastDiscoveryPoll = 0;
53 m_lastStatusPoll = 0;
54 m_lastConfigurationPoll = 0;
55 m_lastInstancePoll = 0;
56 m_lastTopologyPoll = 0;
57 m_lastRTUpdate = 0;
58 m_downSince = 0;
59 m_bootTime = 0;
60 m_agentUpTime = 0;
61 m_hAgentAccessMutex = MutexCreate();
62 m_hSmclpAccessMutex = MutexCreate();
63 m_mutexRTAccess = MutexCreate();
64 m_mutexTopoAccess = MutexCreate();
65 m_agentConnection = NULL;
66 m_proxyConnections = new ObjectLock<AgentConnectionEx>[MAX_PROXY_TYPE];
67 m_smclpConnection = NULL;
68 m_lastAgentTrapId = 0;
69 m_lastSNMPTrapId = 0;
70 m_lastSyslogMessageId = 0;
71 m_lastAgentPushRequestId = 0;
72 m_agentVersion[0] = 0;
73 m_platformName[0] = 0;
74 m_sysDescription = NULL;
75 m_sysName = NULL;
76 m_sysContact = NULL;
77 m_sysLocation = NULL;
78 m_lldpNodeId = NULL;
79 m_lldpLocalPortInfo = NULL;
80 m_paramList = NULL;
81 m_tableList = NULL;
82 m_pollerNode = 0;
83 m_agentProxy = 0;
84 m_snmpProxy = 0;
85 m_icmpProxy = 0;
86 memset(m_lastEvents, 0, sizeof(QWORD) * MAX_LAST_EVENTS);
87 m_routingLoopEvents = new ObjectArray<RoutingLoopEvent>(0, 16, true);
88 m_pRoutingTable = NULL;
89 m_failTimeSNMP = 0;
90 m_failTimeAgent = 0;
91 m_lastAgentCommTime = 0;
92 m_lastAgentConnectAttempt = 0;
93 m_linkLayerNeighbors = NULL;
94 m_vrrpInfo = NULL;
95 m_topology = NULL;
96 m_topologyRebuildTimestamp = 0;
97 m_iPendingStatus = -1;
98 m_iPollCount = 0;
99 m_iRequiredPollCount = 0; // Use system default
100 m_nUseIfXTable = IFXTABLE_DEFAULT; // Use system default
101 m_jobQueue = new ServerJobQueue();
102 m_fdb = NULL;
103 m_vlans = NULL;
104 m_wirelessStations = NULL;
105 m_adoptedApCount = 0;
106 m_totalApCount = 0;
107 m_driver = NULL;
108 m_driverData = NULL;
109 m_components = NULL;
110 m_softwarePackages = NULL;
111 m_winPerfObjects = NULL;
112 memset(m_baseBridgeAddress, 0, MAC_ADDR_LENGTH);
113 m_fileUpdateConn = NULL;
114 m_rackId = 0;
115 m_rackPosition = 0;
116 m_rackHeight = 1;
117 m_chassisId = 0;
118 m_syslogMessageCount = 0;
119 m_snmpTrapCount = 0;
120 m_sshLogin[0] = 0;
121 m_sshPassword[0] = 0;
122 m_sshProxy = 0;
123 m_portNumberingScheme = NDD_PN_UNKNOWN;
124 m_portRowCount = 0;
125 m_agentCompressionMode = NODE_AGENT_COMPRESSION_DEFAULT;
126 }
127
128 /**
129 * Constructor for new node object
130 */
131 Node::Node(const InetAddress& addr, UINT32 flags, UINT32 capabilities, UINT32 agentProxy, UINT32 snmpProxy, UINT32 icmpProxy, UINT32 sshProxy, UINT32 zoneUIN) : DataCollectionTarget()
132 {
133 addr.toString(m_primaryName);
134 m_status = STATUS_UNKNOWN;
135 m_type = NODE_TYPE_UNKNOWN;
136 m_subType[0] = 0;
137 m_ipAddress = addr;
138 m_capabilities = capabilities;
139 m_flags = flags;
140 m_zoneUIN = zoneUIN;
141 m_agentPort = AGENT_LISTEN_PORT;
142 m_agentAuthMethod = AUTH_NONE;
143 m_agentCacheMode = AGENT_CACHE_DEFAULT;
144 m_szSharedSecret[0] = 0;
145 m_iStatusPollType = POLL_ICMP_PING;
146 m_snmpVersion = SNMP_VERSION_1;
147 m_snmpPort = SNMP_DEFAULT_PORT;
148 m_snmpSecurity = new SNMP_SecurityContext("public");
149 addr.toString(m_name); // Make default name from IP address
150 m_snmpObjectId[0] = 0;
151 m_lastDiscoveryPoll = 0;
152 m_lastStatusPoll = 0;
153 m_lastConfigurationPoll = 0;
154 m_lastInstancePoll = 0;
155 m_lastTopologyPoll = 0;
156 m_lastRTUpdate = 0;
157 m_downSince = 0;
158 m_bootTime = 0;
159 m_agentUpTime = 0;
160 m_hAgentAccessMutex = MutexCreate();
161 m_hSmclpAccessMutex = MutexCreate();
162 m_mutexRTAccess = MutexCreate();
163 m_mutexTopoAccess = MutexCreate();
164 m_agentConnection = NULL;
165 m_proxyConnections = new ObjectLock<AgentConnectionEx>[MAX_PROXY_TYPE];
166 m_smclpConnection = NULL;
167 m_lastAgentTrapId = 0;
168 m_lastSNMPTrapId = 0;
169 m_lastSyslogMessageId = 0;
170 m_lastAgentPushRequestId = 0;
171 m_agentVersion[0] = 0;
172 m_platformName[0] = 0;
173 m_sysDescription = NULL;
174 m_sysName = NULL;
175 m_sysContact = NULL;
176 m_sysLocation = NULL;
177 m_lldpNodeId = NULL;
178 m_lldpLocalPortInfo = NULL;
179 m_paramList = NULL;
180 m_tableList = NULL;
181 m_pollerNode = 0;
182 m_agentProxy = agentProxy;
183 m_snmpProxy = snmpProxy;
184 m_icmpProxy = icmpProxy;
185 memset(m_lastEvents, 0, sizeof(QWORD) * MAX_LAST_EVENTS);
186 m_routingLoopEvents = new ObjectArray<RoutingLoopEvent>(0, 16, true);
187 m_isHidden = true;
188 m_pRoutingTable = NULL;
189 m_failTimeSNMP = 0;
190 m_failTimeAgent = 0;
191 m_lastAgentCommTime = 0;
192 m_lastAgentConnectAttempt = 0;
193 m_linkLayerNeighbors = NULL;
194 m_vrrpInfo = NULL;
195 m_topology = NULL;
196 m_topologyRebuildTimestamp = 0;
197 m_iPendingStatus = -1;
198 m_iPollCount = 0;
199 m_iRequiredPollCount = 0; // Use system default
200 m_nUseIfXTable = IFXTABLE_DEFAULT; // Use system default
201 m_jobQueue = new ServerJobQueue();
202 m_fdb = NULL;
203 m_vlans = NULL;
204 m_wirelessStations = NULL;
205 m_adoptedApCount = 0;
206 m_totalApCount = 0;
207 m_driver = NULL;
208 m_driverData = NULL;
209 m_components = NULL;
210 m_softwarePackages = NULL;
211 m_winPerfObjects = NULL;
212 memset(m_baseBridgeAddress, 0, MAC_ADDR_LENGTH);
213 m_fileUpdateConn = NULL;
214 m_rackId = 0;
215 m_rackPosition = 0;
216 m_rackHeight = 1;
217 m_chassisId = 0;
218 m_syslogMessageCount = 0;
219 m_snmpTrapCount = 0;
220 m_sshLogin[0] = 0;
221 m_sshPassword[0] = 0;
222 m_sshProxy = sshProxy;
223 m_portNumberingScheme = NDD_PN_UNKNOWN;
224 m_portRowCount = 0;
225 m_agentCompressionMode = NODE_AGENT_COMPRESSION_DEFAULT;
226 }
227
228 /**
229 * Node destructor
230 */
231 Node::~Node()
232 {
233 delete m_driverData;
234 MutexDestroy(m_hAgentAccessMutex);
235 MutexDestroy(m_hSmclpAccessMutex);
236 MutexDestroy(m_mutexRTAccess);
237 MutexDestroy(m_mutexTopoAccess);
238 if (m_agentConnection != NULL)
239 m_agentConnection->decRefCount();
240 for(int i = 0; i < MAX_PROXY_TYPE; i++)
241 if(m_proxyConnections[i].get() != NULL)
242 m_proxyConnections[i].get()->decRefCount();
243 delete[] m_proxyConnections;
244 delete m_smclpConnection;
245 delete m_paramList;
246 delete m_tableList;
247 free(m_sysDescription);
248 DestroyRoutingTable(m_pRoutingTable);
249 if (m_linkLayerNeighbors != NULL)
250 m_linkLayerNeighbors->decRefCount();
251 delete m_vrrpInfo;
252 delete m_topology;
253 delete m_jobQueue;
254 delete m_snmpSecurity;
255 if (m_fdb != NULL)
256 m_fdb->decRefCount();
257 if (m_vlans != NULL)
258 m_vlans->decRefCount();
259 delete m_wirelessStations;
260 if (m_components != NULL)
261 m_components->decRefCount();
262 delete m_lldpLocalPortInfo;
263 delete m_softwarePackages;
264 delete m_winPerfObjects;
265 free(m_sysName);
266 free(m_sysContact);
267 free(m_sysLocation);
268 delete m_routingLoopEvents;
269 }
270
271 /**
272 * Create object from database data
273 */
274 bool Node::loadFromDatabase(DB_HANDLE hdb, UINT32 dwId)
275 {
276 int i, iNumRows;
277 UINT32 dwSubnetId;
278 NetObj *pObject;
279 bool bResult = false;
280
281 m_id = dwId;
282
283 if (!loadCommonProperties(hdb))
284 {
285 DbgPrintf(2, _T("Cannot load common properties for node object %d"), dwId);
286 return false;
287 }
288
289 DB_STATEMENT hStmt = DBPrepare(hdb,
290 _T("SELECT primary_name,primary_ip,")
291 _T("snmp_version,auth_method,secret,")
292 _T("agent_port,status_poll_type,snmp_oid,agent_version,")
293 _T("platform_name,poller_node_id,zone_guid,")
294 _T("proxy_node,snmp_proxy,required_polls,uname,")
295 _T("use_ifxtable,snmp_port,community,usm_auth_password,")
296 _T("usm_priv_password,usm_methods,snmp_sys_name,bridge_base_addr,")
297 _T("down_since,boot_time,driver_name,icmp_proxy,")
298 _T("agent_cache_mode,snmp_sys_contact,snmp_sys_location,")
299 _T("rack_id,rack_image,rack_position,rack_height,")
300 _T("last_agent_comm_time,syslog_msg_count,snmp_trap_count,")
301 _T("node_type,node_subtype,ssh_login,ssh_password,ssh_proxy,")
302 _T("port_rows,port_numbering_scheme,agent_comp_mode,")
303 _T("tunnel_id,lldp_id,capabilities,fail_time_snmp,fail_time_agent FROM nodes WHERE id=?"));
304 if (hStmt == NULL)
305 return false;
306
307 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, dwId);
308 DB_RESULT hResult = DBSelectPrepared(hStmt);
309 if (hResult == NULL)
310 {
311 DBFreeStatement(hStmt);
312 return false; // Query failed
313 }
314
315 if (DBGetNumRows(hResult) == 0)
316 {
317 DBFreeResult(hResult);
318 DBFreeStatement(hStmt);
319 DbgPrintf(2, _T("Missing record in \"nodes\" table for node object %d"), dwId);
320 return false;
321 }
322
323 DBGetField(hResult, 0, 0, m_primaryName, MAX_DNS_NAME);
324 m_ipAddress = DBGetFieldInetAddr(hResult, 0, 1);
325 m_snmpVersion = DBGetFieldLong(hResult, 0, 2);
326 m_agentAuthMethod = (WORD)DBGetFieldLong(hResult, 0, 3);
327 DBGetField(hResult, 0, 4, m_szSharedSecret, MAX_SECRET_LENGTH);
328 m_agentPort = (WORD)DBGetFieldLong(hResult, 0, 5);
329 m_iStatusPollType = DBGetFieldLong(hResult, 0, 6);
330 DBGetField(hResult, 0, 7, m_snmpObjectId, MAX_OID_LEN * 4);
331 DBGetField(hResult, 0, 8, m_agentVersion, MAX_AGENT_VERSION_LEN);
332 DBGetField(hResult, 0, 9, m_platformName, MAX_PLATFORM_NAME_LEN);
333 m_pollerNode = DBGetFieldULong(hResult, 0, 10);
334 m_zoneUIN = DBGetFieldULong(hResult, 0, 11);
335 m_agentProxy = DBGetFieldULong(hResult, 0, 12);
336 m_snmpProxy = DBGetFieldULong(hResult, 0, 13);
337 m_iRequiredPollCount = DBGetFieldLong(hResult, 0, 14);
338 m_sysDescription = DBGetField(hResult, 0, 15, NULL, 0);
339 m_nUseIfXTable = (BYTE)DBGetFieldLong(hResult, 0, 16);
340 m_snmpPort = (WORD)DBGetFieldLong(hResult, 0, 17);
341
342 // SNMP authentication parameters
343 char snmpAuthObject[256], snmpAuthPassword[256], snmpPrivPassword[256];
344 DBGetFieldA(hResult, 0, 18, snmpAuthObject, 256);
345 DBGetFieldA(hResult, 0, 19, snmpAuthPassword, 256);
346 DBGetFieldA(hResult, 0, 20, snmpPrivPassword, 256);
347 int snmpMethods = DBGetFieldLong(hResult, 0, 21);
348 delete m_snmpSecurity;
349 if (m_snmpVersion == SNMP_VERSION_3)
350 {
351 m_snmpSecurity = new SNMP_SecurityContext(snmpAuthObject, snmpAuthPassword, snmpPrivPassword, snmpMethods & 0xFF, snmpMethods >> 8);
352 }
353 else
354 {
355 // This will create security context with V2C security model
356 // USM fields will be loaded but keys will not be calculated
357 m_snmpSecurity = new SNMP_SecurityContext(snmpAuthObject);
358 m_snmpSecurity->setAuthMethod(snmpMethods & 0xFF);
359 m_snmpSecurity->setAuthPassword(snmpAuthPassword);
360 m_snmpSecurity->setPrivMethod(snmpMethods >> 8);
361 m_snmpSecurity->setPrivPassword(snmpPrivPassword);
362 }
363
364 m_sysName = DBGetField(hResult, 0, 22, NULL, 0);
365
366 TCHAR baseAddr[16];
367 TCHAR *value = DBGetField(hResult, 0, 23, baseAddr, 16);
368 if (value != NULL)
369 StrToBin(value, m_baseBridgeAddress, MAC_ADDR_LENGTH);
370
371 m_downSince = DBGetFieldLong(hResult, 0, 24);
372 m_bootTime = DBGetFieldLong(hResult, 0, 25);
373
374 // Setup driver
375 TCHAR driverName[34];
376 DBGetField(hResult, 0, 26, driverName, 34);
377 StrStrip(driverName);
378 if (driverName[0] != 0)
379 m_driver = FindDriverByName(driverName);
380
381 m_icmpProxy = DBGetFieldULong(hResult, 0, 27);
382 m_agentCacheMode = (INT16)DBGetFieldLong(hResult, 0, 28);
383 if ((m_agentCacheMode != AGENT_CACHE_ON) && (m_agentCacheMode != AGENT_CACHE_OFF))
384 m_agentCacheMode = AGENT_CACHE_DEFAULT;
385
386 m_sysContact = DBGetField(hResult, 0, 29, NULL, 0);
387 m_sysLocation = DBGetField(hResult, 0, 30, NULL, 0);
388
389 m_rackId = DBGetFieldULong(hResult, 0, 31);
390 m_rackImage = DBGetFieldGUID(hResult, 0, 32);
391 m_rackPosition = (INT16)DBGetFieldLong(hResult, 0, 33);
392 m_rackHeight = (INT16)DBGetFieldLong(hResult, 0, 34);
393 m_lastAgentCommTime = DBGetFieldLong(hResult, 0, 35);
394 m_syslogMessageCount = DBGetFieldInt64(hResult, 0, 36);
395 m_snmpTrapCount = DBGetFieldInt64(hResult, 0, 37);
396 m_type = (NodeType)DBGetFieldLong(hResult, 0, 38);
397 DBGetField(hResult, 0, 39, m_subType, MAX_NODE_SUBTYPE_LENGTH);
398 DBGetField(hResult, 0, 40, m_sshLogin, MAX_SSH_LOGIN_LEN);
399 DBGetField(hResult, 0, 41, m_sshPassword, MAX_SSH_PASSWORD_LEN);
400 m_sshProxy = DBGetFieldULong(hResult, 0, 42);
401 m_portRowCount = DBGetFieldULong(hResult, 0, 43);
402 m_portNumberingScheme = DBGetFieldULong(hResult, 0, 44);
403 m_agentCompressionMode = (INT16)DBGetFieldLong(hResult, 0, 45);
404 m_tunnelId = DBGetFieldGUID(hResult, 0, 46);
405 m_lldpNodeId = DBGetField(hResult, 0, 47, NULL, 0);
406 if ((m_lldpNodeId != NULL) && (*m_lldpNodeId == 0))
407 safe_free_and_null(m_lldpNodeId);
408 m_capabilities = DBGetFieldULong(hResult, 0, 48);
409 m_failTimeSNMP = DBGetFieldLong(hResult, 0, 49);
410 m_failTimeAgent = DBGetFieldLong(hResult, 0, 50);
411
412 DBFreeResult(hResult);
413 DBFreeStatement(hStmt);
414
415 if (!m_isDeleted)
416 {
417 // Link node to subnets
418 hStmt = DBPrepare(hdb, _T("SELECT subnet_id FROM nsmap WHERE node_id=?"));
419 if (hStmt == NULL)
420 return false;
421
422 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
423 hResult = DBSelectPrepared(hStmt);
424 if (hResult == NULL)
425 {
426 DBFreeStatement(hStmt);
427 return false; // Query failed
428 }
429
430 iNumRows = DBGetNumRows(hResult);
431 for(i = 0; i < iNumRows; i++)
432 {
433 dwSubnetId = DBGetFieldULong(hResult, i, 0);
434 pObject = FindObjectById(dwSubnetId);
435 if (pObject == NULL)
436 {
437 nxlog_write(MSG_INVALID_SUBNET_ID, EVENTLOG_ERROR_TYPE, "dd", dwId, dwSubnetId);
438 break;
439 }
440 else if (pObject->getObjectClass() != OBJECT_SUBNET)
441 {
442 nxlog_write(MSG_SUBNET_NOT_SUBNET, EVENTLOG_ERROR_TYPE, "dd", dwId, dwSubnetId);
443 break;
444 }
445 else
446 {
447 pObject->addChild(this);
448 addParent(pObject);
449 }
450 }
451
452 DBFreeResult(hResult);
453 DBFreeStatement(hStmt);
454
455 loadItemsFromDB(hdb);
456 loadACLFromDB(hdb);
457
458 // Walk through all items in the node and load appropriate thresholds
459 bResult = true;
460 for(i = 0; i < m_dcObjects->size(); i++)
461 {
462 if (!m_dcObjects->get(i)->loadThresholdsFromDB(hdb))
463 {
464 DbgPrintf(3, _T("Cannot load thresholds for DCI %d of node %d (%s)"),
465 m_dcObjects->get(i)->getId(), dwId, m_name);
466 bResult = false;
467 }
468 }
469
470 updatePhysicalContainerBinding(OBJECT_RACK, m_rackId);
471 updatePhysicalContainerBinding(OBJECT_CHASSIS, m_chassisId);
472 }
473 else
474 {
475 bResult = true;
476 }
477
478 return bResult;
479 }
480
481 /**
482 * Save object to database
483 */
484 bool Node::saveToDatabase(DB_HANDLE hdb)
485 {
486 // Lock object's access
487 lockProperties();
488
489 if (!saveCommonProperties(hdb))
490 {
491 unlockProperties();
492 return false;
493 }
494
495 // Form and execute INSERT or UPDATE query
496 int snmpMethods = m_snmpSecurity->getAuthMethod() | (m_snmpSecurity->getPrivMethod() << 8);
497 DB_STATEMENT hStmt;
498 if (IsDatabaseRecordExist(hdb, _T("nodes"), _T("id"), m_id))
499 {
500 hStmt = DBPrepare(hdb,
501 _T("UPDATE nodes SET primary_ip=?,primary_name=?,snmp_port=?,capabilities=?,snmp_version=?,community=?,")
502 _T("status_poll_type=?,agent_port=?,auth_method=?,secret=?,snmp_oid=?,uname=?,agent_version=?,")
503 _T("platform_name=?,poller_node_id=?,zone_guid=?,proxy_node=?,snmp_proxy=?,icmp_proxy=?,required_polls=?,")
504 _T("use_ifxtable=?,usm_auth_password=?,usm_priv_password=?,usm_methods=?,snmp_sys_name=?,bridge_base_addr=?,")
505 _T("down_since=?,driver_name=?,rack_image=?,rack_position=?,rack_height=?,rack_id=?,boot_time=?,")
506 _T("agent_cache_mode=?,snmp_sys_contact=?,snmp_sys_location=?,last_agent_comm_time=?,")
507 _T("syslog_msg_count=?,snmp_trap_count=?,node_type=?,node_subtype=?,ssh_login=?,ssh_password=?,")
508 _T("ssh_proxy=?,chassis_id=?,port_rows=?,port_numbering_scheme=?,agent_comp_mode=?,tunnel_id=?,")
509 _T("lldp_id=?,fail_time_snmp=?,fail_time_agent=? WHERE id=?"));
510 }
511 else
512 {
513 hStmt = DBPrepare(hdb,
514 _T("INSERT INTO nodes (primary_ip,primary_name,snmp_port,capabilities,snmp_version,community,status_poll_type,")
515 _T("agent_port,auth_method,secret,snmp_oid,uname,agent_version,platform_name,poller_node_id,zone_guid,")
516 _T("proxy_node,snmp_proxy,icmp_proxy,required_polls,use_ifxtable,usm_auth_password,usm_priv_password,usm_methods,")
517 _T("snmp_sys_name,bridge_base_addr,down_since,driver_name,rack_image,rack_position,rack_height,rack_id,boot_time,")
518 _T("agent_cache_mode,snmp_sys_contact,snmp_sys_location,last_agent_comm_time,syslog_msg_count,snmp_trap_count,")
519 _T("node_type,node_subtype,ssh_login,ssh_password,ssh_proxy,chassis_id,port_rows,port_numbering_scheme,agent_comp_mode,")
520 _T("tunnel_id,lldp_id,fail_time_snmp,fail_time_agent,id) ")
521 _T("VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
522 }
523 if (hStmt == NULL)
524 {
525 unlockProperties();
526 return false;
527 }
528
529 TCHAR ipAddr[64], baseAddress[16], cacheMode[16], compressionMode[16];
530
531 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, m_ipAddress.toString(ipAddr), DB_BIND_STATIC);
532 DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, m_primaryName, DB_BIND_STATIC);
533 DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, (LONG)m_snmpPort);
534 DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, m_capabilities);
535 DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, (LONG)m_snmpVersion);
536 #ifdef UNICODE
537 DBBind(hStmt, 6, DB_SQLTYPE_VARCHAR, WideStringFromMBString(m_snmpSecurity->getCommunity()), DB_BIND_DYNAMIC);
538 #else
539 DBBind(hStmt, 6, DB_SQLTYPE_VARCHAR, m_snmpSecurity->getCommunity(), DB_BIND_STATIC);
540 #endif
541 DBBind(hStmt, 7, DB_SQLTYPE_INTEGER, (LONG)m_iStatusPollType);
542 DBBind(hStmt, 8, DB_SQLTYPE_INTEGER, (LONG)m_agentPort);
543 DBBind(hStmt, 9, DB_SQLTYPE_INTEGER, (LONG)m_agentAuthMethod);
544 DBBind(hStmt, 10, DB_SQLTYPE_VARCHAR, m_szSharedSecret, DB_BIND_STATIC);
545 DBBind(hStmt, 11, DB_SQLTYPE_VARCHAR, m_snmpObjectId, DB_BIND_STATIC);
546 DBBind(hStmt, 12, DB_SQLTYPE_VARCHAR, m_sysDescription, DB_BIND_STATIC);
547 DBBind(hStmt, 13, DB_SQLTYPE_VARCHAR, m_agentVersion, DB_BIND_STATIC);
548 DBBind(hStmt, 14, DB_SQLTYPE_VARCHAR, m_platformName, DB_BIND_STATIC);
549 DBBind(hStmt, 15, DB_SQLTYPE_INTEGER, m_pollerNode);
550 DBBind(hStmt, 16, DB_SQLTYPE_INTEGER, m_zoneUIN);
551 DBBind(hStmt, 17, DB_SQLTYPE_INTEGER, m_agentProxy);
552 DBBind(hStmt, 18, DB_SQLTYPE_INTEGER, m_snmpProxy);
553 DBBind(hStmt, 19, DB_SQLTYPE_INTEGER, m_icmpProxy);
554 DBBind(hStmt, 20, DB_SQLTYPE_INTEGER, (LONG)m_iRequiredPollCount);
555 DBBind(hStmt, 21, DB_SQLTYPE_INTEGER, (LONG)m_nUseIfXTable);
556 #ifdef UNICODE
557 DBBind(hStmt, 22, DB_SQLTYPE_VARCHAR, WideStringFromMBString(m_snmpSecurity->getAuthPassword()), DB_BIND_DYNAMIC);
558 DBBind(hStmt, 23, DB_SQLTYPE_VARCHAR, WideStringFromMBString(m_snmpSecurity->getPrivPassword()), DB_BIND_DYNAMIC);
559 #else
560 DBBind(hStmt, 22, DB_SQLTYPE_VARCHAR, m_snmpSecurity->getAuthPassword(), DB_BIND_STATIC);
561 DBBind(hStmt, 23, DB_SQLTYPE_VARCHAR, m_snmpSecurity->getPrivPassword(), DB_BIND_STATIC);
562 #endif
563 DBBind(hStmt, 24, DB_SQLTYPE_INTEGER, (LONG)snmpMethods);
564 DBBind(hStmt, 25, DB_SQLTYPE_VARCHAR, m_sysName, DB_BIND_STATIC);
565 DBBind(hStmt, 26, DB_SQLTYPE_VARCHAR, BinToStr(m_baseBridgeAddress, MAC_ADDR_LENGTH, baseAddress), DB_BIND_STATIC);
566 DBBind(hStmt, 27, DB_SQLTYPE_INTEGER, (LONG)m_downSince);
567 DBBind(hStmt, 28, DB_SQLTYPE_VARCHAR, (m_driver != NULL) ? m_driver->getName() : _T(""), DB_BIND_STATIC);
568 DBBind(hStmt, 29, DB_SQLTYPE_VARCHAR, m_rackImage); // rack image
569 DBBind(hStmt, 30, DB_SQLTYPE_INTEGER, m_rackPosition); // rack position
570 DBBind(hStmt, 31, DB_SQLTYPE_INTEGER, m_rackHeight); // device height in rack units
571 DBBind(hStmt, 32, DB_SQLTYPE_INTEGER, m_rackId); // rack ID
572 DBBind(hStmt, 33, DB_SQLTYPE_INTEGER, (LONG)m_bootTime);
573 DBBind(hStmt, 34, DB_SQLTYPE_VARCHAR, _itot(m_agentCacheMode, cacheMode, 10), DB_BIND_STATIC, 1);
574 DBBind(hStmt, 35, DB_SQLTYPE_VARCHAR, m_sysContact, DB_BIND_STATIC);
575 DBBind(hStmt, 36, DB_SQLTYPE_VARCHAR, m_sysLocation, DB_BIND_STATIC);
576 DBBind(hStmt, 37, DB_SQLTYPE_INTEGER, (LONG)m_lastAgentCommTime);
577 DBBind(hStmt, 38, DB_SQLTYPE_BIGINT, m_syslogMessageCount);
578 DBBind(hStmt, 39, DB_SQLTYPE_BIGINT, m_snmpTrapCount);
579 DBBind(hStmt, 40, DB_SQLTYPE_INTEGER, (INT32)m_type);
580 DBBind(hStmt, 41, DB_SQLTYPE_VARCHAR, m_subType, DB_BIND_STATIC);
581 DBBind(hStmt, 42, DB_SQLTYPE_VARCHAR, m_sshLogin, DB_BIND_STATIC);
582 DBBind(hStmt, 43, DB_SQLTYPE_VARCHAR, m_sshPassword, DB_BIND_STATIC);
583 DBBind(hStmt, 44, DB_SQLTYPE_INTEGER, m_sshProxy);
584 DBBind(hStmt, 45, DB_SQLTYPE_INTEGER, m_chassisId);
585 DBBind(hStmt, 46, DB_SQLTYPE_INTEGER, m_portRowCount);
586 DBBind(hStmt, 47, DB_SQLTYPE_INTEGER, m_portNumberingScheme);
587 DBBind(hStmt, 48, DB_SQLTYPE_VARCHAR, _itot(m_agentCompressionMode, compressionMode, 10), DB_BIND_STATIC, 1);
588 DBBind(hStmt, 49, DB_SQLTYPE_VARCHAR, m_tunnelId);
589 DBBind(hStmt, 50, DB_SQLTYPE_VARCHAR, m_lldpNodeId, DB_BIND_STATIC);
590 DBBind(hStmt, 51, DB_SQLTYPE_INTEGER, (LONG)m_failTimeSNMP);
591 DBBind(hStmt, 52, DB_SQLTYPE_INTEGER, (LONG)m_failTimeAgent);
592 DBBind(hStmt, 53, DB_SQLTYPE_INTEGER, m_id);
593
594 bool bResult = DBExecute(hStmt);
595 DBFreeStatement(hStmt);
596
597 // Save access list
598 saveACLToDB(hdb);
599
600 unlockProperties();
601
602 // Save data collection items
603 if (bResult)
604 {
605 lockDciAccess(false);
606 for(int i = 0; i < m_dcObjects->size(); i++)
607 m_dcObjects->get(i)->saveToDatabase(hdb);
608 unlockDciAccess();
609 }
610
611 // Clear modifications flag
612 lockProperties();
613 m_isModified = false;
614 unlockProperties();
615
616 return bResult;
617 }
618
619 /**
620 * Save runtime data to database. Called only on server shutdown to save
621 * less important but frequently changing runtime data when it is not feasible
622 * to mark object as modified on each change of such data.
623 */
624 bool Node::saveRuntimeData(DB_HANDLE hdb)
625 {
626 if (!DataCollectionTarget::saveRuntimeData(hdb))
627 return false;
628
629 DB_STATEMENT hStmt = DBPrepare(hdb, _T("UPDATE nodes SET last_agent_comm_time=?,syslog_msg_count=?,snmp_trap_count=? WHERE id=?"));
630 if (hStmt == NULL)
631 return false;
632
633 lockProperties();
634 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, (INT32)m_lastAgentCommTime);
635 DBBind(hStmt, 2, DB_SQLTYPE_BIGINT, m_syslogMessageCount);
636 DBBind(hStmt, 3, DB_SQLTYPE_BIGINT, m_snmpTrapCount);
637 DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, m_id);
638 unlockProperties();
639
640 bool success = DBExecute(hStmt);
641 DBFreeStatement(hStmt);
642 return success;
643 }
644
645 /**
646 * Delete object from database
647 */
648 bool Node::deleteFromDatabase(DB_HANDLE hdb)
649 {
650 bool success = DataCollectionTarget::deleteFromDatabase(hdb);
651 if (success)
652 success = executeQueryOnObject(hdb, _T("DELETE FROM nodes WHERE id=?"));
653 if (success)
654 success = executeQueryOnObject(hdb, _T("DELETE FROM nsmap WHERE node_id=?"));
655 return success;
656 }
657
658 /**
659 * Get ARP cache from node
660 */
661 ARP_CACHE *Node::getArpCache()
662 {
663 ARP_CACHE *pArpCache = NULL;
664
665 if (m_capabilities & NC_IS_LOCAL_MGMT)
666 {
667 pArpCache = GetLocalArpCache();
668 }
669 else if (m_capabilities & NC_IS_NATIVE_AGENT)
670 {
671 agentLock();
672 if (connectToAgent())
673 pArpCache = m_agentConnection->getArpCache();
674 agentUnlock();
675 }
676 else if (m_capabilities & NC_IS_SNMP)
677 {
678 SNMP_Transport *pTransport;
679
680 pTransport = createSnmpTransport();
681 if (pTransport != NULL)
682 {
683 pArpCache = SnmpGetArpCache(m_snmpVersion, pTransport);
684 delete pTransport;
685 }
686 }
687
688 return pArpCache;
689 }
690
691 /**
692 * Get list of interfaces from node
693 */
694 InterfaceList *Node::getInterfaceList()
695 {
696 InterfaceList *pIfList = NULL;
697
698 if ((m_capabilities & NC_IS_NATIVE_AGENT) && (!(m_flags & NF_DISABLE_NXCP)))
699 {
700 agentLock();
701 if (connectToAgent())
702 {
703 pIfList = m_agentConnection->getInterfaceList();
704 }
705 agentUnlock();
706 }
707 if ((pIfList == NULL) && (m_capabilities & NC_IS_LOCAL_MGMT))
708 {
709 pIfList = GetLocalInterfaceList();
710 }
711 if ((pIfList == NULL) && (m_capabilities & NC_IS_SNMP) &&
712 (!(m_flags & NF_DISABLE_SNMP)) && (m_driver != NULL))
713 {
714 SNMP_Transport *pTransport = createSnmpTransport();
715 if (pTransport != NULL)
716 {
717 bool useIfXTable;
718 if (m_nUseIfXTable == IFXTABLE_DEFAULT)
719 {
720 useIfXTable = (ConfigReadInt(_T("UseIfXTable"), 1) != 0) ? true : false;
721 }
722 else
723 {
724 useIfXTable = (m_nUseIfXTable == IFXTABLE_ENABLED) ? true : false;
725 }
726
727 int useAliases = ConfigReadInt(_T("UseInterfaceAliases"), 0);
728 pIfList = m_driver->getInterfaces(pTransport, &m_customAttributes, m_driverData, useAliases, useIfXTable);
729
730 if ((pIfList != NULL) && (m_capabilities & NC_IS_BRIDGE))
731 {
732 BridgeMapPorts(pTransport, pIfList);
733 }
734 delete pTransport;
735 }
736 }
737
738 if (pIfList != NULL)
739 {
740 checkInterfaceNames(pIfList);
741 addVrrpInterfaces(pIfList);
742 }
743
744 return pIfList;
745 }
746
747 /**
748 * Add VRRP interfaces to interface list
749 */
750 void Node::addVrrpInterfaces(InterfaceList *ifList)
751 {
752 int i, j, k;
753 TCHAR buffer[32];
754
755 lockProperties();
756 if (m_vrrpInfo != NULL)
757 {
758 DbgPrintf(6, _T("Node::addVrrpInterfaces(node=%s [%d]): m_vrrpInfo->size()=%d"), m_name, (int)m_id, m_vrrpInfo->size());
759
760 for(i = 0; i < m_vrrpInfo->size(); i++)
761 {
762 VrrpRouter *router = m_vrrpInfo->getRouter(i);
763 DbgPrintf(6, _T("Node::addVrrpInterfaces(node=%s [%d]): vrouter %d state=%d"), m_name, (int)m_id, i, router->getState());
764 if (router->getState() != VRRP_STATE_MASTER)
765 continue; // Do not add interfaces if router is not in master state
766
767 // Get netmask for this VR
768 int maskBits = 0;
769 for(j = 0; j < ifList->size(); j++)
770 {
771 InterfaceInfo *iface = ifList->get(j);
772 if (iface->index == router->getIfIndex())
773 {
774 for(int k = 0; k < iface->ipAddrList.size(); k++)
775 {
776 const InetAddress& addr = iface->ipAddrList.get(k);
777 if (addr.getSubnetAddress().contain(router->getVip(0)))
778 {
779 maskBits = addr.getMaskBits();
780 }
781 }
782 break;
783 }
784 }
785
786 // Walk through all VR virtual IPs
787 for(j = 0; j < router->getVipCount(); j++)
788 {
789 UINT32 vip = router->getVip(j);
790 DbgPrintf(6, _T("Node::addVrrpInterfaces(node=%s [%d]): checking VIP %s@%d"), m_name, (int)m_id, IpToStr(vip, buffer), i);
791 if (vip != 0)
792 {
793 for(k = 0; k < ifList->size(); k++)
794 if (ifList->get(k)->hasAddress(vip))
795 break;
796 if (k == ifList->size())
797 {
798 InterfaceInfo *iface = new InterfaceInfo(0);
799 _sntprintf(iface->name, MAX_DB_STRING, _T("vrrp.%u.%u.%d"), router->getId(), router->getIfIndex(), j);
800 memcpy(iface->macAddr, router->getVirtualMacAddr(), MAC_ADDR_LENGTH);
801 InetAddress addr(vip);
802 addr.setMaskBits(maskBits);
803 iface->ipAddrList.add(addr);
804 ifList->add(iface);
805 DbgPrintf(6, _T("Node::addVrrpInterfaces(node=%s [%d]): added interface %s"), m_name, (int)m_id, iface->name);
806 }
807 }
808 }
809 }
810 }
811 unlockProperties();
812 }
813
814 /**
815 * Find interface by index.
816 *
817 * @param ifIndex interface index to match
818 * @return pointer to interface object or NULL if appropriate interface couldn't be found
819 */
820 Interface *Node::findInterfaceByIndex(UINT32 ifIndex)
821 {
822 lockChildList(false);
823 for(int i = 0; i < m_childList->size(); i++)
824 if (m_childList->get(i)->getObjectClass() == OBJECT_INTERFACE)
825 {
826 Interface *pInterface = (Interface *)m_childList->get(i);
827 if (pInterface->getIfIndex() == ifIndex)
828 {
829 unlockChildList();
830 return pInterface;
831 }
832 }
833 unlockChildList();
834 return NULL;
835 }
836
837 /**
838 * Find interface by name or description
839 * Returns pointer to interface object or NULL if appropriate interface couldn't be found
840 */
841 Interface *Node::findInterfaceByName(const TCHAR *name)
842 {
843 if ((name == NULL) || (name[0] == 0))
844 return NULL;
845
846 Interface *pInterface;
847
848 lockChildList(false);
849 for(int i = 0; i < m_childList->size(); i++)
850 if (m_childList->get(i)->getObjectClass() == OBJECT_INTERFACE)
851 {
852 pInterface = (Interface *)m_childList->get(i);
853 if (!_tcsicmp(pInterface->getName(), name) || !_tcsicmp(pInterface->getDescription(), name))
854 {
855 unlockChildList();
856 return pInterface;
857 }
858 }
859 unlockChildList();
860 return NULL;
861 }
862
863 /**
864 * Find interface by slot/port pair
865 * Returns pointer to interface object or NULL if appropriate interface couldn't be found
866 */
867 Interface *Node::findInterfaceBySlotAndPort(UINT32 slot, UINT32 port)
868 {
869 lockChildList(false);
870 for(int i = 0; i < m_childList->size(); i++)
871 if (m_childList->get(i)->getObjectClass() == OBJECT_INTERFACE)
872 {
873 Interface *pInterface = (Interface *)m_childList->get(i);
874 if (pInterface->isPhysicalPort() && (pInterface->getSlotNumber() == slot) && (pInterface->getPortNumber() == port))
875 {
876 unlockChildList();
877 return pInterface;
878 }
879 }
880 unlockChildList();
881 return NULL;
882 }
883
884 /**
885 * Find interface by MAC address
886 * Returns pointer to interface object or NULL if appropriate interface couldn't be found
887 */
888 Interface *Node::findInterfaceByMAC(const BYTE *macAddr)
889 {
890 Interface *iface = NULL;
891 lockChildList(false);
892 for(int i = 0; i < m_childList->size(); i++)
893 {
894 NetObj *curr = m_childList->get(i);
895 if (curr->getObjectClass() == OBJECT_INTERFACE)
896 {
897 if (!memcmp(((Interface *)curr)->getMacAddr(), macAddr, MAC_ADDR_LENGTH))
898 {
899 iface = (Interface *)curr;
900 break;
901 }
902 }
903 }
904 unlockChildList();
905 return iface;
906 }
907
908 /**
909 * Find interface by IP address
910 * Returns pointer to interface object or NULL if appropriate interface couldn't be found
911 */
912 Interface *Node::findInterfaceByIP(const InetAddress& addr)
913 {
914 if (!addr.isValid())
915 return NULL;
916
917 lockChildList(false);
918 for(int i = 0; i < m_childList->size(); i++)
919 if (m_childList->get(i)->getObjectClass() == OBJECT_INTERFACE)
920 {
921 Interface *pInterface = (Interface *)m_childList->get(i);
922 if (pInterface->getIpAddressList()->hasAddress(addr))
923 {
924 unlockChildList();
925 return pInterface;
926 }
927 }
928 unlockChildList();
929 return NULL;
930 }
931
932 /**
933 * Find interface by bridge port number
934 */
935 Interface *Node::findBridgePort(UINT32 bridgePortNumber)
936 {
937 lockChildList(false);
938 for(int i = 0; i < m_childList->size(); i++)
939 if (m_childList->get(i)->getObjectClass() == OBJECT_INTERFACE)
940 {
941 Interface *pInterface = (Interface *)m_childList->get(i);
942 if (pInterface->getBridgePortNumber() == bridgePortNumber)
943 {
944 unlockChildList();
945 return pInterface;
946 }
947 }
948 unlockChildList();
949 return NULL;
950 }
951
952 /**
953 * Find connection point for node
954 */
955 NetObj *Node::findConnectionPoint(UINT32 *localIfId, BYTE *localMacAddr, int *type)
956 {
957 NetObj *cp = NULL;
958 lockChildList(false);
959 for(int i = 0; i < m_childList->size(); i++)
960 {
961 if (m_childList->get(i)->getObjectClass() == OBJECT_INTERFACE)
962 {
963 Interface *iface = (Interface *)m_childList->get(i);
964 cp = FindInterfaceConnectionPoint(iface->getMacAddr(), type);
965 if (cp != NULL)
966 {
967 *localIfId = iface->getId();
968 memcpy(localMacAddr, iface->getMacAddr(), MAC_ADDR_LENGTH);
969 break;
970 }
971 }
972 }
973 unlockChildList();
974 return cp;
975 }
976
977 /**
978 * Find attached access point by MAC address
979 */
980 AccessPoint *Node::findAccessPointByMAC(const BYTE *macAddr)
981 {
982 AccessPoint *ap = NULL;
983 lockChildList(false);
984 for(int i = 0; i < m_childList->size(); i++)
985 {
986 NetObj *curr = m_childList->get(i);
987 if (curr->getObjectClass() == OBJECT_ACCESSPOINT)
988 {
989 if (!memcmp(((AccessPoint *)curr)->getMacAddr(), macAddr, MAC_ADDR_LENGTH))
990 {
991 ap = (AccessPoint *)curr;
992 break;
993 }
994 }
995 }
996 unlockChildList();
997 return ap;
998 }
999
1000 /**
1001 * Find access point by radio ID (radio interface index)
1002 */
1003 AccessPoint *Node::findAccessPointByRadioId(int rfIndex)
1004 {
1005 AccessPoint *ap = NULL;
1006 lockChildList(false);
1007 for(int i = 0; i < m_childList->size(); i++)
1008 {
1009 NetObj *curr = m_childList->get(i);
1010 if (curr->getObjectClass() == OBJECT_ACCESSPOINT)
1011 {
1012 if (((AccessPoint *)curr)->isMyRadio(rfIndex))
1013 {
1014 ap = (AccessPoint *)curr;
1015 break;
1016 }
1017 }
1018 }
1019 unlockChildList();
1020 return ap;
1021 }
1022
1023 /**
1024 * Find attached access point by BSSID
1025 */
1026 AccessPoint *Node::findAccessPointByBSSID(const BYTE *bssid)
1027 {
1028 AccessPoint *ap = NULL;
1029 lockChildList(false);
1030 for(int i = 0; i < m_childList->size(); i++)
1031 {
1032 NetObj *curr = m_childList->get(i);
1033 if (curr->getObjectClass() == OBJECT_ACCESSPOINT)
1034 {
1035 if (!memcmp(((AccessPoint *)curr)->getMacAddr(), bssid, MAC_ADDR_LENGTH) ||
1036 ((AccessPoint *)curr)->isMyRadio(bssid))
1037 {
1038 ap = (AccessPoint *)curr;
1039 break;
1040 }
1041 }
1042 }
1043 unlockChildList();
1044 return ap;
1045 }
1046
1047 /**
1048 * Check if given IP address is one of node's interfaces
1049 */
1050 bool Node::isMyIP(const InetAddress& addr)
1051 {
1052 lockChildList(false);
1053 for(int i = 0; i < m_childList->size(); i++)
1054 if (m_childList->get(i)->getObjectClass() == OBJECT_INTERFACE)
1055 {
1056 if (((Interface *)m_childList->get(i))->getIpAddressList()->hasAddress(addr))
1057 {
1058 unlockChildList();
1059 return true;
1060 }
1061 }
1062 unlockChildList();
1063 return false;
1064 }
1065
1066 /**
1067 * Filter interface - should return true if system should proceed with interface creation
1068 */
1069 bool Node::filterInterface(InterfaceInfo *info)
1070 {
1071 NXSL_VM *vm = CreateServerScriptVM(_T("Hook::CreateInterface"));
1072 if (vm == NULL)
1073 {
1074 DbgPrintf(7, _T("Node::filterInterface(%s [%u]): hook script \"Hook::CreateInterface\" not found"), m_name, m_id);
1075 return true;
1076 }
1077
1078 Interface *iface;
1079 if (info->name[0] != 0)
1080 {
1081 iface = new Interface(info->name, (info->description[0] != 0) ? info->description : info->name,
1082 info->index, info->ipAddrList, info->type, m_zoneUIN);
1083 }
1084 else
1085 {
1086 iface = new Interface(info->ipAddrList, m_zoneUIN, false);
1087 }
1088 iface->setMacAddr(info->macAddr, false);
1089 iface->setBridgePortNumber(info->bridgePort);
1090 iface->setSlotNumber(info->slot);
1091 iface->setPortNumber(info->port);
1092 iface->setPhysicalPortFlag(info->isPhysicalPort);
1093 iface->setManualCreationFlag(false);
1094 iface->setSystemFlag(info->isSystem);
1095 iface->setMTU(info->mtu);
1096 iface->setSpeed(info->speed);
1097 iface->setIfTableSuffix(info->ifTableSuffixLength, info->ifTableSuffix);
1098
1099 bool pass = true;
1100 NXSL_Value *argv = new NXSL_Value(new NXSL_Object(&g_nxslInterfaceClass, iface));
1101 vm->setGlobalVariable(_T("$node"), new NXSL_Value(new NXSL_Object(&g_nxslNodeClass, this)));
1102 if (vm->run(1, &argv))
1103 {
1104 NXSL_Value *result = vm->getResult();
1105 if ((result != NULL) && result->isInteger())
1106 {
1107 pass = (result->getValueAsInt32() != 0);
1108 }
1109 }
1110 else
1111 {
1112 DbgPrintf(4, _T("Node::filterInterface(%s [%u]): hook script execution error: %s"), m_name, m_id, vm->getErrorText());
1113 }
1114 delete vm;
1115 delete iface;
1116
1117 DbgPrintf(6, _T("Node::filterInterface(%s [%u]): interface \"%s\" (ifIndex=%d) %s by filter"),
1118 m_name, m_id, info->name, info->index, pass ? _T("accepted") : _T("rejected"));
1119 return pass;
1120 }
1121
1122 /**
1123 * Create new interface - convenience wrapper
1124 */
1125 Interface *Node::createNewInterface(const InetAddress& ipAddr, BYTE *macAddr, bool fakeInterface)
1126 {
1127 InterfaceInfo info(1);
1128 info.ipAddrList.add(ipAddr);
1129 if (macAddr != NULL)
1130 memcpy(info.macAddr, macAddr, MAC_ADDR_LENGTH);
1131 return createNewInterface(&info, false, fakeInterface);
1132 }
1133
1134 /**
1135 * Create new interface
1136 */
1137 Interface *Node::createNewInterface(InterfaceInfo *info, bool manuallyCreated, bool fakeInterface)
1138 {
1139 bool bSyntheticMask = false;
1140 TCHAR buffer[64];
1141
1142 DbgPrintf(5, _T("Node::createNewInterface(\"%s\", %d, %d, bp=%d, slot=%d, port=%d) called for node %s [%d]"),
1143 info->name, info->index, info->type, info->bridgePort, info->slot, info->port, m_name, m_id);
1144 for(int i = 0; i < info->ipAddrList.size(); i++)
1145 {
1146 const InetAddress& addr = info->ipAddrList.get(i);
1147 DbgPrintf(5, _T("Node::createNewInterface(%s): IP address %s/%d"), info->name, addr.toString(buffer), addr.getMaskBits());
1148 }
1149
1150 // Find subnet to place interface object to
1151 if (info->type != IFTYPE_SOFTWARE_LOOPBACK)
1152 {
1153 Cluster *pCluster = getMyCluster();
1154 for(int i = 0; i < info->ipAddrList.size(); i++)
1155 {
1156 InetAddress addr = info->ipAddrList.get(i);
1157 bool addToSubnet = addr.isValidUnicast() && ((pCluster == NULL) || !pCluster->isSyncAddr(addr));
1158 DbgPrintf(5, _T("Node::createNewInterface: node=%s [%d] ip=%s/%d cluster=%s [%d] add=%s"),
1159 m_name, m_id, addr.toString(buffer), addr.getMaskBits(),
1160 (pCluster != NULL) ? pCluster->getName() : _T("(null)"),
1161 (pCluster != NULL) ? pCluster->getId() : 0, addToSubnet ? _T("yes") : _T("no"));
1162 if (addToSubnet)
1163 {
1164 Subnet *pSubnet = FindSubnetForNode(m_zoneUIN, addr);
1165 if (pSubnet == NULL)
1166 {
1167 // Check if netmask is 0 (detect), and if yes, create
1168 // new subnet with default mask
1169 if (addr.getMaskBits() == 0)
1170 {
1171 bSyntheticMask = true;
1172 addr.setMaskBits((addr.getFamily() == AF_INET) ? ConfigReadInt(_T("DefaultSubnetMaskIPv4"), 24) : ConfigReadInt(_T("DefaultSubnetMaskIPv6"), 64));
1173 info->ipAddrList.replace(addr);
1174 }
1175
1176 // Create new subnet object
1177 if (addr.getHostBits() >= 2)
1178 {
1179 pSubnet = createSubnet(addr, bSyntheticMask);
1180 if (bSyntheticMask)
1181 {
1182 // createSubnet may adjust address mask bits
1183 info->ipAddrList.replace(addr);
1184 }
1185 }
1186 }
1187 else
1188 {
1189 // Set correct netmask if we were asked for it
1190 if (addr.getMaskBits() == 0)
1191 {
1192 bSyntheticMask = pSubnet->isSyntheticMask();
1193 addr.setMaskBits(pSubnet->getIpAddress().getMaskBits());
1194 info->ipAddrList.replace(addr);
1195 }
1196 }
1197 if (pSubnet != NULL)
1198 {
1199 pSubnet->addNode(this);
1200 }
1201 } // addToSubnet
1202 } // loop by address list
1203 }
1204
1205 // Create interface object
1206 Interface *iface;
1207 if (info->name[0] != 0)
1208 iface = new Interface(info->name, (info->description[0] != 0) ? info->description : info->name,
1209 info->index, info->ipAddrList, info->type, m_zoneUIN);
1210 else
1211 iface = new Interface(info->ipAddrList, m_zoneUIN, bSyntheticMask);
1212 iface->setMacAddr(info->macAddr, false);
1213 iface->setBridgePortNumber(info->bridgePort);
1214 iface->setSlotNumber(info->slot);
1215 iface->setPortNumber(info->port);
1216 iface->setPhysicalPortFlag(info->isPhysicalPort);
1217 iface->setManualCreationFlag(manuallyCreated);
1218 iface->setSystemFlag(info->isSystem);
1219 iface->setMTU(info->mtu);
1220 iface->setSpeed(info->speed);
1221 iface->setIfTableSuffix(info->ifTableSuffixLength, info->ifTableSuffix);
1222
1223 int defaultExpectedState = ConfigReadInt(_T("DefaultInterfaceExpectedState"), IF_DEFAULT_EXPECTED_STATE_UP);
1224 switch(defaultExpectedState)
1225 {
1226 case IF_DEFAULT_EXPECTED_STATE_AUTO:
1227 iface->setExpectedState(fakeInterface ? IF_EXPECTED_STATE_UP : IF_EXPECTED_STATE_AUTO);
1228 break;
1229 case IF_DEFAULT_EXPECTED_STATE_IGNORE:
1230 iface->setExpectedState(IF_EXPECTED_STATE_IGNORE);
1231 break;
1232 default:
1233 iface->setExpectedState(IF_EXPECTED_STATE_UP);
1234 break;
1235 }
1236
1237 // Insert to objects' list and generate event
1238 NetObjInsert(iface, true, false);
1239 addInterface(iface);
1240 if (!m_isHidden)
1241 iface->unhide();
1242 if (!iface->isSystem())
1243 {
1244 const InetAddress& addr = iface->getFirstIpAddress();
1245 PostEvent(EVENT_INTERFACE_ADDED, m_id, "dsAdd", iface->getId(),
1246 iface->getName(), &addr, addr.getMaskBits(), iface->getIfIndex());
1247 }
1248
1249 return iface;
1250 }
1251
1252 /**
1253 * Delete interface from node
1254 */
1255 void Node::deleteInterface(Interface *iface)
1256 {
1257 DbgPrintf(5, _T("Node::deleteInterface(node=%s [%d], interface=%s [%d])"), m_name, m_id, iface->getName(), iface->getId());
1258
1259 // Check if we should unlink node from interface's subnet
1260 if (!iface->isExcludedFromTopology())
1261 {
1262 const ObjectArray<InetAddress> *list = iface->getIpAddressList()->getList();
1263 for(int i = 0; i < list->size(); i++)
1264 {
1265 bool doUnlink = true;
1266 const InetAddress *addr = list->get(i);
1267
1268 lockChildList(false);
1269 for(int j = 0; j < m_childList->size(); j++)
1270 {
1271 NetObj *curr = m_childList->get(j);
1272 if ((curr->getObjectClass() == OBJECT_INTERFACE) && (curr != iface) &&
1273 ((Interface *)curr)->getIpAddressList()->findSameSubnetAddress(*addr).isValid())
1274 {
1275 doUnlink = false;
1276 break;
1277 }
1278 }
1279 unlockChildList();
1280
1281 if (doUnlink)
1282 {
1283 // Last interface in subnet, should unlink node
1284 Subnet *pSubnet = FindSubnetByIP(m_zoneUIN, addr->getSubnetAddress());
1285 if (pSubnet != NULL)
1286 {
1287 deleteParent(pSubnet);
1288 pSubnet->deleteChild(this);
1289 }
1290 DbgPrintf(5, _T("Node::deleteInterface(node=%s [%d], interface=%s [%d]): unlinked from subnet %s [%d]"),
1291 m_name, m_id, iface->getName(), iface->getId(),
1292 (pSubnet != NULL) ? pSubnet->getName() : _T("(null)"),
1293 (pSubnet != NULL) ? pSubnet->getId() : 0);
1294 }
1295 }
1296 }
1297 iface->deleteObject();
1298 }
1299
1300 /**
1301 * Calculate node status based on child objects status
1302 */
1303 void Node::calculateCompoundStatus(BOOL bForcedRecalc)
1304 {
1305 int iOldStatus = m_status;
1306 static UINT32 dwEventCodes[] = { EVENT_NODE_NORMAL, EVENT_NODE_WARNING,
1307 EVENT_NODE_MINOR, EVENT_NODE_MAJOR, EVENT_NODE_CRITICAL,
1308 EVENT_NODE_UNKNOWN, EVENT_NODE_UNMANAGED };
1309
1310 DataCollectionTarget::calculateCompoundStatus(bForcedRecalc);
1311 if (m_status != iOldStatus)
1312 PostEvent(dwEventCodes[m_status], m_id, "d", iOldStatus);
1313 }
1314
1315 /**
1316 * Perform status poll on node
1317 */
1318 void Node::statusPoll(PollerInfo *poller, ClientSession *pSession, UINT32 rqId)
1319 {
1320 if (m_runtimeFlags & DCDF_DELETE_IN_PROGRESS)
1321 {
1322 if (rqId == 0)
1323 m_runtimeFlags &= ~DCDF_QUEUED_FOR_STATUS_POLL;
1324 return;
1325 }
1326
1327 if (IsShutdownInProgress())
1328 return;
1329
1330 UINT32 oldCapabilities = m_capabilities;
1331 UINT32 oldState = m_state;
1332 NetObj *pPollerNode = NULL, **ppPollList;
1333 SNMP_Transport *pTransport;
1334 Cluster *pCluster;
1335 time_t tNow, tExpire;
1336
1337 Queue *pQueue = new Queue; // Delayed event queue
1338 poller->setStatus(_T("wait for lock"));
1339 pollerLock();
1340
1341 if (IsShutdownInProgress())
1342 {
1343 delete pQueue;
1344 pollerUnlock();
1345 return;
1346 }
1347
1348 m_pollRequestor = pSession;
1349 sendPollerMsg(rqId, _T("Starting status poll for node %s\r\n"), m_name);
1350 nxlog_debug(5, _T("Starting status poll for node %s (ID: %d)"), m_name, m_id);
1351
1352 // Read capability expiration time and current time
1353 tExpire = (time_t)ConfigReadULong(_T("CapabilityExpirationTime"), 604800);
1354 tNow = time(NULL);
1355
1356 bool agentConnected = false;
1357
1358 int retryCount = 5;
1359
1360 restart_agent_check:
1361 if (g_flags & AF_RESOLVE_IP_FOR_EACH_STATUS_POLL)
1362 {
1363 updatePrimaryIpAddr();
1364 }
1365
1366 // Check SNMP agent connectivity
1367 if ((m_capabilities & NC_IS_SNMP) && (!(m_flags & NF_DISABLE_SNMP)) && m_ipAddress.isValidUnicast())
1368 {
1369 TCHAR szBuffer[256];
1370 UINT32 dwResult;
1371
1372 nxlog_debug(6, _T("StatusPoll(%s): check SNMP"), m_name);
1373 pTransport = createSnmpTransport();
1374 if (pTransport != NULL)
1375 {
1376 poller->setStatus(_T("check SNMP"));
1377 sendPollerMsg(rqId, _T("Checking SNMP agent connectivity\r\n"));
1378 const TCHAR *testOid = m_customAttributes.get(_T("snmp.testoid"));
1379 if (testOid == NULL)
1380 {
1381 testOid = _T(".1.3.6.1.2.1.1.2.0");
1382 }
1383 dwResult = SnmpGet(m_snmpVersion, pTransport, testOid, NULL, 0, szBuffer, sizeof(szBuffer), 0);
1384 if ((dwResult == SNMP_ERR_SUCCESS) || (dwResult == SNMP_ERR_NO_OBJECT))
1385 {
1386 if (m_state & NSF_SNMP_UNREACHABLE)
1387 {
1388 m_state &= ~NSF_SNMP_UNREACHABLE;
1389 PostEventEx(pQueue, EVENT_SNMP_OK, m_id, NULL);
1390 sendPollerMsg(rqId, POLLER_INFO _T("Connectivity with SNMP agent restored\r\n"));
1391 }
1392
1393 // Update authoritative engine data for SNMPv3
1394 if ((pTransport->getSnmpVersion() == SNMP_VERSION_3) && (pTransport->getAuthoritativeEngine() != NULL))
1395 {
1396 lockProperties();
1397 m_snmpSecurity->setAuthoritativeEngine(*pTransport->getAuthoritativeEngine());
1398 unlockProperties();
1399 }
1400 }
1401 else if ((dwResult == SNMP_ERR_ENGINE_ID) && (m_snmpVersion == SNMP_VERSION_3) && (retryCount > 0))
1402 {
1403 // Reset authoritative engine data
1404 lockProperties();
1405 m_snmpSecurity->setAuthoritativeEngine(SNMP_Engine());
1406 unlockProperties();
1407 delete pTransport;
1408 retryCount--;
1409 goto restart_agent_check;
1410 }
1411 else
1412 {
1413 if (pTransport->isProxyTransport() && (dwResult == SNMP_ERR_COMM))
1414 {
1415 nxlog_debug(6, _T("StatusPoll(%s): got communication error on proxy transport, checking connection to proxy"), m_name);
1416 AgentConnectionEx *pconn = acquireProxyConnection(SNMP_PROXY, true);
1417 if (pconn != NULL)
1418 {
1419 pconn->decRefCount();
1420 if (retryCount > 0)
1421 {
1422 retryCount--;
1423 delete pTransport;
1424 goto restart_agent_check;
1425 }
1426 }
1427 }
1428
1429 sendPollerMsg(rqId, POLLER_ERROR _T("SNMP agent unreachable\r\n"));
1430 if (m_state & NSF_SNMP_UNREACHABLE)
1431 {
1432 if ((tNow > m_failTimeSNMP + tExpire) && (!(m_state & DCSF_UNREACHABLE)))
1433 {
1434 m_capabilities &= ~NC_IS_SNMP;
1435 m_state &= ~NSF_SNMP_UNREACHABLE;
1436 m_snmpObjectId[0] = 0;
1437 sendPollerMsg(rqId, POLLER_WARNING _T("Attribute isSNMP set to FALSE\r\n"));
1438 }
1439 }
1440 else
1441 {
1442 m_state |= NSF_SNMP_UNREACHABLE;
1443 PostEventEx(pQueue, EVENT_SNMP_FAIL, m_id, NULL);
1444 m_failTimeSNMP = tNow;
1445 }
1446 }
1447 delete pTransport;
1448 }
1449 else
1450 {
1451 nxlog_debug(6, _T("StatusPoll(%s): cannot create SNMP transport"), m_name);
1452 }
1453 nxlog_debug(6, _T("StatusPoll(%s): SNMP check finished"), m_name);
1454 }
1455
1456 // Check native agent connectivity
1457 if ((m_capabilities & NC_IS_NATIVE_AGENT) && (!(m_flags & NF_DISABLE_NXCP)))
1458 {
1459 nxlog_debug(6, _T("StatusPoll(%s): checking agent"), m_name);
1460 poller->setStatus(_T("check agent"));
1461 sendPollerMsg(rqId, _T("Checking NetXMS agent connectivity\r\n"));
1462
1463 UINT32 error, socketError;
1464 bool newConnection;
1465 agentLock();
1466 if (connectToAgent(&error, &socketError, &newConnection, true))
1467 {
1468 nxlog_debug(7, _T("StatusPoll(%s): connected to agent"), m_name);
1469 if (m_state & NSF_AGENT_UNREACHABLE)
1470 {
1471 m_state &= ~NSF_AGENT_UNREACHABLE;
1472 PostEventEx(pQueue, EVENT_AGENT_OK, m_id, NULL);
1473 sendPollerMsg(rqId, POLLER_INFO _T("Connectivity with NetXMS agent restored\r\n"));
1474 }
1475 agentConnected = true;
1476 }
1477 else
1478 {
1479 nxlog_debug(6, _T("StatusPoll(%s): agent unreachable, error=%d, socketError=%d"), m_name, (int)error, (int)socketError);
1480 sendPollerMsg(rqId, POLLER_ERROR _T("NetXMS agent unreachable\r\n"));
1481 if (m_state & NSF_AGENT_UNREACHABLE)
1482 {
1483 if ((tNow > m_failTimeAgent + tExpire) && !(m_state & DCSF_UNREACHABLE))
1484 {
1485 m_capabilities &= ~NC_IS_NATIVE_AGENT;
1486 m_state &= ~NSF_AGENT_UNREACHABLE;
1487 m_platformName[0] = 0;
1488 m_agentVersion[0] = 0;
1489 sendPollerMsg(rqId, POLLER_WARNING _T("Attribute isNetXMSAgent set to FALSE\r\n"));
1490 }
1491 }
1492 else
1493 {
1494 m_state |= NSF_AGENT_UNREACHABLE;
1495 PostEventEx(pQueue, EVENT_AGENT_FAIL, m_id, NULL);
1496 m_failTimeAgent = tNow;
1497 //cancel file monitoring locally(on agent it is canceled if agent have fallen)
1498 g_monitoringList.removeDisconnectedNode(m_id);
1499 }
1500 }
1501 agentUnlock();
1502 nxlog_debug(7, _T("StatusPoll(%s): agent check finished"), m_name);
1503
1504 // If file update connection is active, send NOP command to prevent disconnection by idle timeout
1505 AgentConnection *fileUpdateConnection;
1506 lockProperties();
1507 fileUpdateConnection = m_fileUpdateConn;
1508 if (fileUpdateConnection != NULL)
1509 fileUpdateConnection->incRefCount();
1510 unlockProperties();
1511 if (fileUpdateConnection != NULL)
1512 {
1513 nxlog_debug(6, _T("StatusPoll(%s): sending keepalive command on file monitoring connection"), m_name);
1514 fileUpdateConnection->nop();
1515 fileUpdateConnection->decRefCount();
1516 }
1517 }
1518
1519 poller->setStatus(_T("prepare polling list"));
1520
1521 // Find service poller node object
1522 lockProperties();
1523 if (m_pollerNode != 0)
1524 {
1525 UINT32 id = m_pollerNode;
1526 unlockProperties();
1527 pPollerNode = FindObjectById(id);
1528 if (pPollerNode != NULL)
1529 {
1530 if (pPollerNode->getObjectClass() != OBJECT_NODE)
1531 pPollerNode = NULL;
1532 }
1533 }
1534 else
1535 {
1536 unlockProperties();
1537 }
1538
1539 // If nothing found, use management server
1540 if (pPollerNode == NULL)
1541 {
1542 pPollerNode = FindObjectById(g_dwMgmtNode);
1543 if (pPollerNode != NULL)
1544 pPollerNode->incRefCount();
1545 }
1546 else
1547 {
1548 pPollerNode->incRefCount();
1549 }
1550
1551 // Create polling list
1552 ppPollList = (NetObj **)malloc(sizeof(NetObj *) * m_childList->size());
1553 lockChildList(false);
1554 int pollListSize = 0;
1555 for(int i = 0; i < m_childList->size(); i++)
1556 {
1557 NetObj *curr = m_childList->get(i);
1558 if (curr->getStatus() != STATUS_UNMANAGED)
1559 {
1560 curr->incRefCount();
1561 ppPollList[pollListSize++] = curr;
1562 }
1563 }
1564 unlockChildList();
1565
1566 // Poll interfaces and services
1567 poller->setStatus(_T("child poll"));
1568 DbgPrintf(7, _T("StatusPoll(%s): starting child object poll"), m_name);
1569 pCluster = getMyCluster();
1570 pTransport = createSnmpTransport();
1571 for(int i = 0; i < pollListSize; i++)
1572 {
1573 switch(ppPollList[i]->getObjectClass())
1574 {
1575 case OBJECT_INTERFACE:
1576 DbgPrintf(7, _T("StatusPoll(%s): polling interface %d [%s]"), m_name, ppPollList[i]->getId(), ppPollList[i]->getName());
1577 ((Interface *)ppPollList[i])->statusPoll(pSession, rqId, pQueue, pCluster, pTransport, m_icmpProxy);
1578 break;
1579 case OBJECT_NETWORKSERVICE:
1580 DbgPrintf(7, _T("StatusPoll(%s): polling network service %d [%s]"), m_name, ppPollList[i]->getId(), ppPollList[i]->getName());
1581 ((NetworkService *)ppPollList[i])->statusPoll(pSession, rqId, (Node *)pPollerNode, pQueue);
1582 break;
1583 case OBJECT_ACCESSPOINT:
1584 DbgPrintf(7, _T("StatusPoll(%s): polling access point %d [%s]"), m_name, ppPollList[i]->getId(), ppPollList[i]->getName());
1585 ((AccessPoint *)ppPollList[i])->statusPollFromController(pSession, rqId, pQueue, this, pTransport);
1586 break;
1587 default:
1588 DbgPrintf(7, _T("StatusPoll(%s): skipping object %d [%s] class %d"), m_name, ppPollList[i]->getId(), ppPollList[i]->getName(), ppPollList[i]->getObjectClass());
1589 break;
1590 }
1591 ppPollList[i]->decRefCount();
1592 }
1593 delete pTransport;
1594 free(ppPollList);
1595 DbgPrintf(7, _T("StatusPoll(%s): finished child object poll"), m_name);
1596
1597 // Check if entire node is down
1598 // This check is disabled for nodes without IP address
1599 // The only exception is node without valid address connected via agent tunnel
1600 if (m_ipAddress.isValidUnicast() || agentConnected)
1601 {
1602 bool allDown = true;
1603 lockChildList(false);
1604 for(int i = 0; i < m_childList->size(); i++)
1605 {
1606 NetObj *curr = m_childList->get(i);
1607 if ((curr->getObjectClass() == OBJECT_INTERFACE) &&
1608 (((Interface *)curr)->getAdminState() != IF_ADMIN_STATE_DOWN) &&
1609 (((Interface *)curr)->getConfirmedOperState() == IF_OPER_STATE_UP) &&
1610 (curr->getStatus() != STATUS_UNMANAGED))
1611 {
1612 allDown = false;
1613 break;
1614 }
1615 }
1616 unlockChildList();
1617 if (allDown && (m_capabilities & NC_IS_NATIVE_AGENT) &&
1618 (!(m_flags & NF_DISABLE_NXCP)))
1619 if (!(m_state & NSF_AGENT_UNREACHABLE))
1620 allDown = false;
1621 if (allDown && (m_capabilities & NC_IS_SNMP) &&
1622 (!(m_flags & NF_DISABLE_SNMP)))
1623 if (!(m_state & NSF_SNMP_UNREACHABLE))
1624 allDown = false;
1625
1626 DbgPrintf(6, _T("StatusPoll(%s): allDown=%s, statFlags=0x%08X"), m_name, allDown ? _T("true") : _T("false"), m_state);
1627 if (allDown)
1628 {
1629 if (!(m_state & DCSF_UNREACHABLE))
1630 {
1631 m_state |= DCSF_UNREACHABLE;
1632 m_downSince = time(NULL);
1633 poller->setStatus(_T("check network path"));
1634 if (checkNetworkPath(rqId))
1635 {
1636 m_state |= DCSF_NETWORK_PATH_PROBLEM;
1637
1638 // Set interfaces and network services to UNKNOWN state
1639 lockChildList(false);
1640 for(int i = 0; i < m_childList->size(); i++)
1641 {
1642 NetObj *curr = m_childList->get(i);
1643 if ((curr->getObjectClass() == OBJECT_INTERFACE) || (curr->getObjectClass() == OBJECT_NETWORKSERVICE))
1644 {
1645 curr->resetStatus();
1646 }
1647 }
1648 unlockChildList();
1649
1650 // Clear delayed event queue
1651 while(true)
1652 {
1653 Event *e = (Event *)pQueue->get();
1654 if (e == NULL)
1655 break;
1656 delete e;
1657 }
1658 delete_and_null(pQueue);
1659
1660 PostEvent(EVENT_NODE_UNREACHABLE, m_id, NULL);
1661 }
1662 else
1663 {
1664 PostEvent(EVENT_NODE_DOWN, m_id, NULL);
1665 }
1666 g_monitoringList.removeDisconnectedNode(m_id);
1667 sendPollerMsg(rqId, POLLER_ERROR _T("Node is unreachable\r\n"));
1668 }
1669 else
1670 {
1671 sendPollerMsg(rqId, POLLER_WARNING _T("Node is still unreachable\r\n"));
1672 }
1673 }
1674 else
1675 {
1676 m_downSince = 0;
1677 if (m_state & DCSF_UNREACHABLE)
1678 {
1679 int reason = (m_state & DCSF_NETWORK_PATH_PROBLEM) ? 1 : 0;
1680 m_state &= ~(DCSF_UNREACHABLE | NSF_SNMP_UNREACHABLE | NSF_AGENT_UNREACHABLE | DCSF_NETWORK_PATH_PROBLEM);
1681 PostEvent(EVENT_NODE_UP, m_id, "d", reason);
1682 sendPollerMsg(rqId, POLLER_INFO _T("Node recovered from unreachable state\r\n"));
1683 goto restart_agent_check;
1684 }
1685 else
1686 {
1687 sendPollerMsg(rqId, POLLER_INFO _T("Node is connected\r\n"));
1688 }
1689 }
1690 }
1691
1692 // Get uptime and update boot time
1693 if (!(m_state & DCSF_UNREACHABLE))
1694 {
1695 TCHAR buffer[MAX_RESULT_LENGTH];
1696 if (getItemFromAgent(_T("System.Uptime"), MAX_RESULT_LENGTH, buffer) == DCE_SUCCESS)
1697 {
1698 m_bootTime = time(NULL) - _tcstol(buffer, NULL, 0);
1699 DbgPrintf(5, _T("StatusPoll(%s [%d]): boot time set to %u from agent"), m_name, m_id, (UINT32)m_bootTime);
1700 }
1701 else if (getItemFromSNMP(m_snmpPort, _T(".1.3.6.1.2.1.1.3.0"), MAX_RESULT_LENGTH, buffer, SNMP_RAWTYPE_NONE) == DCE_SUCCESS)
1702 {
1703 m_bootTime = time(NULL) - _tcstol(buffer, NULL, 0) / 100; // sysUpTime is in hundredths of a second
1704 DbgPrintf(5, _T("StatusPoll(%s [%d]): boot time set to %u from SNMP"), m_name, m_id, (UINT32)m_bootTime);
1705 }
1706 else
1707 {
1708 DbgPrintf(5, _T("StatusPoll(%s [%d]): unable to get system uptime"), m_name, m_id);
1709 }
1710 }
1711 else
1712 {
1713 m_bootTime = 0;
1714 }
1715
1716 // Get agent uptime to check if it was restared
1717 if (!(m_state & DCSF_UNREACHABLE) && isNativeAgent())
1718 {
1719 TCHAR buffer[MAX_RESULT_LENGTH];
1720 if (getItemFromAgent(_T("Agent.Uptime"), MAX_RESULT_LENGTH, buffer) == DCE_SUCCESS)
1721 {
1722 time_t oldAgentuptime = m_agentUpTime;
1723 m_agentUpTime = _tcstol(buffer, NULL, 0);
1724 if ((UINT32)oldAgentuptime > (UINT32)m_agentUpTime)
1725 {
1726 //cancel file monitoring locally(on agent it is canceled if agent have fallen)
1727 g_monitoringList.removeDisconnectedNode(m_id);
1728 }
1729 }
1730 else
1731 {
1732 DbgPrintf(5, _T("StatusPoll(%s [%d]): unable to get agent uptime"), m_name, m_id);
1733 g_monitoringList.removeDisconnectedNode(m_id);
1734 m_agentUpTime = 0;
1735 }
1736 }
1737 else
1738 {
1739 m_agentUpTime = 0;
1740 }
1741
1742 // Get geolocation
1743 if (!(m_state & DCSF_UNREACHABLE) && isNativeAgent())
1744 {
1745 TCHAR buffer[MAX_RESULT_LENGTH];
1746 if (getItemFromAgent(_T("GPS.LocationData"), MAX_RESULT_LENGTH, buffer) == DCE_SUCCESS)
1747 {
1748 GeoLocation loc = GeoLocation::parseAgentData(buffer);
1749 if (loc.getType() != GL_UNSET)
1750 {
1751 DbgPrintf(5, _T("StatusPoll(%s [%d]): location set to %s, %s from agent"), m_name, m_id, loc.getLatitudeAsString(), loc.getLongitudeAsString());
1752 lockProperties();
1753 m_geoLocation = loc;
1754 setModified();
1755 unlockProperties();
1756 }
1757 }
1758 else
1759 {
1760 DbgPrintf(5, _T("StatusPoll(%s [%d]): unable to get system location"), m_name, m_id);
1761 }
1762 }
1763
1764 // Get agent log and agent local database status
1765 if (!(m_state & DCSF_UNREACHABLE) && isNativeAgent())
1766 {
1767 TCHAR buffer[MAX_RESULT_LENGTH];
1768 if (getItemFromAgent(_T("Agent.LogFile.Status"), MAX_RESULT_LENGTH, buffer) == DCE_SUCCESS)
1769 {
1770 UINT32 status = _tcstol(buffer, NULL, 0);
1771 if (status != 0)
1772 PostEvent(EVENT_AGENT_LOG_PROBLEM, m_id, "ds", status, _T("could not open"));
1773 }
1774 else
1775 {
1776 nxlog_debug(5, _T("StatusPoll(%s [%d]): unable to get agent log status"), m_name, m_id);
1777 }
1778
1779 if (getItemFromAgent(_T("Agent.LocalDatabase.Status"), MAX_RESULT_LENGTH, buffer) == DCE_SUCCESS)
1780 {
1781 UINT32 status = _tcstol(buffer, NULL, 0);
1782 const TCHAR *statusDescription[3]= {
1783 _T("normal"),
1784 _T("could not open database"),
1785 _T("could not update database"),
1786 };
1787 if (status != 0)
1788 PostEvent(EVENT_AGENT_LOCAL_DATABASE_PROBLEM, m_id, "ds", status, statusDescription[status]);
1789 }
1790 else
1791 {
1792 nxlog_debug(5, _T("StatusPoll(%s [%d]): unable to get agent local database status"), m_name, m_id);
1793 }
1794 }
1795
1796 // Send delayed events and destroy delayed event queue
1797 if (pQueue != NULL)
1798 {
1799 ResendEvents(pQueue);
1800 delete pQueue;
1801 }
1802
1803 // Call hooks in loaded modules
1804 for(UINT32 i = 0; i < g_dwNumModules; i++)
1805 {
1806 if (g_pModuleList[i].pfStatusPollHook != NULL)
1807 {
1808 DbgPrintf(5, _T("StatusPoll(%s [%d]): calling hook in module %s"), m_name, m_id, g_pModuleList[i].szName);
1809 g_pModuleList[i].pfStatusPollHook(this, pSession, rqId, poller);
1810 }
1811 }
1812
1813 // Execute hook script
1814 poller->setStatus(_T("hook"));
1815 executeHookScript(_T("StatusPoll"));
1816
1817 poller->setStatus(_T("cleanup"));
1818 if (pPollerNode != NULL)
1819 pPollerNode->decRefCount();
1820
1821 if (oldCapabilities != m_capabilities) //currectly not flags but capabilities
1822 PostEvent(EVENT_NODE_CAPABILITIES_CHANGED, m_id, "xx", oldCapabilities, m_capabilities);
1823
1824 if (oldState != m_state || oldCapabilities != m_capabilities)
1825 {
1826 lockProperties();
1827 setModified();
1828 unlockProperties();
1829 }
1830
1831 calculateCompoundStatus();
1832 m_lastStatusPoll = time(NULL);
1833 sendPollerMsg(rqId, _T("Finished status poll for node %s\r\n"), m_name);
1834 sendPollerMsg(rqId, _T("Node status after poll is %s\r\n"), GetStatusAsText(m_status, true));
1835 m_pollRequestor = NULL;
1836 if (rqId == 0)
1837 m_runtimeFlags &= ~DCDF_QUEUED_FOR_STATUS_POLL;
1838 pollerUnlock();
1839 DbgPrintf(5, _T("Finished status poll for node %s (ID: %d)"), m_name, m_id);
1840
1841 // Check if the node has to be deleted due to long downtime
1842 if (rqId == 0)
1843 {
1844 time_t unreachableDeleteDays = (time_t)ConfigReadInt(_T("DeleteUnreachableNodesPeriod"), 0);
1845 if ((unreachableDeleteDays > 0) && (m_downSince > 0) &&
1846 (time(NULL) - m_downSince > unreachableDeleteDays * 24 * 3600))
1847 {
1848 deleteObject();
1849 }
1850 }
1851 }
1852
1853 /**
1854 * Check single element of network path
1855 */
1856 bool Node::checkNetworkPathElement(UINT32 nodeId, const TCHAR *nodeType, bool isProxy, UINT32 requestId, bool secondPass)
1857 {
1858 Node *node = (Node *)FindObjectById(nodeId, OBJECT_NODE);
1859 if (node == NULL)
1860 return false;
1861
1862 nxlog_debug(6, _T("Node::checkNetworkPathElement(%s [%d]): found %s: %s [%d]"), m_name, m_id, nodeType, node->getName(), node->getId());
1863
1864 if (secondPass && (node->m_lastStatusPoll < time(NULL) - 1))
1865 {
1866 DbgPrintf(6, _T("Node::checkNetworkPathElement(%s [%d]): forced status poll on node %s [%d]"),
1867 m_name, m_id, node->getName(), node->getId());
1868 PollerInfo *poller = RegisterPoller(POLLER_TYPE_STATUS, node);
1869 poller->startExecution();
1870 node->statusPoll(poller, NULL, 0);
1871 delete poller;
1872 }
1873
1874 if (node->isDown())
1875 {
1876 DbgPrintf(5, _T("Node::checkNetworkPathElement(%s [%d]): %s %s [%d] is down"),
1877 m_name, m_id, nodeType, node->getName(), node->getId());
1878 sendPollerMsg(requestId, POLLER_WARNING _T(" %s %s is down\r\n"), nodeType, node->getName());
1879 return true;
1880 }
1881 if (isProxy && node->isNativeAgent() && (node->getState() & NSF_AGENT_UNREACHABLE))
1882 {
1883 DbgPrintf(5, _T("Node::checkNetworkPathElement(%s [%d]): agent on %s %s [%d] is down"),
1884 m_name, m_id, nodeType, node->getName(), node->getId());
1885 sendPollerMsg(requestId, POLLER_WARNING _T(" Agent on %s %s is down\r\n"), nodeType, node->getName());
1886 return true;
1887 }
1888 return false;
1889 }
1890
1891 /**
1892 * Check network path between node and management server to detect possible intermediate node failure - layer 2
1893 *
1894 * @return true if network path problems found
1895 */
1896 bool Node::checkNetworkPathLayer2(UINT32 requestId, bool secondPass)
1897 {
1898 time_t now = time(NULL);
1899
1900 // Check proxy node(s)
1901 if (IsZoningEnabled() && (m_zoneUIN != 0))
1902 {
1903 Zone *zone = FindZoneByUIN(m_zoneUIN);
1904 if ((zone != NULL) && (zone->getProxyNodeId() != 0) && (zone->getProxyNodeId() != m_id))
1905 {
1906 if (checkNetworkPathElement(zone->getProxyNodeId(), _T("zone proxy"), true, requestId, secondPass))
1907 return true;
1908 }
1909 }
1910
1911 // Check directly connected switch
1912 sendPollerMsg(requestId, _T("Checking ethernet connectivity...\r\n"));
1913 Interface *iface = findInterfaceByIP(m_ipAddress);
1914 if (iface != NULL)
1915 {
1916 if (iface->getPeerNodeId() != 0)
1917 {
1918 nxlog_debug(6, _T("Node::checkNetworkPath(%s [%d]): found interface object for primary IP: %s [%d]"), m_name, m_id, iface->getName(), iface->getId());
1919 if (checkNetworkPathElement(iface->getPeerNodeId(), _T("upstream switch"), false, requestId, secondPass))
1920 return true;
1921
1922 Node *switchNode = (Node *)FindObjectById(iface->getPeerNodeId(), OBJECT_NODE);
1923 Interface *switchIface = (Interface *)FindObjectById(iface->getPeerInterfaceId(), OBJECT_INTERFACE);
1924 if ((switchNode != NULL) && (switchIface != NULL) && (switchIface->getExpectedState() != IF_EXPECTED_STATE_IGNORE) &&
1925 ((switchIface->getAdminState() == IF_ADMIN_STATE_DOWN) || (switchIface->getAdminState() == IF_ADMIN_STATE_TESTING) ||
1926 (switchIface->getOperState() == IF_OPER_STATE_DOWN) || (switchIface->getOperState() == IF_OPER_STATE_TESTING)))
1927 {
1928 nxlog_debug(5, _T("Node::checkNetworkPath(%s [%d]): upstream interface %s [%d] on switch %s [%d] is down"),
1929 m_name, m_id, switchIface->getName(), switchIface->getId(), switchNode->getName(), switchNode->getId());
1930 sendPollerMsg(requestId, POLLER_WARNING _T(" Upstream interface %s on node %s is down\r\n"), switchIface->getName(), switchNode->getName());
1931 return true;
1932 }
1933 }
1934 else
1935 {
1936 BYTE localMacAddr[MAC_ADDR_LENGTH];
1937 memcpy(localMacAddr, iface->getMacAddr(), MAC_ADDR_LENGTH);
1938 int type = 0;
1939 NetObj *cp = FindInterfaceConnectionPoint(localMacAddr, &type);
1940 if (cp != NULL)
1941 {
1942 nxlog_debug(6, _T("Node::checkNetworkPath(%s [%d]): found connection point: %s [%d]"), m_name, m_id, cp->getName(), cp->getId());
1943 if (secondPass)
1944 {
1945 Node *node = (cp->getObjectClass() == OBJECT_INTERFACE) ? ((Interface *)cp)->getParentNode() : ((AccessPoint *)cp)->getParentNode();
1946 if ((node != NULL) && !node->isDown() && (node->m_lastStatusPoll < now - 1))
1947 {
1948 nxlog_debug(6, _T("Node::checkNetworkPath(%s [%d]): forced status poll on node %s [%d]"),
1949 m_name, m_id, node->getName(), node->getId());
1950 node->statusPollPollerEntry(RegisterPoller(POLLER_TYPE_STATUS, node), NULL, 0);
1951 }
1952 }
1953
1954 if (cp->getObjectClass() == OBJECT_INTERFACE)
1955 {
1956 Interface *iface = (Interface *)cp;
1957 if ((iface->getExpectedState() != IF_EXPECTED_STATE_IGNORE) &&
1958 ((iface->getAdminState() == IF_ADMIN_STATE_DOWN) || (iface->getAdminState() == IF_ADMIN_STATE_TESTING) ||
1959 (iface->getOperState() == IF_OPER_STATE_DOWN) || (iface->getOperState() == IF_OPER_STATE_TESTING)))
1960 {
1961 nxlog_debug(5, _T("Node::checkNetworkPath(%s [%d]): upstream interface %s [%d] on switch %s [%d] is down"),
1962 m_name, m_id, iface->getName(), iface->getId(), iface->getParentNode()->getName(), iface->getParentNode()->getId());
1963 sendPollerMsg(requestId, POLLER_WARNING _T(" Upstream interface %s on node %s is down\r\n"),
1964 iface->getName(), iface->getParentNode()->getName());
1965 return true;
1966 }
1967 }
1968 else if (cp->getObjectClass() == OBJECT_ACCESSPOINT)
1969 {
1970 AccessPoint *ap = (AccessPoint *)cp;
1971 if (ap->getStatus() == STATUS_CRITICAL) // FIXME: how to correctly determine if AP is down?
1972 {
1973 nxlog_debug(5, _T("Node::checkNetworkPath(%s [%d]): wireless access point %s [%d] is down"),
1974 m_name, m_id, ap->getName(), ap->getId());
1975 sendPollerMsg(requestId, POLLER_WARNING _T(" Wireless access point %s is down\r\n"), ap->getName());
1976 return true;
1977 }
1978 }
1979 }
1980 }
1981 }
1982 else
1983 {
1984 DbgPrintf(5, _T("Node::checkNetworkPath(%s [%d]): cannot find interface object for primary IP"), m_name, m_id);
1985 }
1986 return false;
1987 }
1988
1989 /**
1990 * Check network path between node and management server to detect possible intermediate node failure - layer 3
1991 *
1992 * @return true if network path problems found
1993 */
1994 bool Node::checkNetworkPathLayer3(UINT32 requestId, bool secondPass)
1995 {
1996 Node *mgmtNode = (Node *)FindObjectById(g_dwMgmtNode);
1997 if (mgmtNode == NULL)
1998 {
1999 DbgPrintf(5, _T("Node::checkNetworkPath(%s [%d]): cannot find management node"), m_name, m_id);
2000 return false;
2001 }
2002
2003 NetworkPath *trace = TraceRoute(mgmtNode, this);
2004 if (trace == NULL)
2005 {
2006 DbgPrintf(5, _T("Node::checkNetworkPath(%s [%d]): trace not available"), m_name, m_id);
2007 return false;
2008 }
2009 DbgPrintf(5, _T("Node::checkNetworkPath(%s [%d]): trace available, %d hops, %s"),
2010 m_name, m_id, trace->getHopCount(), trace->isComplete() ? _T("complete") : _T("incomplete"));
2011
2012 // We will do path check in two passes
2013 // If unreachable intermediate node will be found on first pass,
2014 // then method will just return true. Otherwise, we will do
2015 // second pass, this time forcing status poll on each node in the path.
2016 sendPollerMsg(requestId, _T("Checking network path (%s pass)...\r\n"), secondPass ? _T("second") : _T("first"));
2017 bool pathProblemFound = false;
2018 for(int i = 0; i < trace->getHopCount(); i++)
2019 {
2020 HOP_INFO *hop = trace->getHopInfo(i);
2021 if ((hop->object == NULL) || (hop->object == this) || (hop->object->getObjectClass() != OBJECT_NODE))
2022 continue;
2023
2024 // Check for loops
2025 if (i > 0)
2026 {
2027 for(int j = i - 1; j >= 0; j--)
2028 {
2029 HOP_INFO *prevHop = trace->getHopInfo(j);
2030 if (prevHop->object == hop->object)
2031 {
2032 prevHop = trace->getHopInfo(i - 1);
2033 nxlog_debug(5, _T("Node::checkNetworkPath(%s [%d]): routing loop detected on upstream node %s [%d]"),
2034 m_name, m_id, prevHop->object->getName(), prevHop->object->getId());
2035 sendPollerMsg(requestId, POLLER_WARNING _T(" Routing loop detected on upstream node %s\r\n"), prevHop->object->getName());
2036
2037 static const TCHAR *names[] =
2038 { _T("protocol"), _T("destNodeId"), _T("destAddress"),
2039 _T("sourceNodeId"), _T("sourceAddress"), _T("prefix"),
2040 _T("prefixLength"), _T("nextHopNodeId"), _T("nextHopAddress")
2041 };
2042 PostEventWithNames(EVENT_ROUTING_LOOP_DETECTED, prevHop->object->getId(), "siAiAAdiA", names,
2043 (trace->getSourceAddress().getFamily() == AF_INET6) ? _T("IPv6") : _T("IPv4"),
2044 m_id, &m_ipAddress, g_dwMgmtNode, &(trace->getSourceAddress()),
2045 &prevHop->route, prevHop->route.getMaskBits(), hop->object->getId(), &prevHop->nextHop);
2046
2047 pathProblemFound = true;
2048 break;
2049 }
2050 }
2051 if (pathProblemFound)
2052 break;
2053 }
2054
2055 nxlog_debug(6, _T("Node::checkNetworkPath(%s [%d]): checking upstream router %s [%d]"),
2056 m_name, m_id, hop->object->getName(), hop->object->getId());
2057 if (checkNetworkPathElement(hop->object->getId(), _T("upstream router"), false, requestId, secondPass))
2058 {
2059 pathProblemFound = true;
2060 break;
2061 }
2062
2063 if (hop->isVpn)
2064 {
2065 // Next hop is behind VPN tunnel
2066 VPNConnector *vpnConn = (VPNConnector *)FindObjectById(hop->ifIndex, OBJECT_VPNCONNECTOR);
2067 if ((vpnConn != NULL) && (vpnConn->getStatus() == STATUS_CRITICAL))
2068 {
2069 /* TODO: mark as path problem */
2070 }
2071 }
2072 else
2073 {
2074 Interface *iface = ((Node *)hop->object)->findInterfaceByIndex(hop->ifIndex);
2075 if ((iface != NULL) && (iface->getExpectedState() != IF_EXPECTED_STATE_IGNORE) &&
2076 ((iface->getAdminState() == IF_ADMIN_STATE_DOWN) || (iface->getAdminState() == IF_ADMIN_STATE_TESTING) ||
2077 (iface->getOperState() == IF_OPER_STATE_DOWN) || (iface->getOperState() == IF_OPER_STATE_TESTING)))
2078 {
2079 nxlog_debug(5, _T("Node::checkNetworkPath(%s [%d]): upstream interface %s [%d] on node %s [%d] is down"),
2080 m_name, m_id, iface->getName(), iface->getId(), hop->object->getName(), hop->object->getId());
2081 sendPollerMsg(requestId, POLLER_WARNING _T(" Upstream interface %s on node %s is down\r\n"), iface->getName(), hop->object->getName());
2082 break;
2083 }
2084 }
2085 }
2086
2087 delete trace;
2088 return pathProblemFound;
2089 }
2090
2091 /**
2092 * Check network path between node and management server to detect possible intermediate node failure
2093 *
2094 * @return true if network path problems found
2095 */
2096 bool Node::checkNetworkPath(UINT32 requestId)
2097 {
2098 if (checkNetworkPathLayer2(requestId, false))
2099 return true;
2100
2101 if (checkNetworkPathLayer3(requestId, false))
2102 return true;
2103
2104 nxlog_debug(5, _T("Node::checkNetworkPath(%s [%d]): will do second pass"), m_name, m_id);
2105
2106 if (checkNetworkPathLayer2(requestId, true))
2107 return true;
2108
2109 if (checkNetworkPathLayer3(requestId, true))
2110 return true;
2111
2112 return false;
2113 }
2114
2115 /**
2116 * Check agent policy binding
2117 * Intended to be called only from configuration poller
2118 */
2119 void Node::checkAgentPolicyBinding(AgentConnection *conn)
2120 {
2121 AgentPolicyInfo *ap;
2122 UINT32 rcc = conn->getPolicyInventory(&ap);
2123 if (rcc == ERR_SUCCESS)
2124 {
2125 // Check for unbound but installed policies
2126 for(int i = 0; i < ap->size(); i++)
2127 {
2128 uuid guid = ap->getGuid(i);
2129 NetObj *object = FindObjectByGUID(guid, -1);
2130 if ((object != NULL) && (!object->isChild(m_id)))
2131 {
2132 object->addChild(this);
2133 addParent(object);
2134 DbgPrintf(5, _T("ConfPoll(%s): bound to policy object %s [%d]"), m_name, object->getName(), object->getId());
2135 }
2136 }
2137
2138 // Check for bound but not installed policies and schedule it's installation again
2139 //Job will be unbound if it was not possible to add job
2140 lockParentList(false);
2141 NetObj **unbindList = (NetObj **)malloc(sizeof(NetObj *) * m_parentList->size());
2142 int unbindListSize = 0;
2143 for(int i = 0; i < m_parentList->size(); i++)
2144 {
2145 if (IsAgentPolicyObject(m_parentList->get(i)))
2146 {
2147 const uuid& guid = m_parentList->get(i)->getGuid();
2148 int j;
2149 for(j = 0; j < ap->size(); j++)
2150 {
2151 if (ap->getGuid(j).equals(guid))
2152 break;
2153 }
2154 if (j == ap->size())
2155 {
2156 ServerJob *job = new PolicyInstallJob(this, (AgentPolicy *)m_parentList->get(i), 0);
2157 if (AddJob(job))
2158 {
2159 DbgPrintf(5, _T("ConfPoll(%s): \"%s\" policy deploy scheduled for \"%s\" node"), m_name, m_parentList->get(i)->getName(), m_name );
2160 }
2161 else
2162 {
2163 DbgPrintf(5, _T("ConfPoll(%s): \"%s\" policy deploy is not possible to scheduled for \"%s\" node"), m_name, m_parentList->get(i)->getName(), m_name);
2164 delete job;
2165 unbindList[unbindListSize++] = m_parentList->get(i);
2166 }
2167 }
2168 }
2169 }
2170 unlockParentList();
2171
2172 for(int i = 0; i < unbindListSize; i++)
2173 {
2174 unbindList[i]->deleteChild(this);
2175 deleteParent(unbindList[i]);
2176 DbgPrintf(5, _T("ConfPoll(%s): unbound from policy object %s [%d]"), m_name, unbindList[i]->getName(), unbindList[i]->getId());
2177 }
2178 safe_free(unbindList);
2179
2180 delete ap;
2181 }
2182 else
2183 {
2184 DbgPrintf(5, _T("ConfPoll(%s): AgentConnection::getPolicyInventory() failed: rcc=%d"), m_name, rcc);
2185 }
2186 }
2187
2188 /**
2189 * Update primary IP address from primary name
2190 */
2191 void Node::updatePrimaryIpAddr()
2192 {
2193 if (m_primaryName[0] == 0)
2194 return;
2195
2196 InetAddress ipAddr = ResolveHostName(m_zoneUIN, m_primaryName);
2197 if (!ipAddr.equals(m_ipAddress) && (ipAddr.isValidUnicast() || !_tcscmp(m_primaryName, _T("0.0.0.0"))))
2198 {
2199 TCHAR buffer1[64], buffer2[64];
2200
2201 DbgPrintf(4, _T("IP address for node %s [%d] changed from %s to %s"),
2202 m_name, (int)m_id, m_ipAddress.toString(buffer1), ipAddr.toString(buffer2));
2203 PostEvent(EVENT_IP_ADDRESS_CHANGED, m_id, "AA", &ipAddr, &m_ipAddress);
2204
2205 if (m_flags & NF_REMOTE_AGENT)
2206 {
2207 lockProperties();
2208 m_ipAddress = ipAddr;
2209 setModified();
2210 unlockProperties();
2211 }
2212 else
2213 {
2214 setPrimaryIPAddress(ipAddr);
2215 }
2216
2217 agentLock();
2218 deleteAgentConnection();
2219 agentUnlock();
2220 }
2221 }
2222
2223 /**
2224 * Comparator for package names
2225 */
2226 static int PackageNameComparator(const SoftwarePackage **p1, const SoftwarePackage **p2)
2227 {
2228 return _tcscmp((*p1)->getName(), (*p2)->getName());
2229 }
2230
2231 /**
2232 * Update list of software packages for node
2233 */
2234 bool Node::updateSoftwarePackages(PollerInfo *poller, UINT32 requestId)
2235 {
2236 if (!(m_capabilities & NC_IS_NATIVE_AGENT))
2237 return false;
2238
2239 poller->setStatus(_T("software check"));
2240 sendPollerMsg(requestId, _T("Reading list of installed software packages\r\n"));
2241
2242 Table *table;
2243 if (getTableFromAgent(_T("System.InstalledProducts"), &table) != DCE_SUCCESS)
2244 {
2245 sendPollerMsg(requestId, POLLER_WARNING _T("Unable to get information about installed software packages\r\n"));
2246 return false;
2247 }
2248
2249 ObjectArray<SoftwarePackage> *packages = new ObjectArray<SoftwarePackage>(table->getNumRows(), 16, true);
2250 for(int i = 0; i < table->getNumRows(); i++)
2251 {
2252 SoftwarePackage *pkg = SoftwarePackage::createFromTableRow(table, i);
2253 if (pkg != NULL)
2254 packages->add(pkg);
2255 }
2256 packages->sort(PackageNameComparator);
2257 delete table;
2258 sendPollerMsg(requestId, POLLER_INFO _T("Got information about %d installed software packages\r\n"), packages->size());
2259
2260 lockProperties();
2261 if (m_softwarePackages != NULL)
2262 {
2263 // Check for removed and updated packages
2264 for(int i = 0; i < m_softwarePackages->size(); i++)
2265 {
2266 SoftwarePackage *p = m_softwarePackages->get(i);
2267 SoftwarePackage *np = (SoftwarePackage *)packages->find(p, PackageNameComparator);
2268 if (np != NULL)
2269 {
2270 if (_tcscmp(p->getVersion(), np->getVersion()))
2271 {
2272 nxlog_debug(5, _T("ConfPoll(%s): package %s updated (%s -> %s)"), m_name, p->getName(), p->getVersion(), np->getVersion());
2273 sendPollerMsg(requestId, _T(" Package %s updated (%s -> %s)\r\n"), p->getName(), p->getVersion(), np->getVersion());
2274
2275 static const TCHAR *names[] = { _T("name"), _T("version"), _T("previousVersion") };
2276 PostEventWithNames(EVENT_PACKAGE_UPDATED, m_id, "sss", names, p->getName(), np->getVersion(), p->getVersion());
2277 }
2278 }
2279 else
2280 {
2281 nxlog_debug(5, _T("ConfPoll(%s): package %s removed (last installed version was %s)"), m_name, p->getName(), p->getVersion());
2282 sendPollerMsg(requestId, _T(" Package %s removed (last installed version was %s)\r\n"), p->getName(), p->getVersion());
2283
2284 static const TCHAR *names[] = { _T("name"), _T("version") };
2285 PostEventWithNames(EVENT_PACKAGE_REMOVED, m_id, "ss", names, p->getName(), p->getVersion());
2286 }
2287 }
2288
2289 // Check for new packages
2290 for(int i = 0; i < packages->size(); i++)
2291 {
2292 SoftwarePackage *p = packages->get(i);
2293 if (m_softwarePackages->find(p, PackageNameComparator) == NULL)
2294 {
2295 nxlog_debug(5, _T("ConfPoll(%s): new package %s (version %s)"), m_name, p->getName(), p->getVersion());
2296 sendPollerMsg(requestId, _T(" New package %s (version %s)\r\n"), p->getName(), p->getVersion());
2297
2298 static const TCHAR *names[] = { _T("name"), _T("version") };
2299 PostEventWithNames(EVENT_PACKAGE_INSTALLED, m_id, "ss", names, p->getName(), p->getVersion());
2300 }
2301 }
2302
2303 delete m_softwarePackages;
2304 }
2305 m_softwarePackages = packages;
2306 unlockProperties();
2307 return true;
2308 }
2309
2310
2311 /**
2312 * Perform configuration poll on node
2313 */
2314 void Node::configurationPoll(PollerInfo *poller, ClientSession *session, UINT32 rqId)
2315 {
2316 if (m_runtimeFlags & DCDF_DELETE_IN_PROGRESS)
2317 {
2318 if (rqId == 0)
2319 m_runtimeFlags &= ~DCDF_QUEUED_FOR_CONFIGURATION_POLL;
2320 return;
2321 }
2322
2323 if (IsShutdownInProgress())
2324 return;
2325
2326 UINT32 dwOldFlags = m_capabilities;
2327 TCHAR szBuffer[4096];
2328 bool hasChanges = false;
2329
2330 poller->setStatus(_T("wait for lock"));
2331 pollerLock();
2332
2333 if (IsShutdownInProgress())
2334 {
2335 pollerUnlock();
2336 return;
2337 }
2338
2339 m_pollRequestor = session;
2340 sendPollerMsg(rqId, _T("Starting configuration poll for node %s\r\n"), m_name);
2341 nxlog_debug(4, _T("Starting configuration poll for node %s (ID: %d)"), m_name, m_id);
2342
2343 // Check for forced capabilities recheck
2344 if (m_runtimeFlags & NDF_RECHECK_CAPABILITIES)
2345 {
2346 sendPollerMsg(rqId, POLLER_WARNING _T("Capability reset\r\n"));
2347 m_capabilities = 0;
2348 m_runtimeFlags &= ~DCDF_CONFIGURATION_POLL_PASSED;
2349 m_snmpObjectId[0] = 0;
2350 m_platformName[0] = 0;
2351 m_agentVersion[0] = 0;
2352 safe_free_and_null(m_sysDescription);
2353 safe_free_and_null(m_sysName);
2354 safe_free_and_null(m_sysContact);
2355 safe_free_and_null(m_sysLocation);
2356 safe_free_and_null(m_lldpNodeId);
2357 }
2358
2359 // Check if node is marked as unreachable
2360 if ((m_state & DCSF_UNREACHABLE) && !(m_runtimeFlags & NDF_RECHECK_CAPABILITIES))
2361 {
2362 sendPollerMsg(rqId, POLLER_WARNING _T("Node is marked as unreachable, configuration poll aborted\r\n"));
2363 DbgPrintf(4, _T("Node is marked as unreachable, configuration poll aborted"));
2364 m_lastConfigurationPoll = time(NULL);
2365 }
2366 else
2367 {
2368 updatePrimaryIpAddr();
2369
2370 poller->setStatus(_T("capability check"));
2371 sendPollerMsg(rqId, _T("Checking node's capabilities...\r\n"));
2372
2373 if (confPollAgent(rqId))
2374 hasChanges = true;
2375 if (confPollSnmp(rqId))
2376 hasChanges = true;
2377
2378 // Check for CheckPoint SNMP agent on port 260
2379 if (ConfigReadInt(_T("EnableCheckPointSNMP"), 0))
2380 {
2381 nxlog_debug(5, _T("ConfPoll(%s): checking for CheckPoint SNMP on port 260"), m_name);
2382 if (!((m_capabilities & NC_IS_CPSNMP) && (m_state & NSF_CPSNMP_UNREACHABLE)) && m_ipAddress.isValidUnicast())
2383 {
2384 SNMP_Transport *pTransport = new SNMP_UDPTransport;
2385 ((SNMP_UDPTransport *)pTransport)->createUDPTransport(m_ipAddress, CHECKPOINT_SNMP_PORT);
2386 if (SnmpGet(SNMP_VERSION_1, pTransport,
2387 _T(".1.3.6.1.4.1.2620.1.1.10.0"), NULL, 0, szBuffer, sizeof(szBuffer), 0) == SNMP_ERR_SUCCESS)
2388 {
2389 lockProperties();
2390 m_capabilities |= NC_IS_CPSNMP | NC_IS_ROUTER;
2391 m_state &= ~NSF_CPSNMP_UNREACHABLE;
2392 unlockProperties();
2393 sendPollerMsg(rqId, POLLER_INFO _T(" CheckPoint SNMP agent on port 260 is active\r\n"));
2394 }
2395 delete pTransport;
2396 }
2397 }
2398
2399 // Generate event if node flags has been changed
2400 if (dwOldFlags != m_capabilities)
2401 {
2402 PostEvent(EVENT_NODE_CAPABILITIES_CHANGED, m_id, "xx", dwOldFlags, m_capabilities);
2403 hasChanges = true;
2404 }
2405
2406 // Retrieve interface list
2407 poller->setStatus(_T("interface check"));
2408 sendPollerMsg(rqId, _T("Capability check finished\r\n"));
2409
2410 if (updateInterfaceConfiguration(rqId, 0)) // maskBits
2411 hasChanges = true;
2412
2413 m_lastConfigurationPoll = time(NULL);
2414
2415 // Check node name
2416 sendPollerMsg(rqId, _T("Checking node name\r\n"));
2417 UINT32 dwAddr = ntohl(_t_inet_addr(m_name));
2418 if ((g_flags & AF_RESOLVE_NODE_NAMES) &&
2419 (dwAddr != INADDR_NONE) &&
2420 (dwAddr != INADDR_ANY) &&
2421 isMyIP(dwAddr))
2422 {
2423 sendPollerMsg(rqId, _T("Node name is an IP address and need to be resolved\r\n"));
2424 poller->setStatus(_T("resolving name"));
2425 if (resolveName(FALSE))
2426 {
2427 sendPollerMsg(rqId, POLLER_INFO _T("Node name resolved to %s\r\n"), m_name);
2428 hasChanges = true;
2429 }
2430 else
2431 {
2432 sendPollerMsg(rqId, POLLER_WARNING _T("Node name cannot be resolved\r\n"));
2433 }
2434 }
2435 else
2436 {
2437 if (g_flags & AF_SYNC_NODE_NAMES_WITH_DNS)
2438 {
2439 sendPollerMsg(rqId, _T("Syncing node name with DNS\r\n"));
2440 poller->setStatus(_T("resolving name"));
2441 if (resolveName(TRUE))
2442 {
2443 sendPollerMsg(rqId, POLLER_INFO _T("Node name resolved to %s\r\n"), m_name);
2444 hasChanges = true;
2445 }
2446 }
2447 else
2448 {
2449 sendPollerMsg(rqId, _T("Node name is OK\r\n"));
2450 }
2451 }
2452
2453 applyUserTemplates();
2454 updateContainerMembership();
2455 updateSoftwarePackages(poller, rqId);
2456
2457 // Call hooks in loaded modules
2458 for(UINT32 i = 0; i < g_dwNumModules; i++)
2459 {
2460 if (g_pModuleList[i].pfConfPollHook != NULL)
2461 {
2462 DbgPrintf(5, _T("ConfigurationPoll(%s [%d]): calling hook in module %s"), m_name, m_id, g_pModuleList[i].szName);
2463 if (g_pModuleList[i].pfConfPollHook(this, session, rqId, poller))
2464 hasChanges = true;
2465 }
2466 }
2467
2468 // Setup permanent connection to agent if not present (needed for proper configuration re-sync)
2469 if (m_capabilities & NC_IS_NATIVE_AGENT)
2470 {
2471 agentLock();
2472 connectToAgent();
2473 agentUnlock();
2474 }
2475
2476 // Update node type
2477 NodeType type = detectNodeType();
2478 nxlog_debug(5, _T("ConfPoll(%s): detected node type: %d (%s)"), m_name, type, typeName(type));
2479 lockProperties();
2480 if ((type != NODE_TYPE_UNKNOWN) && (type != m_type))
2481 {
2482 m_type = type;
2483 hasChanges = true;
2484 nxlog_debug(5, _T("ConfPoll(%s): node type set to %d (%s)"), m_name, type, typeName(type));
2485 sendPollerMsg(rqId, _T(" Node type changed to %s\r\n"), typeName(type));
2486 }
2487 unlockProperties();
2488
2489 // Execute hook script
2490 poller->setStatus(_T("hook"));
2491 executeHookScript(_T("ConfigurationPoll"));
2492
2493 sendPollerMsg(rqId, _T("Finished configuration poll for node %s\r\n"), m_name);
2494 sendPollerMsg(rqId, _T("Node configuration was%schanged after poll\r\n"), hasChanges ? _T(" ") : _T(" not "));
2495
2496 m_runtimeFlags |= DCDF_CONFIGURATION_POLL_PASSED;
2497 }
2498
2499 // Finish configuration poll
2500 poller->setStatus(_T("cleanup"));
2501 if (rqId == 0)
2502 m_runtimeFlags &= ~DCDF_QUEUED_FOR_CONFIGURATION_POLL;
2503 m_runtimeFlags &= ~NDF_RECHECK_CAPABILITIES;
2504 pollerUnlock();
2505 DbgPrintf(4, _T("Finished configuration poll for node %s (ID: %d)"), m_name, m_id);
2506
2507 if (hasChanges)
2508 {
2509 lockProperties();
2510 setModified();
2511 unlockProperties();
2512 }
2513 }
2514
2515 /**
2516 * Detect node type
2517 */
2518 NodeType Node::detectNodeType()
2519 {
2520 NodeType type = NODE_TYPE_UNKNOWN;
2521 if (m_capabilities & NC_IS_SNMP)
2522 {
2523 nxlog_debug(6, _T("Node::detectNodeType(%s [%d]): SNMP node, driver name is %s"), m_name, m_id, m_driver->getName());
2524
2525 // Assume physical device if it supports SNMP and driver is not "GENERIC"
2526 // FIXME: add driver method to determine node type
2527 if (_tcscmp(m_driver->getName(), _T("GENERIC")))
2528 {
2529 type = NODE_TYPE_PHYSICAL;
2530 }
2531 else
2532 {
2533 if (m_capabilities & NC_IS_PRINTER)
2534 {
2535 // Assume that printers are physical devices
2536 type = NODE_TYPE_PHYSICAL;
2537 }
2538 }
2539 }
2540 return type;
2541 }
2542
2543 /**
2544 * Configuration poll: check for NetXMS agent
2545 */
2546 bool Node::confPollAgent(UINT32 rqId)
2547 {
2548 nxlog_debug(5, _T("ConfPoll(%s): checking for NetXMS agent Flags={%08X} StateFlags={%08X} RuntimeFlags={%08X}"), m_name, m_flags, m_state, m_runtimeFlags);
2549 if (((m_capabilities & NC_IS_NATIVE_AGENT) && (m_state & NSF_AGENT_UNREACHABLE)) || (m_flags & NF_DISABLE_NXCP))
2550 return false;
2551
2552 bool hasChanges = false;
2553
2554 sendPollerMsg(rqId, _T(" Checking NetXMS agent...\r\n"));
2555 AgentTunnel *tunnel = GetTunnelForNode(m_id);
2556 AgentConnectionEx *pAgentConn;
2557 if (tunnel != NULL)
2558 {
2559 pAgentConn = new AgentConnectionEx(m_id, tunnel, m_agentAuthMethod, m_szSharedSecret, isAgentCompressionAllowed());
2560 tunnel->decRefCount();
2561 }
2562 else
2563 {
2564 if (!m_ipAddress.isValidUnicast())
2565 {
2566 sendPollerMsg(rqId, POLLER_ERROR _T(" Node primary IP is invalid and there are no active tunnels\r\n"));
2567 nxlog_debug(5, _T("ConfPoll(%s): node primary IP is invalid and there are no active tunnels"), m_name);
2568 return false;
2569 }
2570 pAgentConn = new AgentConnectionEx(m_id, m_ipAddress, m_agentPort, m_agentAuthMethod, m_szSharedSecret, isAgentCompressionAllowed());
2571 setAgentProxy(pAgentConn);
2572 }
2573 pAgentConn->setCommandTimeout(g_agentCommandTimeout);
2574 nxlog_debug(5, _T("ConfPoll(%s): checking for NetXMS agent - connecting"), m_name);
2575
2576 // Try to connect to agent
2577 UINT32 rcc;
2578 if (!pAgentConn->connect(g_pServerKey, &rcc))
2579 {
2580 // If there are authentication problem, try default shared secret
2581 if ((rcc == ERR_AUTH_REQUIRED) || (rcc == ERR_AUTH_FAILED))
2582 {
2583 TCHAR secret[MAX_SECRET_LENGTH];
2584 ConfigReadStr(_T("AgentDefaultSharedSecret"), secret, MAX_SECRET_LENGTH, _T("netxms"));
2585 DecryptPassword(_T("netxms"), secret, secret, MAX_SECRET_LENGTH);
2586 pAgentConn->setAuthData(AUTH_SHA1_HASH, secret);
2587 if (pAgentConn->connect(g_pServerKey, &rcc))
2588 {
2589 m_agentAuthMethod = AUTH_SHA1_HASH;
2590 nx_strncpy(m_szSharedSecret, secret, MAX_SECRET_LENGTH);
2591 nxlog_debug(5, _T("ConfPoll(%s): checking for NetXMS agent - shared secret changed to system default"), m_name);
2592 }
2593 }
2594 }
2595
2596 if (rcc == ERR_SUCCESS)
2597 {
2598 nxlog_debug(5, _T("ConfPoll(%s): checking for NetXMS agent - connected"), m_name);
2599 lockProperties();
2600 m_capabilities |= NC_IS_NATIVE_AGENT;
2601 if (m_state & NSF_AGENT_UNREACHABLE)
2602 {
2603 m_state &= ~NSF_AGENT_UNREACHABLE;
2604 PostEvent(EVENT_AGENT_OK, m_id, NULL);
2605 sendPollerMsg(rqId, POLLER_INFO _T(" Connectivity with NetXMS agent restored\r\n"));
2606 }
2607 else
2608 {
2609 sendPollerMsg(rqId, POLLER_INFO _T(" NetXMS native agent is active\r\n"));
2610 }
2611 unlockProperties();
2612
2613 TCHAR buffer[MAX_RESULT_LENGTH];
2614 if (pAgentConn->getParameter(_T("Agent.Version"), MAX_AGENT_VERSION_LEN, buffer) == ERR_SUCCESS)
2615 {
2616 lockProperties();
2617 if (_tcscmp(m_agentVersion, buffer))
2618 {
2619 _tcscpy(m_agentVersion, buffer);
2620 hasChanges = true;
2621 sendPollerMsg(rqId, _T(" NetXMS agent version changed to %s\r\n"), m_agentVersion);
2622 }
2623 unlockProperties();
2624 }
2625
2626 if (pAgentConn->getParameter(_T("System.PlatformName"), MAX_PLATFORM_NAME_LEN, buffer) == ERR_SUCCESS)
2627 {
2628 lockProperties();
2629 if (_tcscmp(m_platformName, buffer))
2630 {
2631 _tcscpy(m_platformName, buffer);
2632 hasChanges = true;
2633 sendPollerMsg(rqId, _T(" Platform name changed to %s\r\n"), m_platformName);
2634 }
2635 unlockProperties();
2636 }
2637
2638 // Check IP forwarding status
2639 if (pAgentConn->getParameter(_T("Net.IP.Forwarding"), 16, buffer) == ERR_SUCCESS)
2640 {
2641 if (_tcstoul(buffer, NULL, 10) != 0)
2642 m_capabilities |= NC_IS_ROUTER;
2643 else
2644 m_capabilities &= ~NC_IS_ROUTER;
2645 }
2646
2647 // Get uname
2648 if (pAgentConn->getParameter(_T("System.Uname"), MAX_DB_STRING, buffer) == ERR_SUCCESS)
2649 {
2650 TranslateStr(buffer, _T("\r\n"), _T(" "));
2651 TranslateStr(buffer, _T("\n"), _T(" "));
2652 TranslateStr(buffer, _T("\r"), _T(" "));
2653 lockProperties();
2654 if ((m_sysDescription == NULL) || _tcscmp(m_sysDescription, buffer))
2655 {
2656 safe_free(m_sysDescription);
2657 m_sysDescription = _tcsdup(buffer);
2658 hasChanges = true;
2659 sendPollerMsg(rqId, _T(" System description changed to %s\r\n"), m_sysDescription);
2660 }
2661 unlockProperties();
2662 }
2663
2664 // Check for 64 bit counter support.
2665 // if Net.Interface.64BitCounters not supported by agent then use
2666 // only presence of 64 bit parameters as indicator
2667 bool netIf64bitCounters = true;
2668 if (pAgentConn->getParameter(_T("Net.Interface.64BitCounters"), MAX_DB_STRING, buffer) == ERR_SUCCESS)
2669 {
2670 netIf64bitCounters = _tcstol(buffer, NULL, 10) ? true : false;
2671 }
2672
2673 ObjectArray<AgentParameterDefinition> *plist;
2674 ObjectArray<AgentTableDefinition> *tlist;
2675 UINT32 rcc = pAgentConn->getSupportedParameters(&plist, &tlist);
2676 if (rcc == ERR_SUCCESS)
2677 {
2678 lockProperties();
2679 delete m_paramList;
2680 delete m_tableList;
2681 m_paramList = plist;
2682 m_tableList = tlist;
2683
2684 // Check for 64-bit interface counters
2685 m_capabilities &= ~NC_HAS_AGENT_IFXCOUNTERS;
2686 if (netIf64bitCounters)
2687 {
2688 for(int i = 0; i < plist->size(); i++)
2689 {
2690 if (!_tcsicmp(plist->get(i)->getName(), _T("Net.Interface.BytesIn64(*)")))
2691 {
2692 m_capabilities |= NC_HAS_AGENT_IFXCOUNTERS;
2693 break;
2694 }
2695 }
2696 }
2697
2698 unlockProperties();
2699 }
2700 else
2701 {
2702 DbgPrintf(5, _T("ConfPoll(%s): AgentConnection::getSupportedParameters() failed: rcc=%d"), m_name, rcc);
2703 }
2704
2705 // Get supported Windows Performance Counters
2706 if (!_tcsncmp(m_platformName, _T("windows-"), 8))
2707 {
2708 sendPollerMsg(rqId, _T(" Reading list of available Windows Performance Counters...\r\n"));
2709 ObjectArray<WinPerfObject> *perfObjects = WinPerfObject::getWinPerfObjectsFromNode(this, pAgentConn);
2710 lockProperties();
2711 delete m_winPerfObjects;
2712 m_winPerfObjects = perfObjects;
2713 if (m_winPerfObjects != NULL)
2714 {
2715 sendPollerMsg(rqId, POLLER_INFO _T(" %d counters read\r\n"), m_winPerfObjects->size());
2716 if (!(m_capabilities & NC_HAS_WINPDH))
2717 {
2718 m_capabilities |= NC_HAS_WINPDH;
2719 hasChanges = true;
2720 }
2721 }
2722 else
2723 {
2724 sendPollerMsg(rqId, POLLER_ERROR _T(" unable to get Windows Performance Counters list\r\n"));
2725 if (m_capabilities & NC_HAS_WINPDH)
2726 {
2727 m_capabilities &= ~NC_HAS_WINPDH;
2728 hasChanges = true;
2729 }
2730 }
2731 unlockProperties();
2732 }
2733
2734 checkAgentPolicyBinding(pAgentConn);
2735
2736 pAgentConn->disconnect();
2737 }
2738 else
2739 {
2740 nxlog_debug(5, _T("ConfPoll(%s): checking for NetXMS agent - failed to connect (error %d)"), m_name, rcc);
2741 }
2742 pAgentConn->decRefCount();
2743 nxlog_debug(5, _T("ConfPoll(%s): checking for NetXMS agent - finished"), m_name);
2744 return hasChanges;
2745 }
2746
2747 /**
2748 * SNMP walker callback which sets indicator to true after first varbind and aborts walk
2749 */
2750 static UINT32 IndicatorSnmpWalkerCallback(SNMP_Variable *var, SNMP_Transport *transport, void *arg)
2751 {
2752 (*((bool *)arg)) = true;
2753 return SNMP_ERR_COMM;
2754 }
2755
2756 /**
2757 * Configuration poll: check for SNMP
2758 */
2759 bool Node::confPollSnmp(UINT32 rqId)
2760 {
2761 if (((m_capabilities & NC_IS_SNMP) && (m_state & NSF_SNMP_UNREACHABLE)) ||
2762 !m_ipAddress.isValidUnicast() || (m_flags & NF_DISABLE_SNMP))
2763 return false;
2764
2765 bool hasChanges = false;
2766
2767 sendPollerMsg(rqId, _T(" Checking SNMP...\r\n"));
2768 DbgPrintf(5, _T("ConfPoll(%s): calling SnmpCheckCommSettings()"), m_name);
2769 StringList oids;
2770 const TCHAR *customOid = m_customAttributes.get(_T("snmp.testoid"));
2771 if (customOid != NULL)
2772 oids.add(customOid);
2773 oids.add(_T(".1.3.6.1.2.1.1.2.0"));
2774 oids.add(_T(".1.3.6.1.2.1.1.1.0"));
2775 AddDriverSpecificOids(&oids);
2776 SNMP_Transport *pTransport = SnmpCheckCommSettings(getEffectiveSnmpProxy(), (getEffectiveSnmpProxy() == m_id) ? InetAddress::LOOPBACK : m_ipAddress, &m_snmpVersion, m_snmpPort, m_snmpSecurity, &oids);
2777 if (pTransport == NULL)
2778 {
2779 DbgPrintf(5, _T("ConfPoll(%s): unable to create SNMP transport"), m_name);
2780 return false;
2781 }
2782
2783 lockProperties();
2784 m_snmpPort = pTransport->getPort();
2785 delete m_snmpSecurity;
2786 m_snmpSecurity = new SNMP_SecurityContext(pTransport->getSecurityContext());
2787 m_capabilities |= NC_IS_SNMP;
2788 if (m_state & NSF_SNMP_UNREACHABLE)
2789 {
2790 m_state &= ~NSF_SNMP_UNREACHABLE;
2791 PostEvent(EVENT_SNMP_OK, m_id, NULL);
2792 sendPollerMsg(rqId, POLLER_INFO _T(" Connectivity with SNMP agent restored\r\n"));
2793 }
2794 unlockProperties();
2795 sendPollerMsg(rqId, _T(" SNMP agent is active (version %s)\r\n"),
2796 (m_snmpVersion == SNMP_VERSION_3) ? _T("3") : ((m_snmpVersion == SNMP_VERSION_2C) ? _T("2c") : _T("1")));
2797
2798 TCHAR szBuffer[4096];
2799 if (SnmpGet(m_snmpVersion, pTransport, _T(".1.3.6.1.2.1.1.2.0"), NULL, 0, szBuffer, sizeof(szBuffer), SG_STRING_RESULT) != SNMP_ERR_SUCCESS)
2800 {
2801 // Set snmp object ID to .0.0 if it cannot be read
2802 _tcscpy(szBuffer, _T(".0.0"));
2803 }
2804 lockProperties();
2805 if (_tcscmp(m_snmpObjectId, szBuffer))
2806 {
2807 nx_strncpy(m_snmpObjectId, szBuffer, MAX_OID_LEN * 4);
2808 hasChanges = true;
2809 }
2810 unlockProperties();
2811
2812 // Get system description
2813 if (SnmpGet(m_snmpVersion, pTransport, _T(".1.3.6.1.2.1.1.1.0"), NULL, 0, szBuffer, sizeof(szBuffer), SG_STRING_RESULT) == SNMP_ERR_SUCCESS)
2814 {
2815 TranslateStr(szBuffer, _T("\r\n"), _T(" "));
2816 TranslateStr(szBuffer, _T("\n"), _T(" "));
2817 TranslateStr(szBuffer, _T("\r"), _T(" "));
2818 lockProperties();
2819 if ((m_sysDescription == NULL) || _tcscmp(m_sysDescription, szBuffer))
2820 {
2821 free(m_sysDescription);
2822 m_sysDescription = _tcsdup(szBuffer);
2823 hasChanges = true;
2824 sendPollerMsg(rqId, _T(" System description changed to %s\r\n"), m_sysDescription);
2825 }
2826 unlockProperties();
2827 }
2828
2829 // Select device driver
2830 NetworkDeviceDriver *driver = FindDriverForNode(this, pTransport);
2831 DbgPrintf(5, _T("ConfPoll(%s): selected device driver %s"), m_name, driver->getName());
2832 lockProperties();
2833 if (driver != m_driver)
2834 {
2835 m_driver = driver;
2836 sendPollerMsg(rqId, _T(" New network device driver selected: %s\r\n"), m_driver->getName());
2837 }
2838 unlockProperties();
2839
2840 // Allow driver to gather additional info
2841 m_driver->analyzeDevice(pTransport, m_snmpObjectId, &m_customAttributes, &m_driverData);
2842 NDD_MODULE_LAYOUT layout;
2843 m_driver->getModuleLayout(pTransport, &m_customAttributes, m_driverData, 1, &layout); // TODO module set to 1
2844 if (layout.numberingScheme == NDD_PN_UNKNOWN)
2845 {
2846 // Try to find port numbering information in database
2847 LookupDevicePortLayout(SNMP_ObjectId::parse(m_snmpObjectId), &layout);
2848 }
2849 m_portRowCount = layout.rows;
2850 m_portNumberingScheme = layout.numberingScheme;
2851
2852 // Get sysName, sysContact, sysLocation
2853 if (querySnmpSysProperty(pTransport, _T(".1.3.6.1.2.1.1.5.0"), _T("name"), rqId, &m_sysName))
2854 hasChanges = true;
2855 if (querySnmpSysProperty(pTransport, _T(".1.3.6.1.2.1.1.4.0"), _T("contact"), rqId, &m_sysContact))
2856 hasChanges = true;
2857 if (querySnmpSysProperty(pTransport, _T(".1.3.6.1.2.1.1.6.0"), _T("location"), rqId, &m_sysLocation))
2858 hasChanges = true;
2859
2860 // Check IP forwarding
2861 if (checkSNMPIntegerValue(pTransport, _T(".1.3.6.1.2.1.4.1.0"), 1))
2862 {
2863 lockProperties();
2864 m_capabilities |= NC_IS_ROUTER;
2865 unlockProperties();
2866 }
2867 else
2868 {
2869 lockProperties();
2870 m_capabilities &= ~NC_IS_ROUTER;
2871 unlockProperties();
2872 }
2873
2874 checkIfXTable(pTransport);
2875 checkBridgeMib(pTransport);
2876
2877 // Check for ENTITY-MIB support
2878 if (SnmpGet(m_snmpVersion, pTransport, _T(".1.3.6.1.2.1.47.1.4.1.0"), NULL, 0, szBuffer, sizeof(szBuffer), SG_RAW_RESULT) == SNMP_ERR_SUCCESS)
2879 {
2880 lockProperties();
2881 m_capabilities |= NC_HAS_ENTITY_MIB;
2882 unlockProperties();
2883
2884 ComponentTree *components = BuildComponentTree(this, pTransport);
2885 lockProperties();
2886 if (m_components != NULL)
2887 m_components->decRefCount();
2888 m_components = components;
2889 unlockProperties();
2890 }
2891 else
2892 {
2893 lockProperties();
2894 m_capabilities &= ~NC_HAS_ENTITY_MIB;
2895 if (m_components != NULL)
2896 {
2897 m_components->decRefCount();
2898 m_components = NULL;
2899 }
2900 unlockProperties();
2901 }
2902
2903 // Check for printer MIB support
2904 bool present = false;
2905 SnmpWalk(pTransport, _T(".1.3.6.1.2.1.43"), IndicatorSnmpWalkerCallback, &present);
2906 if (present)
2907 {
2908 lockProperties();
2909 m_capabilities |= NC_IS_PRINTER;
2910 unlockProperties();
2911 }
2912 else
2913 {
2914 lockProperties();
2915 m_capabilities &= ~NC_IS_PRINTER;
2916 unlockProperties();
2917 }
2918
2919 // Check for CDP (Cisco Discovery Protocol) support
2920 if (checkSNMPIntegerValue(pTransport, _T(".1.3.6.1.4.1.9.9.23.1.3.1.0"), 1))
2921 {
2922 lockProperties();
2923 m_capabilities |= NC_IS_CDP;
2924 unlockProperties();
2925 }
2926 else
2927 {
2928 lockProperties();
2929 m_capabilities &= ~NC_IS_CDP;
2930 unlockProperties();
2931 }
2932
2933 // Check for NDP (Nortel Discovery Protocol) support
2934 if (checkSNMPIntegerValue(pTransport, _T(".1.3.6.1.4.1.45.1.6.13.1.2.0"), 1))
2935 {
2936 lockProperties();
2937 m_capabilities |= NC_IS_NDP;
2938 unlockProperties();
2939 }
2940 else
2941 {
2942 lockProperties();
2943 m_capabilities &= ~NC_IS_NDP;
2944 unlockProperties();
2945 }
2946
2947 // Check for LLDP (Link Layer Discovery Protocol) support
2948 if (SnmpGet(m_snmpVersion, pTransport, _T(".1.0.8802.1.1.2.1.3.2.0"), NULL, 0, szBuffer, sizeof(szBuffer), 0) == SNMP_ERR_SUCCESS)
2949 {
2950 lockProperties();
2951 m_capabilities |= NC_IS_LLDP;
2952 unlockProperties();
2953
2954 INT32 type;
2955 BYTE data[256];
2956 UINT32 dataLen;
2957 if ((SnmpGetEx(pTransport, _T(".1.0.8802.1.1.2.1.3.1.0"), NULL, 0, &type, sizeof(INT32), 0, NULL) == SNMP_ERR_SUCCESS) &&
2958 (SnmpGetEx(pTransport, _T(".1.0.8802.1.1.2.1.3.2.0"), NULL, 0, data, 256, SG_RAW_RESULT, &dataLen) == SNMP_ERR_SUCCESS))
2959 {
2960 BuildLldpId(type, data, dataLen, szBuffer, 1024);
2961 lockProperties();
2962 if ((m_lldpNodeId == NULL) || _tcscmp(m_lldpNodeId, szBuffer))
2963 {
2964 free(m_lldpNodeId);
2965 m_lldpNodeId = _tcsdup(szBuffer);
2966 hasChanges = true;
2967 sendPollerMsg(rqId, _T(" LLDP node ID changed to %s\r\n"), m_lldpNodeId);
2968 }
2969 unlockProperties();
2970 }
2971
2972 ObjectArray<LLDP_LOCAL_PORT_INFO> *lldpPorts = GetLLDPLocalPortInfo(pTransport);
2973 lockProperties();
2974 delete m_lldpLocalPortInfo;
2975 m_lldpLocalPortInfo = lldpPorts;
2976 unlockProperties();
2977 }
2978 else
2979 {
2980 lockProperties();
2981 m_capabilities &= ~NC_IS_LLDP;
2982 unlockProperties();
2983 }
2984
2985 // Check for 802.1x support
2986 if (checkSNMPIntegerValue(pTransport, _T(".1.0.8802.1.1.1.1.1.1.0"), 1))
2987 {
2988 lockProperties();
2989 m_capabilities |= NC_IS_8021X;
2990 unlockProperties();
2991 }
2992 else
2993 {
2994 lockProperties();
2995 m_capabilities &= ~NC_IS_8021X;
2996 unlockProperties();
2997 }
2998
2999 checkOSPFSupport(pTransport);
3000
3001 // Get VRRP information
3002 VrrpInfo *vrrpInfo = GetVRRPInfo(this);
3003 if (vrrpInfo != NULL)
3004 {
3005 lockProperties();
3006 m_capabilities |= NC_IS_VRRP;
3007 delete m_vrrpInfo;
3008 m_vrrpInfo = vrrpInfo;
3009 unlockProperties();
3010 }
3011 else
3012 {
3013 lockProperties();
3014 m_capabilities &= ~NC_IS_VRRP;
3015 unlockProperties();
3016 }
3017
3018 // Get wireless controller data
3019 if ((m_driver != NULL) && m_driver->isWirelessController(pTransport, &m_customAttributes, m_driverData))
3020 {
3021 DbgPrintf(5, _T("ConfPoll(%s): node is wireless controller, reading access point information"), m_name);
3022 sendPollerMsg(rqId, _T(" Reading wireless access point information\r\n"));
3023 lockProperties();
3024 m_capabilities |= NC_IS_WIFI_CONTROLLER;
3025 unlockProperties();
3026
3027 int clusterMode = m_driver->getClusterMode(pTransport, &m_customAttributes, m_driverData);
3028
3029 ObjectArray<AccessPointInfo> *aps = m_driver->getAccessPoints(pTransport, &m_customAttributes, m_driverData);
3030 if (aps != NULL)
3031 {
3032 sendPollerMsg(rqId, POLLER_INFO _T(" %d wireless access points found\r\n"), aps->size());
3033 DbgPrintf(5, _T("ConfPoll(%s): got information about %d access points"), m_name, aps->size());
3034 int adopted = 0;
3035 for(int i = 0; i < aps->size(); i++)
3036 {
3037 AccessPointInfo *info = aps->get(i);
3038 if (info->getState() == AP_ADOPTED)
3039 adopted++;
3040
3041 bool newAp = false;
3042 AccessPoint *ap = (clusterMode == CLUSTER_MODE_STANDALONE) ? findAccessPointByMAC(info->getMacAddr()) : FindAccessPointByMAC(info->getMacAddr());
3043 if (ap == NULL)
3044 {
3045 String name;
3046
3047 if (info->getName() != NULL)
3048 {
3049 name = info->getName();
3050 }
3051 else
3052 {
3053 for(int j = 0; j < info->getRadioInterfaces()->size(); j++)
3054 {
3055 if (j > 0)
3056 name += _T("/");
3057 name += info->getRadioInterfaces()->get(j)->name;
3058 }
3059 }
3060 ap = new AccessPoint((const TCHAR *)name, info->getIndex(), info->getMacAddr());
3061 NetObjInsert(ap, true, false);
3062 DbgPrintf(5, _T("ConfPoll(%s): created new access point object %s [%d]"), m_name, ap->getName(), ap->getId());
3063 newAp = true;
3064 }
3065 ap->attachToNode(m_id);
3066 ap->setIpAddress(info->getIpAddr());
3067 if ((info->getState() == AP_ADOPTED) || newAp)
3068 {
3069 ap->updateRadioInterfaces(info->getRadioInterfaces());
3070 ap->updateInfo(info->getVendor(), info->getModel(), info->getSerial());
3071 }
3072 ap->unhide();
3073 ap->updateState(info->getState());
3074 }
3075
3076 lockProperties();
3077 m_adoptedApCount = adopted;
3078 m_totalApCount = aps->size();
3079 unlockProperties();
3080
3081 delete aps;
3082 }
3083 else
3084 {
3085 DbgPrintf(5, _T("ConfPoll(%s): failed to read access point information"), m_name);
3086 sendPollerMsg(rqId, POLLER_ERROR _T(" Failed to read access point information\r\n"));
3087 }
3088 }
3089 else
3090 {
3091 lockProperties();
3092 m_capabilities &= ~NC_IS_WIFI_CONTROLLER;
3093 unlockProperties();
3094 }
3095
3096 if (ConfigReadInt(_T("EnableCheckPointSNMP"), 0))
3097 {
3098 // Check for CheckPoint SNMP agent on port 161
3099 DbgPrintf(5, _T("ConfPoll(%s): checking for CheckPoint SNMP"), m_name);
3100 TCHAR szBuffer[4096];
3101 if (SnmpGet(SNMP_VERSION_1, pTransport, _T(".1.3.6.1.4.1.2620.1.1.10.0"), NULL, 0, szBuffer, sizeof(szBuffer), 0) == SNMP_ERR_SUCCESS)
3102 {
3103 lockProperties();
3104 if (_tcscmp(m_snmpObjectId, _T(".1.3.6.1.4.1.2620.1.1")))
3105 {
3106 nx_strncpy(m_snmpObjectId, _T(".1.3.6.1.4.1.2620.1.1"), MAX_OID_LEN * 4);
3107 hasChanges = true;
3108 }
3109
3110 m_capabilities |= NC_IS_SNMP | NC_IS_ROUTER;
3111 m_state &= ~NSF_SNMP_UNREACHABLE;
3112 unlockProperties();
3113 sendPollerMsg(rqId, POLLER_INFO _T(" CheckPoint SNMP agent on port 161 is active\r\n"));
3114 }
3115 }
3116 delete pTransport;
3117 return hasChanges;
3118 }
3119
3120 /**
3121 * Query SNMP sys property (sysName, sysLocation, etc.)
3122 */
3123 bool Node::querySnmpSysProperty(SNMP_Transport *snmp, const TCHAR *oid, const TCHAR *propName, UINT32 pollRqId, TCHAR **value)
3124 {
3125 TCHAR buffer[256];
3126 bool hasChanges = false;
3127
3128 if (SnmpGet(m_snmpVersion, snmp, oid, NULL, 0, buffer, sizeof(buffer), SG_STRING_RESULT) == SNMP_ERR_SUCCESS)
3129 {
3130 lockProperties();
3131 if ((*value == NULL) || _tcscmp(*value, buffer))
3132 {
3133 safe_free(*value);
3134 *value = _tcsdup(buffer);
3135 hasChanges = true;
3136 sendPollerMsg(pollRqId, _T(" System %s changed to %s\r\n"), propName, *value);
3137 }
3138 unlockProperties();
3139 }
3140 return hasChanges;
3141 }
3142
3143 /**
3144 * Configuration poll: check for BRIDGE MIB
3145 */
3146 void Node::checkBridgeMib(SNMP_Transport *pTransport)
3147 {
3148 TCHAR szBuffer[4096];
3149 if (SnmpGet(m_snmpVersion, pTransport, _T(".1.3.6.1.2.1.17.1.1.0"), NULL, 0, szBuffer, sizeof(szBuffer), SG_RAW_RESULT) == SNMP_ERR_SUCCESS)
3150 {
3151 lockProperties();
3152 m_capabilities |= NC_IS_BRIDGE;
3153 memcpy(m_baseBridgeAddress, szBuffer, 6);
3154 unlockProperties();
3155
3156 // Check for Spanning Tree (IEEE 802.1d) MIB support
3157 if (checkSNMPIntegerValue(pTransport, _T(".1.3.6.1.2.1.17.2.1.0"), 3))
3158 {
3159 lockProperties();
3160 m_capabilities |= NC_IS_STP;
3161 unlockProperties();
3162 }
3163 else
3164 {
3165 lockProperties();
3166 m_capabilities &= ~NC_IS_STP;
3167 unlockProperties();
3168 }
3169 }
3170 else
3171 {
3172 lockProperties();
3173 m_capabilities &= ~(NC_IS_BRIDGE | NC_IS_STP);
3174 unlockProperties();
3175 }
3176 }
3177
3178 /**
3179 * Configuration poll: check for ifXTable
3180 */
3181 void Node::checkIfXTable(SNMP_Transport *pTransport)
3182 {
3183 bool present = false;
3184 SnmpWalk(pTransport, _T(".1.3.6.1.2.1.31.1.1.1.1"), IndicatorSnmpWalkerCallback, &present);
3185 if (present)
3186 {
3187 lockProperties();
3188 m_capabilities |= NC_HAS_IFXTABLE;
3189 unlockProperties();
3190 }
3191 else
3192 {
3193 lockProperties();
3194 m_capabilities &= ~NC_HAS_IFXTABLE;
3195 unlockProperties();
3196 }
3197 }
3198
3199 /**
3200 * Delete duplicate interfaces
3201 * (find and delete multiple interfaces with same ifIndex value created by version prior to 2.0-M3)
3202 */
3203 bool Node::deleteDuplicateInterfaces(UINT32 rqid)
3204 {
3205 ObjectArray<Interface> deleteList(16, 16, false);
3206
3207 lockChildList(false);
3208 for(int i = 0; i < m_childList->size(); i++)
3209 {
3210 NetObj *curr = m_childList->get(i);
3211
3212 if ((curr->getObjectClass() != OBJECT_INTERFACE) ||
3213 ((Interface *)curr)->isManuallyCreated())
3214 continue;
3215 Interface *iface = (Interface *)curr;
3216 for(int j = i + 1; j < m_childList->size(); j++)
3217 {
3218 NetObj *next = m_childList->get(j);
3219
3220 if ((next->getObjectClass() != OBJECT_INTERFACE) ||
3221 ((Interface *)next)->isManuallyCreated() ||
3222 (deleteList.contains((Interface *)next)))
3223 continue;
3224 if (iface->getIfIndex() == ((Interface *)next)->getIfIndex())
3225 {
3226 deleteList.add((Interface *)next);
3227 DbgPrintf(6, _T("Node::deleteDuplicateInterfaces(%s [%d]): found duplicate interface %s [%d], original %s [%d], ifIndex=%d"),
3228 m_name, m_id, next->getName(), next->getId(), iface->getName(), iface->getId(), iface->getIfIndex());
3229 }
3230 }
3231 }
3232 unlockChildList();
3233
3234 for(int i = 0; i < deleteList.size(); i++)
3235 {
3236 Interface *iface = deleteList.get(i);
3237 sendPollerMsg(rqid, POLLER_WARNING _T(" Duplicate interface \"%s\" deleted\r\n"), iface->getName());
3238 deleteInterface(iface);
3239 }
3240
3241 return deleteList.size() > 0;
3242 }
3243
3244 /**
3245 * Update interface configuration
3246 */
3247 bool Node::updateInterfaceConfiguration(UINT32 rqid, int maskBits)
3248 {
3249 sendPollerMsg(rqid, _T("Checking interface configuration...\r\n"));
3250
3251 bool hasChanges = deleteDuplicateInterfaces(rqid);
3252
3253 InterfaceList *ifList = getInterfaceList();
3254 if (ifList != NULL)
3255 {
3256 nxlog_debug(6, _T("Node::updateInterfaceConfiguration(%s [%u]): got %d interfaces"), m_name, m_id, ifList->size());
3257
3258 // Find non-existing interfaces
3259 lockChildList(false);
3260 ObjectArray<Interface> deleteList(m_childList->size(), 8, false);
3261 for(int i = 0; i < m_childList->size(); i++)
3262 {
3263 if (m_childList->get(i)->getObjectClass() == OBJECT_INTERFACE)
3264 {
3265 Interface *iface = (Interface *)m_childList->get(i);
3266 if (iface->isFake())
3267 {
3268 // always delete fake interfaces if we got actual interface list
3269 deleteList.add(iface);
3270 continue;
3271 }
3272
3273 if (!iface->isManuallyCreated())
3274 {
3275 int j;
3276 for(j = 0; j < ifList->size(); j++)
3277 {
3278 if (ifList->get(j)->index == iface->getIfIndex())
3279 break;
3280 }
3281
3282 if (j == ifList->size())
3283 {
3284 // No such interface in current configuration, add it to delete list
3285 deleteList.add(iface);
3286 }
3287 }
3288 }
3289 }
3290 unlockChildList();
3291
3292 // Delete non-existent interfaces
3293 if (deleteList.size() > 0)
3294 {
3295 for(int j = 0; j < deleteList.size(); j++)
3296 {
3297 Interface *iface = deleteList.get(j);
3298 sendPollerMsg(rqid, POLLER_WARNING _T(" Interface \"%s\" is no longer exist\r\n"), iface->getName());
3299 const InetAddress& addr = iface->getFirstIpAddress();
3300 PostEvent(EVENT_INTERFACE_DELETED, m_id, "dsAd", iface->getIfIndex(), iface->getName(), &addr, addr.getMaskBits());
3301 deleteInterface(iface);
3302 }
3303 hasChanges = true;
3304 }
3305
3306 // Add new interfaces and check configuration of existing
3307 for(int j = 0; j < ifList->size(); j++)
3308 {
3309 InterfaceInfo *ifInfo = ifList->get(j);
3310 bool isNewInterface = true;
3311
3312 lockChildList(false);
3313 for(int i = 0; i < m_childList->size(); i++)
3314 {
3315 if (m_childList->get(i)->getObjectClass() == OBJECT_INTERFACE)
3316 {
3317 Interface *pInterface = (Interface *)m_childList->get(i);
3318
3319 if (ifInfo->index == pInterface->getIfIndex())
3320 {
3321 // Existing interface, check configuration
3322 if (memcmp(ifInfo->macAddr, "\x00\x00\x00\x00\x00\x00", MAC_ADDR_LENGTH) &&
3323 memcmp(ifInfo->macAddr, pInterface->getMacAddr(), MAC_ADDR_LENGTH))
3324 {
3325 TCHAR szOldMac[16], szNewMac[16];
3326
3327 BinToStr((BYTE *)pInterface->getMacAddr(), MAC_ADDR_LENGTH, szOldMac);
3328 BinToStr(ifInfo->macAddr, MAC_ADDR_LENGTH, szNewMac);
3329 PostEvent(EVENT_MAC_ADDR_CHANGED, m_id, "idsss",
3330 pInterface->getId(), pInterface->getIfIndex(),
3331 pInterface->getName(), szOldMac, szNewMac);
3332 pInterface->setMacAddr(ifInfo->macAddr, true);
3333 }
3334 if (_tcscmp(ifInfo->name, pInterface->getName()))
3335 {
3336 pInterface->setName(ifInfo->name);
3337 }
3338 if (_tcscmp(ifInfo->description, pInterface->getDescription()))
3339 {
3340 pInterface->setDescription(ifInfo->description);
3341 }
3342 if (_tcscmp(ifInfo->alias, pInterface->getAlias()))
3343 {
3344 pInterface->setAlias(ifInfo->alias);
3345 }
3346 if (ifInfo->bridgePort != pInterface->getBridgePortNumber())
3347 {
3348 pInterface->setBridgePortNumber(ifInfo->bridgePort);
3349 }
3350 if (ifInfo->slot != pInterface->getSlotNumber())
3351 {
3352 pInterface->setSlotNumber(ifInfo->slot);
3353 }
3354 if (ifInfo->port != pInterface->getPortNumber())
3355 {
3356 pInterface->setPortNumber(ifInfo->port);
3357 }
3358 if (ifInfo->isPhysicalPort != pInterface->isPhysicalPort())
3359 {
3360 pInterface->setPhysicalPortFlag(ifInfo->isPhysicalPort);
3361 }
3362 if (ifInfo->mtu != pInterface->getMTU())
3363 {
3364 pInterface->setMTU(ifInfo->mtu);
3365 }
3366 if (ifInfo->speed != pInterface->getSpeed())
3367 {
3368 pInterface->setSpeed(ifInfo->speed);
3369 }
3370 if ((ifInfo->ifTableSuffixLength != pInterface->getIfTableSuffixLen()) ||
3371 memcmp(ifInfo->ifTableSuffix, pInterface->getIfTableSuffix(),
3372 std::min(ifInfo->ifTableSuffixLength, pInterface->getIfTableSuffixLen())))
3373 {
3374 pInterface->setIfTableSuffix(ifInfo->ifTableSuffixLength, ifInfo->ifTableSuffix);
3375 }
3376
3377 // Check for deleted IPs and changed masks
3378 const InetAddressList *ifList = pInterface->getIpAddressList();
3379 for(int n = 0; n < ifList->size(); n++)
3380 {
3381 const InetAddress& ifAddr = ifList->get(n);
3382 const InetAddress& addr = ifInfo->ipAddrList.findAddress(ifAddr);
3383 if (addr.isValid())
3384 {
3385 if (addr.getMaskBits() != ifAddr.getMaskBits())
3386 {
3387 PostEvent(EVENT_IF_MASK_CHANGED, m_id, "dsAddd", pInterface->getId(), pInterface->getName(),
3388 &addr, addr.getMaskBits(), pInterface->getIfIndex(), ifAddr.getMaskBits());
3389 pInterface->setNetMask(addr);
3390 sendPollerMsg(rqid, POLLER_INFO _T(" IP network mask changed to /%d on interface \"%s\" address %s\r\n"),
3391 addr.getMaskBits(), pInterface->getName(), (const TCHAR *)ifAddr.toString());
3392 }
3393 }
3394 else
3395 {
3396 sendPollerMsg(rqid, POLLER_WARNING _T(" IP address %s removed from interface \"%s\"\r\n"),
3397 (const TCHAR *)ifAddr.toString(), pInterface->getName());
3398 PostEvent(EVENT_IF_IPADDR_DELETED, m_id, "dsAdd", pInterface->getId(), pInterface->getName(),
3399 &ifAddr, ifAddr.getMaskBits(), pInterface->getIfIndex());
3400 pInterface->deleteIpAddress(ifAddr);
3401 }
3402 }
3403
3404 // Check for added IPs
3405 for(int m = 0; m < ifInfo->ipAddrList.size(); m++)
3406 {
3407 const InetAddress& addr = ifInfo->ipAddrList.get(m);
3408 if (!ifList->hasAddress(addr))
3409 {
3410 pInterface->addIpAddress(addr);
3411 PostEvent(EVENT_IF_IPADDR_ADDED, m_id, "dsAdd", pInterface->getId(), pInterface->getName(),
3412 &addr, addr.getMaskBits(), pInterface->getIfIndex());
3413 sendPollerMsg(rqid, POLLER_INFO _T(" IP address %s added to interface \"%s\"\r\n"),
3414 (const TCHAR *)addr.toString(), pInterface->getName());
3415 }
3416 }
3417
3418 isNewInterface = false;
3419 break;
3420 }
3421 }
3422 }
3423 unlockChildList();
3424
3425 if (isNewInterface)
3426 {
3427 // New interface
3428 sendPollerMsg(rqid, POLLER_INFO _T(" Found new interface \"%s\"\r\n"), ifInfo->name);
3429 if (filterInterface(ifInfo))
3430 {
3431 createNewInterface(ifInfo, false, false);
3432 hasChanges = true;
3433 }
3434 else
3435 {
3436 sendPollerMsg(rqid, POLLER_WARNING _T(" Creation of interface object \"%s\" blocked by filter\r\n"), ifInfo->name);