puresnmp
puresnmp copied to clipboard
Trap receiver throws exception
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
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.