2013-08-22 67 views
2

我在Linux下的C++程序中使用了net-snmp庫(版本5.7.1)。我有一個Web-Frontend,用戶可以選擇一個SNMP版本並對其進行配置。 SNMPv1和SNMPv2工作得很好,但是我遇到了SNMPv3的一些問題。net-snmp沒有正確地改變auth和priv協議

這裏是前端的圖片:Screenshot of Webinterface(對不起,直接在這裏沒有上傳,但我至少需要10美譽做到這一點)

當我開始了C++後端,正確輸入所有必要的SNMPv3憑證,一切工作正常,設備是可及的。如果我將身份驗證協議從MD5更改爲SHA,但將其餘憑證保持不變,則我預計該設備不再可用。實際上它保持可達。重新啓動後端後,設備(如預期的)不能再通過相同的設置進行訪問。

發現這個問題後,我跑了一些測試。爲了測試,我使用了不同的用戶和不同的設置。他們用不同廠商的三種不同設備運行,每次都得到相同的結果。所以它不能成爲設備相關的問題。結果可以在這裏看到:Test results

我的結論測試後,net-snmp似乎緩存選定的auth和priv協議爲一個用戶名。在測試2中可以看到這一點。第一次使用具有特定協議的用戶名時,我得到了預期的結果。在更改協議 後,預計會有不同的結果,但我仍然可以得到與以前相同的結果。

在最後的一些信息的SNMP的電話是如何製造:

  • 有一個叫SNMPWrapper類,它HANDELS構造我叫init_snmp()給init NET-裏面全SNMP通信
  • 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; 

}

回答

3

我發現溶液自己:

NET-SNMP的高速緩存用於每ENGINEID(裝置)中的用戶。如果存在engineID的現有用戶,並嘗試與該用戶打開新會話,則net-snmp將使用緩存的用戶。所以解決方案是用緩存的用戶清除列表。

有了這個代碼片斷,我可以解決我的問題:

usmUser* actUser = usm_get_userList(); 
while (actUser != NULL) { 
    usmUser* dummy = actUser; 
    usm_remove_user(actUser); 
    actUser = dummy->next; 
} 

我希望我能幫助別人與此有關。