net-snmp v2c 运行良好但 v3 return STAT_ERROR
net-snmp v2c working well but v3 return STAT_ERROR
我目前正在尝试在我的嵌入式设备中开发 snmpManager(linux OS)。此设备应与另一个设备的 snmpAgent 通信。好吧,我的代码适用于 snmpV2c,我的 snmp 数据包也显示在 wireshark pcap 中。但是当我尝试 snmpV3 packets snmp_synch_response(session, requestPdu, &responsePdu)
func return STAT_ERROR
顺便说一句 snmpV2c 是 returning STAT_SUCCESS
我的代码如下所示,我为 v2 创建了 snmp 会话并且v3.
snmp_session *snmptypes::fCreateSession(QString IP)
{
struct snmp_session session;
snmp_sess_init(&session);
session.peername = strdup(IP.toAscii());
static const char* v3_passphrase = "blablabl";
session.retries = 2;
session.timeout = 1000000;
session.engineBoots = 0;
session.engineTime = 0;
QString engineID = "0000000c000000007f000001";
session.contextEngineID = reinterpret_cast<uchar*>(strdup(engineID.toAscii()));
qDebug()<<"contextEngineID:"<<session.contextEngineID;
/*memory allocated by strdup() will be freed by calling snmp_close() */
if(SnmpMainWidget::activeWaveForm == SnmpMainWidget::snmpv2c)
{
session.version = SNMP_VERSION_2c;
const char *str;
QString path = "user";
QByteArray ba;
ba = path.toLatin1();
str = ba.data();
session.community = const_cast<unsigned char*>(reinterpret_cast<const unsigned char *>(str));
session.community_len = path.length();
session.retries = 2;
session.timeout = 1000000;
}
else if (SnmpMainWidget::activeWaveForm == SnmpMainWidget::snmpv3)
{
session.version = SNMP_VERSION_3;
session.securityName = strdup("blabl");
session.securityNameLen = strlen(session.securityName);
session.securityModel = USM_SEC_MODEL_NUMBER;
session.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
session.securityAuthProto = usmHMACMD5AuthProtocol;
// session.securityAuthProtoLen = sizeof (usmHMACMD5AuthProtocol) / sizeof (oid);
session.securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
session.securityPrivProto = usmNoPrivProtocol;
session.securityPrivProtoLen = USM_PRIV_PROTO_NOPRIV_LEN;
session.securityAuthKeyLen =USM_AUTH_KU_LEN;
if (generate_Ku(session.securityAuthProto,session.securityAuthProtoLen,(u_char *) (v3_passphrase),
strlen(v3_passphrase),session.securityAuthKey,
&session.securityAuthKeyLen) != SNMPERR_SUCCESS)
{
qWarning()<<"ERROR KODU"<<generate_Ku(session.securityAuthProto,session.securityAuthProtoLen,(u_char *) (v3_passphrase),
strlen(v3_passphrase),session.securityAuthKey,
&session.securityAuthKeyLen);
snmp_log(LOG_ERR,"Error generating Ku from authentication pass phrase. \n");
exit(1);
}
}
struct snmp_session* openedSession = snmp_open(&session);
if(openedSession == nullptr)
{
snmp_sess_perror(reinterpret_cast<const char*>("No Ack!"), openedSession);
qWarning()<<"Error while Session opening! FILE:"<<__FILE__<<"LINE:"<<__LINE__;
}
else
qDebug()<<"creating session is succeed!";
return openedSession;
}
会话创建成功。到目前为止没有问题。让我们继续,然后我创建如下所示的 pdu,
snmp_pdu *snmptypes::fCreatePDU(tsPDUvariables PDUvariables)
{
// qDebug()<<"nrepeaters"<<PDUvariables.nrepeaters;
// qDebug()<<"mrepeaters"<<PDUvariables.mrepetitions;
qDebug()<<"setParam"<<PDUvariables.setParam;
qDebug()<<"dataType"<<PDUvariables.dataType;
struct snmp_pdu* requestPdu;
oid requestOid[MAX_OID_LEN];
size_t requestOidLength = MAX_OID_LEN;
snmp_parse_oid(static_cast<const char*>(PDUvariables.OID.toAscii()), requestOid, &requestOidLength);
switch (PDUvariables.msgType) {
case snmpGet:
requestPdu = snmp_pdu_create(SNMP_MSG_GET);
if (SnmpMainWidget::activeWaveForm == SnmpMainWidget::snmpv3){
requestPdu->version = SNMP_VERSION_3;
requestPdu->securityName = strdup("user");
requestPdu->securityNameLen = strlen(requestPdu->securityName);
requestPdu->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
requestPdu->securityModel = USM_SEC_MODEL_NUMBER;
}
snmp_add_null_var(requestPdu, requestOid, requestOidLength);
break;
//there are some other case like set,getbulk but don't need to focus these.get enough for now.
}
qDebug()<<"creating PDU is succeed!";
return requestPdu;
}
我终于使用了 snmpget func。用于将 snmp 数据包发送到专用 IP;
问题就在这里,snmpv2 snmpStatus
return 成功但是snmpv3 reutn错误。 snmpv3 数据包没有出现在 wireshark 上,也没有发送。当 V2 运行良好时,我不明白我在 V3 中出了什么问题。
bool snmptypes::fSnmpGet(QString IP,QString OID)
{
const char PACKET_HEADER_BYTE = 4;//4Byte = SOH + len/256 + len%256 + EOH
struct snmp_session* session = fCreateSession(IP);
tsPDUvariables PDUvariables;
PDUvariables.OID = OID;
PDUvariables.msgType = snmpGet;
struct snmp_pdu* requestPdu = fCreatePDU(PDUvariables);
qDebug()<<"PDUvariables.msgType"<<PDUvariables.msgType;
qDebug()<<"PDUvariables.dataType"<<PDUvariables.dataType;
qDebug()<<"PDUvariables.OID"<<PDUvariables.OID;
qDebug()<<"PDUvariables.setParam"<<PDUvariables.setParam;
struct snmp_pdu* responsePdu = nullptr;
if(requestPdu != nullptr && session != nullptr)
{
int snmpStatus = snmp_synch_response(session, requestPdu, &responsePdu);
qDebug()<<"snmpStatus"<<snmpStatus;
qDebug()<<"requestStatus::errStat"<<requestPdu->errstat;
qDebug()<<"session->s_errno"<<session->s_errno;
if(snmpStatus == STAT_SUCCESS)
{
if( responsePdu->errstat == SNMP_ERR_NOERROR and responsePdu->errstat == SNMP_ERR_NOERROR)
{
/* SUCCESS: Print the result variables */
struct variable_list *snmpVariables;
for(snmpVariables = responsePdu->variables; snmpVariables; snmpVariables = snmpVariables->next_variable)
{ qDebug()<<"fSnmpGet"<<__LINE__;
print_variable(snmpVariables->name, snmpVariables->name_length, snmpVariables);
}
for(snmpVariables = responsePdu->variables; snmpVariables != nullptr; snmpVariables = snmpVariables->next_variable)
{
QString strOID;
for(size_t i =0; i<snmpVariables->name_length;i++)
{
qDebug()<<"snmpVariables->name[i]"<<snmpVariables->name[i];
strOID.append(".");
strOID.append(QString::number( snmpVariables->name[i]));
}
qDebug()<<"strOID"<<strOID;
unsigned int OIDLen = static_cast<unsigned int> (strOID.length());
qDebug()<<"OID_Length:"<< static_cast<unsigned int> (OIDLen);
unsigned int paramLen = static_cast<unsigned int> (snmpVariables->val_len);
qDebug()<<"paramLen"<<paramLen;
unsigned int txDataLen = 5+OIDLen + paramLen;
qDebug()<<"txDataLen"<<txDataLen;
int totalTxDataLen = txDataLen+PACKET_HEADER_BYTE;
unsigned char *outMessBuff = static_cast<unsigned char *>(malloc(totalTxDataLen));
unsigned char *dataBuff = static_cast<unsigned char *>(malloc(txDataLen));
dataBuff[0] = snmpReqResponse;
dataBuff[1] = static_cast<unsigned char>(OIDLen/256 );
dataBuff[2] = static_cast<unsigned char>(OIDLen%256) ;
dataBuff[3] = static_cast<unsigned char>(paramLen/256) ;
dataBuff[4] = static_cast<unsigned char>(paramLen%256 );
if(OIDLen > 0)
{
memcpy(dataBuff+5,strOID.toAscii(),OIDLen);
}
if(paramLen > 0)
{
memcpy(dataBuff+5+OIDLen,snmpVariables->val.string,paramLen);
}
totalTxDataLen = SnmpMainWidget::IPC.prepareIPCmessage(outMessBuff, dataBuff, static_cast<int>(txDataLen));
SnmpMainWidget::IPC.sendIpcMessageToQt(reinterpret_cast<const char *>(outMessBuff),static_cast<unsigned int>(totalTxDataLen)); // reinterpret_cast bit of dangerous should be good test !!
SnmpMainWidget::IPC.PrintPacketInHex("SNMP-->QT :",outMessBuff, static_cast<unsigned int>(totalTxDataLen));
free(dataBuff);
free(outMessBuff);
}
}
}
else
{
if(snmpStatus == STAT_SUCCESS)
{
fprintf(stderr, "Error in packet\nReason: %s\n", snmp_errstring(responsePdu->errstat));
}
else if(snmpStatus == STAT_TIMEOUT)
{
fprintf(stderr, "Timeout: No response from %s.\n", session->peername);
}
else
{
printf("snmp get requestPdu->command: %d\n", requestPdu->command);
printf("snmp get errstat: %s\n", snmp_errstring(requestPdu->errstat));
printf("snmp get errindex: %s\n", snmp_errstring(requestPdu->errindex));
fprintf(stderr, "session->s_errno %d,session->s_snmp_errno %d \n", session->s_errno, session->s_snmp_errno);
}
if(responsePdu)
{
snmp_free_pdu(responsePdu);
}
snmp_close(session);
}
}
else
return false;
return true;
}
我只是在解决问题。当我查看互联网时,我发现我的代码中缺少 init_snmp("snmpapp");
函数。添加init snmp后,v3 set get message完美发送
snmp_session *snmptypes::fCreateSession(QString IP)
{
struct snmp_session session;
init_snmp("snmpapp");
snmp_sess_init(&session);
session.peername = strdup(IP.toAscii());
.....
}
对于遇到同样问题的人来说,这可能是一个有用的答案。
我目前正在尝试在我的嵌入式设备中开发 snmpManager(linux OS)。此设备应与另一个设备的 snmpAgent 通信。好吧,我的代码适用于 snmpV2c,我的 snmp 数据包也显示在 wireshark pcap 中。但是当我尝试 snmpV3 packets snmp_synch_response(session, requestPdu, &responsePdu)
func return STAT_ERROR
顺便说一句 snmpV2c 是 returning STAT_SUCCESS
我的代码如下所示,我为 v2 创建了 snmp 会话并且v3.
snmp_session *snmptypes::fCreateSession(QString IP)
{
struct snmp_session session;
snmp_sess_init(&session);
session.peername = strdup(IP.toAscii());
static const char* v3_passphrase = "blablabl";
session.retries = 2;
session.timeout = 1000000;
session.engineBoots = 0;
session.engineTime = 0;
QString engineID = "0000000c000000007f000001";
session.contextEngineID = reinterpret_cast<uchar*>(strdup(engineID.toAscii()));
qDebug()<<"contextEngineID:"<<session.contextEngineID;
/*memory allocated by strdup() will be freed by calling snmp_close() */
if(SnmpMainWidget::activeWaveForm == SnmpMainWidget::snmpv2c)
{
session.version = SNMP_VERSION_2c;
const char *str;
QString path = "user";
QByteArray ba;
ba = path.toLatin1();
str = ba.data();
session.community = const_cast<unsigned char*>(reinterpret_cast<const unsigned char *>(str));
session.community_len = path.length();
session.retries = 2;
session.timeout = 1000000;
}
else if (SnmpMainWidget::activeWaveForm == SnmpMainWidget::snmpv3)
{
session.version = SNMP_VERSION_3;
session.securityName = strdup("blabl");
session.securityNameLen = strlen(session.securityName);
session.securityModel = USM_SEC_MODEL_NUMBER;
session.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
session.securityAuthProto = usmHMACMD5AuthProtocol;
// session.securityAuthProtoLen = sizeof (usmHMACMD5AuthProtocol) / sizeof (oid);
session.securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
session.securityPrivProto = usmNoPrivProtocol;
session.securityPrivProtoLen = USM_PRIV_PROTO_NOPRIV_LEN;
session.securityAuthKeyLen =USM_AUTH_KU_LEN;
if (generate_Ku(session.securityAuthProto,session.securityAuthProtoLen,(u_char *) (v3_passphrase),
strlen(v3_passphrase),session.securityAuthKey,
&session.securityAuthKeyLen) != SNMPERR_SUCCESS)
{
qWarning()<<"ERROR KODU"<<generate_Ku(session.securityAuthProto,session.securityAuthProtoLen,(u_char *) (v3_passphrase),
strlen(v3_passphrase),session.securityAuthKey,
&session.securityAuthKeyLen);
snmp_log(LOG_ERR,"Error generating Ku from authentication pass phrase. \n");
exit(1);
}
}
struct snmp_session* openedSession = snmp_open(&session);
if(openedSession == nullptr)
{
snmp_sess_perror(reinterpret_cast<const char*>("No Ack!"), openedSession);
qWarning()<<"Error while Session opening! FILE:"<<__FILE__<<"LINE:"<<__LINE__;
}
else
qDebug()<<"creating session is succeed!";
return openedSession;
}
会话创建成功。到目前为止没有问题。让我们继续,然后我创建如下所示的 pdu,
snmp_pdu *snmptypes::fCreatePDU(tsPDUvariables PDUvariables)
{
// qDebug()<<"nrepeaters"<<PDUvariables.nrepeaters;
// qDebug()<<"mrepeaters"<<PDUvariables.mrepetitions;
qDebug()<<"setParam"<<PDUvariables.setParam;
qDebug()<<"dataType"<<PDUvariables.dataType;
struct snmp_pdu* requestPdu;
oid requestOid[MAX_OID_LEN];
size_t requestOidLength = MAX_OID_LEN;
snmp_parse_oid(static_cast<const char*>(PDUvariables.OID.toAscii()), requestOid, &requestOidLength);
switch (PDUvariables.msgType) {
case snmpGet:
requestPdu = snmp_pdu_create(SNMP_MSG_GET);
if (SnmpMainWidget::activeWaveForm == SnmpMainWidget::snmpv3){
requestPdu->version = SNMP_VERSION_3;
requestPdu->securityName = strdup("user");
requestPdu->securityNameLen = strlen(requestPdu->securityName);
requestPdu->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
requestPdu->securityModel = USM_SEC_MODEL_NUMBER;
}
snmp_add_null_var(requestPdu, requestOid, requestOidLength);
break;
//there are some other case like set,getbulk but don't need to focus these.get enough for now.
}
qDebug()<<"creating PDU is succeed!";
return requestPdu;
}
我终于使用了 snmpget func。用于将 snmp 数据包发送到专用 IP;
问题就在这里,snmpv2 snmpStatus
return 成功但是snmpv3 reutn错误。 snmpv3 数据包没有出现在 wireshark 上,也没有发送。当 V2 运行良好时,我不明白我在 V3 中出了什么问题。
bool snmptypes::fSnmpGet(QString IP,QString OID)
{
const char PACKET_HEADER_BYTE = 4;//4Byte = SOH + len/256 + len%256 + EOH
struct snmp_session* session = fCreateSession(IP);
tsPDUvariables PDUvariables;
PDUvariables.OID = OID;
PDUvariables.msgType = snmpGet;
struct snmp_pdu* requestPdu = fCreatePDU(PDUvariables);
qDebug()<<"PDUvariables.msgType"<<PDUvariables.msgType;
qDebug()<<"PDUvariables.dataType"<<PDUvariables.dataType;
qDebug()<<"PDUvariables.OID"<<PDUvariables.OID;
qDebug()<<"PDUvariables.setParam"<<PDUvariables.setParam;
struct snmp_pdu* responsePdu = nullptr;
if(requestPdu != nullptr && session != nullptr)
{
int snmpStatus = snmp_synch_response(session, requestPdu, &responsePdu);
qDebug()<<"snmpStatus"<<snmpStatus;
qDebug()<<"requestStatus::errStat"<<requestPdu->errstat;
qDebug()<<"session->s_errno"<<session->s_errno;
if(snmpStatus == STAT_SUCCESS)
{
if( responsePdu->errstat == SNMP_ERR_NOERROR and responsePdu->errstat == SNMP_ERR_NOERROR)
{
/* SUCCESS: Print the result variables */
struct variable_list *snmpVariables;
for(snmpVariables = responsePdu->variables; snmpVariables; snmpVariables = snmpVariables->next_variable)
{ qDebug()<<"fSnmpGet"<<__LINE__;
print_variable(snmpVariables->name, snmpVariables->name_length, snmpVariables);
}
for(snmpVariables = responsePdu->variables; snmpVariables != nullptr; snmpVariables = snmpVariables->next_variable)
{
QString strOID;
for(size_t i =0; i<snmpVariables->name_length;i++)
{
qDebug()<<"snmpVariables->name[i]"<<snmpVariables->name[i];
strOID.append(".");
strOID.append(QString::number( snmpVariables->name[i]));
}
qDebug()<<"strOID"<<strOID;
unsigned int OIDLen = static_cast<unsigned int> (strOID.length());
qDebug()<<"OID_Length:"<< static_cast<unsigned int> (OIDLen);
unsigned int paramLen = static_cast<unsigned int> (snmpVariables->val_len);
qDebug()<<"paramLen"<<paramLen;
unsigned int txDataLen = 5+OIDLen + paramLen;
qDebug()<<"txDataLen"<<txDataLen;
int totalTxDataLen = txDataLen+PACKET_HEADER_BYTE;
unsigned char *outMessBuff = static_cast<unsigned char *>(malloc(totalTxDataLen));
unsigned char *dataBuff = static_cast<unsigned char *>(malloc(txDataLen));
dataBuff[0] = snmpReqResponse;
dataBuff[1] = static_cast<unsigned char>(OIDLen/256 );
dataBuff[2] = static_cast<unsigned char>(OIDLen%256) ;
dataBuff[3] = static_cast<unsigned char>(paramLen/256) ;
dataBuff[4] = static_cast<unsigned char>(paramLen%256 );
if(OIDLen > 0)
{
memcpy(dataBuff+5,strOID.toAscii(),OIDLen);
}
if(paramLen > 0)
{
memcpy(dataBuff+5+OIDLen,snmpVariables->val.string,paramLen);
}
totalTxDataLen = SnmpMainWidget::IPC.prepareIPCmessage(outMessBuff, dataBuff, static_cast<int>(txDataLen));
SnmpMainWidget::IPC.sendIpcMessageToQt(reinterpret_cast<const char *>(outMessBuff),static_cast<unsigned int>(totalTxDataLen)); // reinterpret_cast bit of dangerous should be good test !!
SnmpMainWidget::IPC.PrintPacketInHex("SNMP-->QT :",outMessBuff, static_cast<unsigned int>(totalTxDataLen));
free(dataBuff);
free(outMessBuff);
}
}
}
else
{
if(snmpStatus == STAT_SUCCESS)
{
fprintf(stderr, "Error in packet\nReason: %s\n", snmp_errstring(responsePdu->errstat));
}
else if(snmpStatus == STAT_TIMEOUT)
{
fprintf(stderr, "Timeout: No response from %s.\n", session->peername);
}
else
{
printf("snmp get requestPdu->command: %d\n", requestPdu->command);
printf("snmp get errstat: %s\n", snmp_errstring(requestPdu->errstat));
printf("snmp get errindex: %s\n", snmp_errstring(requestPdu->errindex));
fprintf(stderr, "session->s_errno %d,session->s_snmp_errno %d \n", session->s_errno, session->s_snmp_errno);
}
if(responsePdu)
{
snmp_free_pdu(responsePdu);
}
snmp_close(session);
}
}
else
return false;
return true;
}
我只是在解决问题。当我查看互联网时,我发现我的代码中缺少 init_snmp("snmpapp");
函数。添加init snmp后,v3 set get message完美发送
snmp_session *snmptypes::fCreateSession(QString IP)
{
struct snmp_session session;
init_snmp("snmpapp");
snmp_sess_init(&session);
session.peername = strdup(IP.toAscii());
.....
}
对于遇到同样问题的人来说,这可能是一个有用的答案。