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