[SNMP4J] USM error handling

Tharsiny Markandu tmarkandu at gmail.com
Wed Aug 12 22:48:23 CEST 2009


Hi Frank,

I'm looking at how USM errors are handled in Snmp4j.  I would like to report
to the users of SNMP code, when SNMP receives an USM error.
That is, I would like to report the following errors:
- unsupported security level
- not in time window
- unknown user name
- unknown engine id
- wrong digest
- decrypt error.


I'm working on the manager code and I do gets on the agents (various types
of NEs). This is the code I'm using to check the response to my synchronous
get requests.

public VarBindList checkRequestStatus(ResponseEvent respEvt,
                                          boolean recovTooBig,
                                          SnmpIpAddress nodeIpAddr,
                                          boolean updateReachability,
                                          SnmpConfig snmpConfig)
            throws SnmpException {
        if (respEvt == null) { // The request got interrupted
            Log.logWarning(SnmpConstants.SNMP_LOG_MODULE, "SNMP request
interrupted");
            throw new SnmpInterruptedException();
        }
        PDU resp = respEvt.getResponse();
        PDU req = respEvt.getRequest();
        if (isDebugLog()) {
            Log.logDebug(SnmpConstants.SNMP_LOG_MODULE,
respEvtToString(respEvt));
        }

        if (resp == null) { // Request Timed Out
            Log.logInfo(SnmpConstants.SNMP_LOG_MODULE, "SNMP Request Timeout
for " +
                        nodeIpAddr + ": " + req);

            throw new SnmpTimeoutException(snmpConfig.getTimeout(),
                    snmpConfig.getRetries(),
                    nodeIpAddr);
        } else {

            // extract address from the message
            Address addr = respEvt.getPeerAddress();
            StringTokenizer st = new StringTokenizer(addr.toString(), "/");
            String ipAddr = st.nextToken();
            int port = ((TransportIpAddress) addr).getPort();
            SnmpIpAddress nodeIp = new SnmpIpAddress(ipAddr, port);
            if (!nodeIp.equals(nodeIpAddr)) {
                Log.logError(SnmpConstants.SNMP_LOG_MODULE,
                        "Invalid Node Ip Address Argument: Node Ip Address
Passed: " + nodeIpAddr +
                                " IP address from Transport: " + nodeIp);
                throw new UnexpectedException("IP address specifed does not
match IP addrss from Transport");
            }
            int status = resp.getErrorStatus();
            if (status != PDU.noError) {
                if (status == PDU.authorizationError) {
                    Log.logError(SnmpConstants.SNMP_LOG_MODULE,
                            "Authorization Failed" + resp);
                    throw new SnmpRequestException(respEvt);
                } else if (status == PDU.wrongEncoding || status ==
PDU.genErr) {
                    // FIXME - retry here - the DecodingError may be
transient
                    Log.logError(SnmpConstants.SNMP_LOG_MODULE,
                            "Bad PDU from " + nodeIpAddr +
                                    " (node bug that should be reported):\n"
+ resp);
                    throw new SnmpRequestException(respEvt);
                } else if ((status == PDU.tooBig)) {
                    Log.logError(SnmpConstants.SNMP_LOG_MODULE,
                            "Too Big error (" + resp.getErrorStatusText()
                                    + "). Request: " + req + " from "
                                    + nodeIpAddr);
                    if (req.getType() == PDU.GET && recovTooBig) {
                        Log.logInfo(SnmpConstants.SNMP_LOG_MODULE,
                                "Attempting to recover from Too Big error"
                                        + "for Get Request: " +
req.getRequestID()
                                        + " to " + nodeIpAddr);
                        return recoverTooBigGetRequest(
                                (Vector<VariableBinding>)
req.getVariableBindings(), nodeIpAddr, snmpConfig);
                    } else {
                        throw new SnmpRequestException(respEvt);
                    }
                } else if (status == PDU.wrongLength) {
                    // Don't log the the error.  It's sometimes expected.
                    throw new SnmpRequestException(respEvt);
                } else {
                    Log.logError(SnmpConstants.SNMP_LOG_MODULE,
                            "Error (" + resp.getErrorStatusText()
                                    + "). Response: " + resp
                                    + " from " + nodeIpAddr);
                    throw new SnmpRequestException(respEvt);
                }
            } else if (resp.getType() == PDU.REPORT) {
                Log.logError(SnmpConstants.SNMP_LOG_MODULE,
                        "Received REPORT PDU:" + resp + " from " +
nodeIpAddr);
                *throwReportPduException(resp, snmpConfig, nodeIpAddr);
*                return null;
            } else {
                return null;
            }
        }
    }

    private void throwReportPduException(PDU resp, SnmpConfig snmpConfig,
SnmpIpAddress ipAddr) throws SnmpException {
        Log.logError(SnmpConstants.SNMP_LOG_MODULE,
                "Received REPORT PDU:" + resp + " from " + ipAddr);
        Vector varBindList = resp.getVariableBindings();
        VariableBinding vb = (VariableBinding) varBindList.elementAt(0);
        determineUsmStats(vb, snmpConfig, ipAddr);

    }

    private void determineUsmStats(VariableBinding vb, SnmpConfig
snmpConfig, SnmpIpAddress ipAddr)
            throws SnmpException {
        MibOid oid = new MibOid(vb.getOid().getValue());
        int errCount = vb.getVariable().toInt();
        if (oid.equals(SnmpConstants.USM_STATS_UNSUPPORTED_SEC_LEVELS)) {
            Log.logError(SnmpConstants.SNMP_LOG_MODULE, "REPORT PDU received
from " + ipAddr +
                    " with Unsupported Security Level count of " + errCount
+ "(SnmpConfig: " + snmpConfig + ")");
            throw new SnmpUsmUnsupportedSecLevelException(ipAddr,
String.valueOf(errCount));
        } else if (oid.equals(SnmpConstants.USM_STATS_DECRYPT_ERRORS)) {
            Log.logError(SnmpConstants.SNMP_LOG_MODULE, "REPORT PDU received
from " + ipAddr +
                    " with Decryption Error count of " + errCount +
"(SnmpConfig: " + snmpConfig + ")");
            throw new SnmpUsmDecryptErrorException(ipAddr,
String.valueOf(errCount));
        } else if (oid.equals(SnmpConstants.USM_STATS_NOT_IN_TIME_WINDOWS))
{
            Log.logError(SnmpConstants.SNMP_LOG_MODULE, "REPORT PDU received
from " + ipAddr +
                    " with Not In Time Window count of " + errCount +
"(SnmpConfig: " + snmpConfig + ")");
            throw new SnmpUsmNotInTimeWindowException(ipAddr,
String.valueOf(errCount));
        } else if (oid.equals(SnmpConstants.USM_STATS_UNKNOWN_ENGINE_ID)) {
            Log.logError(SnmpConstants.SNMP_LOG_MODULE, "REPORT PDU received
from " + ipAddr +
                    " with Unknown Engine Id count of " + errCount +
"(SnmpConfig: " + snmpConfig + ")");
            throw new SnmpUsmUnknownEngineIdException(ipAddr,
String.valueOf(errCount));
        } else if (oid.equals(SnmpConstants.USM_STATS_UNKNOWN_USER_NAME)) {
            Log.logError(SnmpConstants.SNMP_LOG_MODULE, "REPORT PDU received
from " + ipAddr +
                    " with Unknown Security Name count of " + errCount +
"(SnmpConfig: " + snmpConfig + ")");
            throw new SnmpUsmUnknownSecurityNameException(ipAddr,
String.valueOf(errCount));
        } else if (oid.equals(SnmpConstants.USM_STATS_WRONG_DIGEST)) {
            Log.logError(SnmpConstants.SNMP_LOG_MODULE, "REPORT PDU received
from " + ipAddr +
                    " with Wrong Digest count of " + errCount +
"(SnmpConfig: " + snmpConfig + ")");
            throw new SnmpUsmWrongDigestException(ipAddr,
String.valueOf(errCount));
        } else {
            Log.logError(SnmpConstants.SNMP_LOG_MODULE, "Unexpected OID
found in REPORT PDU: " + oid);
            throw new IllegalStateException("Unexpected OID found in REPORT
PDU: " + oid);
        }
    }


I've noticed that when I get an unknownEngineId and notInTimeWindow Report
PDU from the NEs (agents),  respEvt.getResponse() is null.  But if I get an
unknown securityName and wrong digest error from the agent,
respEvt.getResonpse() is of type REPORT and I can get the corresponding
error log.

Is respEvent.getResponse() supposed to be null when agent returns
"unknownEngineId and notInTimeWindow"?  Do I need to add
AuthenticationFailureListeners to listen to unknownEngineId and
notInTimeWindow errors?



Thanks,
Tharsiny



More information about the SNMP4J mailing list