etingof / pysnmp

Python SNMP library
http://snmplabs.com/pysnmp/
BSD 2-Clause "Simplified" License
581 stars 200 forks source link

getNext can only return "children" of requested OID or walk the full MIB tree #153

Open Parcley opened 6 years ago

Parcley commented 6 years ago

when I am sending a single getNext for SNMPv2-MIB::sysUpTime.0, I am expecting to get a reply with the single binding SNMPv2-MIB::sysContact.0

This is also, what I am getting when using the net-snmp command line tools:

# snmpgetnext -v 2c -r 0 -c public <some-ip>:161 SNMPv2-MIB::sysUpTime.0 
SNMPv2-MIB::sysContact.0 = STRING: <some-string>
#

when I try to to the same with pysnmp using the command generator, I have two choices: a)

nextCmd(SnmpEngine(),
    CommunityData(community),
    UdpTransportTarget((host, port)),
    ContextData(),
    ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysUpTime')),
        lexicographicMode=False):   

requesting with lexicographicMode=False (which is the default). In this case, I get no bindings as result (NoSuchObject).

b)

nextCmd(SnmpEngine(),
    CommunityData(community),
    UdpTransportTarget((host, port)),
    ContextData(),
    ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysUpTime')),
        lexicographicMode=True):    

requesting with lexicographicMode=True. In this case, I get the whole MIB tree following sysUpTime as result.

I can see no way to achieve the net-snmp behaviour (which is the correct behaviour in my opinion)

I think that this line is causing the problem: https://github.com/etingof/pysnmp/blob/master/pysnmp/hlapi/asyncore/sync/cmdgen.py#L385

by checking for initialVars[idx].isPrefixOf(name), any siblings or parents of the initially requested OID are no valid results (which they should be)

would it be valid to remove this check?

etingof commented 6 years ago

First of, I am sorry for not handling this issue for so long... Life happens, you know. ;-)

Looking at the situation "a", I think this query should return just sys.UpTime.0 if this object exists at the agent or nothing e.g. empty list of var-binds. At least this is how it is supposed to behave.

With situation "b" you should get the whole MIB, that's right. I'm interested to learn if sysUpTime.0 object is among the returned set?

Note that when you request sysUpTime, the likely next object is sysUpTime.0. If it is absent at the agent, the next object might be sysContact.0 which belongs to a different OID subtree than sysUpTime therefore it should not be returned. This is exactly what the condition you dropped is all about.

To figure out why GETNEXT sysUpTime does not return sysUpTime.0 we probably need to enable pysnmp debugging and look what's coming from your agent:

from pysnmp import debug
debug.setLogger(debug.Debug('all'))

What do you think?

Parcley commented 6 years ago

regarding situation "a":

here is my complete source code for the test

from pysnmp.entity.rfc3413.oneliner import cmdgen
from pysnmp import debug as pysnmpdebug

pysnmpdebug.setLogger(pysnmpdebug.Debug('all'))

mibVar = cmdgen.MibVariable('SNMPv2-MIB', 'sysUpTime', 0)
mibVar.addAsn1MibSource('/usr/share/snmp/mibs/')

errorIndication, errorStatus, errorIndex, varBinds = cmdgen.CommandGenerator().nextCmd(
    cmdgen.CommunityData("public"),
    cmdgen.UdpTransportTarget( ('172.29.13.235', 161)),
    mibVar,
    **({'lookupNames':'True', 'lookupValues':'True'})#, 'lexicographicMode':'True'})
)
print('varbinds: ')
print '[%s]' % ', '.join(map(str, varBinds))

and this is the output generated: output.txt

In line 1038 of output.txt, you can see that the varBind is received but when printing varBinds (or checking it in the debugger), varBinds (in line 9 of my code) is an empty list

regarding situation "b":

so sysUpTime.0 is missing

lextm commented 2 months ago

The old nextCmd is actually GET NEXT based WALK operation.

This was only fixed in recent releases, where nextCmd and walkCmd are both presented and serve different purposes.