def walk(self, host, starting_oid=None, port=161, timeout=10, max_initial_failures=1, max_consequtive_failures=3): """Walks the MIB from the given starting oid, returns a list of (oid, object) tuples""" # TODO: perhaps an OrderedDict is more appropriate? responses = [] attempts_remaining = max_initial_failures datagram = SNMPDatagram(pdu=GetNextRequest.from_oid(starting_oid)) while attempts_remaining: future = self.sendto(datagram, host, port) try: response = yield from asyncio.wait_for(future, timeout=timeout) except asyncio.TimeoutError: logging.debug("Timeout for GetNextRequest(%s, %s)", host, datagram.pdu.oid) if isinstance(attempts_remaining, int): attempts_remaining -= 1 else: assert isinstance(response.pdu, GetResponse) attempts_remaining = max_consequtive_failures logging.debug("Response from host %s: %s=%s", host, response.pdu.oid, response.pdu.response) if datagram.pdu.oid == response.pdu.oid: # end of mib condition break else: responses.append((response.pdu.oid, response.pdu.response)) pdu = GetNextRequest.from_oid(response.pdu.oid) datagram = SNMPDatagram(pdu=pdu) # else: # raise ExceededRetries('Maximum retries exceeded') return responses
def datagram_received(self, datagram, addr): (host, port) = addr try: datagram = SNMPDatagram.decode(datagram) except: print("Malformed packet from:", host, binascii.hexlify(bytes(datagram))) else: # TODO: implement object comparison/equivalence testing key = (host, datagram.pdu.request_id.value) if key in self.requests: try: self.requests[key].set_result(datagram) except asyncio.InvalidStateError: del self.requests[key] else: logging.debug("Unexpected SNMP datagram from %s: %s.", host, datagram) logging.debug("%s", self.requests)
def test_decode(self): snmp_datagrams = list(map(binascii.a2b_hex, ['302602010004067075626c6963a119020452447053020100020100300b300906052b060102010500', '307902010004067075626c6963a26c020452447053020100020100305e305c06082b0601020101010004504c696e7578206e696e6a616c6170707920342e322e352d312d4152434820233120534d5020505245454d505420547565204f63742032372030383a31333a3238204345542032303135207838365f3634', '302902010004067075626c6963a11c020452447054020100020100300e300c06082b060102010101000500', '303302010004067075626c6963a2260204524470540201000201003018301606082b06010201010200060a2b06010401bf0803020a'])) for datagram in snmp_datagrams: print(binascii.hexlify(datagram)) decoded = SNMPDatagram.decode(datagram) print(decoded) encoded = bytes(decoded) print(binascii.hexlify(encoded)) # TODO: __cmp__ or __hash__ perhaps # Not always true for BER # DER uses a canonical form, eg: representation of booleans, and ambiguous length encodings # assert encoded == datagram self.assertEqual(datagram, encoded)
def get_next(self, host, oid=system, port=161): """Creates GetNextResponse PDU / datagram and returns a Future""" pdu = GetNextRequest.from_oid(oid) datagram = SNMPDatagram(pdu=pdu) return self.sendto(datagram, host, port)