additional debug output
[public/netxms.git] / src / server / core / agent.cpp
CommitLineData
9fa031cd 1/*
5039dede 2** NetXMS - Network Management System
df94e0ce 3** Copyright (C) 2003-2012 Victor Kirhenshtein
5039dede
AK
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: agent.cpp
20**
21**/
22
23#include "nxcore.h"
24
489b117b 25/**
26 * Externals
27 */
28extern Queue g_nodePollerQueue;
c75e9ee4 29void ProcessTrap(SNMP_PDU *pdu, const InetAddress& srcAddr, int srcPort, SNMP_Transport *pTransport, SNMP_Engine *localEngine, bool isInformRq);
489b117b 30
d1c1c522
VK
31/**
32 * Destructor for extended agent connection class
33 */
5039dede
AK
34AgentConnectionEx::~AgentConnectionEx()
35{
36}
37
d1c1c522
VK
38/**
39 * Trap processor
40 */
b368969c 41void AgentConnectionEx::onTrap(NXCPMessage *pMsg)
5039dede 42{
967893bb 43 UINT32 dwEventCode;
5039dede 44 int i, iNumArgs;
d1c1c522 45 Node *pNode = NULL;
5039dede 46 TCHAR *pszArgList[32], szBuffer[32];
35f836fe 47 char szFormat[] = "ssssssssssssssssssssssssssssssss";
5039dede 48
c11eee9b 49 DbgPrintf(3, _T("AgentConnectionEx::onTrap(): Received trap message from agent at %s, node ID %d"), getIpAddr().toString(szBuffer), m_nodeId);
d1c1c522
VK
50 if (m_nodeId != 0)
51 pNode = (Node *)FindObjectById(m_nodeId, OBJECT_NODE);
52 if (pNode == NULL)
c11eee9b 53 pNode = FindNodeByIP(0, getIpAddr().getAddressV4());
5039dede
AK
54 if (pNode != NULL)
55 {
5c5c7111
VK
56 if (pNode->Status() != STATUS_UNMANAGED)
57 {
58 // Check for duplicate traps - only accept traps with ID
59 // higher than last received
60 // agents prior to 1.1.6 will not send trap id
61 // we should accept trap in that case to maintain compatibility
62 bool acceptTrap;
b368969c 63 QWORD trapId = pMsg->getFieldAsUInt64(VID_TRAP_ID);
5c5c7111
VK
64 if (trapId != 0)
65 {
66 acceptTrap = pNode->checkAgentTrapId(trapId);
67 DbgPrintf(5, _T("AgentConnectionEx::onTrap(): trapID is%s valid"), acceptTrap ? _T("") : _T(" not"));
68 }
69 else
70 {
71 acceptTrap = true;
72 DbgPrintf(5, _T("AgentConnectionEx::onTrap(): trap ID not provided"));
73 }
fed33789 74
5c5c7111
VK
75 if (acceptTrap)
76 {
b368969c 77 dwEventCode = pMsg->getFieldAsUInt32(VID_EVENT_CODE);
5c5c7111
VK
78 if ((dwEventCode == 0) && pMsg->isFieldExist(VID_EVENT_NAME))
79 {
80 TCHAR eventName[256];
b368969c 81 pMsg->getFieldAsString(VID_EVENT_NAME, eventName, 256);
5c5c7111
VK
82 dwEventCode = EventCodeFromName(eventName, 0);
83 }
b368969c 84 iNumArgs = (int)pMsg->getFieldAsUInt16(VID_NUM_ARGS);
5c5c7111
VK
85 if (iNumArgs > 32)
86 iNumArgs = 32;
87 for(i = 0; i < iNumArgs; i++)
b368969c 88 pszArgList[i] = pMsg->getFieldAsString(VID_EVENT_ARG_BASE + i);
5c5c7111 89 DbgPrintf(3, _T("Event from trap: %d"), dwEventCode);
5039dede 90
5c5c7111 91 szFormat[iNumArgs] = 0;
c42b4551 92 PostEvent(dwEventCode, pNode->getId(), (iNumArgs > 0) ? szFormat : NULL,
5c5c7111
VK
93 pszArgList[0], pszArgList[1], pszArgList[2], pszArgList[3],
94 pszArgList[4], pszArgList[5], pszArgList[6], pszArgList[7],
95 pszArgList[8], pszArgList[9], pszArgList[10], pszArgList[11],
96 pszArgList[12], pszArgList[13], pszArgList[14], pszArgList[15],
97 pszArgList[16], pszArgList[17], pszArgList[18], pszArgList[19],
98 pszArgList[20], pszArgList[21], pszArgList[22], pszArgList[23],
99 pszArgList[24], pszArgList[25], pszArgList[26], pszArgList[27],
100 pszArgList[28], pszArgList[29], pszArgList[30], pszArgList[31]);
9fa031cd 101
5c5c7111
VK
102 // Cleanup
103 for(i = 0; i < iNumArgs; i++)
104 free(pszArgList[i]);
105 }
106 }
107 else
108 {
c42b4551 109 DbgPrintf(3, _T("AgentConnectionEx::onTrap(): node %s [%d] in in UNMANAGED state - trap ignored"), pNode->getName(), pNode->getId());
5c5c7111 110 }
5039dede
AK
111 }
112 else
113 {
c11eee9b 114 DbgPrintf(3, _T("AgentConnectionEx::onTrap(): Cannot find node for IP address %s"), getIpAddr().toString(szBuffer));
5039dede
AK
115 }
116}
45d84f8a 117
d1c1c522
VK
118/**
119 * Handler for data push
120 */
b368969c 121void AgentConnectionEx::onDataPush(NXCPMessage *msg)
f480bdd4
VK
122{
123 TCHAR name[MAX_PARAM_NAME], value[MAX_RESULT_LENGTH];
124
b368969c
VK
125 msg->getFieldAsString(VID_NAME, name, MAX_PARAM_NAME);
126 msg->getFieldAsString(VID_VALUE, value, MAX_RESULT_LENGTH);
f480bdd4 127
e3ee1478 128 Node *sender = NULL;
42a3be4f
VK
129 if (m_nodeId != 0)
130 sender = (Node *)FindObjectById(m_nodeId, OBJECT_NODE);
131 if (sender == NULL)
6fbaa926 132 sender = FindNodeByIP(0, getIpAddr());
42a3be4f 133
4e46505f 134 if (sender != NULL)
f480bdd4 135 {
42a3be4f
VK
136 // Check for duplicate data requests - only accept requests with ID
137 // higher than last received
138 // agents prior to 1.2.10 will not send request id
139 // we should accept data in that case to maintain compatibility
140 bool acceptRequest;
b368969c 141 QWORD requestId = msg->getFieldAsUInt64(VID_REQUEST_ID);
42a3be4f
VK
142 if (requestId != 0)
143 {
144 acceptRequest = sender->checkAgentPushRequestId(requestId);
145 DbgPrintf(5, _T("AgentConnectionEx::onDataPush(): requestId is%s valid"), acceptRequest ? _T("") : _T(" not"));
146 }
147 else
148 {
149 acceptRequest = true;
150 DbgPrintf(5, _T("AgentConnectionEx::onDataPush(): request ID not provided"));
151 }
152
153 if (acceptRequest)
154 {
155 Node *target;
b368969c 156 UINT32 objectId = msg->getFieldAsUInt32(VID_OBJECT_ID);
42a3be4f 157 if (objectId != 0)
4e46505f 158 {
42a3be4f
VK
159 // push on behalf of other node
160 target = (Node *)FindObjectById(objectId, OBJECT_NODE);
161 if (target != NULL)
4e46505f 162 {
c42b4551 163 if (target->isTrustedNode(sender->getId()))
42a3be4f 164 {
c42b4551 165 DbgPrintf(5, _T("%s: agent data push: target set to %s [%d]"), sender->getName(), target->getName(), target->getId());
42a3be4f
VK
166 }
167 else
168 {
c42b4551 169 DbgPrintf(5, _T("%s: agent data push: not in trusted node list for target %s [%d]"), sender->getName(), target->getName(), target->getId());
42a3be4f
VK
170 target = NULL;
171 }
4e46505f
VK
172 }
173 }
42a3be4f
VK
174 else
175 {
176 target = sender;
177 }
4e46505f 178
42a3be4f
VK
179 if (target != NULL)
180 {
c42b4551 181 DbgPrintf(5, _T("%s: agent data push: %s=%s"), target->getName(), name, value);
42a3be4f
VK
182 DCObject *dci = target->getDCObjectByName(name);
183 if ((dci != NULL) && (dci->getType() == DCO_TYPE_ITEM) && (dci->getDataSource() == DS_PUSH_AGENT) && (dci->getStatus() == ITEM_STATUS_ACTIVE))
184 {
c42b4551 185 DbgPrintf(5, _T("%s: agent data push: found DCI %d"), target->getName(), dci->getId());
b60584cf
VK
186 time_t t = msg->getFieldAsTime(VID_TIMESTAMP);
187 if (t == 0)
188 t = time(NULL);
42a3be4f 189 target->processNewDCValue(dci, t, value);
b60584cf
VK
190 if (t > dci->getLastPollTime())
191 dci->setLastPollTime(t);
42a3be4f
VK
192 }
193 else
194 {
c42b4551 195 DbgPrintf(5, _T("%s: agent data push: DCI not found for %s"), target->getName(), name);
42a3be4f
VK
196 }
197 }
198 else
199 {
c42b4551 200 DbgPrintf(5, _T("%s: agent data push: target node not found or not accessible"), sender->getName());
42a3be4f 201 }
4e46505f 202 }
f480bdd4
VK
203 }
204}
205
af21affe
VK
206/**
207 * Print message.
208 */
209void AgentConnectionEx::printMsg(const TCHAR *format, ...)
210{
211 va_list args;
212
213 va_start(args, format);
214 DbgPrintf2(6, format, args);
215 va_end(args);
216}
217
76b4edb5 218/**
9fa031cd 219 * Recieve file monitoring information and resend to all required user sessions
220 */
b368969c 221void AgentConnectionEx::onFileMonitoringData(NXCPMessage *pMsg)
9fa031cd 222{
489b117b 223 Node *object = NULL;
9fa031cd 224 if (m_nodeId != 0)
225 object = (Node *)FindObjectById(m_nodeId, OBJECT_NODE);
226 if (object != NULL)
227 {
18b237f7 228 TCHAR remoteFile[MAX_PATH];
b368969c 229 pMsg->getFieldAsString(VID_FILE_NAME, remoteFile, MAX_PATH);
c42b4551
VK
230 ObjectArray<ClientSession>* result = g_monitoringList.findClientByFNameAndNodeID(remoteFile, object->getId());
231 DbgPrintf(6, _T("AgentConnectionEx::onFileMonitoringData: found %d sessions for remote file %s on node %s [%d]"), result->size(), remoteFile, object->getName(), object->getId());
9fa031cd 232 for(int i = 0; i < result->size(); i++)
233 {
234 result->get(i)->sendMessage(pMsg);
05e3ba32 235 }
236 if(result->size() == 0)
237 {
238 DbgPrintf(6, _T("AgentConnectionEx::onFileMonitoringData: unknown subscription will be canceled."));
489b117b 239 AgentConnection *conn = object->createAgentConnection();
05e3ba32 240 if(conn != NULL)
241 {
b368969c
VK
242 NXCPMessage request;
243 request.setId(conn->generateRequestId());
244 request.setCode(CMD_CANCEL_FILE_MONITORING);
245 request.setField(VID_FILE_NAME, remoteFile);
246 request.setField(VID_OBJECT_ID, object->getId());
247 NXCPMessage* response = conn->customRequest(&request);
05e3ba32 248 delete response;
249 }
250 delete conn;
9fa031cd 251 }
ece85e30 252 delete result;
9fa031cd 253 }
254 else
255 {
256 g_monitoringList.removeDisconectedNode(m_nodeId);
18b237f7 257 DbgPrintf(6, _T("AgentConnectionEx::onFileMonitoringData: node object not found"));
9fa031cd 258 }
259}
260
5bbb1485 261/**
262 * Ask modules if they can procress custom message
263 */
264bool AgentConnectionEx::processCustomMessage(NXCPMessage *msg)
265{
ac1a1de4
VK
266 TCHAR buffer[128];
267 DbgPrintf(6, _T("AgentConnectionEx::processCustomMessage: processing message %s ID %d"),
268 NXCPMessageCodeName(msg->getCode(), buffer), msg->getId());
5bbb1485 269
ac1a1de4
VK
270 for(UINT32 i = 0; i < g_dwNumModules; i++)
271 {
272 if (g_pModuleList[i].pfOnAgentMessage != NULL)
273 {
274 if (g_pModuleList[i].pfOnAgentMessage(msg, m_nodeId))
275 return true; // accepted by module
276 }
277 }
5bbb1485 278 return false;
279}
280
489b117b 281/**
282 * Recieve trap sent throught proxy agent
283 */
b368969c 284void AgentConnectionEx::onSnmpTrap(NXCPMessage *msg)
489b117b 285{
286 Node *proxyNode = NULL;
287 TCHAR ipStringBuffer[4096];
288
289 static BYTE engineId[] = { 0x80, 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00 };
290 SNMP_Engine localEngine(engineId, 12);
291
ac1a1de4
VK
292 DbgPrintf(3, _T("AgentConnectionEx::onSnmpTrap(): Received SNMP trap message from agent at %s, node ID %d"),
293 getIpAddr().toString(ipStringBuffer), m_nodeId);
294
489b117b 295 if (m_nodeId != 0)
296 proxyNode = (Node *)FindObjectById(m_nodeId, OBJECT_NODE);
297 if (proxyNode != NULL)
298 {
299 // Check for duplicate traps - only accept traps with ID
300 // higher than last received
301 bool acceptTrap;
b368969c 302 UINT32 trapId = msg->getId();
489b117b 303 if (trapId != 0)
304 {
305 acceptTrap = proxyNode->checkSNMPTrapId(trapId);
306 DbgPrintf(5, _T("AgentConnectionEx::onSnmpTrap(): SNMP trapID is%s valid"), acceptTrap ? _T("") : _T(" not"));
307 }
308 else
309 {
310 acceptTrap = false;
311 DbgPrintf(5, _T("AgentConnectionEx::onSnmpTrap(): SNMP trap ID not provided"));
312 }
313
314 if (acceptTrap)
315 {
c75e9ee4 316 InetAddress originSenderIP = msg->getFieldAsInetAddress(VID_IP_ADDRESS);
b368969c 317 UINT32 pduLenght = msg->getFieldAsUInt32(VID_PDU_SIZE);
489b117b 318 BYTE *pduBytes = (BYTE*)malloc(pduLenght);
b368969c 319 msg->getFieldAsBinary(VID_PDU, pduBytes, pduLenght);
489b117b 320 Node *originNode = FindNodeByIP(0, originSenderIP); //create function
321
322 SNMP_ProxyTransport *pTransport;
323 if(originNode != NULL)
b368969c 324 pTransport = (SNMP_ProxyTransport*)originNode->createSnmpTransport((WORD)msg->getFieldAsUInt16(VID_PORT));
489b117b 325
326 if(ConfigReadInt(_T("LogAllSNMPTraps"), FALSE) && originNode == NULL)
327 {
328 AgentConnection *pConn;
329
330 pConn = proxyNode->createAgentConnection();
331 if (pConn != NULL)
332 {
b368969c 333 pTransport = new SNMP_ProxyTransport(pConn, originSenderIP, msg->getFieldAsUInt16(VID_PORT));
489b117b 334 }
335 }
336
337 if(pTransport != NULL)
338 {
339 pTransport->setWaitForResponse(false);
340 SNMP_PDU *pdu = new SNMP_PDU;
341 if(pdu->parse(pduBytes, pduLenght, (originNode != NULL) ? originNode->getSnmpSecurityContext() : NULL, true))
342 {
343 DbgPrintf(6, _T("SNMPTrapReceiver: received PDU of type %d"), pdu->getCommand());
344 if ((pdu->getCommand() == SNMP_TRAP) || (pdu->getCommand() == SNMP_INFORM_REQUEST))
345 {
346 if ((pdu->getVersion() == SNMP_VERSION_3) && (pdu->getCommand() == SNMP_INFORM_REQUEST))
347 {
348 SNMP_SecurityContext *context = pTransport->getSecurityContext();
349 context->setAuthoritativeEngine(localEngine);
350 }
c75e9ee4 351 ProcessTrap(pdu, originSenderIP, msg->getFieldAsUInt16(VID_PORT), pTransport, &localEngine, pdu->getCommand() == SNMP_INFORM_REQUEST);
489b117b 352 }
353 else if ((pdu->getVersion() == SNMP_VERSION_3) && (pdu->getCommand() == SNMP_GET_REQUEST) && (pdu->getAuthoritativeEngine().getIdLen() == 0))
354 {
355 // Engine ID discovery
356 DbgPrintf(6, _T("SNMPTrapReceiver: EngineId discovery"));
357
358 SNMP_PDU *response = new SNMP_PDU(SNMP_REPORT, pdu->getRequestId(), pdu->getVersion());
359 response->setReportable(false);
360 response->setMessageId(pdu->getMessageId());
361 response->setContextEngineId(localEngine.getId(), localEngine.getIdLen());
362
363 SNMP_Variable *var = new SNMP_Variable(_T(".1.3.6.1.6.3.15.1.1.4.0"));
364 var->setValueFromString(ASN_INTEGER, _T("2"));
365 response->bindVariable(var);
366
367 SNMP_SecurityContext *context = new SNMP_SecurityContext();
368 localEngine.setTime((int)time(NULL));
369 context->setAuthoritativeEngine(localEngine);
370 context->setSecurityModel(SNMP_SECURITY_MODEL_USM);
371 context->setAuthMethod(SNMP_AUTH_NONE);
372 context->setPrivMethod(SNMP_ENCRYPT_NONE);
373 pTransport->setSecurityContext(context);
374
375 pTransport->sendMessage(response);
376 delete response;
377 }
378 else if (pdu->getCommand() == SNMP_REPORT)
379 {
380 DbgPrintf(6, _T("AgentConnectionEx::onSnmpTrap(): REPORT PDU with error %s"), pdu->getVariable(0)->getName()->getValueAsText());
381 }
382 delete pdu;
383 }
384 else if (pdu->getCommand() == SNMP_REPORT)
385 {
386 DbgPrintf(6, _T("AgentConnectionEx::onSnmpTrap(): REPORT PDU with error %s"), pdu->getVariable(0)->getName()->getValueAsText());
387 }
388 }
389 else
390 {
c75e9ee4 391 DbgPrintf(3, _T("AgentConnectionEx::onSnmpTrap(): cannot find origin node with IP %s and not accepting traps from unknown sources"), originSenderIP.toString(ipStringBuffer));
489b117b 392 }
393 }
394 }
395 else
396 {
c11eee9b 397 DbgPrintf(3, _T("AgentConnectionEx::onSnmpTrap(): Cannot find node for IP address %s"), getIpAddr().toString(ipStringBuffer));
489b117b 398 }
399}
400
d1c1c522
VK
401/**
402 * Deploy policy to agent
403 */
967893bb 404UINT32 AgentConnectionEx::deployPolicy(AgentPolicy *policy)
45d84f8a 405{
967893bb 406 UINT32 rqId, rcc;
b368969c 407 NXCPMessage msg(getProtocolVersion());
45d84f8a
VK
408
409 rqId = generateRequestId();
b368969c
VK
410 msg.setId(rqId);
411 msg.setCode(CMD_DEPLOY_AGENT_POLICY);
8051849b
VK
412 if (policy->createDeploymentMessage(&msg))
413 {
7c521895 414 if (sendMessage(&msg))
8051849b 415 {
7c521895 416 rcc = waitForRCC(rqId, getCommandTimeout());
8051849b
VK
417 }
418 else
419 {
420 rcc = ERR_CONNECTION_BROKEN;
421 }
422 }
423 else
424 {
425 rcc = ERR_INTERNAL_ERROR;
426 }
45d84f8a
VK
427 return rcc;
428}
93599cfd 429
d1c1c522
VK
430/**
431 * Uninstall policy from agent
432 */
967893bb 433UINT32 AgentConnectionEx::uninstallPolicy(AgentPolicy *policy)
93599cfd 434{
967893bb 435 UINT32 rqId, rcc;
b368969c 436 NXCPMessage msg(getProtocolVersion());
93599cfd
VK
437
438 rqId = generateRequestId();
b368969c
VK
439 msg.setId(rqId);
440 msg.setCode(CMD_UNINSTALL_AGENT_POLICY);
93599cfd
VK
441 if (policy->createUninstallMessage(&msg))
442 {
7c521895 443 if (sendMessage(&msg))
93599cfd 444 {
7c521895 445 rcc = waitForRCC(rqId, getCommandTimeout());
93599cfd
VK
446 }
447 else
448 {
449 rcc = ERR_CONNECTION_BROKEN;
450 }
451 }
452 else
453 {
454 rcc = ERR_INTERNAL_ERROR;
455 }
456 return rcc;
457}
6fbaa926
VK
458
459/**
460 * Process collected data information (for DCI with agent-side cache)
461 */
462void AgentConnectionEx::processCollectedData(NXCPMessage *msg)
463{
366440e8 464
6fbaa926 465}