# Transport tweaks

## Broadcast SNMP message (IPv4)

Send SNMP GET request to broadcast address and wait for respons(es):

- with SNMPv2c, community ‘public’

- over IPv4/UDP

- to all Agents via broadcast address 255.255.255.255:161

- for OIDs in tuple form

Here we send out a single SNMP request and wait for potentially many SNMP responses from multiple SNMP Agents listening in local broadcast domain. Since we can’t predict the exact number of Agents responding, this script just waits for arbitrary time for collecting all responses. This technology is also known as SNMP-based discovery.

This script performs similar to the following Net-SNMP command:

$ snmpget -v2c -c public -ObentU 255.255.255.255 1.3.6.1.2.1.1.1.0 1.3.6.1.2.1.1.3.0

    from pysnmp.carrier.asyncio.dispatch import AsyncioDispatcher
    from pysnmp.carrier.asyncio.dgram import udp
    from pyasn1.codec.ber import encoder, decoder
    from pysnmp.proto import api

    # Broadcast manager settings
    maxWaitForResponses = 5
    maxNumberResponses = 10

    # Protocol version to use
    # pMod = api.PROTOCOL_MODULES[api.SNMP_VERSION_1]
    pMod = api.PROTOCOL_MODULES[api.SNMP_VERSION_2C]

    # Build PDU
    reqPDU = pMod.GetRequestPDU()
    pMod.apiPDU.set_defaults(reqPDU)
    pMod.apiPDU.set_varbinds(
        reqPDU, (("1.3.6.1.2.1.1.1.0", pMod.Null("")), ("1.3.6.1.2.1.1.3.0", pMod.Null("")))
    )

    # Build message
    reqMsg = pMod.Message()
    pMod.apiMessage.set_defaults(reqMsg)
    pMod.apiMessage.set_community(reqMsg, "public")
    pMod.apiMessage.set_pdu(reqMsg, reqPDU)

    # noinspection PyUnusedLocal,PyUnusedLocal
    def __callback(
        transportDispatcher, transportDomain, transportAddress, wholeMsg, reqPDU=reqPDU
    ):
        while wholeMsg:
            rspMsg, wholeMsg = decoder.decode(wholeMsg, asn1Spec=pMod.Message())
            rspPDU = pMod.apiMessage.get_pdu(rspMsg)
            # Match response to request
            if pMod.apiPDU.get_request_id(reqPDU) == pMod.apiPDU.get_request_id(rspPDU):
                # Check for SNMP errors reported
                errorStatus = pMod.apiPDU.get_error_status(rspPDU)
                if errorStatus:
                    print(errorStatus.prettyPrint())
                else:
                    for oid, val in pMod.apiPDU.get_varbinds(rspPDU):
                        print(f"{oid.prettyPrint()} = {val.prettyPrint()}")
                transportDispatcher.job_finished(1)
        return wholeMsg

    transportDispatcher = AsyncioDispatcher()

    transportDispatcher.register_recv_callback(__callback)

    # UDP/IPv4
    udpSocketTransport = udp.UdpAsyncioTransport().open_client_mode(allow_broadcast=True)
    transportDispatcher.register_transport(udp.DOMAIN_NAME, udpSocketTransport)

    # Pass message to dispatcher
    transportDispatcher.send_message(
        encoder.encode(reqMsg), udp.DOMAIN_NAME, ("255.255.255.255", 161)
    )

    # wait for a maximum of 10 responses or time out
    transportDispatcher.job_started(1, maxNumberResponses)

    # Dispatcher will finish as all jobs counter reaches zero
    try:
        transportDispatcher.run_dispatcher(maxWaitForResponses)
    except:
        raise
    finally:
        transportDispatcher.close_dispatcher()

`Download` script.

See also: library reference.

Advertisement