1
votes

I've applied a sample of using snmp4j for sending and receiving traps and everything is ok.
but the issue is :
when using mule esb for receiving snmp traps, I can't convert the incoming message payload to PDU (or any snmp4j suitable object) to extract data from, I've done a lot of search but in vain.
can anyone assist me to :
convert mule esb message payload that I've received from udp endpoint to org.snmp4j.PDU object to extract trap data from?
here is my code :

public synchronized MuleEvent process(MuleEvent event) throws MuleException {
        byte[] encodedMessage = event.getMessage().getPayload(byte[].class);
        //next line is not working but its only sample of what I Am looking for 
        PDU pdu = new PDU(encodedMessage );
.....

any assistance is highly appreciated
3
What does the byte[] payload consist in? Is it a serialized org.snmp4j.PDU object? Something else?David Dossot

3 Answers

1
votes
public class SNMP4JParser implements Callable {

    /**
     * The following objects are all necessary in order to use SNMP4j as a parser for raw messages.
     * This was all inspired by SNMP4j source code, in particular MessageDispatcherImpl.java
     */
    private MessageProcessingModel model = null;
    private MessageDispatcher dispatcher = null;
    private Address listenAddress = null;
    private Integer32 messageProcessingModel = null;
    private Integer32 securityModel = null;
    private OctetString securityName = null;
    private Integer32 securityLevel = null;
    private PduHandle handle = null;
    private StatusInformation statusInfo = null;
    private MutableStateReference mutableStateReference = null;

    /**
     * Taken from org.snmp4j.transport.AbstractTransportMapping class
     */
    protected Integer32 maxInboundMessageSize = new Integer32 ( (1 << 16) - 1 );

    /**
     * Taken from org.snmp4j.MessageDispatcherImpl class
     */
    private int transactionID = new Random().nextInt(Integer.MAX_VALUE - 2) + 1;

    /**
     * Create all objects that SNMP4j needs to parse a raw SNMP message
     */
    public SNMP4JParser()
    {
        model = new MPv1();
        dispatcher = new MessageDispatcherImpl();
        listenAddress = GenericAddress.parse("udp:0.0.0.0/2001");
        messageProcessingModel = new Integer32();
        securityModel = new Integer32();
        securityName = new OctetString();
        securityLevel = new Integer32();
        handle = new PduHandle(transactionID);
        statusInfo = new StatusInformation();
        mutableStateReference = new MutableStateReference();
    }

    /**
     * @see org.mule.api.lifecycle.Callable#onCall(org.mule.api.MuleEventContext)
     */
    @Override
    public Object onCall(MuleEventContext eventContext) throws Exception
    {
        byte[] payloadBytes = eventContext.getMessage().getPayloadAsBytes();
        ByteBuffer buffer = ByteBuffer.wrap(payloadBytes);
        BERInputStream wholeMessage = new BERInputStream(buffer);
        MutablePDU mutablePdu = new MutablePDU();

        int status = model.prepareDataElements(
                dispatcher, 
                listenAddress, 
                wholeMessage,
                messageProcessingModel, 
                securityModel,
                securityName, 
                securityLevel, 
                mutablePdu,
                handle, 
                maxInboundMessageSize, 
                statusInfo,
                mutableStateReference);

        if ( status !=  SnmpConstants.SNMP_MP_OK )
            throw new RuntimeException(
                "Couldn't parse SNMP message. model.prepareDataElements() returned " + status);

        return mutablePdu.getPdu();
    }

}

I've tested it with a flow like this ( I used snmp4j-1.11.5 and mule-standalone-3.4.0 )

<udp:connector name="connector" doc:name="UDP"/>
<flow name="snmp-demo-trapHandlingFlow" doc:name="snmp-demo-trapHandlingFlow">
    <udp:inbound-endpoint host="0.0.0.0" port="2001" responseTimeout="10000"  doc:name="UDP"/>
    <logger message="TRAP RECEIVED - #[System.currentTimeMillis()]" level="DEBUG" doc:name="Inbound timestamp"/>
    <component class="com.netboss.flow.demo.SNMP4JParser" doc:name="SNMP4JParser"/>
    [...]

And it works.

Now, I realize there are still some open questions:

  1. Is there a better/more efficient way of doing it?
  2. This works only for SNMP v1, how do I modify the above code to make it work with v2 and v3 as well?
1
votes

You can convert a BER stream to a SNMP4J PDU much easier when you implement your own TransportMapping and associate that with the SNMP4J MessageDispatcherImpl. Then add all the necessary MessageProcessingModels and SecurityProtocols to the message dispatcher.

Finally, add your implementation of the CommandResponder interface to the message dispatcher and you are done.

0
votes

You need to create a custom transformer that transforms the message payload in the relevant SNMP4J object. Alternatively this can be done with an expression transformer if the SNMP4J API is simple enough.