/
makhinova
/
ClassSNMP
Обзор
Документация
Войти
/
makhinova
/
ClassSNMP
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
snmp.cpp
249 строк
8 KB
makhinova
class snmp
09 окт 2025, 09:39
09 окт 2025, 09:39
6e8160d
Код
Авторство
О чём код?
#include "snmp.h" #include <cstring> #include <sstream> #include <iomanip> #include <iostream> static bool snmp_library_initialized = false; static std::mutex library_mutex; SNMP::SNMP() : session_(std::make_unique<SNMPInternalSession>()) { InitializeSNMPLibrary(); } SNMP::~SNMP() { Disconnect(); } bool SNMP::InitializeSNMPLibrary() { std::lock_guard<std::mutex> lock(library_mutex); if (!snmp_library_initialized) { netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_READ_CONFIGS, 1); netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_PERSIST_STATE, 1); init_snmp("snmp_client"); snmp_library_initialized = true; } return true; } bool SNMP::ConnectV3(const SNMPSessionConfig& config) { Disconnect(); if (config.host.empty() || config.user_name.empty()) { return false; } snmp_session session{}; snmp_sess_init(&session); session.peername = const_cast<char*>(config.host.c_str()); session.version = SNMP_VERSION_3; session.timeout = config.timeout_ms * 1000; session.retries = config.retries; session.securityName = const_cast<char*>(config.user_name.c_str()); session.securityNameLen = config.user_name.length(); struct KeyCleanup { u_char auth_key[USM_AUTH_KU_LEN] = {0}; u_char priv_key[USM_PRIV_KU_LEN] = {0}; ~KeyCleanup() { std::memset(auth_key, 0, sizeof(auth_key)); std::memset(priv_key, 0, sizeof(priv_key)); } } keys; size_t auth_key_len = 0, priv_key_len = 0; if (!config.auth_password.empty()) { session.securityAuthProto = usmHMACMD5AuthProtocol; session.securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN; auth_key_len = USM_AUTH_KU_LEN; if (GenerateKeys(config.auth_password, keys.auth_key, &auth_key_len, session.securityAuthProto, session.securityAuthProtoLen)) { std::memcpy(session.securityAuthKey, keys.auth_key, auth_key_len); session.securityAuthKeyLen = auth_key_len; if (!config.priv_password.empty()) { session.securityLevel = SNMP_SEC_LEVEL_AUTHPRIV; session.securityPrivProto = usmDESPrivProtocol; session.securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN; priv_key_len = USM_PRIV_KU_LEN; if (GenerateKeys(config.priv_password, keys.priv_key, &priv_key_len, session.securityAuthProto, session.securityAuthProtoLen)) { std::memcpy(session.securityPrivKey, keys.priv_key, priv_key_len); session.securityPrivKeyLen = priv_key_len; } } else { session.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV; } } } else { session.securityLevel = SNMP_SEC_LEVEL_NOAUTH; } session_->session = snmp_open(&session); is_connected_ = (session_->session != nullptr); std::memset(session.securityAuthKey, 0, sizeof(session.securityAuthKey)); std::memset(session.securityPrivKey, 0, sizeof(session.securityPrivKey)); return is_connected_; } void SNMP::Disconnect() { if (session_ && session_->session) { snmp_close(session_->session); session_->session = nullptr; } is_connected_ = false; } SNMPValue SNMP::Read(const std::string& oid) { if (!is_connected_ || !session_ || !session_->session) { return {.quality = 1, .error_message = "Not connected"}; } auto pdu = snmp_pdu_create(SNMP_MSG_GET); if (!pdu) { return {.quality = 1, .error_message = "Failed to create PDU"}; } ::oid an_oid[MAX_OID_LEN]; size_t an_oid_len = MAX_OID_LEN; if (!read_objid(oid.c_str(), an_oid, &an_oid_len)) { snmp_free_pdu(pdu); return {.quality = 1, .error_message = "Invalid OID format"}; } snmp_add_null_var(pdu, an_oid, an_oid_len); snmp_pdu* response = nullptr; int status = snmp_synch_response(session_->session, pdu, &response); SNMPValue result; if (status == STAT_SUCCESS && response && response->errstat == SNMP_ERR_NOERROR && response->variables) { result = ParseVariable(response->variables); result.quality = 0; } else { result.quality = 1; if (status != STAT_SUCCESS) { result.error_message = "SNMP request failed with status: " + std::to_string(status); } else if (response) { result.error_message = "SNMP error: " + std::to_string(response->errstat); } else { result.error_message = "No response from SNMP agent"; } } if (response) snmp_free_pdu(response); return result; } std::vector<SNMPValue> SNMP::Read(const std::vector<std::string>& oids) { if (!is_connected_ || !session_ || !session_->session || oids.empty()) { return {}; } auto pdu = snmp_pdu_create(SNMP_MSG_GET); if (!pdu) return {}; for (const auto& oid : oids) { ::oid an_oid[MAX_OID_LEN]; size_t an_oid_len = MAX_OID_LEN; if (read_objid(oid.c_str(), an_oid, &an_oid_len)) { snmp_add_null_var(pdu, an_oid, an_oid_len); } } snmp_pdu* response = nullptr; int status = snmp_synch_response(session_->session, pdu, &response); std::vector<SNMPValue> results; if (status == STAT_SUCCESS && response && response->errstat == SNMP_ERR_NOERROR) { for (auto* vars = response->variables; vars; vars = vars->next_variable) { results.emplace_back(ParseVariable(vars)); } } if (response) snmp_free_pdu(response); return results; } bool SNMP::GenerateKeys(const std::string& password, u_char* key, size_t* key_len, const oid* proto, size_t proto_len) { return !password.empty() && generate_Ku(proto, proto_len, reinterpret_cast<const u_char*>(password.c_str()), password.length(), key, key_len) == SNMPERR_SUCCESS; } SNMPValue SNMP::ParseVariable(const variable_list* var) { if (!var) { return {.quality = 1, .error_message = "Null variable"}; } SNMPValue value; value.timestamp = std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::system_clock::now().time_since_epoch()).count(); char buffer[1024]; switch (var->type) { case ASN_OCTET_STR: value.type = SNMPValue::Type::STRING; if (var->val.string && var->val_len > 0) { value.string_value.assign(reinterpret_cast<char*>(var->val.string), var->val_len); } break; case ASN_INTEGER: value.type = SNMPValue::Type::INTEGER; if (var->val.integer) value.long_value = *var->val.integer; break; case ASN_TIMETICKS: value.type = SNMPValue::Type::TIMETICKS; if (var->val.integer) value.timeticks_value = *var->val.integer; break; case ASN_OBJECT_ID: value.type = SNMPValue::Type::OBJECT_ID; if (var->val.objid) { snprint_objid(buffer, sizeof(buffer), var->val.objid, var->val_len / sizeof(oid)); value.string_value = buffer; } break; default: value.type = SNMPValue::Type::UNKNOWN; snprint_value(buffer, sizeof(buffer), var->name, var->name_length, var); value.string_value = buffer; value.error_message = value.string_value; if (value.string_value.find("No Such Object") != std::string::npos) value.quality = 3; else if (value.string_value.find("Timeout") != std::string::npos) value.quality = 2; else value.quality = 1; break; } return value; } std::string SNMP::FormatUptime(unsigned long timeticks) const { unsigned long seconds = timeticks / 100; unsigned long days = seconds / 86400; unsigned long hours = (seconds % 86400) / 3600; unsigned long minutes = (seconds % 3600) / 60; unsigned long secs = seconds % 60; std::ostringstream oss; oss << days << " дней " << std::setw(2) << std::setfill('0') << hours << ":" << std::setw(2) << std::setfill('0') << minutes << ":" << std::setw(2) << std::setfill('0') << secs; return oss.str(); }