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());
.....
}

对于遇到同样问题的人来说,这可能是一个有用的答案。