agent tunnel now identified by GUID pair - node + tunnel
authorVictor Kirhenshtein <victor@netxms.org>
Tue, 28 Mar 2017 07:21:59 +0000 (10:21 +0300)
committerVictor Kirhenshtein <victor@netxms.org>
Tue, 28 Mar 2017 07:21:59 +0000 (10:21 +0300)
include/nms_cscp.h
src/server/core/console.cpp
src/server/core/node.cpp
src/server/core/tunnel.cpp
src/server/include/agent_tunnel.h
src/server/include/nms_objects.h

index 7015ab9..9c112a5 100644 (file)
@@ -1175,6 +1175,7 @@ typedef struct
 #define VID_CHANNEL_ID              ((UINT32)574)
 #define VID_NUM_URLS                ((UINT32)575)
 #define VID_GRACE_LOGINS            ((UINT32)576)
+#define VID_TUNNEL_GUID             ((UINT32)577)
 
 // Base variabe for single threshold in message
 #define VID_THRESHOLD_BASE          ((UINT32)0x00800000)
index 97b3abd..863def4 100644 (file)
@@ -36,6 +36,7 @@ extern ThreadPool *g_schedulerThreadPool;
 void ShowPredictionEngines(CONSOLE_CTX console);
 void ShowAgentTunnels(CONSOLE_CTX console);
 UINT32 BindAgentTunnel(UINT32 tunnelId, UINT32 nodeId);
+UINT32 UnbindAgentTunnel(UINT32 nodeId);
 
 /**
  * Format string to show value of global flag
@@ -1097,6 +1098,21 @@ int ProcessConsoleCommand(const TCHAR *pszCmdLine, CONSOLE_CTX pCtx)
             ConsoleWrite(pCtx, _T("ERROR: Invalid or missing argument(s)\n\n"));
          }
       }
+      else if (IsCommand(_T("UNBIND"), szBuffer, 1))
+      {
+         ExtractWord(pArg, szBuffer);
+         UINT32 nodeId = _tcstoul(szBuffer, NULL, 0);
+
+         if (nodeId != 0)
+         {
+            UINT32 rcc = UnbindAgentTunnel(nodeId);
+            ConsolePrintf(pCtx, _T("Unbind tunnel from node %d: RCC = %d\n\n"), nodeId, rcc);
+         }
+         else
+         {
+            ConsoleWrite(pCtx, _T("ERROR: Invalid or missing argument(s)\n\n"));
+         }
+      }
       else
       {
          ConsoleWrite(pCtx, _T("ERROR: Invalid TUNNEL subcommand\n\n"));
index fdb3232..8ba0406 100644 (file)
@@ -7948,3 +7948,17 @@ void Node::setRoutingLoopEvent(const InetAddress& address, UINT32 nodeId, UINT64
    }
    m_routingLoopEvents->add(new RoutingLoopEvent(address, nodeId, eventId));
 }
+
+/**
+ * Set tunnel ID
+ */
+void Node::setTunnelId(const uuid& tunnelId)
+{
+   lockProperties();
+   m_tunnelId = tunnelId;
+   setModified(false);
+   unlockProperties();
+
+   TCHAR buffer[128];
+   nxlog_debug(4, _T("Tunnel ID for node %s [%d] set to %s"), m_name, m_id, tunnelId.toString(buffer));
+}
index 1027fa8..6b35bbc 100644 (file)
@@ -129,6 +129,31 @@ UINT32 BindAgentTunnel(UINT32 tunnelId, UINT32 nodeId)
 }
 
 /**
+ * Bind agent tunnel from node
+ */
+UINT32 UnbindAgentTunnel(UINT32 nodeId)
+{
+   Node *node = FindObjectById(nodeId, OBJECT_NODE);
+   if (node == NULL)
+      return RCC_INVALID_OBJECT_ID;
+
+   if (node->getTunnelId().isNull())
+      return RCC_SUCCESS;  // tunnel is not set
+
+   node->setTunnelId(uuid::NULL_UUID);
+
+   AgentTunnel *tunnel = GetTunnelForNode(nodeId);
+   if (tunnel != NULL)
+   {
+      nxlog_debug(4, _T("UnbindAgentTunnel(%s): shutting down existing tunnel"), node->getName());
+      tunnel->shutdown();
+      tunnel->decRefCount();
+   }
+
+   return RCC_SUCCESS;
+}
+
+/**
  * Get list of unbound agent tunnels into NXCP message
  */
 void GetUnboundAgentTunnels(NXCPMessage *msg)
@@ -212,8 +237,7 @@ AgentTunnel::AgentTunnel(SSL_CTX *context, SSL *ssl, SOCKET sock, const InetAddr
 AgentTunnel::~AgentTunnel()
 {
    m_channels.clear();
-   if (m_socket != INVALID_SOCKET)
-      shutdown(m_socket, SHUT_RDWR);
+   shutdown();
    ThreadJoin(m_recvThread);
    SSL_CTX_free(m_context);
    SSL_free(m_ssl);
@@ -377,6 +401,15 @@ void AgentTunnel::start()
 }
 
 /**
+ * Shutdown tunnel
+ */
+void AgentTunnel::shutdown()
+{
+   if (m_socket != INVALID_SOCKET)
+      ::shutdown(m_socket, SHUT_RDWR);
+}
+
+/**
  * Process setup request
  */
 void AgentTunnel::setup(const NXCPMessage *request)
@@ -427,6 +460,8 @@ UINT32 AgentTunnel::bind(UINT32 nodeId)
    msg.setId(InterlockedIncrement(&m_requestId));
    msg.setField(VID_SERVER_ID, g_serverId);
    msg.setField(VID_GUID, node->getGuid());
+   m_guid = uuid::generate();
+   msg.setField(VID_TUNNEL_GUID, m_guid);
 
    m_bindRequestId = msg.getId();
    m_bindGuid = node->getGuid();
@@ -468,7 +503,10 @@ void AgentTunnel::processCertificateRequest(NXCPMessage *request)
          X509_REQ *certRequest = d2i_X509_REQ(NULL, &certRequestData, (long)certRequestLen);
          if (certRequest != NULL)
          {
-            char *cn = m_bindGuid.toString().getUTF8String();
+            String cnBuilder = m_bindGuid.toString();
+            cnBuilder.append(_T('@'));
+            cnBuilder.append(m_guid.toString());
+            char *cn = cnBuilder.getUTF8String();
             X509 *cert = IssueCertificate(certRequest, cn, 365);
             free(cn);
             if (cert != NULL)
@@ -481,6 +519,12 @@ void AgentTunnel::processCertificateRequest(NXCPMessage *request)
                   response.setField(VID_CERTIFICATE, buffer, len);
                   OPENSSL_free(buffer);
                   debugPrintf(4, _T("Certificate issued"));
+
+                  Node *node = FindObjectByGUID(m_bindGuid, OBJECT_NODE);
+                  if (node != NULL)
+                  {
+                     node->setTunnelId(m_guid);
+                  }
                }
                else
                {
@@ -705,6 +749,21 @@ void AgentTunnelCommChannel::putData(const BYTE *data, size_t size)
 }
 
 /**
+ * Parse tunnel certificate CN
+ */
+static bool ParseTunnelCertificateCN(TCHAR *cn, uuid& nodeGuid, uuid& tunnelGuid)
+{
+   TCHAR *p = _tcschr(cn, _T('@'));
+   if (p == NULL)
+      return false;
+   *p = 0;
+   p++;
+   nodeGuid = uuid::parse(cn);
+   tunnelGuid = uuid::parse(p);
+   return !nodeGuid.isNull() && !tunnelGuid.isNull();
+}
+
+/**
  * Incoming connection data
  */
 struct ConnectionRequest
@@ -792,23 +851,33 @@ retry:
          TCHAR cn[256];
          if (GetCertificateCN(cert, cn, 256))
          {
-            uuid guid = uuid::parse(cn);
-            if (!guid.isNull())
+            nxlog_debug(4, _T("SetupTunnel(%s): certificate CN: %s"), (const TCHAR *)request->addr.toString(), cn);
+            uuid nodeGuid, tunnelGuid;
+            if (ParseTunnelCertificateCN(cn, nodeGuid, tunnelGuid))
             {
-               Node *node = (Node *)FindObjectByGUID(guid, OBJECT_NODE);
+               Node *node = (Node *)FindObjectByGUID(nodeGuid, OBJECT_NODE);
                if (node != NULL)
                {
-                  nxlog_debug(4, _T("SetupTunnel(%s): Tunnel attached to node %s [%d]"), (const TCHAR *)request->addr.toString(), node->getName(), node->getId());
-                  nodeId = node->getId();
+                  if (tunnelGuid.equals(node->getTunnelId()))
+                  {
+                     nxlog_debug(4, _T("SetupTunnel(%s): Tunnel attached to node %s [%d]"), (const TCHAR *)request->addr.toString(), node->getName(), node->getId());
+                     nodeId = node->getId();
+                  }
+                  else
+                  {
+                     nxlog_debug(4, _T("SetupTunnel(%s): Tunnel ID %s is not valid for node %s [%d]"),
+                              (const TCHAR *)request->addr.toString(), (const TCHAR *)tunnelGuid.toString(),
+                              node->getName(), node->getId());
+                  }
                }
                else
                {
-                  nxlog_debug(4, _T("SetupTunnel(%s): Node with GUID %s not found"), (const TCHAR *)request->addr.toString(), (const TCHAR *)guid.toString());
+                  nxlog_debug(4, _T("SetupTunnel(%s): Node with GUID %s not found"), (const TCHAR *)request->addr.toString(), (const TCHAR *)nodeGuid.toString());
                }
             }
             else
             {
-               nxlog_debug(4, _T("SetupTunnel(%s): Certificate CN is not a valid GUID"), (const TCHAR *)request->addr.toString());
+               nxlog_debug(4, _T("SetupTunnel(%s): Certificate CN is not a valid tunnel ID"), (const TCHAR *)request->addr.toString());
             }
          }
          else
index 2bf257c..31684e7 100644 (file)
@@ -78,6 +78,7 @@ class AgentTunnel : public RefCountObject
 {
 protected:
    INT32 m_id;
+   uuid m_guid;
    InetAddress m_address;
    SOCKET m_socket;
    SSL_CTX *m_context;
@@ -116,6 +117,7 @@ public:
    AgentTunnel(SSL_CTX *context, SSL *ssl, SOCKET sock, const InetAddress& addr, UINT32 nodeId);
    
    void start();
+   void shutdown();
    UINT32 bind(UINT32 nodeId);
    AgentTunnelCommChannel *createChannel();
    void closeChannel(AgentTunnelCommChannel *channel);
index 6680b29..4020f72 100644 (file)
@@ -1383,6 +1383,7 @@ private:
 protected:
    InetAddress m_ipAddress;
        TCHAR m_primaryName[MAX_DNS_NAME];
+       uuid m_tunnelId;
    UINT32 m_dwDynamicFlags;       // Flags used at runtime by server
    NodeType m_type;
    TCHAR m_subType[MAX_NODE_SUBTYPE_LENGTH];
@@ -1607,6 +1608,7 @@ public:
    UINT32 getSshProxy() const { return m_sshProxy; }
    time_t getLastAgentCommTime() const { return m_lastAgentCommTime; }
    const TCHAR *getPrimaryName() const { return m_primaryName; }
+   const uuid& getTunnelId() const { return m_tunnelId; }
 
    bool isDown() { return (m_dwDynamicFlags & NDF_UNREACHABLE) ? true : false; }
        time_t getDownTime() const { return m_downSince; }
@@ -1622,6 +1624,7 @@ public:
    void setSshCredentials(const TCHAR *login, const TCHAR *password);
    void changeIPAddress(const InetAddress& ipAddr);
        void changeZone(UINT32 newZone);
+       void setTunnelId(const uuid& tunnelId);
        void setFileUpdateConnection(AgentConnection *conn);
    void clearDataCollectionConfigFromAgent(AgentConnectionEx *conn);
    void forceSyncDataCollectionConfig();