Search code examples
responsesnmpsnmp4j

SNMP4j - Cannot send RESPONSE PDU on some OID


I'm trying to respond to SNMP GET requests from SnmpB with SNMP4j 2.3.1 (running on Windows).

In "Discover" mode, SnmpB queries by broadcasting 255.255.255.255 (checked with Wireshark) and I receive a GET request with standard OID (sysDescr, sysUpTime, sysContact, sysName and sysLocation). It finds my instance with the information I coded ("My System", "Myself", ...) (note that it also works when I enter the IP address under the "IP networks" textboxes, though I don't see any traffic on Wireshark but I receive the GET request):

SnmpB discovery

I did write a very simple MIB file that I imported into SnmpB. It defines a single Integer32 data that I want to retrieve using an SNMP GET request from SnmpB.

However, using the same code than for the standard sys* OID, SnmpB doesn't seem to receive that data ("Timeout" in red on the top-right):

SnmpB timeout

I did try Wireshark to check network activity and I don't see anything, so I guess it takes place on localhost (which is not accessible with Wireshark on Windows)? But the traces below show it does not (peerAddress=192.168.56.1)...

Here is the MIB file (code follows):

MY-TEST-MIB DEFINITIONS ::= BEGIN

IMPORTS
    enterprises, MODULE-IDENTITY, OBJECT-TYPE, Integer32
        FROM SNMPv2-SMI;

myTest MODULE-IDENTITY
    LAST-UPDATED "201412301216Z"
    ORGANIZATION "My org"
    CONTACT-INFO "Matthieu Labas"
    DESCRIPTION "MIB Test"
    REVISION "201412301216Z"
    DESCRIPTION "Generated"
    ::= { enterprises 12121 }

myData OBJECT-TYPE
    SYNTAX Integer32
    MAX-ACCESS read-only
    STATUS current
    DESCRIPTION "My data for test"
    ::= { myTest 1 }

END

... and the code:

public class RespondGET implements CommandResponder {

    public static final OID sysDescr = new OID("1.3.6.1.2.1.1.1.0");
    public static final OID sysUpTime = new OID("1.3.6.1.2.1.1.3.0");
    public static final OID sysContact = new OID("1.3.6.1.2.1.1.4.0");
    public static final OID sysName = new OID("1.3.6.1.2.1.1.5.0");
    public static final OID sysLocation = new OID("1.3.6.1.2.1.1.6.0");

    public static final OID myData = new OID("1.3.6.1.4.1.12121.1.0");

    private Snmp snmp;

    public RespondGET() throws IOException {
        MessageDispatcher dispatcher = new MessageDispatcherImpl();
        dispatcher.addMessageProcessingModel(new MPv2c()); // v2c only
        snmp = new Snmp(dispatcher, new DefaultUdpTransportMapping(new UdpAddress("192.168.56.1/161"), true));
        snmp.addCommandResponder(this);
        snmp.listen();
    }

    @Override
    public void processPdu(CommandResponderEvent event) {
        System.out.println("Received PDU "+event);
        PDU pdu = event.getPDU();
        switch (pdu.getType()) {
            case PDU.GET:
                List<VariableBinding> responses = new ArrayList<VariableBinding>(pdu.size());
                for (VariableBinding v : pdu.getVariableBindings()) {
                    OID oid = v.getOid();
                    // Answer the usual SNMP requests
                    if (sysDescr.equals(oid)) {
                        responses.add(new VariableBinding(oid, new OctetString("My System description")));
                    } else if (sysUpTime.equals(oid)) {
                        responses.add(new VariableBinding(oid, new TimeTicks(ManagementFactory.getRuntimeMXBean().getUptime())));
                    } else if (sysContact.equals(oid)) {
                        responses.add(new VariableBinding(oid, new OctetString("Myself")));
                    } else if (sysName.equals(oid)) {
                        responses.add(new VariableBinding(oid, new OctetString("My System")));
                    } else if (sysLocation.equals(oid)) {
                        responses.add(new VariableBinding(oid, new OctetString("In here")));
                    } else if (myData.equals(oid)) { // MyData handled here
                        responses.add(new VariableBinding(oid, new Integer32(18)));
                    }
                }

                try {
                    CommunityTarget comm = new CommunityTarget(event.getPeerAddress(), new OctetString(event.getSecurityName()));
                    comm.setSecurityLevel(event.getSecurityLevel());
                    comm.setSecurityModel(event.getSecurityModel());
                    PDU resp = new PDU(PDU.RESPONSE, responses);
                    System.out.println(String.format("Sending response PDU to %s/%s: %s", event.getPeerAddress(), new String(event.getSecurityName()), resp));
                    snmp.send(resp, comm);
                } catch (IOException e) {
                    System.err.println(String.format("Unable to send response PDU! (%s)", e.getMessage()));
                }
                event.setProcessed(true);
                break;

            default:
                System.err.println(String.format("Unhandled PDU type %s.", PDU.getTypeString(pdu.getType())));
                break;
        }
    }

    public static void main(String[] args) throws IOException {
        RespondGET rg = new RespondGET();
        System.out.println("Listening...");
        int n = 300; // 5 min
        while (true) {
            try { Thread.sleep(1000); } catch (InterruptedException e) { }
            if (--n <= 0) break;
        }
        System.out.println("Stopping...");
        rg.snmp.close();
    }

}

It produces the following output when I click "discover" under SnmpB and right-click on myData in the MIB Tree and "Get" (slightly reformatted for readability):

Listening...
Received PDU CommandResponderEvent[securityModel=2, securityLevel=1, maxSizeResponsePDU=65535,
    pduHandle=PduHandle[16736], stateReference=StateReference[msgID=0,pduHandle=PduHandle[16736],
    securityEngineID=null,securityModel=null,securityName=public,securityLevel=1,
    contextEngineID=null,contextName=null,retryMsgIDs=null], pdu=GET[requestID=16736, errorStatus=Success(0), errorIndex=0,
    VBS[1.3.6.1.2.1.1.1.0 = Null; 1.3.6.1.2.1.1.3.0 = Null; 1.3.6.1.2.1.1.4.0 = Null; 1.3.6.1.2.1.1.5.0 = Null; 1.3.6.1.2.1.1.6.0 = Null]],
    messageProcessingModel=1, securityName=public, processed=false, peerAddress=192.168.56.1/49561, transportMapping=org.snmp4j.transport.DefaultUdpTransportMapping@120d62b, tmStateReference=null]

Sending response PDU to 192.168.56.1/49561/public: RESPONSE[requestID=0, errorStatus=Success(0), errorIndex=0,
    VBS[1.3.6.1.2.1.1.1.0 = My System description; 1.3.6.1.2.1.1.3.0 = 0:01:03.18; 1.3.6.1.2.1.1.4.0 = Myself; 1.3.6.1.2.1.1.5.0 = My System; 1.3.6.1.2.1.1.6.0 = In here]]

Received PDU CommandResponderEvent[securityModel=2, securityLevel=1, maxSizeResponsePDU=65535,
    pduHandle=PduHandle[1047], stateReference=StateReference[msgID=0,pduHandle=PduHandle[1047],
    securityEngineID=null,securityModel=null,securityName=public,securityLevel=1,
    contextEngineID=null,contextName=null,retryMsgIDs=null], pdu=GET[requestID=1047, errorStatus=Success(0), errorIndex=0,
    VBS[1.3.6.1.4.1.12121.1.0 = Null]], messageProcessingModel=1, securityName=public, processed=false, peerAddress=192.168.56.1/49560, transportMapping=org.snmp4j.transport.DefaultUdpTransportMapping@120d62b, tmStateReference=null]

Sending response PDU to 192.168.56.1/49560/public: RESPONSE[requestID=0, errorStatus=Success(0), errorIndex=0, VBS[1.3.6.1.4.1.12121.1.0 = 18]]

Stopping...

What am I missing here? Could that "just" be a network routing issue?


Solution

  • After setting up a VM and checking with Wireshark, it turned out I forgot to set, on the response PDU, the same request ID than the GET PDU.

    GET request ID Response null request ID

    It was solved by adding resp.setRequestID(pdu.getRequestID()); when building the response PDU

    CommunityTarget comm = new CommunityTarget(event.getPeerAddress(), new OctetString(event.getSecurityName()));
    comm.setSecurityLevel(event.getSecurityLevel());
    comm.setSecurityModel(event.getSecurityModel());
    PDU resp = new PDU(PDU.RESPONSE, responses);
    resp.setRequestID(pdu.getRequestID()); // Forgot that!
    snmp.send(resp, comm);
    

    SnmpB received PDU

    Thanks to @Jolta for his patience during New Year holiday and his insisting on using Wireshark for further checking. :)