net-snmp没有正确更改auth和priva协议
net-snmp is not changing auth and priv protocol correctly
我在Linux下的c++程序中使用net-snmp库(版本5.7.1)。我有一个Web前端,用户可以在其中选择SNMP版本并对其进行配置。SNMPv1和SNMPv2运行良好,但我在SNMPv3方面遇到了一些问题。
这是前端的图片:Webinterface的截图(很抱歉没有直接上传到这里,但我需要至少10个信誉才能做到这一点)
当我启动c++后端并正确输入所有需要的SNMPv3凭据时,一切都正常,设备可以访问。例如,如果我将Auth协议从MD5更改为SHA,但保留其余凭据不变,我会认为该设备不再可访问。事实上,它是可以到达的。在重新启动后端后,设备(如预期)无法使用相同的设置访问。
发现这个问题后,我进行了一些测试。对于测试,我使用了不同的用户和不同的设置。他们用不同供应商的三种不同设备运行,每次我都得到相同的结果。所以这不可能是设备重新分配的问题。结果可以在这里看到:测试结果
经过测试,我的结论是,net-snmp似乎为一个用户名缓存了选定的auth和priva协议。在测试2中可以看出这一点非常好。当我第一次使用特定协议的用户名时,我得到了预期的结果。更改协议后预计会有不同的结果,但我得到的结果仍然和以前一样。
最后介绍了如何进行SNMP调用的一些信息:
- 有一个名为
SNMPWrapper
的类,它处理整个SNMP通信 - 在构造函数中,我调用
init_snmp()
来初始化net-snmp - 从外面我只能呼叫
get()
、set()
和walk()
。每次调用其中一个方法时,都会创建一个新的SNMP会话(首先,我用snmp_sess_init()
创建一个新会话,然后设置所需的内容,最后用snmp_sess_open()
打开会话 - 在我提出请求并收到答复后,我结束了与
snmp_sess_close()
的会话
问题:在更改协议之前,我是否必须进行任何其他清理才能使其正常工作?
编辑 :我添加了一些代码,显示了所描述的行为
int main(int argc, char** argv) {
struct snmp_session session, session1, *ss, *ss1;
struct snmp_pdu *pdu, *pdu1;
struct snmp_pdu *response, *response1;
oid anOID[MAX_OID_LEN];
size_t anOID_len = MAX_OID_LEN;
struct variable_list *vars;
int status, status1;
init_snmp("snmpapp");
const char* user = "md5";
string authpw = "123123123";
string privpw = "";
string ipString = "192.168.15.32";
char ip[16];
memset(&ip, 0, sizeof (ip));
ipString.copy(ip, sizeof (ip) - 1, 0);
/*
* First request: AuthProto is MD5, no PrivProto is used. The snmp-get
* request is successful
*/
snmp_sess_init(&session); /* set up defaults */
session.peername = ip;
session.version = SNMP_VERSION_3;
/* set the SNMPv3 user name */
session.securityName = strdup(user);
session.securityNameLen = strlen(session.securityName);
// set the authentication method to MD5
session.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
session.securityAuthProto = usmHMACMD5AuthProtocol;
session.securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
session.securityAuthKeyLen = USM_AUTH_KU_LEN;;
if (generate_Ku(session.securityAuthProto,
session.securityAuthProtoLen,
(u_char *) authpw.c_str(), strlen(authpw.c_str()),
session.securityAuthKey,
&session.securityAuthKeyLen) != SNMPERR_SUCCESS) {
//if code reaches here, the creation of the security key was not successful
}
cout << "SecurityAuthProto - session: " << session.securityAuthProto[9] << " / SecurityAuthKey - session: " << session.securityAuthKey << endl;
ss = snmp_open(&session); /* establish the session */
if (!ss) {
cout << "Couldn't open session1 correctly";
exit(2);
}
cout << "SecurityAuthProto - ss: " << ss->securityAuthProto[9] << " / SecurityAuthKey - ss: " << ss->securityAuthKey << endl;
//send message
pdu = snmp_pdu_create(SNMP_MSG_GET);
read_objid(".1.3.6.1.2.1.1.1.0", anOID, &anOID_len);
snmp_add_null_var(pdu, anOID, anOID_len);
status = snmp_synch_response(ss, pdu, &response);
/*
* Process the response.
*/
if (status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR) {
cout << "SNMP-read success" << endl;
} else {
cout << "SNMP-read fail" << endl;
}
if (response)
snmp_free_pdu(response);
if (!snmp_close(ss))
cout << "Snmp closing failed" << endl;
/*
* Second request: Only the authProto is changed from MD5 to SHA1. I expect,
* that the snmp-get fails, but it still succeeds.
*/
snmp_sess_init(&session1);
session1.peername = ip;
session1.version = SNMP_VERSION_3;
/* set the SNMPv3 user name */
session1.securityName = strdup(user);
session1.securityNameLen = strlen(session1.securityName);
// set the authentication method to SHA1
session1.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
session1.securityAuthProto = usmHMACSHA1AuthProtocol;
session1.securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
session1.securityAuthKeyLen = USM_AUTH_KU_LEN;
if (generate_Ku(session1.securityAuthProto,
session1.securityAuthProtoLen,
(u_char *) authpw.c_str(), strlen(authpw.c_str()),
session1.securityAuthKey,
&session1.securityAuthKeyLen) != SNMPERR_SUCCESS) {
//if code reaches here, the creation of the security key was not successful
}
cout << "SecurityAuthProto - session1: " << session1.securityAuthProto[9] << " / SecurityAuthKey - session1: " << session1.securityAuthKey << endl;
ss1 = snmp_open(&session1); /* establish the session */
if (!ss1) {
cout << "Couldn't open session1 correctly";
exit(2);
}
cout << "SecurityAuthProto - ss1: " << ss1->securityAuthProto[9] << " / SecurityAuthKey - ss1: " << ss1->securityAuthKey << endl;
//send message
pdu1 = snmp_pdu_create(SNMP_MSG_GET);
read_objid(".1.3.6.1.2.1.1.1.0", anOID, &anOID_len);
snmp_add_null_var(pdu1, anOID, anOID_len);
status1 = snmp_synch_response(ss1, pdu1, &response1);
/*
* Process the response.
*/
if (status1 == STAT_SUCCESS && response1->errstat == SNMP_ERR_NOERROR) {
cout << "SNMP-read success" << endl;
} else {
cout << "SNMP-read fail" << endl;
}
if (response1)
snmp_free_pdu(response1);
snmp_close(ss1);
return 0;
}
我自己找到了解决方案:
net snmp为用户的每个EngineId(设备)缓存。如果engineID有一个现有用户,并且您试图与该用户打开一个新会话,那么net-snmp将使用缓存的会话。因此,解决方案是用缓存的用户清除列表。
有了这个代码片段,我可以解决我的问题:
usmUser* actUser = usm_get_userList();
while (actUser != NULL) {
usmUser* dummy = actUser;
usm_remove_user(actUser);
actUser = dummy->next;
}
我希望我能帮助别人。
您还可以更新现有用户的密码:
for (usmUser* actUser = usm_get_userList(); actUser != NULL; actUser = actUser->next) {
if (strcmp(actUser->secName, user) == 0) {
//this method calls generate_Ku with previous security data but with specified password
usm_set_user_password(actUser, "userSetAuthPass", authpw.c_str());
break;
}
}