puresnmp icon indicating copy to clipboard operation
puresnmp copied to clipboard

Trap receiver throws exception

Open aschamberger opened this issue 2 years ago • 1 comments

Issue Description

I tried to implement a trap receiver and it raises the following exception:

Exception in callback _SelectorDatagramTransport._read_ready()
handle: <Handle _SelectorDatagramTransport._read_ready()>
Traceback (most recent call last):
  File "/usr/lib/python3.9/asyncio/events.py", line 80, in _run
    self._context.run(self._callback, *self._args)
  File "/usr/lib/python3.9/asyncio/selector_events.py", line 1029, in _read_ready
    self._protocol.datagram_received(data, addr)
  File "/usr/local/lib/python3.9/dist-packages/puresnmp/transport.py", line 80, in datagram_received
    self.callback(SocketResponse(data, SocketInfo(addr[0], addr[1])))
  File "/usr/local/lib/python3.9/dist-packages/puresnmp/api/raw.py", line 903, in decode
    mproc = mpm.create(obj[0].value, handler, lcd)
TypeError: 'Integer' object is not subscriptable

My code:

import asyncio
from puresnmp import V1, V2C
from puresnmp.api.raw import register_trap_callback

port = 162
credentials = V2C('public')

def callback(trap)
    print(trap)

loop = register_trap_callback(callback, port=port, credentials=credentials)

async def main():
    while True:
        await asyncio.sleep(3600)

loop.run_until_complete(main())

HexDump

aschamberger avatar Oct 07 '22 18:10 aschamberger

First, @aschamberger - in your code: Your callback needs to be async (and, it's missing a trailing colon). Fixing that block:

async def callback(trap):
	print(trap)

Then, there is an issue within the library here that also needs to be fixed.

Referencing: https://github.com/exhuma/puresnmp/blob/18acb9ade68ace5c998693ab942cbe70279aa149/puresnmp/api/raw.py#L889-L904

I don't believe the cast type on line # 900 is correct, as as_sequence[0] actually comes back as Integer(1) - reflecting the received SNMP version, in this case, v2c. As such, obj becomes (only) that Integer - and the current code is then trying to subscript an Integer, which is not possible - but also, surely not the intended action.

I think the quickest and one of the more correct fixes here is to fix the cast on the same line to instead cast the entire sequence,

However, then as_sequence actually comes back as Sequence[Integer, OctetString, Trap] - where the middle value / OctetString is the received SNMP community name (not a 2nd Integer, as currently declared). I'm not concerned with the Sequence vs. Tuple here. Combined, this is all just for semantics to support type hints...

Combined, this should be a proper fix:

        obj = cast(Tuple[Integer, OctetString, Trap], as_sequence)

Finally - I'd have too many questions for @exhuma here - but to start with, I think it would be nice to make more information around the larger trap that was received to the callback. I.E., I'd like to still at least have a supportable option for getting back the SocketInfo (for knowledge of the IP address and port that the trap was sent from), the community, and even the SNMP version indicator for potential consideration and use within the callback.

ziesemer avatar Mar 26 '23 21:03 ziesemer