snmp_sess_openを使って、open、closeするサンプル。
メモリリークしないように、特に注意して書いたつもり。
自分でテストしたときは、mainの処理をforで10万回ループさせても、
とりあえずメモリリークしなかったので、大丈夫だと思う。思いたい。
(v3をopenする処理、1回だけならいいけど、10万回もループさせると、とても重い。)
a.cpp
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/session_api.h>
#include <string>
#include <map>
#define OIDSIZE(p) (sizeof(p)/sizeof(oid))
struct snmp_node_param_t {
std::string host;
std::string community;
std::string port;
std::string target;
std::string timeout; // 秒指定
std::string retry;
std::string version; // 1 or v2c or 3のいずれか。
std::string username;
std::string level; // noAuthNoPriv or authNoPriv or authPrivのいずれか。
std::string auth_protocol; // MD5 or SHAのいずれか。
std::string auth_key;
std::string priv_protocol; // AES or DESのいずれか。
std::string priv_key;
};
struct snmp_sessp_t {
struct snmp_session session;
void* sess = nullptr;
};
int sess_open(const snmp_node_param_t &node_param, snmp_sessp_t &sessp);
void sess_close(snmp_sessp_t &sessp);
int sess_open(const snmp_node_param_t &node_param, snmp_sessp_t &sessp) {
// 呼び出し元で、あらかじめ
// init_snmp("snmpapp");
// 呼び出しておくこと。
// 呼び出さなかった場合、snmpv3の処理は失敗する。
sess_close(sessp);
snmp_sess_init(&sessp.session);
char hostport[4096];
char community[4096];
char security_name[4096];
char auth_key[4096];
char priv_key[4096];
sprintf(hostport, "%s:%s", node_param.host.c_str(), node_param.port.c_str());
sprintf(community, "%s", node_param.community.c_str());
sprintf(security_name, "%s", node_param.username.c_str());
sprintf(auth_key, "%s", node_param.auth_key.c_str());
sprintf(priv_key, "%s", node_param.priv_key.c_str());
sessp.session.securityEngineID = 0;
sessp.session.securityEngineIDLen = 0;
sessp.session.securityName = 0;
sessp.session.securityNameLen = 0;
sessp.session.contextEngineID = 0;
sessp.session.contextEngineIDLen = 0;
sessp.session.contextName = 0;
sessp.session.contextNameLen = 0;
sessp.session.securityAuthProto = nullptr;
sessp.session.securityPrivProto = nullptr;
sessp.session.peername = hostport;
sessp.session.remote_port = static_cast<u_short>(atoi(node_param.port.c_str()));
sessp.session.timeout = atoi(node_param.timeout.c_str()) * 1000000;
sessp.session.retries = atoi(node_param.retry.c_str());
if (node_param.version == "3") {
sessp.session.version = SNMP_VERSION_3;
sessp.session.securityModel = USM_SEC_MODEL_NUMBER;
sessp.session.securityName = security_name;
sessp.session.securityNameLen = node_param.username.size();
bool ap = false;
bool pp = false;
if (node_param.level == "authNoPriv") {
sessp.session.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
ap = true;
} else if (node_param.level == "authPriv") {
sessp.session.securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
ap = true;
pp = true;
} else {
// 謎のレベルを指定してきたら、とりあえずnoAuthNoPriv。
sessp.session.securityLevel = SNMP_SEC_LEVEL_NOAUTH;
}
if (node_param.auth_protocol == "SHA") {
sessp.session.securityAuthProto = snmp_duplicate_objid(usmHMACSHA1AuthProtocol, USM_AUTH_PROTO_SHA_LEN);
sessp.session.securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
} else {
// 謎のauthProtocolを指定してきたら、とりあえずMD5。
sessp.session.securityAuthProto = snmp_duplicate_objid(usmHMACMD5AuthProtocol, USM_AUTH_PROTO_MD5_LEN);
sessp.session.securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
}
if (node_param.priv_protocol == "AES") {
sessp.session.securityPrivProto = snmp_duplicate_objid(usmAESPrivProtocol, USM_PRIV_PROTO_AES_LEN);
sessp.session.securityPrivProtoLen = USM_PRIV_PROTO_AES_LEN;
} else if (node_param.priv_protocol == "AES128") {
sessp.session.securityPrivProto = snmp_duplicate_objid(usmAES128PrivProtocol, USM_PRIV_PROTO_AES128_LEN);
sessp.session.securityPrivProtoLen = USM_PRIV_PROTO_AES128_LEN;
} else {
// 謎のprivProtocolを指定してきたら、とりあえずDES。
sessp.session.securityPrivProto = snmp_duplicate_objid(usmDESPrivProtocol, USM_PRIV_PROTO_DES_LEN);
sessp.session.securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
}
if (ap && !node_param.auth_key.empty()) {
sessp.session.securityAuthKeyLen = USM_AUTH_KU_LEN;
if (
generate_Ku(
sessp.session.securityAuthProto,
sessp.session.securityAuthProtoLen,
reinterpret_cast<unsigned char*>(auth_key),
node_param.auth_key.size(),
sessp.session.securityAuthKey,
&sessp.session.securityAuthKeyLen
) != SNMPERR_SUCCESS
) {
printf("Error generating a key (Ku) from the supplied authentication pass phrase.\n");
}
}
if (pp && !node_param.priv_key.empty()) {
sessp.session.securityPrivKeyLen = USM_PRIV_KU_LEN;
if (
generate_Ku(
sessp.session.securityAuthProto,
sessp.session.securityAuthProtoLen,
reinterpret_cast<unsigned char*>(priv_key),
node_param.priv_key.size(),
sessp.session.securityPrivKey,
&sessp.session.securityPrivKeyLen
) != SNMPERR_SUCCESS
) {
printf("Error generating a key (Ku) from the supplied privacy pass phrase.\n");
}
} else {
sessp.session.securityPrivProto = snmp_duplicate_objid(usmNoPrivProtocol, OIDSIZE(usmNoPrivProtocol));
sessp.session.securityPrivProtoLen = OIDSIZE(usmNoPrivProtocol);
sessp.session.securityPrivKeyLen = USM_PRIV_KU_LEN;
}
} else if (node_param.version == "2c") {
sessp.session.version = SNMP_VERSION_2c;
sessp.session.securityModel = SNMP_SEC_MODEL_SNMPv2c;
sessp.session.community = reinterpret_cast<unsigned char*>(community);
sessp.session.community_len = node_param.community.size();
} else {
sessp.session.version = SNMP_VERSION_1;
sessp.session.securityModel = SNMP_SEC_MODEL_SNMPv1;
sessp.session.community = reinterpret_cast<unsigned char*>(community);
sessp.session.community_len = node_param.community.size();
}
sessp.sess = snmp_sess_open(&sessp.session);
if (sessp.sess == nullptr) {
int liberror;
int syserror;
char *buf;
snmp_error(&sessp.session, &liberror, &syserror, &buf);
printf("%s\n", buf);
free(buf);
return -1;
}
return 0;
}
void sess_close(snmp_sessp_t &sessp) {
if (sessp.sess == nullptr) {
return;
}
snmp_sess_close(sessp.sess);
sessp.sess = nullptr;
// snmp_duplicate_objidで確保した領域は、freeしないとダメっぽい。。。
free(sessp.session.securityAuthProto);
free(sessp.session.securityPrivProto);
}
int main(int, char**) {
init_snmp("snmpapp");
snmp_node_param_t node_param;
node_param.host = "192.168.0.1";
node_param.community = "public";
node_param.port = "161";
node_param.timeout = "2";
node_param.retry = "1";
node_param.version = "3";
node_param.username = "test1";
node_param.level = "authPriv";
node_param.auth_protocol = "MD5";
node_param.auth_key = "authp1234";
node_param.priv_protocol = "DES";
node_param.priv_key = "encp1234";
snmp_sessp_t sessp;
if (sess_open(node_param, sessp)) {
printf("sess_open fail.\n");
return 1;
}
// sess_openが成功したら、sessp.sess(snmp_sess_openの戻り値)を使って、
// getやwalkの処理ができる。これはまた無駄に長い処理がいるので、
// 別の機会にzzz
// sess_closeを呼ばないと、もれなくメモリリークする。
// また、ソケットも閉じないので、そのうちソケットが開けなくなる。
// 繰り返し処理で使うときは忘れないように。
sess_close(sessp);
return 0;
}