"Fossies" - the Fresh Open Source Software Archive

Member "netxms-3.8.166/src/agent/core/dcsnmp.cpp" (23 Feb 2021, 11634 Bytes) of package /linux/misc/netxms-3.8.166.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dcsnmp.cpp" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 3.6.300_vs_3.7.95.

    1 /*
    2 ** NetXMS multiplatform core agent
    3 ** Copyright (C) 2003-2020 Victor Kirhenshtein
    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: dcsnmp.cpp
   20 **
   21 **/
   22 
   23 #include "nxagentd.h"
   24 
   25 #define DEBUG_TAG _T("dc.snmp")
   26 
   27 /**
   28  * SNMP targets
   29  */
   30 static SharedHashMap<uuid_t, SNMPTarget> s_snmpTargets;
   31 static Mutex s_snmpTargetsLock;
   32 
   33 /**
   34  * Create SNMP target from NXCP message
   35  */
   36 SNMPTarget::SNMPTarget(uint64_t serverId, const NXCPMessage& msg, uint32_t baseId)
   37 {
   38    m_guid = msg.getFieldAsGUID(baseId);
   39    m_serverId = serverId;
   40    m_ipAddress = msg.getFieldAsInetAddress(baseId + 1);
   41    m_snmpVersion = static_cast<SNMP_Version>(msg.getFieldAsInt16(baseId + 2));
   42    m_port = msg.getFieldAsUInt16(baseId + 3);
   43    m_authType = static_cast<SNMP_AuthMethod>(msg.getFieldAsInt16(baseId + 4));
   44    m_encType = static_cast<SNMP_EncryptionMethod>(msg.getFieldAsInt16(baseId + 5));
   45    m_authName = msg.getFieldAsUtf8String(baseId + 6);
   46    m_authPassword = msg.getFieldAsUtf8String(baseId + 7);
   47    m_encPassword = msg.getFieldAsUtf8String(baseId + 8);
   48    m_transport = nullptr;
   49 }
   50 
   51 /**
   52  * Create SNMP target from database record
   53  * Expected field order:
   54  *   guid,server_id,ip_address,snmp_version,port,auth_type,enc_type,auth_name,auth_pass,enc_pass
   55  */
   56 SNMPTarget::SNMPTarget(DB_RESULT hResult, int row)
   57 {
   58    m_guid = DBGetFieldGUID(hResult, row, 0);
   59    m_serverId = DBGetFieldUInt64(hResult, row, 1);
   60    m_ipAddress = DBGetFieldInetAddr(hResult, row, 2);
   61    m_snmpVersion = static_cast<SNMP_Version>(DBGetFieldLong(hResult, row, 3));
   62    m_port = static_cast<uint16_t>(DBGetFieldLong(hResult, row, 4));
   63    m_authType = static_cast<SNMP_AuthMethod>(DBGetFieldLong(hResult, row, 5));
   64    m_encType = static_cast<SNMP_EncryptionMethod>(DBGetFieldLong(hResult, row, 6));
   65    m_authName = DBGetFieldUTF8(hResult, row, 7, nullptr, 0);
   66    m_authPassword = DBGetFieldUTF8(hResult, row, 8, nullptr, 0);
   67    m_encPassword = DBGetFieldUTF8(hResult, row, 9, nullptr, 0);
   68    m_transport = nullptr;
   69 }
   70 
   71 /**
   72  * SNMP target destructor
   73  */
   74 SNMPTarget::~SNMPTarget()
   75 {
   76    MemFree(m_authName);
   77    MemFree(m_authPassword);
   78    MemFree(m_encPassword);
   79    delete m_transport;
   80 }
   81 
   82 /**
   83  * Save SNMP target object to database
   84  */
   85 bool SNMPTarget::saveToDatabase(DB_HANDLE hdb)
   86 {
   87    DB_STATEMENT hStmt;
   88    if (IsDatabaseRecordExist(hdb, _T("dc_snmp_targets"), _T("guid"), m_guid))
   89       hStmt = DBPrepare(hdb, _T("UPDATE dc_snmp_targets SET server_id=?,ip_address=?,snmp_version=?,port=?,auth_type=?,enc_type=?,auth_name=?,auth_pass=?,enc_pass=? WHERE guid=?"));
   90    else
   91       hStmt = DBPrepare(hdb, _T("INSERT INTO dc_snmp_targets (server_id,ip_address,snmp_version,port,auth_type,enc_type,auth_name,auth_pass,enc_pass,guid) VALUES (?,?,?,?,?,?,?,?,?,?)"));
   92    if (hStmt == nullptr)
   93       return false;
   94 
   95    DBBind(hStmt, 1, DB_SQLTYPE_BIGINT, m_serverId);
   96    DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, (const TCHAR *)m_ipAddress.toString(), DB_BIND_TRANSIENT);
   97    DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, static_cast<int32_t>(m_snmpVersion));
   98    DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, static_cast<int32_t>(m_port));
   99    DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, static_cast<int32_t>(m_authType));
  100    DBBind(hStmt, 6, DB_SQLTYPE_INTEGER, static_cast<int32_t>(m_encType));
  101 #ifdef UNICODE
  102    DBBind(hStmt, 7, DB_SQLTYPE_VARCHAR, WideStringFromUTF8String(m_authName), DB_BIND_DYNAMIC);
  103    DBBind(hStmt, 8, DB_SQLTYPE_VARCHAR, WideStringFromUTF8String(m_authPassword), DB_BIND_DYNAMIC);
  104    DBBind(hStmt, 9, DB_SQLTYPE_VARCHAR, WideStringFromUTF8String(m_encPassword), DB_BIND_DYNAMIC);
  105 #else
  106    DBBind(hStmt, 7, DB_SQLTYPE_VARCHAR, m_authName, DB_BIND_STATIC);
  107    DBBind(hStmt, 8, DB_SQLTYPE_VARCHAR, m_authPassword, DB_BIND_STATIC);
  108    DBBind(hStmt, 9, DB_SQLTYPE_VARCHAR, m_encPassword, DB_BIND_STATIC);
  109 #endif
  110    DBBind(hStmt, 10, DB_SQLTYPE_VARCHAR, m_guid);
  111 
  112    bool success = DBExecute(hStmt);
  113    DBFreeStatement(hStmt);
  114    return success;
  115 }
  116 
  117 /**
  118  * Get SNMP transport (create if needed)
  119  */
  120 SNMP_Transport *SNMPTarget::getTransport(uint16_t port)
  121 {
  122    if (m_transport != nullptr)
  123       return m_transport;
  124 
  125    m_transport = new SNMP_UDPTransport;
  126     static_cast<SNMP_UDPTransport*>(m_transport)->createUDPTransport(m_ipAddress, (port != 0) ? port : m_port);
  127    m_transport->setSnmpVersion(m_snmpVersion);
  128    SNMP_SecurityContext *ctx = new SNMP_SecurityContext(m_authName, m_authPassword, m_encPassword, m_authType, m_encType);
  129     ctx->setSecurityModel((m_snmpVersion == SNMP_VERSION_3) ? SNMP_SECURITY_MODEL_USM : SNMP_SECURITY_MODEL_V2C);
  130    m_transport->setSecurityContext(ctx);
  131    return m_transport;
  132 }
  133 
  134 /**
  135  * Add (or replace) SNMP target information
  136  */
  137 void UpdateSnmpTarget(shared_ptr<SNMPTarget> target)
  138 {
  139    s_snmpTargetsLock.lock();
  140    s_snmpTargets.set(target->getGuid().getValue(), target);
  141    s_snmpTargetsLock.unlock();
  142 }
  143 
  144 /**
  145  * Get value from SNMP node
  146  */
  147 uint32_t GetSnmpValue(const uuid& target, uint16_t port, SNMP_Version version, const TCHAR *oid, TCHAR *value, int interpretRawValue)
  148 {
  149    s_snmpTargetsLock.lock();
  150    shared_ptr<SNMPTarget> t = s_snmpTargets.getShared(target.getValue());
  151    if (!t) // cannot use t == nullptr because of HP aCC issues
  152    {
  153       s_snmpTargetsLock.unlock();
  154 
  155       TCHAR buffer[64];
  156       nxlog_debug_tag(DEBUG_TAG, 6, _T("SNMP target with guid %s not found"), target.toString(buffer));
  157       return ERR_INTERNAL_ERROR;
  158    }
  159    s_snmpTargetsLock.unlock();
  160 
  161    SNMP_Transport *snmp = t->getTransport(port);
  162    uint32_t rcc;
  163 
  164    if (interpretRawValue == SNMP_RAWTYPE_NONE)
  165    {
  166       rcc = SnmpGetEx(snmp, oid, NULL, 0, value, MAX_RESULT_LENGTH * sizeof(TCHAR), SG_PSTRING_RESULT, NULL);
  167    }
  168    else
  169    {
  170         BYTE rawValue[1024];
  171         memset(rawValue, 0, 1024);
  172       rcc = SnmpGetEx(snmp, oid, NULL, 0, rawValue, 1024, SG_RAW_RESULT, NULL);
  173         if (rcc == SNMP_ERR_SUCCESS)
  174         {
  175             switch(interpretRawValue)
  176             {
  177                 case SNMP_RAWTYPE_INT32:
  178                     _sntprintf(value, MAX_RESULT_LENGTH, _T("%d"), ntohl(*((INT32 *)rawValue)));
  179                     break;
  180                 case SNMP_RAWTYPE_UINT32:
  181                     _sntprintf(value, MAX_RESULT_LENGTH, _T("%u"), ntohl(*((UINT32 *)rawValue)));
  182                     break;
  183                 case SNMP_RAWTYPE_INT64:
  184                     _sntprintf(value, MAX_RESULT_LENGTH, INT64_FMT, (INT64)ntohq(*((INT64 *)rawValue)));
  185                     break;
  186                 case SNMP_RAWTYPE_UINT64:
  187                     _sntprintf(value, MAX_RESULT_LENGTH, UINT64_FMT, ntohq(*((UINT64 *)rawValue)));
  188                     break;
  189                 case SNMP_RAWTYPE_DOUBLE:
  190                     _sntprintf(value, MAX_RESULT_LENGTH, _T("%f"), ntohd(*((double *)rawValue)));
  191                     break;
  192                 case SNMP_RAWTYPE_IP_ADDR:
  193                     IpToStr(ntohl(*((UINT32 *)rawValue)), value);
  194                     break;
  195                 case SNMP_RAWTYPE_MAC_ADDR:
  196                     MACToStr(rawValue, value);
  197                     break;
  198                 default:
  199                     value[0] = 0;
  200                     break;
  201             }
  202         }
  203    }
  204 
  205    return (rcc == SNMP_ERR_SUCCESS) ? ERR_SUCCESS :
  206       ((rcc == SNMP_ERR_NO_OBJECT) ? ERR_UNKNOWN_PARAMETER : ERR_INTERNAL_ERROR);
  207 }
  208 
  209 /**
  210  * Read one row for SNMP table
  211  */
  212 static uint32_t ReadSNMPTableRow(SNMP_Transport *snmp, const SNMP_ObjectId *rowOid, size_t baseOidLen,
  213          uint32_t index, const ObjectArray<SNMPTableColumnDefinition> &columns, Table *table)
  214 {
  215    SNMP_PDU request(SNMP_GET_REQUEST, SnmpNewRequestId(), snmp->getSnmpVersion());
  216    for(int i = 0; i < columns.size(); i++)
  217    {
  218       const SNMPTableColumnDefinition *c = columns.get(i);
  219       if (c->getSnmpOid() != nullptr)
  220       {
  221          uint32_t oid[MAX_OID_LEN];
  222          size_t oidLen = c->getSnmpOid()->length();
  223          memcpy(oid, c->getSnmpOid()->value(), oidLen * sizeof(UINT32));
  224          if (rowOid != nullptr)
  225          {
  226             size_t suffixLen = rowOid->length() - baseOidLen;
  227             memcpy(&oid[oidLen], rowOid->value() + baseOidLen, suffixLen * sizeof(UINT32));
  228             oidLen += suffixLen;
  229          }
  230          else
  231          {
  232             oid[oidLen++] = index;
  233          }
  234          request.bindVariable(new SNMP_Variable(oid, oidLen));
  235       }
  236    }
  237 
  238    SNMP_PDU *response;
  239    uint32_t rc = snmp->doRequest(&request, &response, SnmpGetDefaultTimeout(), 3);
  240    if (rc == SNMP_ERR_SUCCESS)
  241    {
  242       if ((response->getNumVariables() >= columns.size()) &&
  243           (response->getErrorCode() == SNMP_PDU_ERR_SUCCESS))
  244       {
  245          table->addRow();
  246          for(int i = 0; i < response->getNumVariables(); i++)
  247          {
  248             SNMP_Variable *v = response->getVariable(i);
  249             if ((v != nullptr) && (v->getType() != ASN_NO_SUCH_OBJECT) && (v->getType() != ASN_NO_SUCH_INSTANCE))
  250             {
  251                const SNMPTableColumnDefinition *c = columns.get(i);
  252                if ((c != NULL) && c->isConvertSnmpStringToHex())
  253                {
  254                   size_t size = v->getValueLength();
  255                   TCHAR *buffer = MemAllocString(size * 2 + 1);
  256                   BinToStr(v->getValue(), size, buffer);
  257                   table->setPreallocated(i, buffer);
  258                }
  259                else
  260                {
  261                   bool convert = false;
  262                   TCHAR buffer[1024];
  263                   table->set(i, v->getValueAsPrintableString(buffer, 1024, &convert));
  264                }
  265             }
  266          }
  267       }
  268       delete response;
  269    }
  270    return rc;
  271 }
  272 
  273 /**
  274  * Callback for SnmpWalk in Node::getTableFromSNMP
  275  */
  276 static UINT32 SNMPGetTableCallback(SNMP_Variable *varbind, SNMP_Transport *snmp, void *arg)
  277 {
  278    ((ObjectArray<SNMP_ObjectId> *)arg)->add(new SNMP_ObjectId(varbind->getName()));
  279    return SNMP_ERR_SUCCESS;
  280 }
  281 
  282 /**
  283  * Get table from SNMP node
  284  */
  285 uint32_t GetSnmpTable(const uuid& target, uint16_t port, SNMP_Version version, const TCHAR *oid,
  286          const ObjectArray<SNMPTableColumnDefinition> &columns, Table *value)
  287 {
  288    s_snmpTargetsLock.lock();
  289    shared_ptr<SNMPTarget> t = s_snmpTargets.getShared(target.getValue());
  290    if (!t)  // cannot use t == nullptr because of HP aCC issues
  291    {
  292       s_snmpTargetsLock.unlock();
  293 
  294       TCHAR buffer[64];
  295       nxlog_debug_tag(DEBUG_TAG, 6, _T("SNMP target with guid %s not found"), target.toString(buffer));
  296       return ERR_INTERNAL_ERROR;
  297    }
  298    s_snmpTargetsLock.unlock();
  299 
  300    SNMP_Transport *snmp = t->getTransport(port);
  301 
  302    ObjectArray<SNMP_ObjectId> oidList(64, 64, Ownership::True);
  303    uint32_t rcc = SnmpWalk(snmp, oid, SNMPGetTableCallback, &oidList);
  304    if (rcc == SNMP_ERR_SUCCESS)
  305    {
  306       for(int i = 0; i < columns.size(); i++)
  307       {
  308          const SNMPTableColumnDefinition *c = columns.get(i);
  309          if (c->getSnmpOid() != nullptr)
  310             value->addColumn(c->getName(), c->getDataType(), c->getDisplayName(), c->isInstanceColumn());
  311       }
  312 
  313       size_t baseOidLen = SNMPGetOIDLength(oid);
  314       for(int i = 0; i < oidList.size(); i++)
  315       {
  316          rcc = ReadSNMPTableRow(snmp, oidList.get(i), baseOidLen, 0, columns, value);
  317          if (rcc != SNMP_ERR_SUCCESS)
  318             break;
  319       }
  320    }
  321    else
  322    {
  323       nxlog_debug_tag(DEBUG_TAG, 7, _T("GetSnmpTable: SNMP walk on %s failed (%s)"), oid, SNMPGetErrorText(rcc));
  324    }
  325 
  326    return (rcc == SNMP_ERR_SUCCESS) ? ERR_SUCCESS :
  327       ((rcc == SNMP_ERR_NO_OBJECT) ? ERR_UNKNOWN_PARAMETER : ERR_INTERNAL_ERROR);
  328 }