OidCollections Filter

Hi Frank,

I am trying to better understand how to create a better trap receiver. If I understand correctly appending oids to an Snmp_pp::OidCollection and passing it to the snmp.notify_register function will filter incoming trap notification messages. However I am having a hard time understanding how to implement this.

If I understand correctly passing it an OidCollection object that is empty will just allow any and all notifications through. The following code exhibits this expected behavior.

Snmp_pp::OidCollection oidc;
Snmp_pp::TargetCollection targetc;
status = snmp.notify_register(oidc,targetc,static_my_callback,NULL);

I then attempted to modify the code by appending and Oid object to the OidCollection Object to see if it would allow this trap notification to be processed.


Snmp_pp::OidCollection oidc;
oidc += Snmp_pp::Oid("1.2.3.4.5.6.0.7");
Snmp_pp::TargetCollection targetc;
status = snmp.notify_register(oidc,targetc,static_my_callback,NULL);

However this doesn’t seem to work as expected as no traps appear to be processed.

It is my understanding that the typical trap PDU will consist of:

Here’s a code snippet of my snmp4j agent preparing the trap notification PDU:

pdu.add(new VariableBinding( new Oid("1.3.6.1.2.1.1.3.0"), new OctetString("4:06:20.44") ));
pdu.add(new VariableBinding( new Oid("1.3.6.1.6.3.1.1.5"), new OctetString("1.2.3.4.5.6.0.7") ));
pdu.add(new VariableBinding( new Oid("1.2.3.4.5.6.7.0"), new OctetString("Hello_World") ));

I am wondering if I can get some explaination how this OidCollection is expected to behave and how to get it to filter for trap notification that I provide it?

Hi,

the filter filters the received trap Pdu only on the value of pdu.get_notify_id(trapid);.

A filter for the trap produced by the snmpTraps.cpp example would need to set one Oid of the OidCollection to 1.3.6.1.4.1.11.2.16.2.

Kind regards,
Jochen

Okay so the callback function will always be invoked, but the actual filtering occurs in the callback?
A trivial code example would be something like this?

void TrapReciever::static_my_callback(int reason, Snmp_pp::Snmp snmp*, Snmp_pp::Pdu &pdu, Snmp_pp::SnmpTarget &target, void *cd)
{
bool status;
Snmp_pp::oid id;
status = pdu.get_notify_id(id);
if(status)
{
//Do processing
.}
}

So lets say that a single PDU carries multiple variable bindings inside.

The first variable binding will always be a time stamp
pdu.add(new VariableBinding( new Oid("1.3.6.1.2.1.1.3.0"), new OctetString("4:06:20.44") ));

The second variable binding will always be SnmpTrapOid which contains the actual trap Oid Address specified in its MIB documentation.
pdu.add(new VariableBinding( new Oid("1.3.6.1.6.3.1.1.4.1"), new OctetString("1.2.3.4.5.6.0.7") ));

The 3rd-nth variable binding will be the oid and its value that needs to be processed.
pdu.add(new VariableBinding( new Oid("1.2.3.4.5.6.7.0"), new OctetString("Hello_World") ));
pdu.add(new VariableBinding( new Oid("1.2.3.4.5.6.8.0"), new OctetString("Hello_World1") ));
pdu.add(new VariableBinding( new Oid(" 1.3.6.1.4.1.11.2.16.2"), new OctetString("Hello_World2") ));

My questions are:

  • Does the filter only take into consideration of the first variable binding in the PDU
oidc += Snmp_pp::Oid("1.3.6.1.2.1.1.3.0");
  • Does the filter use the 1.3.6.1.6.3.1.1.4. Oid address’s value to use a filter,
oidc += Snmp_pp::Oid("1.2.3.4.5.6.0.7");
  • Or does the filter take into consideration all values in the pdu?
oidc += Snmp_pp::Oid("1.3.6.1.2.1.1.3.0");
oidc += Snmp_pp::Oid("1.2.3.4.5.6.0.7");
oidc += Snmp_pp::Oid("1.2.3.4.5.6.7.0");
oidc += Snmp_pp::Oid("1.2.3.4.5.6.8.0");
oidc += Snmp_pp::Oid(" 1.3.6.1.4.1.11.2.16.2");
  • What if i were to want to use the TargetCollection to use as a filter?

Hi,

if you are setting a OidCollection, the received Pdus are filtered before your callback is called. The code inside snmp++ does something like this for filtering using OidCollection:

  Oid trapid;
  pdu.get_notify_id(trapid); // pdu is the received Pdu
  if (oidCollection.contains(trapid))
     do_the_user_callback();
  else
    drop_the_pdu(); 

In your callback function, you can of course do some additional filtering. In your example the code of snmp++ can only filter on the SnmpTrapOid, as this Oid is set on the Pdu using Pdu::set_notify_id().

If you set both (OidCollection and TargetCollection), your callback will be called if one of the filters matches. The TargetCollection filter will check for the source address (including port if you use UdpAddress), SNMP version and community.

Kind regards,
Jochen

Given the following pdu packed with the following Variable Bindings:
Question 1:
How would I filter this PDU from being processed? Given that the variable binding pdu.add(new VariableBinding( new Oid("1.3.6.1.6.3.1.1.4.1"), new OctetString("1.2.3.4.5.6.0.7") )) specifies a specific Trap Notification and the following Vbs describe what is being notified; would we add, ("1.2.3.4.5.6.0.7") to the OID collection?

Question 2:
Instead of filtering out this specific Trap notification, is there a method to filter all traps except for a given set? So all other trap notifications an informs will be ignored except for notification “1.2.3.4.5.6.0.7”

Hi,

the Oids in the OidCollection specify all Oids that you want your callback to be called with. If you want, that your callback is only called for notifications with id “1.2.3.4.5.6.0.7”, you will have to add “1.2.3.4.5.6.0.7” to the OidCollection.

There is no possibility to pass an OidCollection with ids that should be dropped.

Kind regards,
Jochen

That’s very strange then. The only way that I have been able to get it to trigger the callback is if I provide empty entries for OidCollection and TargetCollection to notify_register. It shouldn’t matter that I’m using snmp4j as the trap sender would it?

It does not matter, which tool is sending the trap. What Oid do you get in the callback from the Pdu using pdu.get_notify_id()?

Kind regards,
Jochen

It doesn’t return anything. if I check the returned boolean it’s == 1. This leads me to think that maybe I’m using the snmpTrapOID incorrectly?

Here is an example of the VBs coming from the received PDU
vb[0]: 1.3.6.1.2.1.1.3.0 = 4:06:20.44
vb[1]: 1.3.6.1.6.3.1.1.4.1.0 = 1.3.6.1.4.1.2.3.2.2.1.0.1
vb[2]: 1.3.6.1.4.1.2.3.2.2.1.1.0 = “Hello World”
vb[3]: 1.3.6.1.4.1.2.3.2.2.1.2.0 = “Hello World2”

If I put 1.3.6.1.4.1.2.3.2.2.1.0.1 into the oidsCollection, the call back is never called

The Vbs inside the Pdu are not used for filtering, only the Oid that you can get using Pdu::get_notify_id(Oid &id).

My apologies, I discovered that I had made a silly mistake! When packing the PDU from the trap sender I accidentally made the variable for the snmpTrapOid as type OctetString and not of type OID…

I Had:
pdu.add(new VariableBinding( new Oid("1.3.6.1.6.3.1.1.4.1.0"), new OctetString("1.3.6.1.4.1.2.3.2.2.1.0.1") ) )
Instead of:
pdu.add(new VariableBinding( new Oid("1.3.6.1.6.3.1.1.4.1.0"), new OID("1.3.6.1.4.1.2.3.2.2.1.0.1") ) )

After changing this the filetering works as expected!

Thank you for for patience and guidance :slight_smile: