Intermidiat commit for SNMP trap proxy
authorzev <zev@radensolutions.com>
Thu, 20 Nov 2014 18:26:03 +0000 (20:26 +0200)
committerzev <zev@radensolutions.com>
Fri, 21 Nov 2014 13:36:14 +0000 (15:36 +0200)
17 files changed:
include/nxsnmp.h
src/agent/core/Makefile.am
src/agent/core/nxagentd.cpp
src/agent/core/nxagentd.h
src/agent/core/session.cpp
src/agent/core/snmpproxy.cpp
src/agent/core/snmptrapproxy.cpp [new file with mode: 0644]
src/libnxcl/snmptrap.cpp
src/server/core/agent.cpp
src/server/core/node.cpp
src/server/core/snmptrap.cpp
src/server/include/nms_core.h
src/server/include/nms_objects.h
src/server/include/nxsrvapi.h
src/server/libnxsrv/agent.cpp
src/server/libnxsrv/snmpproxy.cpp
src/snmp/libnxsnmp/transport.cpp

index 9ed7834..912dd64 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
 ** NetXMS - Network Management System
 ** Copyright (C) 2003-2013 Victor Kirhenshtein
 **
@@ -319,7 +319,7 @@ private:
 public:
    SNMP_MIBObject();
    SNMP_MIBObject(UINT32 dwOID, const TCHAR *pszName);
-   SNMP_MIBObject(UINT32 dwOID, const TCHAR *pszName, int iType, 
+   SNMP_MIBObject(UINT32 dwOID, const TCHAR *pszName, int iType,
                   int iStatus, int iAccess, const TCHAR *pszDescription,
                                                const TCHAR *pszTextualConvention);
    ~SNMP_MIBObject();
@@ -531,7 +531,7 @@ private:
        char m_contextName[SNMP_MAX_CONTEXT_NAME];
        BYTE m_salt[8];
        bool m_reportable;
-       
+
        // The following attributes only used by parser and
        // valid only for received PDUs
        BYTE m_flags;
@@ -632,7 +632,7 @@ public:
       return 0;
    }
 
-   UINT32 doRequest(SNMP_PDU *request, SNMP_PDU **response, 
+   UINT32 doRequest(SNMP_PDU *request, SNMP_PDU **response,
                    UINT32 timeout = INFINITE, int numRetries = 1);
 
        void setSecurityContext(SNMP_SecurityContext *ctx);
@@ -654,7 +654,7 @@ public:
  */
 class LIBNXSNMP_EXPORTABLE SNMP_UDPTransport : public SNMP_Transport
 {
-private:
+protected:
    SOCKET m_hSocket;
    struct sockaddr_in m_peerAddr;
        bool m_connected;
index e8c698f..19de122 100644 (file)
@@ -3,13 +3,13 @@ bin_PROGRAMS = nxagentd
 nxagentd_SOURCES = messages.c actions.cpp appagent.cpp comm.cpp config.cpp \
                    ctrl.cpp epp.cpp exec.cpp extagent.cpp getparam.cpp \
                    master.cpp nxagentd.cpp policy.cpp push.cpp register.cpp \
-                   sa.cpp sd.cpp session.cpp snmpproxy.cpp \
+                   sa.cpp sd.cpp session.cpp snmpproxy.cpp snmptrapproxy.cpp \
                    static_subagents.cpp subagent.cpp sysinfo.cpp tools.cpp \
                    trap.cpp upgrade.cpp watchdog.cpp
 if USE_INTERNAL_EXPAT
-nxagentd_LDADD = ../appagent/libappagent.la @top_srcdir@/src/db/libnxdb/libnxdb.la @top_srcdir@/src/libnetxms/libnetxms.la @top_srcdir@/src/libexpat/libexpat/libnxexpat.la @SUBAGENT_LIBS@
+nxagentd_LDADD = ../appagent/libappagent.la @top_srcdir@/src/db/libnxdb/libnxdb.la @top_srcdir@/src/libnetxms/libnetxms.la @top_srcdir@/src/snmp/libnxsnmp/libnxsnmp.la @top_srcdir@/src/libexpat/libexpat/libnxexpat.la @SUBAGENT_LIBS@
 else
-nxagentd_LDADD = ../appagent/libappagent.la @top_srcdir@/src/db/libnxdb/libnxdb.la @top_srcdir@/src/libnetxms/libnetxms.la @SUBAGENT_LIBS@
+nxagentd_LDADD = ../appagent/libappagent.la @top_srcdir@/src/db/libnxdb/libnxdb.la @top_srcdir@/src/libnetxms/libnetxms.la @top_srcdir@/src/snmp/libnxsnmp/libnxsnmp.la @SUBAGENT_LIBS@ 
 endif
 if STATIC_BUILD
 if ALL_STATIC
index 5ece523..a457b92 100644 (file)
 #endif
 
 
-//
-// Externals
-//
-
+/**
+ * Externals
+ */
 THREAD_RESULT THREAD_CALL ListenerThread(void *);
 THREAD_RESULT THREAD_CALL SessionWatchdog(void *);
 THREAD_RESULT THREAD_CALL TrapSender(void *);
 THREAD_RESULT THREAD_CALL MasterAgentListener(void *arg);
+THREAD_RESULT THREAD_CALL SNMPTrapReciever(void *);
+THREAD_RESULT THREAD_CALL SNMPTrapSender(void *);
 
 void ShutdownTrapSender();
+void ShutdownSNMPTrapSender();
 
 void StartWatchdog();
 void StopWatchdog();
@@ -121,6 +123,7 @@ TCHAR g_szRegistrar[MAX_DB_STRING] = _T("not_set");
 TCHAR g_szListenAddress[MAX_PATH] = _T("*");
 TCHAR g_szConfigIncludeDir[MAX_PATH] = AGENT_DEFAULT_CONFIG_D;
 TCHAR g_masterAgent[MAX_PATH] = _T("not_set");
+TCHAR g_szSNMPTrapListenAddress[MAX_PATH] = _T("*");
 UINT16 g_wListenPort = AGENT_LISTEN_PORT;
 ObjectArray<ServerInfo> g_serverList(8, 8, true);
 UINT32 g_dwServerCount = 0;
@@ -129,6 +132,7 @@ UINT32 g_dwSNMPTimeout = 3000;
 time_t g_tmAgentStartTime;
 UINT32 g_dwStartupDelay = 0;
 UINT32 g_dwMaxSessions = 32;
+UINT32 g_dwSNMPTrapPort = 162;
 UINT32 g_debugLevel = (UINT32)NXCONFIG_UNINITIALIZED_VALUE;
 #ifdef _WIN32
 UINT16 g_sessionAgentPort = 28180;
@@ -165,6 +169,8 @@ static UINT32 m_dwEnabledCiphers = 0xFFFF;
 static THREAD m_thSessionWatchdog = INVALID_THREAD_HANDLE;
 static THREAD m_thListener = INVALID_THREAD_HANDLE;
 static THREAD m_thTrapSender = INVALID_THREAD_HANDLE;
+static THREAD m_thSNMPTrapReciever = INVALID_THREAD_HANDLE;
+static THREAD m_thSNMPTrapSender = INVALID_THREAD_HANDLE;
 static THREAD m_thMasterAgentListener = INVALID_THREAD_HANDLE;
 static TCHAR s_processToWaitFor[MAX_PATH] = _T("");
 static TCHAR s_dumpDir[MAX_PATH] = _T("C:\\");
@@ -174,6 +180,7 @@ static UINT32 m_dwLogRotationMode = NXLOG_ROTATION_BY_SIZE;
 static TCHAR s_dailyLogFileSuffix[64] = _T("");
 static Config *s_registry = NULL;
 static TCHAR s_executableName[MAX_PATH];
+static UINT32 g_messageNumber = time(NULL);
 
 #if defined(_WIN32)
 static CONDITION m_hCondShutdown = INVALID_CONDITION_HANDLE;
@@ -204,6 +211,7 @@ static NX_CFG_TEMPLATE m_cfgTemplate[] =
    { _T("EnableControlConnector"), CT_BOOLEAN, 0, 0, AF_ENABLE_CONTROL_CONNECTOR, 0, &g_dwFlags, NULL },
    { _T("EnableProxy"), CT_BOOLEAN, 0, 0, AF_ENABLE_PROXY, 0, &g_dwFlags, NULL },
    { _T("EnableSNMPProxy"), CT_BOOLEAN, 0, 0, AF_ENABLE_SNMP_PROXY, 0, &g_dwFlags, NULL },
+   { _T("EnableSNMPTrapProxy"), CT_BOOLEAN, 0, 0, AF_ENABLE_SNMP_TRAP_PROXY, 0, &g_dwFlags, NULL },
    { _T("EnableSubagentAutoload"), CT_BOOLEAN, 0, 0, AF_ENABLE_AUTOLOAD, 0, &g_dwFlags, NULL },
    { _T("EnableWatchdog"), CT_BOOLEAN, 0, 0, AF_ENABLE_WATCHDOG, 0, &g_dwFlags, NULL },
    { _T("EncryptedSharedSecret"), CT_STRING, 0, 0, MAX_SECRET_LENGTH, 0, g_szEncryptedSharedSecret, NULL },
@@ -233,6 +241,8 @@ static NX_CFG_TEMPLATE m_cfgTemplate[] =
    { _T("SessionAgentPort"), CT_WORD, 0, 0, 0, 0, &g_sessionAgentPort, NULL },
    { _T("SharedSecret"), CT_STRING, 0, 0, MAX_SECRET_LENGTH, 0, g_szSharedSecret, NULL },
        { _T("SNMPTimeout"), CT_LONG, 0, 0, 0, 0, &g_dwSNMPTimeout, NULL },
+       { _T("SNMPTrapListenAddress"), CT_STRING, 0, 0, 0, 0, &g_szSNMPTrapListenAddress, NULL },
+   { _T("SNMPTrapPort"), CT_LONG, 0, 0, 0, 0, &g_dwSNMPTrapPort, NULL },
    { _T("StartupDelay"), CT_LONG, 0, 0, 0, 0, &g_dwStartupDelay, NULL },
    { _T("SubAgent"), CT_STRING_LIST, '\n', 0, 0, 0, &m_pszSubagentList, NULL },
    { _T("TimeOut"), CT_IGNORE, 0, 0, 0, 0, NULL, NULL },
@@ -966,6 +976,14 @@ BOOL Initialize()
    g_tmAgentStartTime = time(NULL);
 
        m_thTrapSender = ThreadCreateEx(TrapSender, 0, NULL);
+
+       //Start trap proxy threads(recieve and send), if trap proxy is enabled
+       if(g_dwFlags & AF_ENABLE_SNMP_TRAP_PROXY)
+       {
+      m_thSNMPTrapSender = ThreadCreateEx(SNMPTrapSender, 0, NULL);
+      m_thSNMPTrapReciever = ThreadCreateEx(SNMPTrapReciever, 0, NULL);
+   }
+
        if (g_dwFlags & AF_SUBAGENT_LOADER)
        {
                m_thMasterAgentListener = ThreadCreateEx(MasterAgentListener, 0, NULL);
@@ -1038,6 +1056,12 @@ void Shutdown()
                ThreadJoin(m_thListener);
        }
        ThreadJoin(m_thTrapSender);
+       if(g_dwFlags & AF_ENABLE_SNMP_TRAP_PROXY)
+       {
+      ShutdownSNMPTrapSender();
+      //ThreadJoin(m_thSNMPTrapReciever);
+      //ThreadJoin(m_thSNMPTrapSender);
+       }
 
    UnloadAllSubAgents();
    nxlog_write(MSG_AGENT_STOPPED, EVENTLOG_INFORMATION_TYPE, NULL);
@@ -1704,3 +1728,11 @@ int main(int argc, char *argv[])
 
    return iExitCode;
 }
+
+UINT32 GetNewMessageID()
+{
+   MutexLock(g_hSessionListAccess);
+   g_messageNumber++;
+   MutexLock(g_hSessionListAccess);
+   return g_messageNumber;
+}
index d590e62..bc93b7f 100644 (file)
@@ -33,6 +33,7 @@
 #include <nxqueue.h>
 #include <nxlog.h>
 #include "messages.h"
+#include "nxsnmp.h"
 
 #define LIBNXCL_NO_DECLARATIONS
 #include <nxclapi.h>
@@ -53,9 +54,9 @@
 #endif
 
 
-//
-// Version
-//
+/**
+ * Version
+ */
 
 #ifdef _DEBUG
 #define DEBUG_SUFFIX          _T("-debug")
 #define REGISTRY_FILE_NAME       _T("registry.dat")
 
 
-//
-// Constants
-//
-
+/**
+ * Constants
+ */
 #ifdef _WIN32
 #define DEFAULT_AGENT_SERVICE_NAME    _T("NetXMSAgentdW32")
 #define DEFAULT_AGENT_EVENT_SOURCE    _T("NetXMS Win32 Agent")
 #define AF_ENABLE_CONTROL_CONNECTOR 0x00040000
 #define AF_DISABLE_IPV4             0x00080000
 #define AF_DISABLE_IPV6             0x00100000
+#define AF_ENABLE_SNMP_TRAP_PROXY   0x00200000
 
 
 #ifdef _WIN32
 
-//
-// Request types for H_MemoryInfo
-//
-
+/**
+ * Request types for H_MemoryInfo
+ */
 #define MEMINFO_PHYSICAL_FREE       1
 #define MEMINFO_PHYSICAL_FREE_PCT   2
 #define MEMINFO_PHYSICAL_TOTAL      3
 #define MEMINFO_VIRTUAL_USED_PCT    10
 
 
-//
-// Request types for H_DiskInfo
-//
-
+/**
+ * Request types for H_DiskInfo
+ */
 #define DISKINFO_FREE_BYTES      1
 #define DISKINFO_USED_BYTES      2
 #define DISKINFO_TOTAL_BYTES     3
 #endif   /* _WIN32 */
 
 
-//
-// Request types for H_DirInfo
-//
-
+/**
+ * Request types for H_DirInfo
+ */
 #define DIRINFO_FILE_COUNT       1
 #define DIRINFO_FILE_SIZE        2
 
 
-//
-// Request types for H_FileTime
-//
-
+/**
+ * Request types for H_FileTime
+ */
 #define FILETIME_ATIME           1
 #define FILETIME_MTIME           2
 #define FILETIME_CTIME           3
 
 
-//
-// Action types
-//
-
+/**
+ * Action types
+ */
 #define AGENT_ACTION_EXEC        1
 #define AGENT_ACTION_SUBAGENT    2
 #define AGENT_ACTION_SHELLEXEC 3
@@ -378,10 +374,10 @@ public:
        void updateTimeStamp() { m_ts = time(NULL); }
 
    bool canAcceptTraps() { return m_acceptTraps; }
-   
+
    virtual bool isMasterServer() { return m_masterServer; }
    virtual bool isControlServer() { return m_controlServer; }
-   
+
    virtual UINT32 openFile(TCHAR* nameOfFile, UINT32 requestId);
 };
 
@@ -394,7 +390,7 @@ private:
    UINT32 m_id;
    SOCKET m_socket;
    MUTEX m_mutex;
-   CSCP_BUFFER m_msgBuffer; 
+   CSCP_BUFFER m_msgBuffer;
    MsgWaitQueue m_msgQueue;
    UINT32 m_sessionId;
    TCHAR *m_sessionName;
@@ -426,6 +422,17 @@ public:
 };
 
 /**
+ * Class to reciever traps
+ */
+class SNMP_TrapProxyTransport : public SNMP_UDPTransport
+{
+public:
+   SNMP_TrapProxyTransport(SOCKET hSocket);
+   int readMessage(BYTE **rawData, UINT32 timeout = INFINITE,
+                  struct sockaddr *sender = NULL, socklen_t *addrSize = NULL);
+};
+
+/**
  * Functions
  */
 BOOL Initialize();
@@ -526,6 +533,7 @@ bool SendControlMessage(CSCPMessage *msg);
 
 void StartSessionAgentConnector();
 SessionAgentConnector *AcquireSessionAgentConnector(const TCHAR *sessionName);
+UINT32 GetNewMessageID();
 
 #ifdef _WIN32
 
@@ -543,10 +551,9 @@ TCHAR *GetPdhErrorText(UINT32 dwError, TCHAR *pszBuffer, int iBufSize);
 #endif
 
 
-//
-// Global variables
-//
-
+/**
+ * Global variables
+ */
 extern UINT32 g_dwFlags;
 extern TCHAR g_szLogFile[];
 extern TCHAR g_szSharedSecret[];
@@ -557,6 +564,7 @@ extern TCHAR g_szRegistrar[];
 extern TCHAR g_szListenAddress[];
 extern TCHAR g_szConfigIncludeDir[];
 extern TCHAR g_masterAgent[];
+extern TCHAR g_szSNMPTrapListenAddress[];
 extern UINT16 g_wListenPort;
 extern ObjectArray<ServerInfo> g_serverList;
 extern UINT32 g_dwServerCount;
@@ -568,6 +576,7 @@ extern UINT32 g_dwMaxSessions;
 extern UINT32 g_dwExecTimeout;
 extern UINT32 g_dwSNMPTimeout;
 extern UINT32 g_debugLevel;
+extern UINT32 g_dwSNMPTrapPort;
 extern UINT16 g_sessionAgentPort;
 
 extern Config *g_config;
index 0af31cd..2bb6e52 100644 (file)
@@ -713,7 +713,7 @@ void CommSession::action(CSCPMessage *pRequest, CSCPMessage *pMsg)
       // Get action name and arguments
       TCHAR action[MAX_PARAM_NAME];
       pRequest->GetVariableStr(VID_ACTION_NAME, action, MAX_PARAM_NAME);
-      
+
       int numArgs = pRequest->getFieldAsInt32(VID_NUM_ARGS);
       StringList *args = new StringList;
       for(int i = 0; i < numArgs; i++)
index a0ca058..05d5c02 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
 ** NetXMS multiplatform core agent
 ** Copyright (C) 2003-2011 Victor Kirhenshtein
 **
 #include "nxagentd.h"
 
 
-//
-// Constants
-//
+/**
+ * Constants
+ */
 
 #define SNMP_BUFFER_SIZE               65536
 
 
-//
-// Read PDU from network
-//
+/**
+ * Read PDU from network
+ */
 
 static BOOL ReadPDU(SOCKET hSocket, BYTE *pdu, UINT32 *pdwSize)
 {
@@ -84,10 +84,9 @@ static BOOL ReadPDU(SOCKET hSocket, BYTE *pdu, UINT32 *pdwSize)
 }
 
 
-//
-// Send SNMP request to target, receive response, and send it to server
-//
-
+/**
+ * Send SNMP request to target, receive response, and send it to server
+ */
 void ProxySNMPRequest(CSCPMessage *pRequest, CSCPMessage *pResponse)
 {
        BYTE *pduIn, *pduOut;
diff --git a/src/agent/core/snmptrapproxy.cpp b/src/agent/core/snmptrapproxy.cpp
new file mode 100644 (file)
index 0000000..dba25d6
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+** NetXMS multiplatform core agent
+** Copyright (C) 2014 Raden Solutions
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** File: snmptrapproxy.cpp
+**
+**/
+
+#include "nxagentd.h"
+
+struct UdpMessage
+{
+   UINT32 ipAddr;
+   short port;
+   BYTE* rawMessage;
+   int lenght;
+};
+
+/**
+ * Static data
+ */
+static Queue *SNMPTrapQueue = NULL;
+
+/**
+ * Shutdown trap sender
+ */
+void ShutdownSNMPTrapSender()
+{
+       SNMPTrapQueue->SetShutdownMode();
+}
+
+/**
+ * SNMP trap read thread
+ */
+THREAD_RESULT THREAD_CALL SNMPTrapReciever(void *pArg)
+{
+   SOCKET hSocket = (g_dwFlags & AF_DISABLE_IPV4) ? INVALID_SOCKET : socket(AF_INET, SOCK_DGRAM, 0);
+   if ((hSocket == INVALID_SOCKET) && !(g_dwFlags & AF_DISABLE_IPV4))
+   {
+      DebugPrintf(INVALID_INDEX, 1, _T("SNMPTrapRead(): Socket was not opened"));
+      return THREAD_OK;
+   }
+
+   if (!(g_dwFlags & AF_DISABLE_IPV4))
+   {
+      SetSocketExclusiveAddrUse(hSocket);
+      SetSocketReuseFlag(hSocket);
+   }
+
+   // Fill in local address structure
+   struct sockaddr_in addr;
+   memset(&addr, 0, sizeof(struct sockaddr_in));
+   addr.sin_family = AF_INET;
+
+   //rework
+   addr.sin_addr.s_addr = ResolveHostName(g_szSNMPTrapListenAddress);
+   if (!_tcscmp(g_szSNMPTrapListenAddress, _T("*")))
+       {
+               addr.sin_addr.s_addr = htonl(INADDR_ANY);
+       }
+       else
+       {
+      InetAddress bindAddress = InetAddress::resolveHostName(g_szSNMPTrapListenAddress, AF_INET);
+      if (bindAddress.isValid() && (bindAddress.getFamily() == AF_INET))
+      {
+                  addr.sin_addr.s_addr = bindAddress.getAddressV4();
+      }
+      else
+      {
+               addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+      }
+       }
+   addr.sin_port = htons(g_dwSNMPTrapPort);
+
+   // Bind socket
+   if (!(g_dwFlags & AF_DISABLE_IPV4))
+   {
+      if (bind(hSocket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) != 0)
+      {
+         TCHAR *error = WideStringFromUTF8String(strerror(errno));
+         DebugPrintf(INVALID_INDEX, 1, _T("SNMPTrapRead(): Socket error on binding %s"), error);
+         safe_free(error);
+
+         closesocket(hSocket);
+         return THREAD_OK;
+      }
+   }
+   else
+   {
+      return THREAD_OK;
+   }
+
+   DebugPrintf(INVALID_INDEX, 1, _T("Start message listenning for SNMP traps"));
+
+   SNMP_TrapProxyTransport *pTransport; //rewrite class to support
+
+   if (!(g_dwFlags & AF_DISABLE_IPV4))
+   {
+      pTransport = new SNMP_TrapProxyTransport(hSocket);
+      pTransport->enableEngineIdAutoupdate(true);
+      pTransport->setPeerUpdatedOnRecv(true);
+      DebugPrintf(INVALID_INDEX, 1, _T("SNMP Trap Receiver started on port %d, IPv4"), g_dwSNMPTrapPort);
+   }
+
+   BYTE *rawMessage = NULL;
+   int iBytes = 0;
+   socklen_t nAddrLen = sizeof(struct sockaddr_in);
+
+   // Wait for packets
+   while(!(g_dwFlags & AF_SHUTDOWN))
+   {
+      rawMessage = NULL;
+      iBytes = 0;
+      iBytes = pTransport->readMessage(&rawMessage, 2000, (struct sockaddr *)&addr, &nAddrLen);
+      if ((iBytes > 0) && (rawMessage != NULL))
+      {
+         UdpMessage *message = new UdpMessage();
+         message->ipAddr = ntohl(addr.sin_addr.s_addr);
+         message->port = (short)g_dwSNMPTrapPort;
+         message->lenght = iBytes;
+         message->rawMessage = rawMessage;
+         SNMPTrapQueue->Put(message);
+         DebugPrintf(INVALID_INDEX, 1, _T("Got trap and put it in the sending que."));
+      }
+      else
+      {
+         // Sleep on error
+         ThreadSleepMs(100);
+      }
+   }
+
+   delete pTransport;
+   DebugPrintf(INVALID_INDEX, 1, _T("SNMP Trap Receiver terminated"));
+   return THREAD_OK;
+}
+
+/**
+ * SNMP trap read thread
+ */
+THREAD_RESULT THREAD_CALL SNMPTrapSender(void *pArg)
+{
+   SNMPTrapQueue = new Queue;
+   while(1)
+   {
+      DebugPrintf(INVALID_INDEX, 1, _T("Started SNMP Trap sender thread & wait for message."));
+      UdpMessage *pdu = (UdpMessage *)SNMPTrapQueue->GetOrBlock();
+      if (pdu == INVALID_POINTER_VALUE)
+      {
+         DebugPrintf(INVALID_INDEX, 1, _T("Send SNMP thead stoped by que."));
+         break;
+      }
+      bool sent = false;
+
+      CSCPMessage *msg = new CSCPMessage();
+      msg->SetCode(CMD_SNMP_TRAP);
+      msg->SetId(GetNewMessageID());
+      msg->SetVariable(VID_IP_ADDRESS, pdu->ipAddr);
+      msg->SetVariable(VID_PORT, pdu->port);
+      msg->SetVariable(VID_PDU_SIZE, pdu->lenght);
+      msg->SetVariable(VID_PDU, pdu->rawMessage, pdu->lenght);
+
+      if (g_dwFlags & AF_SUBAGENT_LOADER)
+      {
+         sent = SendRawMessageToMasterAgent(msg->createMessage());
+      }
+      else
+      {
+         MutexLock(g_hSessionListAccess);
+         for(int i = 0; i < g_dwMaxSessions; i++)
+         {
+            if (g_pSessionList[i] != NULL)
+            {
+               if (g_pSessionList[i]->canAcceptTraps())
+               {
+                  g_pSessionList[i]->sendRawMessage(msg->createMessage());
+                  sent = true;
+               }
+            }
+         }
+         MutexUnlock(g_hSessionListAccess);
+      }
+
+      free(msg);
+      safe_free(pdu->rawMessage);
+      if(!sent)
+      {
+         DebugPrintf(INVALID_INDEX, 1, _T("Could not send forward trap to server"));
+         SNMPTrapQueue->Put(pdu);
+                       ThreadSleep(1);
+      }
+      else
+      {
+         DebugPrintf(INVALID_INDEX, 1, _T("Trap sucesfully forwarded to server"));
+         safe_free(pdu);
+      }
+   }
+   delete SNMPTrapQueue;
+   SNMPTrapQueue = NULL;
+       DebugPrintf(INVALID_INDEX, 1, _T("SNMP Trap sender thread terminated"));
+   return THREAD_OK;
+}
+
+/** Implementation of class SNMP_TrapProxyTransport **/
+
+/**
+ * Constructor
+ */
+SNMP_TrapProxyTransport::SNMP_TrapProxyTransport(SOCKET hSocket) : SNMP_UDPTransport(hSocket)
+{
+}
+
+/**
+ * Read PDU from socket but do not decode and parse it
+ */
+int SNMP_TrapProxyTransport::readMessage(BYTE **rawData, UINT32 dwTimeout,
+                                   struct sockaddr *pSender, socklen_t *piAddrSize)
+{
+   int bytes;
+   size_t pduLength;
+
+   if (m_dwBytesInBuffer < 2)
+   {
+      bytes = recvData(dwTimeout, pSender, piAddrSize);
+      if (bytes <= 0)
+      {
+         clearBuffer();
+         return bytes;
+      }
+      m_dwBytesInBuffer += bytes;
+   }
+
+   pduLength = preParsePDU();
+   if (pduLength == 0)
+   {
+      // Clear buffer
+      clearBuffer();
+      return 0;
+   }
+
+   // Move existing data to the beginning of buffer if there are not enough space at the end
+   if (pduLength > m_dwBufferSize - m_dwBufferPos)
+   {
+      memmove(m_pBuffer, &m_pBuffer[m_dwBufferPos], m_dwBytesInBuffer);
+      m_dwBufferPos = 0;
+   }
+
+   // Read entire PDU into buffer
+   while(m_dwBytesInBuffer < pduLength)
+   {
+      bytes = recvData(dwTimeout, pSender, piAddrSize);
+      if (bytes <= 0)
+      {
+         clearBuffer();
+         return bytes;
+      }
+      m_dwBytesInBuffer += bytes;
+   }
+
+   *rawData = (BYTE*)malloc(pduLength);
+   memcpy(*rawData, &m_pBuffer[m_dwBufferPos], pduLength);
+
+   m_dwBytesInBuffer -= pduLength;
+   if (m_dwBytesInBuffer == 0)
+      m_dwBufferPos = 0;
+
+   return (int)pduLength;
+}
index ba80ff6..e2f7dc0 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
 ** NetXMS - Network Management System
 ** Client Library
 ** Copyright (C) 2003-2010 Victor Kirhenshtein
 #include "libnxcl.h"
 
 
-//
-// Fill trap configuration record from message
-//
-
+/**
+ * Fill trap configuration record from message
+ */
 static void TrapCfgFromMsg(CSCPMessage *pMsg, NXC_TRAP_CFG_ENTRY *pTrap)
 {
    UINT32 i, dwId1, dwId2, dwId3, dwId4;
@@ -59,10 +58,9 @@ static void TrapCfgFromMsg(CSCPMessage *pMsg, NXC_TRAP_CFG_ENTRY *pTrap)
 }
 
 
-//
-// Process CMD_TRAP_CFG_UPDATE message
-//
-
+/**
+ * Process CMD_TRAP_CFG_UPDATE message
+ */
 void ProcessTrapCfgUpdate(NXCL_Session *pSession, CSCPMessage *pMsg)
 {
    NXC_TRAP_CFG_ENTRY trapCfg;
@@ -76,7 +74,7 @@ void ProcessTrapCfgUpdate(NXCL_Session *pSession, CSCPMessage *pMsg)
       TrapCfgFromMsg(pMsg, &trapCfg);
 
    pSession->callEventHandler(NXC_EVENT_NOTIFICATION, dwCode, &trapCfg);
-   
+
        for(UINT32 i = 0; i < trapCfg.dwNumMaps; i++)
       safe_free(trapCfg.pMaps[i].pdwObjectId);
    safe_free(trapCfg.pMaps);
@@ -84,10 +82,9 @@ void ProcessTrapCfgUpdate(NXCL_Session *pSession, CSCPMessage *pMsg)
 }
 
 
-//
-// Copy NXC_TRAP_CFG_ENTRY
-//
-
+/**
+ * Copy NXC_TRAP_CFG_ENTRY
+ */
 void LIBNXCL_EXPORTABLE NXCCopyTrapCfgEntry(NXC_TRAP_CFG_ENTRY *dst, NXC_TRAP_CFG_ENTRY *src)
 {
        memcpy(dst, src, sizeof(NXC_TRAP_CFG_ENTRY));
@@ -105,10 +102,9 @@ void LIBNXCL_EXPORTABLE NXCCopyTrapCfgEntry(NXC_TRAP_CFG_ENTRY *dst, NXC_TRAP_CF
 }
 
 
-//
-// Duplicate NXC_TRAP_CFG_ENTRY
-//
-
+/**
+ * Duplicate NXC_TRAP_CFG_ENTRY
+ */
 NXC_TRAP_CFG_ENTRY LIBNXCL_EXPORTABLE *NXCDuplicateTrapCfgEntry(NXC_TRAP_CFG_ENTRY *src)
 {
        NXC_TRAP_CFG_ENTRY *dst = (NXC_TRAP_CFG_ENTRY *)malloc(sizeof(NXC_TRAP_CFG_ENTRY));
@@ -117,10 +113,9 @@ NXC_TRAP_CFG_ENTRY LIBNXCL_EXPORTABLE *NXCDuplicateTrapCfgEntry(NXC_TRAP_CFG_ENT
 }
 
 
-//
-// Destroy NXC_TRAP_CFG_ENTRY
-//
-
+/**
+ * Destroy NXC_TRAP_CFG_ENTRY
+ */
 void LIBNXCL_EXPORTABLE NXCDestroyTrapCfgEntry(NXC_TRAP_CFG_ENTRY *e)
 {
        if (e == NULL)
@@ -134,10 +129,9 @@ void LIBNXCL_EXPORTABLE NXCDestroyTrapCfgEntry(NXC_TRAP_CFG_ENTRY *e)
 }
 
 
-//
-// Load trap configuration from server
-//
-
+/**
+ * Load trap configuration from server
+ */
 UINT32 LIBNXCL_EXPORTABLE NXCLoadTrapCfg(NXC_SESSION hSession, UINT32 *pdwNumTraps, NXC_TRAP_CFG_ENTRY **ppTrapList)
 {
    CSCPMessage msg, *pResponse;
@@ -161,7 +155,7 @@ UINT32 LIBNXCL_EXPORTABLE NXCLoadTrapCfg(NXC_SESSION hSession, UINT32 *pdwNumTra
             dwTrapId = pResponse->GetVariableLong(VID_TRAP_ID);
             if (dwTrapId != 0)  // 0 is end of list indicator
             {
-               pList = (NXC_TRAP_CFG_ENTRY *)realloc(pList, 
+               pList = (NXC_TRAP_CFG_ENTRY *)realloc(pList,
                            sizeof(NXC_TRAP_CFG_ENTRY) * (dwNumTraps + 1));
                pList[dwNumTraps].dwId = dwTrapId;
                TrapCfgFromMsg(pResponse, &pList[dwNumTraps]);
@@ -195,10 +189,9 @@ UINT32 LIBNXCL_EXPORTABLE NXCLoadTrapCfg(NXC_SESSION hSession, UINT32 *pdwNumTra
 }
 
 
-//
-// Destroy list of traps
-//
-
+/**
+ * Destroy list of traps
+ */
 void LIBNXCL_EXPORTABLE NXCDestroyTrapList(UINT32 dwNumTraps, NXC_TRAP_CFG_ENTRY *pTrapList)
 {
    UINT32 i, j;
@@ -217,10 +210,9 @@ void LIBNXCL_EXPORTABLE NXCDestroyTrapList(UINT32 dwNumTraps, NXC_TRAP_CFG_ENTRY
 }
 
 
-//
-// Delete trap configuration record by ID
-//
-
+/**
+ * Delete trap configuration record by ID
+ */
 UINT32 LIBNXCL_EXPORTABLE NXCDeleteTrap(NXC_SESSION hSession, UINT32 dwTrapId)
 {
    CSCPMessage msg;
@@ -237,10 +229,9 @@ UINT32 LIBNXCL_EXPORTABLE NXCDeleteTrap(NXC_SESSION hSession, UINT32 dwTrapId)
 }
 
 
-//
-// Create new trap configuration record
-//
-
+/**
+ * Create new trap configuration record
+ */
 UINT32 LIBNXCL_EXPORTABLE NXCCreateTrap(NXC_SESSION hSession, UINT32 *pdwTrapId)
 {
    CSCPMessage msg, *pResponse;
@@ -269,10 +260,9 @@ UINT32 LIBNXCL_EXPORTABLE NXCCreateTrap(NXC_SESSION hSession, UINT32 *pdwTrapId)
 }
 
 
-//
-// Update trap configuration record
-//
-
+/**
+ * Update trap configuration record
+ */
 UINT32 LIBNXCL_EXPORTABLE NXCModifyTrap(NXC_SESSION hSession, NXC_TRAP_CFG_ENTRY *pTrap)
 {
    CSCPMessage msg;
@@ -283,13 +273,13 @@ UINT32 LIBNXCL_EXPORTABLE NXCModifyTrap(NXC_SESSION hSession, NXC_TRAP_CFG_ENTRY
    msg.SetCode(CMD_MODIFY_TRAP);
    msg.SetId(dwRqId);
    msg.SetVariable(VID_TRAP_ID, pTrap->dwId);
-   msg.SetVariable(VID_TRAP_OID_LEN, pTrap->dwOidLen); 
+   msg.SetVariable(VID_TRAP_OID_LEN, pTrap->dwOidLen);
    msg.setFieldInt32Array(VID_TRAP_OID, pTrap->dwOidLen, pTrap->pdwObjectId);
    msg.SetVariable(VID_EVENT_CODE, pTrap->dwEventCode);
    msg.SetVariable(VID_DESCRIPTION, pTrap->szDescription);
    msg.SetVariable(VID_USER_TAG, pTrap->szUserTag);
    msg.SetVariable(VID_TRAP_NUM_MAPS, pTrap->dwNumMaps);
-   for(i = 0, dwId1 = VID_TRAP_PLEN_BASE, dwId2 = VID_TRAP_PNAME_BASE, dwId3 = VID_TRAP_PDESCR_BASE, dwId4 = VID_TRAP_PFLAGS_BASE; 
+   for(i = 0, dwId1 = VID_TRAP_PLEN_BASE, dwId2 = VID_TRAP_PNAME_BASE, dwId3 = VID_TRAP_PDESCR_BASE, dwId4 = VID_TRAP_PFLAGS_BASE;
        i < pTrap->dwNumMaps; i++, dwId1++, dwId2++, dwId3++, dwId4++)
    {
       msg.SetVariable(dwId1, pTrap->pMaps[i].dwOidLen);
@@ -304,10 +294,9 @@ UINT32 LIBNXCL_EXPORTABLE NXCModifyTrap(NXC_SESSION hSession, NXC_TRAP_CFG_ENTRY
 }
 
 
-//
-// Process SNMP trap log records coming from server
-//
-
+/**
+ * Process SNMP trap log records coming from server
+ */
 void ProcessTrapLogRecords(NXCL_Session *pSession, CSCPMessage *pMsg)
 {
    UINT32 i, dwNumRecords, dwId;
@@ -364,10 +353,9 @@ UINT32 LIBNXCL_EXPORTABLE NXCSyncSNMPTrapLog(NXC_SESSION hSession, UINT32 dwMaxR
 }
 
 
-//
-// Get read-only trap configuration without parameter bindings
-//
-
+/**
+ * Get read-only trap configuration without parameter bindings
+ */
 UINT32 LIBNXCL_EXPORTABLE NXCGetTrapCfgRO(NXC_SESSION hSession, UINT32 *pdwNumTraps,
                                          NXC_TRAP_CFG_ENTRY **ppTrapList)
 {
index 68cefbe..212a7d2 100644 (file)
 #include "nxcore.h"
 
 /**
+ * Externals
+ */
+extern Queue g_nodePollerQueue;
+void ProcessTrap(SNMP_PDU *pdu, struct sockaddr_in *pOrigin, SNMP_Transport *pTransport, SNMP_Engine *localEngine, bool isInformRq);
+
+/**
  * Destructor for extended agent connection class
  */
 AgentConnectionEx::~AgentConnectionEx()
@@ -211,7 +217,7 @@ void AgentConnectionEx::printMsg(const TCHAR *format, ...)
  */
 void AgentConnectionEx::onFileMonitoringData(CSCPMessage *pMsg)
 {
-       NetObj *object = NULL;
+       Node *object = NULL;
        if (m_nodeId != 0)
                object = (Node *)FindObjectById(m_nodeId, OBJECT_NODE);
        if (object != NULL)
@@ -227,15 +233,14 @@ void AgentConnectionEx::onFileMonitoringData(CSCPMessage *pMsg)
       if(result->size() == 0)
       {
          DbgPrintf(6, _T("AgentConnectionEx::onFileMonitoringData: unknown subscription will be canceled."));
-         Node *node = (Node *)object;
-         AgentConnection *conn = node->createAgentConnection();
+         AgentConnection *conn = object->createAgentConnection();
          if(conn != NULL)
          {
             CSCPMessage request;
             request.SetId(conn->generateRequestId());
             request.SetCode(CMD_CANCEL_FILE_MONITORING);
             request.SetVariable(VID_FILE_NAME, remoteFile);
-            request.SetVariable(VID_OBJECT_ID, node->getId());
+            request.SetVariable(VID_OBJECT_ID, object->getId());
             CSCPMessage* response = conn->customRequest(&request);
             delete response;
          }
@@ -251,6 +256,128 @@ void AgentConnectionEx::onFileMonitoringData(CSCPMessage *pMsg)
 }
 
 /**
+ * Recieve trap sent throught proxy agent
+ */
+void AgentConnectionEx::onSnmpTrap(CSCPMessage *msg)
+{
+   Node *proxyNode = NULL;
+   TCHAR ipStringBuffer[4096];
+
+   static BYTE engineId[] = { 0x80, 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00 };
+       SNMP_Engine localEngine(engineId, 12);
+
+       DbgPrintf(3, _T("AgentConnectionEx::onSnmpTrap(): Received SNMP trap message from agent at %s, node ID %d"), IpToStr(getIpAddr(), ipStringBuffer), m_nodeId);
+       if (m_nodeId != 0)
+               proxyNode = (Node *)FindObjectById(m_nodeId, OBJECT_NODE);
+   if (proxyNode != NULL)
+   {
+      // Check for duplicate traps - only accept traps with ID
+      // higher than last received
+      bool acceptTrap;
+      UINT32 trapId = msg->GetId();
+      if (trapId != 0)
+      {
+         acceptTrap = proxyNode->checkSNMPTrapId(trapId);
+         DbgPrintf(5, _T("AgentConnectionEx::onSnmpTrap(): SNMP trapID is%s valid"), acceptTrap ? _T("") : _T(" not"));
+      }
+      else
+      {
+         acceptTrap = false;
+         DbgPrintf(5, _T("AgentConnectionEx::onSnmpTrap(): SNMP trap ID not provided"));
+      }
+
+      if (acceptTrap)
+      {
+         UINT32 originSenderIP = msg->GetVariableLong(VID_IP_ADDRESS);
+         UINT32 pduLenght = msg->GetVariableLong(VID_PDU_SIZE);
+         BYTE *pduBytes = (BYTE*)malloc(pduLenght);
+         msg->GetVariableBinary(VID_PDU, pduBytes, pduLenght);
+         Node *originNode = FindNodeByIP(0, originSenderIP); //create function
+
+         SNMP_ProxyTransport *pTransport;
+         if(originNode != NULL)
+            pTransport = (SNMP_ProxyTransport*)originNode->createSnmpTransport((WORD)msg->GetVariableShort(VID_PORT));
+
+         if(ConfigReadInt(_T("LogAllSNMPTraps"), FALSE) && originNode == NULL)
+         {
+            AgentConnection *pConn;
+
+            pConn = proxyNode->createAgentConnection();
+            if (pConn != NULL)
+            {
+               pTransport = new SNMP_ProxyTransport(pConn, originSenderIP, msg->GetVariableShort(VID_PORT));
+            }
+         }
+
+         if(pTransport != NULL)
+         {
+            pTransport->setWaitForResponse(false);
+            SNMP_PDU *pdu = new SNMP_PDU;
+            if(pdu->parse(pduBytes, pduLenght, (originNode != NULL) ? originNode->getSnmpSecurityContext() : NULL, true))
+            {
+               DbgPrintf(6, _T("SNMPTrapReceiver: received PDU of type %d"), pdu->getCommand());
+               if ((pdu->getCommand() == SNMP_TRAP) || (pdu->getCommand() == SNMP_INFORM_REQUEST))
+               {
+                  if ((pdu->getVersion() == SNMP_VERSION_3) && (pdu->getCommand() == SNMP_INFORM_REQUEST))
+                  {
+                     SNMP_SecurityContext *context = pTransport->getSecurityContext();
+                     context->setAuthoritativeEngine(localEngine);
+                  }
+                  struct sockaddr_in addr;
+                  addr.sin_family = AF_INET;
+                  addr.sin_addr.s_addr = htonl(originSenderIP);
+                  addr.sin_port = htons(msg->GetVariableShort(VID_PORT));
+                  ProcessTrap(pdu, &addr, pTransport, &localEngine, pdu->getCommand() == SNMP_INFORM_REQUEST);
+               }
+               else if ((pdu->getVersion() == SNMP_VERSION_3) && (pdu->getCommand() == SNMP_GET_REQUEST) && (pdu->getAuthoritativeEngine().getIdLen() == 0))
+               {
+                  // Engine ID discovery
+                  DbgPrintf(6, _T("SNMPTrapReceiver: EngineId discovery"));
+
+                  SNMP_PDU *response = new SNMP_PDU(SNMP_REPORT, pdu->getRequestId(), pdu->getVersion());
+                  response->setReportable(false);
+                  response->setMessageId(pdu->getMessageId());
+                  response->setContextEngineId(localEngine.getId(), localEngine.getIdLen());
+
+                  SNMP_Variable *var = new SNMP_Variable(_T(".1.3.6.1.6.3.15.1.1.4.0"));
+                  var->setValueFromString(ASN_INTEGER, _T("2"));
+                  response->bindVariable(var);
+
+                  SNMP_SecurityContext *context = new SNMP_SecurityContext();
+                  localEngine.setTime((int)time(NULL));
+                  context->setAuthoritativeEngine(localEngine);
+                  context->setSecurityModel(SNMP_SECURITY_MODEL_USM);
+                  context->setAuthMethod(SNMP_AUTH_NONE);
+                  context->setPrivMethod(SNMP_ENCRYPT_NONE);
+                  pTransport->setSecurityContext(context);
+
+                  pTransport->sendMessage(response);
+                  delete response;
+               }
+               else if (pdu->getCommand() == SNMP_REPORT)
+               {
+                  DbgPrintf(6, _T("AgentConnectionEx::onSnmpTrap(): REPORT PDU with error %s"), pdu->getVariable(0)->getName()->getValueAsText());
+               }
+               delete pdu;
+            }
+            else if (pdu->getCommand() == SNMP_REPORT)
+            {
+               DbgPrintf(6, _T("AgentConnectionEx::onSnmpTrap(): REPORT PDU with error %s"), pdu->getVariable(0)->getName()->getValueAsText());
+            }
+         }
+         else
+         {
+            DbgPrintf(3, _T("AgentConnectionEx::onSnmpTrap(): not possible to find origin node with IP %s and not acepted traps from unknown source."), IpToStr(originSenderIP, ipStringBuffer));
+         }
+      }
+   }
+   else
+   {
+      DbgPrintf(3, _T("AgentConnectionEx::onSnmpTrap(): Cannot find node for IP address %s"), IpToStr(getIpAddr(), ipStringBuffer));
+   }
+}
+
+/**
  * Deploy policy to agent
  */
 UINT32 AgentConnectionEx::deployPolicy(AgentPolicy *policy)
index ac77080..34e378f 100644 (file)
@@ -67,6 +67,7 @@ Node::Node() : DataCollectionTarget()
    m_pAgentConnection = NULL;
    m_smclpConnection = NULL;
        m_lastAgentTrapId = 0;
+       m_lastSNMPTrapId = 0;
    m_lastAgentPushRequestId = 0;
    m_szAgentVersion[0] = 0;
    m_szPlatformName[0] = 0;
@@ -145,6 +146,7 @@ Node::Node(UINT32 dwAddr, UINT32 dwFlags, UINT32 agentProxy, UINT32 snmpProxy, U
    m_pAgentConnection = NULL;
    m_smclpConnection = NULL;
        m_lastAgentTrapId = 0;
+       m_lastSNMPTrapId = 0;
    m_lastAgentPushRequestId = 0;
    m_szAgentVersion[0] = 0;
    m_szPlatformName[0] = 0;
@@ -6106,6 +6108,19 @@ bool Node::checkAgentTrapId(QWORD trapId)
 }
 
 /**
+ * Check and update last agent SNMP trap ID
+ */
+bool Node::checkSNMPTrapId(UINT32 trapId)
+{
+       lockProperties();
+       bool valid = (trapId > m_lastSNMPTrapId);
+       if (valid)
+               m_lastSNMPTrapId = trapId;
+       unlockProperties();
+       return valid;
+}
+
+/**
  * Check and update last agent data push request ID
  */
 bool Node::checkAgentPushRequestId(QWORD requestId)
index 46c5426..e6cdd92 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
 ** NetXMS - Network Management System
 ** Copyright (C) 2003-2014 Victor Kirhenshtein
 **
@@ -106,12 +106,12 @@ static BOOL LoadTrapCfg()
                   m_pTrapCfg[i].pMaps[j].dwOidLen = (UINT32)SNMPParseOID(pszOID, pdwBuffer, MAX_OID_LEN);
                   if (m_pTrapCfg[i].pMaps[j].dwOidLen > 0)
                   {
-                     m_pTrapCfg[i].pMaps[j].pdwObjectId = 
+                     m_pTrapCfg[i].pMaps[j].pdwObjectId =
                         (UINT32 *)nx_memdup(pdwBuffer, m_pTrapCfg[i].pMaps[j].dwOidLen * sizeof(UINT32));
                   }
                   else
                   {
-                     nxlog_write(MSG_INVALID_TRAP_ARG_OID, EVENTLOG_ERROR_TYPE, "sd", 
+                     nxlog_write(MSG_INVALID_TRAP_ARG_OID, EVENTLOG_ERROR_TYPE, "sd",
                               DBGetField(hResult, j, 0, szBuffer, MAX_DB_STRING), m_pTrapCfg[i].dwId);
                      bResult = FALSE;
                   }
@@ -183,8 +183,8 @@ static void GenerateTrapEvent(UINT32 dwObjectId, UINT32 dwIndex, SNMP_PDU *pdu,
          {
                                bool convertToHex = true;
                                argList[i] = _tcsdup(
-               (s_allowVarbindConversion && !(m_pTrapCfg[dwIndex].pMaps[i].dwFlags & TRAP_VARBIND_FORCE_TEXT)) ? 
-                  varbind->getValueAsPrintableString(szBuffer, 256, &convertToHex) : 
+               (s_allowVarbindConversion && !(m_pTrapCfg[dwIndex].pMaps[i].dwFlags & TRAP_VARBIND_FORCE_TEXT)) ?
+                  varbind->getValueAsPrintableString(szBuffer, 256, &convertToHex) :
                   varbind->getValueAsString(szBuffer, 256));
             names[i + 1] = varbind->getName()->getValueAsText();
          }
@@ -202,8 +202,8 @@ static void GenerateTrapEvent(UINT32 dwObjectId, UINT32 dwIndex, SNMP_PDU *pdu,
             {
                                        bool convertToHex = true;
                                        argList[i] = _tcsdup(
-                  (s_allowVarbindConversion && !(m_pTrapCfg[dwIndex].pMaps[i].dwFlags & TRAP_VARBIND_FORCE_TEXT)) ? 
-                     varbind->getValueAsPrintableString(szBuffer, 256, &convertToHex) : 
+                  (s_allowVarbindConversion && !(m_pTrapCfg[dwIndex].pMaps[i].dwFlags & TRAP_VARBIND_FORCE_TEXT)) ?
+                     varbind->getValueAsPrintableString(szBuffer, 256, &convertToHex) :
                      varbind->getValueAsString(szBuffer, 256));
                names[i] = varbind->getName()->getValueAsText();
                break;
@@ -244,7 +244,7 @@ static void BroadcastNewTrap(ClientSession *pSession, void *pArg)
 /**
  * Process trap
  */
-static void ProcessTrap(SNMP_PDU *pdu, struct sockaddr_in *pOrigin, SNMP_Transport *pTransport, SNMP_Engine *localEngine, bool isInformRq)
+void ProcessTrap(SNMP_PDU *pdu, struct sockaddr_in *pOrigin, SNMP_Transport *pTransport, SNMP_Engine *localEngine, bool isInformRq)
 {
    UINT32 dwOriginAddr, dwBufPos, dwBufSize, dwMatchLen, dwMatchIdx;
    TCHAR *pszTrapArgs, szBuffer[4096];
@@ -289,7 +289,7 @@ static void ProcessTrap(SNMP_PDU *pdu, struct sockaddr_in *pOrigin, SNMP_Transpo
                        bool convertToHex = true;
          dwBufPos += _sntprintf(&pszTrapArgs[dwBufPos], dwBufSize - dwBufPos, _T("%s%s == '%s'"),
                                 (dwBufPos == 0) ? _T("") : _T("; "),
-                                pVar->getName()->getValueAsText(), 
+                                pVar->getName()->getValueAsText(),
                                                                                  s_allowVarbindConversion ? pVar->getValueAsPrintableString(szBuffer, 3000, &convertToHex) : pVar->getValueAsString(szBuffer, 3000));
       }
 
@@ -387,13 +387,13 @@ static void ProcessTrap(SNMP_PDU *pdu, struct sockaddr_in *pOrigin, SNMP_Transpo
                                           bool convertToHex = true;
                   dwBufPos += _sntprintf(&pszTrapArgs[dwBufPos], dwBufSize - dwBufPos, _T("%s%s == '%s'"),
                                          (dwBufPos == 0) ? _T("") : _T("; "),
-                                         pVar->getName()->getValueAsText(), 
+                                         pVar->getName()->getValueAsText(),
                                                                                                     s_allowVarbindConversion ? pVar->getValueAsPrintableString(szBuffer, 512, &convertToHex) : pVar->getValueAsString(szBuffer, 512));
                }
 
                // Generate default event for unmatched traps
                const TCHAR *names[3] = { _T("oid"), NULL, _T("sourcePort") };
-               PostEventWithNames(EVENT_SNMP_UNMATCHED_TRAP, pNode->getId(), "ssd", names, 
+               PostEventWithNames(EVENT_SNMP_UNMATCHED_TRAP, pNode->getId(), "ssd", names,
                   pdu->getTrapId()->getValueAsText(), pszTrapArgs, (int)ntohs(pOrigin->sin_port));
                free(pszTrapArgs);
             }
@@ -522,7 +522,7 @@ THREAD_RESULT THREAD_CALL SNMPTrapReceiver(void *pArg)
                        {
                                // Engine ID discovery
                                DbgPrintf(6, _T("SNMPTrapReceiver: EngineId discovery"));
-                               
+
                                SNMP_PDU *response = new SNMP_PDU(SNMP_REPORT, pdu->getRequestId(), pdu->getVersion());
                                response->setReportable(false);
                                response->setMessageId(pdu->getMessageId());
@@ -531,7 +531,7 @@ THREAD_RESULT THREAD_CALL SNMPTrapReceiver(void *pArg)
                                SNMP_Variable *var = new SNMP_Variable(_T(".1.3.6.1.6.3.15.1.1.4.0"));
                                var->setValueFromString(ASN_INTEGER, _T("2"));
                                response->bindVariable(var);
-                               
+
                                SNMP_SecurityContext *context = new SNMP_SecurityContext();
                                localEngine.setTime((int)time(NULL));
                                context->setAuthoritativeEngine(localEngine);
@@ -569,13 +569,13 @@ static void FillTrapConfigDataMsg(CSCPMessage &msg, NXC_TRAP_CFG_ENTRY *trap)
    UINT32 i, dwId1, dwId2, dwId3, dwId4;
 
        msg.SetVariable(VID_TRAP_ID, trap->dwId);
-   msg.SetVariable(VID_TRAP_OID_LEN, trap->dwOidLen); 
+   msg.SetVariable(VID_TRAP_OID_LEN, trap->dwOidLen);
    msg.setFieldInt32Array(VID_TRAP_OID, trap->dwOidLen, trap->pdwObjectId);
    msg.SetVariable(VID_EVENT_CODE, trap->dwEventCode);
    msg.SetVariable(VID_DESCRIPTION, trap->szDescription);
    msg.SetVariable(VID_USER_TAG, trap->szUserTag);
    msg.SetVariable(VID_TRAP_NUM_MAPS, trap->dwNumMaps);
-   for(i = 0, dwId1 = VID_TRAP_PLEN_BASE, dwId2 = VID_TRAP_PNAME_BASE, dwId3 = VID_TRAP_PDESCR_BASE, dwId4 = VID_TRAP_PFLAGS_BASE; 
+   for(i = 0, dwId1 = VID_TRAP_PLEN_BASE, dwId2 = VID_TRAP_PNAME_BASE, dwId3 = VID_TRAP_PDESCR_BASE, dwId4 = VID_TRAP_PFLAGS_BASE;
        i < trap->dwNumMaps; i++, dwId1++, dwId2++, dwId3++, dwId4++)
    {
       msg.SetVariable(dwId1, trap->pMaps[i].dwOidLen);
@@ -623,7 +623,7 @@ void CreateTrapCfgMessage(CSCPMessage &msg)
    for(i = 0, dwId = VID_TRAP_INFO_BASE; i < m_dwNumTraps; i++, dwId += 5)
    {
       msg.SetVariable(dwId++, m_pTrapCfg[i].dwId);
-      msg.SetVariable(dwId++, m_pTrapCfg[i].dwOidLen); 
+      msg.SetVariable(dwId++, m_pTrapCfg[i].dwOidLen);
       msg.setFieldInt32Array(dwId++, m_pTrapCfg[i].dwOidLen, m_pTrapCfg[i].pdwObjectId);
       msg.SetVariable(dwId++, m_pTrapCfg[i].dwEventCode);
       msg.SetVariable(dwId++, m_pTrapCfg[i].szDescription);
@@ -669,7 +669,7 @@ UINT32 DeleteTrap(UINT32 dwId)
    TCHAR szQuery[256];
 
    MutexLock(m_mutexTrapCfgAccess);
-   
+
    for(i = 0; i < m_dwNumTraps; i++)
    {
       if (m_pTrapCfg[i].dwId == dwId)
@@ -759,7 +759,7 @@ UINT32 CreateNewTrap(UINT32 *pdwTrapId)
    TCHAR szQuery[256];
 
    MutexLock(m_mutexTrapCfgAccess);
-   
+
    *pdwTrapId = CreateUniqueId(IDG_SNMP_TRAP);
    m_pTrapCfg = (NXC_TRAP_CFG_ENTRY *)realloc(m_pTrapCfg, sizeof(NXC_TRAP_CFG_ENTRY) * (m_dwNumTraps + 1));
    memset(&m_pTrapCfg[m_dwNumTraps], 0, sizeof(NXC_TRAP_CFG_ENTRY));
@@ -789,7 +789,7 @@ UINT32 CreateNewTrap(NXC_TRAP_CFG_ENTRY *pTrap)
        BOOL bSuccess;
 
    MutexLock(m_mutexTrapCfgAccess);
-   
+
    m_pTrapCfg = (NXC_TRAP_CFG_ENTRY *)realloc(m_pTrapCfg, sizeof(NXC_TRAP_CFG_ENTRY) * (m_dwNumTraps + 1));
    memcpy(&m_pTrapCfg[m_dwNumTraps], pTrap, sizeof(NXC_TRAP_CFG_ENTRY));
    m_pTrapCfg[m_dwNumTraps].dwId = CreateUniqueId(IDG_SNMP_TRAP);
@@ -870,15 +870,15 @@ UINT32 UpdateTrapFromMsg(CSCPMessage *pMsg)
          // Read new mappings from message
          m_pTrapCfg[i].dwNumMaps = pMsg->GetVariableLong(VID_TRAP_NUM_MAPS);
          m_pTrapCfg[i].pMaps = (NXC_OID_MAP *)malloc(sizeof(NXC_OID_MAP) * m_pTrapCfg[i].dwNumMaps);
-         for(j = 0, dwId1 = VID_TRAP_PLEN_BASE, dwId2 = VID_TRAP_PNAME_BASE, dwId3 = VID_TRAP_PDESCR_BASE, dwId4 = VID_TRAP_PFLAGS_BASE; 
+         for(j = 0, dwId1 = VID_TRAP_PLEN_BASE, dwId2 = VID_TRAP_PNAME_BASE, dwId3 = VID_TRAP_PDESCR_BASE, dwId4 = VID_TRAP_PFLAGS_BASE;
              j < m_pTrapCfg[i].dwNumMaps; j++, dwId1++, dwId2++, dwId3++, dwId4++)
          {
             m_pTrapCfg[i].pMaps[j].dwOidLen = pMsg->GetVariableLong(dwId1);
             if ((m_pTrapCfg[i].pMaps[j].dwOidLen & 0x80000000) == 0)
             {
-               m_pTrapCfg[i].pMaps[j].pdwObjectId = 
+               m_pTrapCfg[i].pMaps[j].pdwObjectId =
                   (UINT32 *)malloc(sizeof(UINT32) * m_pTrapCfg[i].pMaps[j].dwOidLen);
-               pMsg->getFieldAsInt32Array(dwId2, m_pTrapCfg[i].pMaps[j].dwOidLen, 
+               pMsg->getFieldAsInt32Array(dwId2, m_pTrapCfg[i].pMaps[j].dwOidLen,
                                            m_pTrapCfg[i].pMaps[j].pdwObjectId);
             }
             else
@@ -959,7 +959,7 @@ void CreateNXMPTrapRecord(String &str, UINT32 dwId)
                                        str.addFormattedString(_T("\t\t\t\t<parameter id=\"%d\">\n")
                                                     _T("\t\t\t\t\t<flags>%d</flags>\n")
                                                               _T("\t\t\t\t\t<description>%s</description>\n"),
-                                                                                                 j + 1, m_pTrapCfg[i].pMaps[j].dwFlags, 
+                                                                                                 j + 1, m_pTrapCfg[i].pMaps[j].dwFlags,
                                                                                                  (const TCHAR *)EscapeStringForXML2(m_pTrapCfg[i].pMaps[j].szDescription));
                if ((m_pTrapCfg[i].pMaps[j].dwOidLen & 0x80000000) == 0)
                                        {
index 103aa9d..e92ed92 100644 (file)
@@ -294,6 +294,7 @@ protected:
    virtual void onTrap(CSCPMessage *msg);
    virtual void onDataPush(CSCPMessage *msg);
    virtual void onFileMonitoringData(CSCPMessage *msg);
+       virtual void onSnmpTrap(CSCPMessage *pMsg);
 
 public:
    AgentConnectionEx(UINT32 nodeId, UINT32 ipAddr, WORD port = AGENT_LISTEN_PORT, int authMethod = AUTH_NONE, const TCHAR *secret = NULL) :
index 887e616..2ec35ad 100644 (file)
@@ -819,7 +819,7 @@ public:
 
        virtual void fillMessage(CSCPMessage *pMsg);
    virtual UINT32 modifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked = FALSE);
-   
+
    virtual void calculateCompoundStatus(BOOL bForcedRecalc = FALSE);
 
    virtual UINT32 getInternalItem(const TCHAR *param, size_t bufSize, TCHAR *buffer);
@@ -1034,6 +1034,7 @@ protected:
    SMCLP_Connection *m_smclpConnection;
        QWORD m_lastAgentTrapId;             // ID of last received agent trap
    QWORD m_lastAgentPushRequestId; // ID of last received agent push request
+   UINT32 m_lastSNMPTrapId;
    UINT32 m_pollerNode;      // Node used for network service polling
    UINT32 m_agentProxy;      // Node used as proxy for agent connection
        UINT32 m_snmpProxy;       // Node used as proxy for SNMP requests
@@ -1216,6 +1217,7 @@ public:
 
    BOOL connectToAgent(UINT32 *error = NULL, UINT32 *socketError = NULL);
        bool checkAgentTrapId(QWORD id);
+       bool checkSNMPTrapId(UINT32 id);
    bool checkAgentPushRequestId(QWORD id);
 
    bool connectToSMCLP();
index 6b4e0df..13903fd 100644 (file)
@@ -480,6 +480,7 @@ protected:
    virtual void onTrap(CSCPMessage *pMsg);
        virtual void onDataPush(CSCPMessage *msg);
        virtual void onFileMonitoringData(CSCPMessage *msg);
+       virtual void onSnmpTrap(CSCPMessage *pMsg);
        virtual bool processCustomMessage(CSCPMessage *pMsg);
        virtual void onFileDownload(BOOL success);
 
@@ -551,6 +552,7 @@ protected:
        CSCPMessage *m_pResponse;
        UINT32 m_dwIpAddr;
        WORD m_wPort;
+       bool m_waitForResponse;
 
 public:
        SNMP_ProxyTransport(AgentConnection *pConn, UINT32 dwIpAddr, WORD wPort);
@@ -561,6 +563,7 @@ public:
                                SNMP_SecurityContext* (*contextFinder)(struct sockaddr *, socklen_t) = NULL);
    virtual int sendMessage(SNMP_PDU *pdu);
    virtual UINT32 getPeerIpAddress();
+   bool setWaitForResponse(bool value) {m_waitForResponse = value;};
 };
 
 /**
index e02671e..88b69ed 100644 (file)
@@ -347,6 +347,9 @@ void AgentConnection::receiverThread()
                onFileMonitoringData(pMsg);
                                        delete pMsg;
                break;
+            case CMD_SNMP_TRAP:
+               onSnmpTrap(pMsg);
+               break;
                                default:
                                        if (processCustomMessage(pMsg))
                                                delete pMsg;
@@ -701,10 +704,9 @@ InterfaceList *AgentConnection::getInterfaceList()
 }
 
 
-//
-// Get parameter value
-//
-
+/**
+ * Get parameter value
+ */
 UINT32 AgentConnection::getParameter(const TCHAR *pszParam, UINT32 dwBufSize, TCHAR *pszBuffer)
 {
    CSCPMessage msg(m_nProtocolVersion), *pResponse;
@@ -745,10 +747,9 @@ UINT32 AgentConnection::getParameter(const TCHAR *pszParam, UINT32 dwBufSize, TC
 }
 
 
-//
-// Get ARP cache
-//
-
+/**
+ * Get ARP cache
+ */
 ARP_CACHE *AgentConnection::getArpCache()
 {
    ARP_CACHE *pArpCache = NULL;
@@ -805,9 +806,9 @@ ARP_CACHE *AgentConnection::getArpCache()
 }
 
 
-//
-// Send dummy command to agent (can be used for keepalive)
-//
+/**
+ * Send dummy command to agent (can be used for keepalive)
+ */
 
 UINT32 AgentConnection::nop()
 {
@@ -824,10 +825,9 @@ UINT32 AgentConnection::nop()
 }
 
 
-//
-// Wait for request completion code
-//
-
+/**
+ * Wait for request completion code
+ */
 UINT32 AgentConnection::waitForRCC(UINT32 dwRqId, UINT32 dwTimeOut)
 {
    CSCPMessage *pMsg;
@@ -932,6 +932,14 @@ void AgentConnection::onFileMonitoringData(CSCPMessage *pMsg)
 }
 
 /**
+ * SNMP trap handler. Should be overriden in derived classes to implement
+ * actual SNMP trap processing. Default implementation do nothing.
+ */
+void AgentConnection::onSnmpTrap(CSCPMessage *pMsg)
+{
+}
+
+/**
  * Custom message handler
  * If returns true, message considered as processed and will not be placed in wait queue
  */
index 16f7c87..ec4e9bb 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
 ** NetXMS - Network Management System
 ** Server Library
 ** Copyright (C) 2003-2013 Victor Kirhenshtein
@@ -32,6 +32,7 @@ SNMP_ProxyTransport::SNMP_ProxyTransport(AgentConnection *pConn, UINT32 dwIpAddr
        m_dwIpAddr = dwIpAddr;
        m_wPort = wPort;
        m_pResponse = NULL;
+       m_waitForResponse = true;
 }
 
 /**
@@ -62,11 +63,14 @@ int SNMP_ProxyTransport::sendMessage(SNMP_PDU *pdu)
                msg.SetVariable(VID_PDU, pBuffer, (UINT32)size);
       free(pBuffer);
 
-               m_pResponse = m_pAgentConnection->customRequest(&msg);
-               if (m_pResponse != NULL)
-               {
-                       nRet = 1;
-               }
+      if(m_waitForResponse)
+      {
+         m_pResponse = m_pAgentConnection->customRequest(&msg);
+         if (m_pResponse != NULL)
+         {
+            nRet = 1;
+         }
+      }
    }
 
    return nRet;
@@ -75,7 +79,7 @@ int SNMP_ProxyTransport::sendMessage(SNMP_PDU *pdu)
 /**
  * Receive PDU
  */
-int SNMP_ProxyTransport::readMessage(SNMP_PDU **ppData, UINT32 dwTimeout, 
+int SNMP_ProxyTransport::readMessage(SNMP_PDU **ppData, UINT32 dwTimeout,
                                      struct sockaddr *pSender, socklen_t *piAddrSize,
                                      SNMP_SecurityContext* (*contextFinder)(struct sockaddr *, socklen_t))
 {
index ce1ba6b..993edf7 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
 ** NetXMS - Network Management System
 ** SNMP support library
 ** Copyright (C) 2003-2014 Victor Kirhenshtein
@@ -267,7 +267,7 @@ UINT32 SNMP_UDPTransport::createUDPTransport(const TCHAR *pszHostName, UINT32 dw
    }
 
    // Create and connect socket
-   if ((m_peerAddr.sin_addr.s_addr != INADDR_ANY) && 
+   if ((m_peerAddr.sin_addr.s_addr != INADDR_ANY) &&
        (m_peerAddr.sin_addr.s_addr != INADDR_NONE))
    {
       m_hSocket = socket(AF_INET, SOCK_DGRAM, 0);
@@ -410,7 +410,7 @@ size_t SNMP_UDPTransport::preParsePDU()
    size_t dwLength, dwIdLength;
    BYTE *pbCurrPos;
 
-   if (!BER_DecodeIdentifier(&m_pBuffer[m_dwBufferPos], m_dwBytesInBuffer, 
+   if (!BER_DecodeIdentifier(&m_pBuffer[m_dwBufferPos], m_dwBytesInBuffer,
                              &dwType, &dwLength, &pbCurrPos, &dwIdLength))
       return 0;
    if (dwType != ASN_SEQUENCE)
@@ -422,7 +422,7 @@ size_t SNMP_UDPTransport::preParsePDU()
 /**
  * Read PDU from socket
  */
-int SNMP_UDPTransport::readMessage(SNMP_PDU **ppData, UINT32 dwTimeout, 
+int SNMP_UDPTransport::readMessage(SNMP_PDU **ppData, UINT32 dwTimeout,
                                    struct sockaddr *pSender, socklen_t *piAddrSize,
                                    SNMP_SecurityContext* (*contextFinder)(struct sockaddr *, socklen_t))
 {