"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 }