def setup_snmp():
    """Configure SNMP server listener"""

    transport_dispatcher = AsynsockDispatcher()

    transport_dispatcher.registerRecvCbFun(snmp_trap_receiver)

    # UDP/IPv4
    transport_dispatcher.registerTransport(
        udp.domainName,
        udp.UdpSocketTransport().openServerMode(('0.0.0.0', 162)))

    # UDP/IPv6
    transport_dispatcher.registerTransport(
        udp6.domainName,
        udp6.Udp6SocketTransport().openServerMode(('::1', 162)))

    transport_dispatcher.jobStarted(1)

    try:
        # Dispatcher will never finish as job#1 never reaches zero
        transport_dispatcher.runDispatcher()
    except:
        transport_dispatcher.closeDispatcher()
        raise
    def testtrapv2(self):
        '''testtrapv2'''
        # Traps have quite different semantics among proto versions
        if verID == api.protoVersion2c:
            var = []
            oid = (1, 3, 6, 1, 4, 1, 2011, 2, 235, 1, 1, 4, 1, 0)
            # 1.3.6.1.4.1.2011.2.235.1.1.15.50.1.5(cpuClockRate).0
            # 1.3.6.1.4.1.2011.2.235.1.1.4.1.0  trapEnable
            val = pMod.Integer(1)
            var.append((oid, val))

            pMod.apiTrapPDU.setVarBinds(trapPDU, var)

        # Build message
        trapMsg = pMod.Message()
        pMod.apiMessage.setDefaults(trapMsg)
        pMod.apiMessage.setCommunity(trapMsg, community)
        pMod.apiMessage.setPDU(trapMsg, trapPDU)

        transportDispatcher = AsynsockDispatcher()
        transportDispatcher.registerTransport(
            udp.domainName,
            udp.UdpSocketTransport().openClientMode())
        # 本机测试使用localhost,应为对应trap server 的IP地址。
        transportDispatcher.sendMessage(encoder.encode(trapMsg),
                                        udp.domainName, (trapdip, 162))
        transportDispatcher.runDispatcher()
        transportDispatcher.closeDispatcher()

        self.assertTrue(True)
def define_request(source, ip, community, snmp_version, fileconfname, pathfile,
                   protocol, srvprovision, enableconfstart, urlfirmware,
                   enablereboot):
    if snmp_version == '2c':
        communityData = CommunityData(community, mpModel=1)
    if snmp_version == '1':
        communityData = CommunityData(community, mpModel=0)
    if source:
        assd = AsynsockDispatcher()
        sock_transport = udp.UdpSocketTransport()
        sock_transport.socket.setsockopt(socket.SOL_SOCKET, 25, source + '\0')
        snmp_engine = engine.SnmpEngine()
        assd.registerTransport(udp.domainName, sock_transport)
        snmp_engine.registerTransportDispatcher(assd)
    else:
        snmp_engine = engine.SnmpEngine()
    varBind = []
    result = []
    for errorIndication, errorStatus, errorIndex, varBinds in setCmd(
            snmp_engine, communityData, UdpTransportTarget((ip, 161)),
            ContextData(),
            ObjectType(
                ObjectIdentity(
                    '1.3.6.1.4.1.4935.1000.100.200.100.800.1.100.100.0'),
                OctetString(fileconfname)),
            ObjectType(
                ObjectIdentity(
                    '.1.3.6.1.4.1.4935.1000.100.200.100.800.1.100.300.0'),
                OctetString(pathfile)),
            ObjectType(
                ObjectIdentity(
                    '.1.3.6.1.4.1.4935.1000.100.200.100.800.1.100.400.100.0'),
                Integer32(protocol)),
            ObjectType(
                ObjectIdentity(
                    '.1.3.6.1.4.1.4935.1000.100.200.100.800.1.100.400.400.0'),
                OctetString(srvprovision)),
            ObjectType(
                ObjectIdentity(
                    '.1.3.6.1.4.1.4935.1000.100.200.100.800.1.100.500.100.0'),
                Integer32(enableconfstart)),
            ObjectType(
                ObjectIdentity(
                    '.1.3.6.1.4.1.4935.1000.100.200.100.1300.1.450.0'),
                OctetString(urlfirmware)),
            ObjectType(
                ObjectIdentity(
                    '.1.3.6.1.4.1.4935.1000.100.200.100.1300.1.500.0'),
                Integer32(enablereboot))):
        varBind.append(varBinds)
        for i in varBinds:
            i = str(i)
            i = i.split('=')[1]
            result.append(i)


#             result.append(str(i))
#             varBind = varBind.split('=')[1]
#             result.append(varBind)
    return result
Exemple #4
0
def main(options, args):

    logname = 'summit_ups'
    logger = ssdlog.make_logger(logname, options)

    power_off = 'obcpPoff'
    power_off = os.path.join(options.dir, power_off)

    try:
        os.remove(power_off)
    except Exception as e:
        logger.warn('warn: is %s there??  %s' % (power_off, e))

    snmp = SnmpTrap(power_off, logger)

    try:
        transportDispatcher = AsynsockDispatcher()
        transportDispatcher.registerTransport(
            udp.domainName,
            udp.UdpSocketTransport().openServerMode(
                ('%s' % options.mgrhost, 162)))
        transportDispatcher.registerRecvCbFun(snmp.trap_cb)
        transportDispatcher.jobStarted(1)  # this job would never finish
        transportDispatcher.runDispatcher()
    except KeyboardInterrupt:
        logger.info('keyboard interrupting...')
        snmp.ev_quit.set()
    except Exception as e:
        logger.error('error: %s' % e)
        snmp.ev_quit.set()
        logger.error('error: snmp trap terminated..')
Exemple #5
0
    def send(self, host, community, oid, value):
        self.pMod.apiPDU.setDefaults(self.reqPDU)
        self.pMod.apiPDU.setVarBinds(
            self.reqPDU,
            ((oid, self.pMod.OctetString(value)),
            )
        )

        # Build message
        reqMsg = self.pMod.Message()
        self.pMod.apiMessage.setDefaults(reqMsg)
        self.pMod.apiMessage.setCommunity(reqMsg, community)
        self.pMod.apiMessage.setPDU(reqMsg, self.reqPDU)

        transportDispatcher = AsynsockDispatcher()
        transportDispatcher.registerRecvCbFun(self.cbRecvFun)
        transportDispatcher.registerTimerCbFun(self.cbTimerFun)

        # UDP/IPv4
        transportDispatcher.registerTransport(
            udp.domainName, udp.UdpSocketTransport().openClientMode()
        )

        # Pass message to dispatcher
        transportDispatcher.sendMessage(
            encoder.encode(reqMsg), udp.domainName, (host, 161)
        )
        transportDispatcher.jobStarted(1)

        # Dispatcher will finish as job#1 counter reaches zero
        transportDispatcher.runDispatcher()
        transportDispatcher.closeDispatcher()
Exemple #6
0
def receive_trap(self):
    
    transportDispatcher = AsynsockDispatcher()

    transportDispatcher.registerRecvCbFun(cbFun)

    # UDP/IPv4
    transportDispatcher.registerTransport(
        udp.domainName, udp.UdpSocketTransport().openServerMode(('192.168.115.187', 162))
        )

    # UDP/IPv6
    transportDispatcher.registerTransport(
        udp6.domainName, udp6.Udp6SocketTransport().openServerMode(('::1', 162))
        )

    transportDispatcher.jobStarted(1)

    try:
        # Dispatcher will never finish as job#1 never reaches zero
        print('run dispatcher')
        transportDispatcher.runDispatcher()
    except:
        transportDispatcher.closeDispatcher()
        raise
Exemple #7
0
def runDispatcherFunction():

    transportDispatcher = AsynsockDispatcher()

    transportDispatcher.registerRecvCbFun(cbFun)

    # UDP/IPv4
    transportDispatcher.registerTransport(
        udp.domainName,
        udp.UdpSocketTransport().openServerMode(('', 162))
        # if test.py is running inside a container named "ra", the traps messages will be for exampleL:
        #snmptrap -v2c -c public ra:162 '' SNMPv2-MIB::coldStart.0 SNMPv2-MIB::sysContact.0 s 'trap testing number #7'
    )

    # UDP/IPv6
    #transportDispatcher.registerTransport(
    #    udp6.domainName, udp6.Udp6SocketTransport().openServerMode(('::1', 162))
    #)

    transportDispatcher.jobStarted(1)

    try:
        # Dispatcher will never finish as job#1 never reaches zero
        print('run dispatcher')
        transportDispatcher.runDispatcher()
    except:
        transportDispatcher.closeDispatcher()
        raise
Exemple #8
0
	def query(self, oidCountersDict):
		resultsDict = dict()

		# SNMP protocol version to use
		pMod = api.protoModules[api.protoVersion1]
		
		# Build PDU
		reqPDU = pMod.GetRequestPDU()
		pMod.apiPDU.setDefaults(reqPDU)
		
		# Create a tuple of OIDs tuples
		oidList = list()
		for oid in oidCountersDict.values():
			oidList.append((oid, pMod.Null()))
		OIDs = tuple(oidList)
		
		pMod.apiPDU.setVarBinds(reqPDU, (OIDs))

		# Build message
		reqMsg = pMod.Message()
		pMod.apiMessage.setDefaults(reqMsg)
		pMod.apiMessage.setCommunity(reqMsg, 'public')
		pMod.apiMessage.setPDU(reqMsg, reqPDU)

		def cbTimerFun(timeNow, startedAt=time()):
			if timeNow - startedAt > self.snmpTimeout:
				transportDispatcher.jobFinished(1)
				raise SNMPTimeOutError("The host %s has not responded in the specified timeout of %ss!" % (self.host, self.snmpTimeout))
    
		def cbRecvFun(transportDispatcher, transportDomain, transportAddress, wholeMsg, reqPDU=reqPDU):
			while wholeMsg:
				rspMsg, wholeMsg = decoder.decode(wholeMsg, asn1Spec=pMod.Message())
				rspPDU = pMod.apiMessage.getPDU(rspMsg)
				# Match response to request
				if pMod.apiPDU.getRequestID(reqPDU)==pMod.apiPDU.getRequestID(rspPDU):
					# Check for SNMP errors reported
					errorStatus = pMod.apiPDU.getErrorStatus(rspPDU)
					if errorStatus:
						print errorStatus.prettyPrint()
						raise SNMPoIDNotSupported("%s: An requested OID is not supported by this device!" % errorStatus.prettyPrint())
					else:
						for oid, val in pMod.apiPDU.getVarBinds(rspPDU):
							#print '%s = %s' % (oid.prettyPrint(), val)
							resultsDict[str(oid)] = str(val)

					transportDispatcher.jobFinished(1)
			return wholeMsg

		transportDispatcher = AsynsockDispatcher()
		transportDispatcher.registerTransport(udp.domainName, udp.UdpSocketTransport().openClientMode())
		transportDispatcher.registerRecvCbFun(cbRecvFun)
		transportDispatcher.registerTimerCbFun(cbTimerFun)
		transportDispatcher.sendMessage(encoder.encode(reqMsg), udp.domainName, (self.host, int(self.port)))
		transportDispatcher.jobStarted(1)
		transportDispatcher.runDispatcher()
		transportDispatcher.closeDispatcher()

		return resultsDict
Exemple #9
0
 def _init_dispatcher(self):
     self.log("init snmp_session object")
     self.__disp = AsynsockDispatcher()
     self.__disp.registerTransport(
         udp.domainName,
         udp.UdpSocketTransport().openClientMode())
     self.__disp.registerRecvCbFun(self._recv_func)
     self.__disp.registerTimerCbFun(self._timer_func)
     self.v1_decoder = api.protoModules[api.protoVersion1]
     self.v2c_decoder = api.protoModules[api.protoVersion2c]
Exemple #10
0
    def __init__(self, zmq_core, logger):
        self.zmq_core = zmq_core
        self.logger = logger
        self.scheduler = SNMPScheduler(logger=logger)

        self.transport_dispatcher = AsynsockDispatcher()
        self.transport_dispatcher.setSocketMap(zmq_core.socket_map)
        snmp_engine = engine.SnmpEngine()
        snmp_engine.registerTransportDispatcher(self.transport_dispatcher)
        self.cmd_gen = cmdgen.AsynCommandGenerator(snmpEngine=snmp_engine)
Exemple #11
0
def Send_GetSystemPDUName(reqMsg, hostname, port=161):
    transportDispatcher = AsynsockDispatcher()
    transportDispatcher.registerTransport(
        udp.domainName,
        udp.UdpSocketTransport().openClientMode())
    transportDispatcher.registerRecvCbFun(cbRecvFun)
    transportDispatcher.registerTimerCbFun(cbTimerFun)
    transportDispatcher.sendMessage(encoder.encode(reqMsg), udp.domainName,
                                    (hostname, 161))
    transportDispatcher.jobStarted(1)
    transportDispatcher.runDispatcher()
    transportDispatcher.closeDispatcher()
Exemple #12
0
    def run(self):
        """Run the sensor on its own thread"""

        # Check for debug mode being activated/deactivated
        self._read_my_msgQ_noWait()

        try:
            self._log_debug("Start processing")

            # Create MIB loader to lookup oids sent in traps
            self._mib_builder()

            # Create an asynchronous dispatcher and register a callback method to handle incoming traps
            transportDispatcher = AsynsockDispatcher()
            transportDispatcher.registerRecvCbFun(self._trap_catcher)

            # UDP/IPv4
            transportDispatcher.registerTransport(
                udp.domainName,
                udp.UdpSocketTransport().openServerMode(
                    (self._bind_ip, self._bind_port)))

            # UDP/IPv6
            transportDispatcher.registerTransport(
                udp6.domainName,
                udp6.Udp6SocketTransport().openServerMode(
                    ('::1', self._bind_port)))

            transportDispatcher.jobStarted(1)

            try:
                # Dispatcher will never finish as job #1 never reaches zero
                transportDispatcher.runDispatcher()
            except Exception as ae:
                self._log_debug("Exception: %r" % ae)
                transportDispatcher.closeDispatcher()

            self._log_debug("Finished processing, restarting SNMP listener")

            # Reset debug mode if persistence is not enabled
            self._disable_debug_if_persist_false()

            # Schedule the next time to run thread
            self._scheduler.enter(10, self._priority, self.run, ())

        # Could not bind to IP:port, log it and exit out module
        except Exception as ae:
            self._log_debug(
                "Unable to process SNMP traps from this node, closing module.")
            self._log_debug(
                f"SNMP Traps sensor attempted to bind to {self._bind_ip}:{self._bind_port}"
            )
Exemple #13
0
    def run(self):
        transport_dispatcher = AsynsockDispatcher()
        transport_dispatcher.registerRecvCbFun(self._callback)
        transport_dispatcher.registerTransport(
            udp.domainName,
            udp.UdpSocketTransport().openServerMode((self.address, self.port)))
        transport_dispatcher.jobStarted(1)

        try:
            transport_dispatcher.runDispatcher()
        except Exception as exc:
            transport_dispatcher.closeDispatcher()
            raise exc
Exemple #14
0
def snmp_trap_receiver(ifname, port=162):
    if_ip = get_ip_address(ifname)
    transportDispatcher = AsynsockDispatcher()
    transportDispatcher.registerRecvCbFun(cbFun)

    transportDispatcher.registerTransport(
        udp.domainName,
        udp.UdpSocketTransport().openServerMode((if_ip, port)))
    transportDispatcher.jobStarted(1)
    print('SNMP Trap Receiver Started!!!')
    try:
        transportDispatcher.runDispatcher()
    except:
        transportDispatcher.closeDispatcher()
        raise
def sent_snmp_trap(product, level, regionId, instanceName, name):
    # Protocol version to use
    verID = api.protoVersion2c
    pMod = api.protoModules[verID]

    # Build PDU
    trapPDU = pMod.TrapPDU()
    pMod.apiTrapPDU.setDefaults(trapPDU)

    # Traps have quite different semantics among proto versions
    if verID == api.protoVersion2c:

        var = []
        oid = (1, 3, 6, 1, 4, 1, 12149, 1)
        val = pMod.OctetString('product:%s' % product)
        var.append((oid, val))
        oid = (1, 3, 6, 1, 4, 1, 12149, 2)
        val = pMod.OctetString('level:%s' % level)
        var.append((oid, val))
        oid = (1, 3, 6, 1, 4, 1, 12149, 3)
        val = pMod.OctetString('regionId:%s' % regionId)
        var.append((oid, val))
        oid = (1, 3, 6, 1, 4, 1, 12149, 4)
        val = pMod.OctetString('instanceName:%s' % instanceName)
        var.append((oid, val))
        oid = (1, 3, 6, 1, 4, 1, 12149, 5)
        val = pMod.OctetString('name:%s' % name)
        var.append((oid, val))
        pMod.apiTrapPDU.setVarBinds(trapPDU, var)

    print(var)
    save_log(str(var))
    # Build message
    trapMsg = pMod.Message()

    pMod.apiMessage.setDefaults(trapMsg)
    pMod.apiMessage.setCommunity(trapMsg, 'public')
    pMod.apiMessage.setPDU(trapMsg, trapPDU)

    transportDispatcher = AsynsockDispatcher()
    transportDispatcher.registerTransport(
        udp.domainName,
        udp.UdpSocketTransport().openClientMode())
    transportDispatcher.sendMessage(encoder.encode(trapMsg), udp.domainName,
                                    ('localhost', 162))
    transportDispatcher.runDispatcher()
    transportDispatcher.closeDispatcher()
Exemple #16
0
 def __init__(self):
     self.log.info("started (org)")
     # Use the default thread transaction manager.
     try:
         self.transaction_manager = transaction.manager
         self.interaction = ParanoidSecurityPolicy(SystemSnmpdParticipation())
         self.transportDispatcher = AsynsockDispatcher()
         self.transportDispatcher.registerTransport(
             #    udp.domainName, udp.UdpSocketTransport().openServerMode(('localhost', 162))
             udp.domainName, udp.UdpSocketTransport().openServerMode(('', 11162))
         )
         self.transportDispatcher.registerRecvCbFun(self.cbFun)
         self.transportDispatcher.jobStarted(1) # this job would never finish
     except:
         # TODO: don't do this
         pass
     threading.Thread.__init__(self)
def main():
    'main program function'
    if os.path.isfile(CONFIG_FILE):
        filename = CONFIG_FILE
    elif os.path.isfile('/config/{0}'.format(CONFIG_FILE)):
        filename = '/config/{0}'.format(CONFIG_FILE)
    else:
        print 'Error: cannot find configuration file', CONFIG_FILE
        return

    processConfig(filename)

    transportDispatcher = AsynsockDispatcher()

    transportDispatcher.registerRecvCbFun(cbFun)

    # UDP/IPv4
    if gArgs.virtual_router:
        lookupVR(gArgs.virtual_router)

    # During startup, the IP address may not be ready yet. So we try a few times
    for retry in range(30):
        try:
            transportDispatcher.registerTransport(
                udp.domainName,
                udp.UdpSocketTransport().openServerMode(
                    (gArgs.ip_address, 162)))
            break
        except Exception:
            time.sleep(5)


# UDP/IPv6
    transportDispatcher.registerTransport(
        udp6.domainName,
        udp6.Udp6SocketTransport().openServerMode(('::1', 162)))

    transportDispatcher.jobStarted(1)

    try:
        # Dispatcher will never finish as job#1 never reaches zero
        transportDispatcher.runDispatcher()
    except Exception:
        transportDispatcher.closeDispatcher()
        raise
Exemple #18
0
def notif_Receiver():
    def cbFun(transportDispatcher, transportDomain, transportAddress,
              wholeMsg):
        transportDispatcher.jobFinished(1)
        return

    transportDispatcher = AsynsockDispatcher()
    transportDispatcher.registerRecvCbFun(cbFun)
    transportDispatcher.registerTransport(
        udp.domainName,
        udp.UdpSocketTransport().openServerMode((raspberry_ip, 1162)))
    transportDispatcher.jobStarted(1)
    try:
        transportDispatcher.runDispatcher()
    except:
        transportDispatcher.closeDispatcher()
        raise
    return
Exemple #19
0
def snmp_trap_receiver(ifname, port=162):
    if_ip = get_ip_address(ifname)
    transportDispatcher = AsynsockDispatcher()  # 创建实例
    transportDispatcher.registerRecvCbFun(cbFun)  # 调用处理Trap信息的函数

    # UDP/IPv4
    transportDispatcher.registerTransport(
        udp.domainName, udp.UdpSocketTransport().openServerMode((if_ip, port))  # 绑定到本地地址与UDP/162号端口
    )

    transportDispatcher.jobStarted(1)  # 开始工作
    print("SNMP Trap Receiver Started!!!")
    try:
        # Dispatcher will never finish as job#1 never reaches zero
        transportDispatcher.runDispatcher()  # 运行
    except:
        transportDispatcher.closeDispatcher()
        raise
def _trap_receiver(trap_filter, host, port, timeout):
    started = time.time()

    def _trap_timer_cb(now):
        if now - started > timeout:
            raise AssertionError('No matching trap received in %s.' %
                                 robot.utils.secs_to_timestr(timeout))

    def _trap_receiver_cb(transport, domain, sock, msg):
        if decodeMessageVersion(msg) != protoVersion2c:
            raise RuntimeError('Only SNMP v2c traps are supported.')

        req, msg = decoder.decode(msg, asn1Spec=v2c.Message())
        pdu = v2c.apiMessage.getPDU(req)

        # ignore any non trap PDUs
        if not pdu.isSameTypeWith(v2c.TrapPDU()):
            return

        if trap_filter(domain, sock, pdu):
            raise StopListener()

        # Stop the receiver if the trap we are looking for was received.
        if False:
            raise StopListener()

    dispatcher = AsynsockDispatcher()
    dispatcher.registerRecvCbFun(_trap_receiver_cb)
    dispatcher.registerTimerCbFun(_trap_timer_cb)

    transport = udp.UdpSocketTransport().openServerMode((host, port))
    dispatcher.registerTransport(udp.domainName, transport)

    # we'll never finish, except through an exception
    dispatcher.jobStarted(1)

    try:
        dispatcher.runDispatcher()
    except StopListener:
        pass
    finally:
        dispatcher.closeDispatcher()
Exemple #21
0
 def run(self):
     
    transportDispatcher = AsynsockDispatcher()
    transportDispatcher.registerRecvCbFun(trapCallback)
    if self.ipv6:
        transport = udp.Udp6SocketTransport()
        domainName = udp6.domainName
    else:
        transport = udp.UdpSocketTransport()  
        domainName = udp.domainName
            
    try:     
        transportDispatcher.registerTransport(domainName, transport.openServerMode((self.host, self.port)))
  
        transportDispatcher.jobStarted(1)
        # Dispatcher will never finish as job#1 never reaches zero
        transportDispatcher.runDispatcher()     
    except: # catch *all* exceptions
        e = sys.exc_info()[1]
        transportDispatcher.closeDispatcher()
        logging.error("Failed to register transport and run dispatcher: %s" % str(e))
        sys.exit(1)
Exemple #22
0
    def start(self):
        transportDispatcher = AsynsockDispatcher()
        transportDispatcher.registerRecvCbFun(self._event_handle)

        if self.ipv4_addr:
            transportDispatcher.registerTransport(
                udp.domainName,
                udp.UdpSocketTransport().openServerMode(
                    (str(self.ipv4_addr), self.port)))
        if self.ipv6_addr:
            transportDispatcher.registerTransport(
                udp6.domainName,
                udp6.Udp6SocketTransport().openServerMode(
                    (str(self.ipv6_addr), self.port)))

        transportDispatcher.jobStarted(1)
        try:
            # Dispatcher will never finish as job#1 never reaches zero
            transportDispatcher.runDispatcher()
        except:
            transportDispatcher.closeDispatcher()
            raise
Exemple #23
0
def snmp_msg_send():
    try:
        verID = api.protoVersion2c
        pMod = api.protoModules[verID]

        trapPDU = pMod.TrapPDU()
        pMod.apiTrapPDU.setDefaults(trapPDU)
        now_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        # Traps have quite different semantics among proto versions
        if verID == api.protoVersion2c:
            var = []
            oid = (1, 3, 6, 1, 4, 1, 3902, 2, 2, 4)
            val = pMod.OctetString("2001")
            var.append((oid, val))
            oid = (1, 3, 6, 1, 4, 1, 3902, 2, 2, 5)
            val = pMod.OctetString("60")
            var.append((oid, val))
            oid = (1, 3, 6, 1, 4, 1, 3902, 2, 2, 6)
            val = pMod.OctetString(now_time)
            var.append((oid, val))
            pMod.apiTrapPDU.setVarBinds(trapPDU, var)

        trapMsg = pMod.Message()
        pMod.apiMessage.setDefaults(trapMsg)
        pMod.apiMessage.setCommunity(trapMsg, 'Beijing JiaoTong University')
        pMod.apiMessage.setPDU(trapMsg, trapPDU)

        transportDispatcher = AsynsockDispatcher()
        transportDispatcher.registerTransport(
            udp.domainName,
            udp.UdpSocketTransport().openClientMode())
        transportDispatcher.sendMessage(encoder.encode(trapMsg),
                                        udp.domainName,
                                        (ntp_ip2, 162))  # 为对应trapserver的IP地址。
        transportDispatcher.runDispatcher()
        transportDispatcher.closeDispatcher()
    except:
        logging.debug('snmp send fail!')
        print('snmp send fail')
Exemple #24
0
def main():
    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)

    # global
    global myamqp, transportDispatcher

    # Connect to amqp bus
    logger.debug("Start AMQP ...")
    myamqp = camqp()

    logger.info("Load all MIBs ...")
    for oid in snmp2amqp_conf.mibs.keys():
        mibs[oid] = mib(snmp2amqp_conf.mibs[oid])

    logger.info("Init SNMP listenner ...")
    transportDispatcher = AsynsockDispatcher()

    transportDispatcher.registerTransport(
        udp.domainName,
        udp.UdpSocketTransport().openServerMode(
            (snmp2amqp_conf.interface, snmp2amqp_conf.port)))

    transportDispatcher.registerRecvCbFun(cbFun)
    transportDispatcher.jobStarted(1)  # this job would never finish

    ## set euid of process
    os.setuid(getpwnam('canopsis')[2])

    myamqp.start()

    logger.info("Wait SNMP traps ...")
    try:
        transportDispatcher.runDispatcher()
    except Exception, err:
        ## Impossible to stop transportDispatcher properly ...
        logger.error(err)
        pass
Exemple #25
0
    def threadFunction(self):
        self.transportDispatcher = AsynsockDispatcher()

        self.transportDispatcher.registerRecvCbFun(onTrap)

        # UDP/IPv4
        self.transportDispatcher.registerTransport(
            udp.domainName,
            udp.UdpSocketTransport().openServerMode((self.target, self.port)))

        self.transportDispatcher.jobStarted(1)

        try:
            # Dispatcher will never finish as job#1 never reaches zero
            self.transportDispatcher.runDispatcher()
        except Exception as exc:
            logger.error("Encounted error '%s' on trap receiver %s:%d" %
                         (exc, self.target, self.port))
            self.transportDispatcher.closeDispatcher()
            raise TrapDaemonError(
                "Trap receiver %s:%d" % (self.target, self.port), exc)
        else:
            self.transportDispatcher.closeDispatcher()
    while wholeMsg:
        rspMsg, wholeMsg = decoder.decode(wholeMsg, asn1Spec=pMod.Message())
        rspPDU = pMod.apiMessage.getPDU(rspMsg)
        # Match response to request
        if pMod.apiPDU.getRequestID(reqPDU)==pMod.apiPDU.getRequestID(rspPDU):
            # Check for SNMP errors reported
            errorStatus = pMod.apiPDU.getErrorStatus(rspPDU)
            if errorStatus:
                print(errorStatus.prettyPrint())
            else:
                for oid, val in pMod.apiPDU.getVarBinds(rspPDU):
                    print('%s = %s' % (oid.prettyPrint(), val.prettyPrint()))
            transportDispatcher.jobFinished(1)
    return wholeMsg

transportDispatcher = AsynsockDispatcher()

transportDispatcher.registerRecvCbFun(cbRecvFun)
transportDispatcher.registerTimerCbFun(cbTimerFun)

# UDP/IPv4
transportDispatcher.registerTransport(
    udp.domainName, udp.UdpSocketTransport().openClientMode()
)

# Pass message to dispatcher
transportDispatcher.sendMessage(
    encoder.encode(reqMsg), udp.domainName, ('192.168.22.241', 161)
)
transportDispatcher.jobStarted(1)
Exemple #27
0
    def start_trap(self, pattern_end_trap, time_end_trap,
                   timeout, port, queue):
        """
            :param pattern_end_trap
               **OPTION** the pattern you are looking for in the trap to
               stop trap. If not defined, trap will be stopped after
               timeout value
            :param time_end_trap
               **OPTION** the time for running trap. Default: 30
            :param timeout
               **OPTION** the timeout for snmp trap. Default: 300.
            :param port
               **OPTION** the port of snmp trap.
            :return:
        """
        t.log("DEBUG", "Entering 'start_trap'\n"+__file__)
        import warnings
        warnings.simplefilter("ignore", ResourceWarning)
        startedat = time.time()
        #global results
        global RESPONSE

        RESPONSE = ''

        def cbfun(transportdispatcher, transportdomain, transportaddress,
                  wholemsg):
            t.log("DEBUG", "Entering 'cbfun'\n"+__file__)
            #global results
            global RESPONSE
            while wholemsg:
                msgver = int(api.decodeMessageVersion(wholemsg))
                if msgver in api.protoModules:
                    pmod = api.protoModules[msgver]
                else:
                    RESPONSE += 'Unsupported SNMP version %s' % msgver
                    return
                reqmsg, wholemsg = decoder.decode(
                    wholemsg, asn1Spec=pmod.Message(),
                    )
                RESPONSE += 'Notification message from %s:%s: \n' % (
                    transportdomain, transportaddress
                    )
                reqpdu = pmod.apiMessage.getPDU(reqmsg)
                if msgver == api.protoVersion1:
                    varbinds = pmod.apiTrapPDU.getVarBindList(reqpdu)
                    RESPONSE += 'Var-binds: \n'
                    for oid, val in varbinds:
                        RESPONSE += '%s = %s \n' % (oid.prettyPrint(),
                                                    val.prettyPrint())
                        if pattern_end_trap and re.search(pattern_end_trap,
                                                          RESPONSE, re.I):
                            transportdispatcher.jobFinished(1)
                            RESPONSE += "Stopped trap \n"

                    RESPONSE += 'Enterprise: %s \n' % (
                        pmod.apiTrapPDU.getEnterprise(reqpdu).prettyPrint()
                        )

                    RESPONSE += 'Agent Address: %s \n' % (
                        pmod.apiTrapPDU.getAgentAddr(reqpdu).prettyPrint()
                        )
                    RESPONSE += 'Generic Trap: %s \n' % (
                        pmod.apiTrapPDU.getGenericTrap(
                            reqpdu).prettyPrint())

                    RESPONSE += 'Specific Trap: %s \n' % (
                        pmod.apiTrapPDU.getSpecificTrap(
                            reqpdu).prettyPrint()
                        )

                    RESPONSE += 'Uptime: %s \n' % (
                        pmod.apiTrapPDU.getTimeStamp(
                            reqpdu).prettyPrint()
                        )
                else:
                    varbinds = pmod.apiPDU.getVarBindList(reqpdu)

        def cbtimerfun(timenow):
            t.log("DEBUG", "Entering 'cbtimerfun'\n"+__file__)
            #global results
            global RESPONSE
            if time_end_trap is not None:
                if timenow - startedat >= time_end_trap:
                    transportdispatcher.jobFinished(1)
                    RESPONSE += "Stopped trap \n"

            if timenow - startedat >= timeout:
                t.log(level="DEBUG", message="Request timed out \n")
                raise Exception("Request timed out \n")

        transportdispatcher = AsynsockDispatcher()
        transportdispatcher.registerRecvCbFun(cbfun)
        transportdispatcher.registerTimerCbFun(cbtimerfun)
        # UDP/IPv4
        transportdispatcher.registerTransport(
            udp.domainName, udp.UdpSocketTransport().openServerMode(
                (self.trap_server_v4, port))
        )

        # UDP/IPv6
        transportdispatcher.registerTransport(
            udp6.domainName, udp6.Udp6SocketTransport().openServerMode(
                (self.trap_server_v6, port))
        )

        transportdispatcher.jobStarted(1)

        try:
            # Dispatcher will never finish as job#1 never reaches zero
            transportdispatcher.runDispatcher()
        except:
            transportdispatcher.closeDispatcher()

        queue.put(RESPONSE)
        t.log(level="DEBUG", message="Exiting 'start_trap' with return value/code :\n")
        return
Exemple #28
0
 def __init__(self, address):
     threading.Thread.__init__(self)
     self._address = address
     self._transportDispatcher = AsynsockDispatcher()
     self._transportDispatcher.registerRecvCbFun(self.onSnmpMessage)
Exemple #29
0
'''
Created on 2012-9-9
@author: zongzong
'''
# Notification Originator Application (TRAP)
from pysnmp.carrier.asynsock.dispatch import AsynsockDispatcher
from pysnmp.carrier.asynsock.dgram import udp
from pyasn1.codec.ber import encoder
from pysnmp.proto import api
# Protocol version to use
verID = api.protoVersion1
pMod = api.protoModules[verID]
# Build PDU
trapPDU = pMod.TrapPDU()
pMod.apiTrapPDU.setDefaults(trapPDU)
# Traps have quite different semantics among proto versions
if verID == api.protoVersion1:
    pMod.apiTrapPDU.setEnterprise(trapPDU, (1, 3, 6, 1, 6, 3, 1, 1, 5, 1))
    pMod.apiTrapPDU.setGenericTrap(trapPDU, 'coldStart')
# Build message
trapMsg = pMod.Message()
pMod.apiMessage.setDefaults(trapMsg)
pMod.apiMessage.setCommunity(trapMsg, 'public')
pMod.apiMessage.setPDU(trapMsg, trapPDU)
transportDispatcher = AsynsockDispatcher()
transportDispatcher.registerTransport(
    udp.domainName,
    udp.UdpSocketTransport().openClientMode())
transportDispatcher.sendMessage(encoder.encode(trapMsg), udp.domainName,
                                ('10.8.80.108', 162))
Exemple #30
0
def main():
    class CommandResponder(cmdrsp.CommandResponderBase):
        pduTypes = (rfc1905.SetRequestPDU.tagSet, rfc1905.GetRequestPDU.tagSet,
                    rfc1905.GetNextRequestPDU.tagSet,
                    rfc1905.GetBulkRequestPDU.tagSet)

        def handleMgmtOperation(self, snmpEngine, stateReference, contextName,
                                pdu, acInfo):
            trunkReq = gCurrentRequestContext.copy()

            trunkReq['snmp-pdu'] = pdu

            pluginIdList = trunkReq['plugins-list']

            logCtx = LogString(trunkReq)

            reqCtx = {}

            for pluginNum, pluginId in enumerate(pluginIdList):

                st, pdu = pluginManager.processCommandRequest(
                    pluginId, snmpEngine, pdu, trunkReq, reqCtx)

                if st == status.BREAK:
                    log.debug('plugin %s inhibits other plugins' % pluginId,
                              ctx=logCtx)
                    pluginIdList = pluginIdList[:pluginNum]
                    break

                elif st == status.DROP:
                    log.debug(
                        'received SNMP message, plugin %s muted request' %
                        pluginId,
                        ctx=logCtx)
                    self.releaseStateInformation(stateReference)
                    return

                elif st == status.RESPOND:
                    log.debug(
                        'received SNMP message, plugin %s forced immediate response'
                        % pluginId,
                        ctx=logCtx)

                    try:
                        self.sendPdu(snmpEngine, stateReference, pdu)

                    except PySnmpError:
                        log.error('failure sending SNMP response', ctx=logCtx)

                    else:
                        self.releaseStateInformation(stateReference)

                    return

            # pass query to trunk

            trunkIdList = trunkReq['trunk-id-list']
            if trunkIdList is None:
                log.error('no route configured', ctx=logCtx)
                self.releaseStateInformation(stateReference)
                return

            for trunkId in trunkIdList:

                cbCtx = pluginIdList, trunkId, trunkReq, snmpEngine, stateReference, reqCtx

                try:
                    msgId = trunkingManager.sendReq(trunkId, trunkReq,
                                                    self.trunkCbFun, cbCtx)

                except SnmpfwdError:
                    log.error(
                        'received SNMP message, message not sent to trunk "%s"'
                        % sys.exc_info()[1],
                        ctx=logCtx)
                    return

                log.debug(
                    'received SNMP message, forwarded as trunk message #%s' %
                    msgId,
                    ctx=logCtx)

        def trunkCbFun(self, msgId, trunkRsp, cbCtx):
            pluginIdList, trunkId, trunkReq, snmpEngine, stateReference, reqCtx = cbCtx

            for key in tuple(trunkRsp):
                if key != 'callflow-id':
                    trunkRsp['client-' + key] = trunkRsp[key]
                    del trunkRsp[key]

            trunkRsp['callflow-id'] = trunkReq['callflow-id']

            logCtx = LogString(trunkRsp)

            if trunkRsp['client-error-indication']:
                log.info(
                    'received trunk message #%s, remote end reported error-indication "%s", NOT responding'
                    % (msgId, trunkRsp['client-error-indication']),
                    ctx=logCtx)

            elif 'client-snmp-pdu' not in trunkRsp:
                log.info(
                    'received trunk message #%s, remote end does not send SNMP PDU, NOT responding'
                    % msgId,
                    ctx=logCtx)

            else:
                pdu = trunkRsp['client-snmp-pdu']

                for pluginId in pluginIdList:
                    st, pdu = pluginManager.processCommandResponse(
                        pluginId, snmpEngine, pdu, trunkReq, reqCtx)

                    if st == status.BREAK:
                        log.debug('plugin %s inhibits other plugins' %
                                  pluginId,
                                  ctx=logCtx)
                        break
                    elif st == status.DROP:
                        log.debug('plugin %s muted response' % pluginId,
                                  ctx=logCtx)
                        self.releaseStateInformation(stateReference)
                        return

                try:
                    self.sendPdu(snmpEngine, stateReference, pdu)

                except PySnmpError:
                    log.error('failure sending SNMP response', ctx=logCtx)

                else:
                    log.debug(
                        'received trunk message #%s, forwarded as SNMP message'
                        % msgId,
                        ctx=logCtx)

            self.releaseStateInformation(stateReference)

    #
    # SNMPv3 NotificationReceiver implementation
    #

    class NotificationReceiver(ntfrcv.NotificationReceiver):
        pduTypes = (rfc1157.TrapPDU.tagSet, rfc1905.SNMPv2TrapPDU.tagSet)

        def processPdu(self, snmpEngine, messageProcessingModel, securityModel,
                       securityName, securityLevel, contextEngineId,
                       contextName, pduVersion, pdu, maxSizeResponseScopedPDU,
                       stateReference):

            trunkReq = gCurrentRequestContext.copy()

            if messageProcessingModel == 0:
                pdu = rfc2576.v1ToV2(pdu)

                # TODO: why this is not automatic?
                v2c.apiTrapPDU.setDefaults(pdu)

            trunkReq['snmp-pdu'] = pdu

            pluginIdList = trunkReq['plugins-list']

            logCtx = LogString(trunkReq)

            reqCtx = {}

            for pluginNum, pluginId in enumerate(pluginIdList):

                st, pdu = pluginManager.processNotificationRequest(
                    pluginId, snmpEngine, pdu, trunkReq, reqCtx)

                if st == status.BREAK:
                    log.debug('plugin %s inhibits other plugins' % pluginId,
                              ctx=logCtx)
                    pluginIdList = pluginIdList[:pluginNum]
                    break

                elif st == status.DROP:
                    log.debug('plugin %s muted request' % pluginId, ctx=logCtx)
                    return

                elif st == status.RESPOND:
                    log.debug('plugin %s NOT forced immediate response' %
                              pluginId,
                              ctx=logCtx)
                    # TODO: implement immediate response for confirmed-class PDU
                    return

            # pass query to trunk

            trunkIdList = trunkReq['trunk-id-list']
            if trunkIdList is None:
                log.error('no route configured', ctx=logCtx)
                return

            for trunkId in trunkIdList:

                # TODO: pass messageProcessingModel to respond
                cbCtx = pluginIdList, trunkId, trunkReq, snmpEngine, stateReference, reqCtx

                try:
                    msgId = trunkingManager.sendReq(trunkId, trunkReq,
                                                    self.trunkCbFun, cbCtx)

                except SnmpfwdError:
                    log.error(
                        'received SNMP message, message not sent to trunk "%s" %s'
                        % (trunkId, sys.exc_info()[1]),
                        ctx=logCtx)
                    return

                log.debug(
                    'received SNMP message, forwarded as trunk message #%s' %
                    msgId,
                    ctx=logCtx)

        def trunkCbFun(self, msgId, trunkRsp, cbCtx):
            pluginIdList, trunkId, trunkReq, snmpEngine, stateReference, reqCtx = cbCtx

            for key in tuple(trunkRsp):
                if key != 'callflow-id':
                    trunkRsp['client-' + key] = trunkRsp[key]
                    del trunkRsp[key]

            trunkRsp['callflow-id'] = trunkReq['callflow-id']

            logCtx = LazyLogString(trunkReq, trunkRsp)

            if trunkRsp['client-error-indication']:
                log.info(
                    'received trunk message #%s, remote end reported error-indication "%s", NOT responding'
                    % (msgId, trunkRsp['client-error-indication']),
                    ctx=logCtx)
            else:
                if 'client-snmp-pdu' not in trunkRsp:
                    log.debug(
                        'received trunk message #%s -- unconfirmed SNMP message'
                        % msgId,
                        ctx=logCtx)
                    return

                pdu = trunkRsp['client-snmp-pdu']

                for pluginId in pluginIdList:
                    st, pdu = pluginManager.processNotificationResponse(
                        pluginId, snmpEngine, pdu, trunkReq, reqCtx)

                    if st == status.BREAK:
                        log.debug('plugin %s inhibits other plugins' %
                                  pluginId,
                                  ctx=logCtx)
                        break
                    elif st == status.DROP:
                        log.debug(
                            'received trunk message #%s, plugin %s muted response'
                            % (msgId, pluginId),
                            ctx=logCtx)
                        return

                log.debug(
                    'received trunk message #%s, forwarded as SNMP message' %
                    msgId,
                    ctx=logCtx)

                # TODO: implement response part

                # # Agent-side API complies with SMIv2
                # if messageProcessingModel == 0:
                #     PDU = rfc2576.v2ToV1(PDU, origPdu)
                #
                # statusInformation = {}
                #
                # # 3.4.3
                # try:
                #     snmpEngine.msgAndPduDsp.returnResponsePdu(
                #         snmpEngine, messageProcessingModel, securityModel,
                #         securityName, securityLevel, contextEngineId,
                #         contextName, pduVersion, rspPDU, maxSizeResponseScopedPDU,
                #         stateReference, statusInformation)
                #
                # except error.StatusInformation:
                #         log.error('processPdu: stateReference %s, statusInformation %s' % (stateReference, sys.exc_info()[1]))

    class LogString(LazyLogString):

        GROUPINGS = [
            ['callflow-id'],
            [
                'snmp-engine-id', 'snmp-transport-domain', 'snmp-bind-address',
                'snmp-bind-port', 'snmp-security-model', 'snmp-security-level',
                'snmp-security-name', 'snmp-credentials-id'
            ],
            ['snmp-context-engine-id', 'snmp-context-name', 'snmp-context-id'],
            ['snmp-pdu', 'snmp-content-id'],
            ['snmp-peer-address', 'snmp-peer-port', 'snmp-peer-id'],
            ['trunk-id'],
            ['client-snmp-pdu'],
        ]

        FORMATTERS = {
            'client-snmp-pdu': LazyLogString.prettyVarBinds,
            'snmp-pdu': LazyLogString.prettyVarBinds,
        }

    def securityAuditObserver(snmpEngine, execpoint, variables, cbCtx):
        securityModel = variables.get('securityModel', 0)

        logMsg = 'SNMPv%s auth failure' % securityModel
        logMsg += ' at %s:%s' % variables['transportAddress'].getLocalAddress()
        logMsg += ' from %s:%s' % variables['transportAddress']

        statusInformation = variables.get('statusInformation', {})

        if securityModel in (1, 2):
            logMsg += ' using snmp-community-name "%s"' % statusInformation.get(
                'communityName', '?')
        elif securityModel == 3:
            logMsg += ' using snmp-usm-user "%s"' % statusInformation.get(
                'msgUserName', '?')

        try:
            logMsg += ': %s' % statusInformation['errorIndication']

        except KeyError:
            pass

        log.error(logMsg)

    def requestObserver(snmpEngine, execpoint, variables, cbCtx):

        trunkReq = {
            'callflow-id': '%10.10x' % random.randint(0, 0xffffffffff),
            'snmp-engine-id': snmpEngine.snmpEngineID,
            'snmp-transport-domain': variables['transportDomain'],
            'snmp-peer-address': variables['transportAddress'][0],
            'snmp-peer-port': variables['transportAddress'][1],
            'snmp-bind-address':
            variables['transportAddress'].getLocalAddress()[0],
            'snmp-bind-port':
            variables['transportAddress'].getLocalAddress()[1],
            'snmp-security-model': variables['securityModel'],
            'snmp-security-level': variables['securityLevel'],
            'snmp-security-name': variables['securityName'],
            'snmp-context-engine-id': variables['contextEngineId'],
            'snmp-context-name': variables['contextName'],
        }

        trunkReq['snmp-credentials-id'] = macro.expandMacro(
            credIdMap.get(
                (str(snmpEngine.snmpEngineID), variables['transportDomain'],
                 variables['securityModel'], variables['securityLevel'],
                 str(variables['securityName']))), trunkReq)

        k = '#'.join([
            str(x)
            for x in (variables['contextEngineId'], variables['contextName'])
        ])
        for x, y in contextIdList:
            if y.match(k):
                trunkReq['snmp-context-id'] = macro.expandMacro(x, trunkReq)
                break
            else:
                trunkReq['snmp-context-id'] = None

        addr = '%s:%s#%s:%s' % (
            variables['transportAddress'][0], variables['transportAddress'][1],
            variables['transportAddress'].getLocalAddress()[0],
            variables['transportAddress'].getLocalAddress()[1])

        for pat, peerId in peerIdMap.get(str(variables['transportDomain']),
                                         ()):
            if pat.match(addr):
                trunkReq['snmp-peer-id'] = macro.expandMacro(peerId, trunkReq)
                break
        else:
            trunkReq['snmp-peer-id'] = None

        pdu = variables['pdu']
        if pdu.tagSet == v1.TrapPDU.tagSet:
            pdu = rfc2576.v1ToV2(pdu)
            v2c.apiTrapPDU.setDefaults(pdu)

        k = '#'.join([
            snmpPduTypesMap.get(variables['pdu'].tagSet, '?'),
            '|'.join([str(x[0]) for x in v2c.apiTrapPDU.getVarBinds(pdu)])
        ])

        for x, y in contentIdList:
            if y.match(k):
                trunkReq['snmp-content-id'] = macro.expandMacro(x, trunkReq)
                break
            else:
                trunkReq['snmp-content-id'] = None

        trunkReq['plugins-list'] = pluginIdMap.get(
            (trunkReq['snmp-credentials-id'], trunkReq['snmp-context-id'],
             trunkReq['snmp-peer-id'], trunkReq['snmp-content-id']), [])
        trunkReq['trunk-id-list'] = trunkIdMap.get(
            (trunkReq['snmp-credentials-id'], trunkReq['snmp-context-id'],
             trunkReq['snmp-peer-id'], trunkReq['snmp-content-id']))

        cbCtx.clear()
        cbCtx.update(trunkReq)

    #
    # main script starts here
    #

    helpMessage = """\
        Usage: %s [--help]
            [--version ]
            [--debug-snmp=<%s>]
            [--debug-asn1=<%s>]
            [--daemonize]
            [--process-user=<uname>] [--process-group=<gname>]
            [--pid-file=<file>]
            [--logging-method=<%s[:args>]>]
            [--log-level=<%s>]
            [--config-file=<file>]""" % (sys.argv[0], '|'.join([
        x for x in pysnmp_debug.flagMap.keys() if x != 'mibview'
    ]), '|'.join([x for x in pyasn1_debug.flagMap.keys()]), '|'.join(
        log.methodsMap.keys()), '|'.join(log.levelsMap))

    try:
        opts, params = getopt.getopt(sys.argv[1:], 'hv', [
            'help', 'version', 'debug=', 'debug-snmp=', 'debug-asn1=',
            'daemonize', 'process-user='******'process-group=', 'pid-file=',
            'logging-method=', 'log-level=', 'config-file='
        ])

    except Exception:
        sys.stderr.write('ERROR: %s\r\n%s\r\n' %
                         (sys.exc_info()[1], helpMessage))
        return

    if params:
        sys.stderr.write('ERROR: extra arguments supplied %s\r\n%s\r\n' %
                         (params, helpMessage))
        return

    pidFile = ''
    cfgFile = CONFIG_FILE
    foregroundFlag = True
    procUser = procGroup = None

    loggingMethod = ['stderr']
    loggingLevel = None

    for opt in opts:
        if opt[0] == '-h' or opt[0] == '--help':
            sys.stderr.write("""\
        Synopsis:
          SNMP Proxy Forwarder: server part. Receives SNMP requests at one or many
          built-in SNMP Agents and routes them to encrypted trunks established with
          Forwarder's Manager part(s) running elsewhere.
          Can implement complex routing logic through analyzing parts of SNMP messages
          and matching them against proxying rules.

        Documentation:
          http://snmpfwd.sourceforge.io/

    %s
    """ % helpMessage)
            return
        if opt[0] == '-v' or opt[0] == '--version':
            import snmpfwd
            import pysnmp
            import pyasn1
            sys.stderr.write("""\
        SNMP Proxy Forwarder version %s, written by Ilya Etingof <*****@*****.**>
        Using foundation libraries: pysnmp %s, pyasn1 %s.
        Python interpreter: %s
        Software documentation and support at https://github.com/etingof/snmpfwd
        %s
        """ % (snmpfwd.__version__, hasattr(pysnmp, '__version__')
               and pysnmp.__version__ or 'unknown',
               hasattr(pyasn1, '__version__') and pyasn1.__version__
               or 'unknown', sys.version, helpMessage))
            return
        elif opt[0] == '--debug-snmp':
            pysnmp_debug.setLogger(
                pysnmp_debug.Debug(*opt[1].split(','),
                                   **dict(loggerName=PROGRAM_NAME +
                                          '.pysnmp')))
        elif opt[0] == '--debug-asn1':
            pyasn1_debug.setLogger(
                pyasn1_debug.Debug(*opt[1].split(','),
                                   **dict(loggerName=PROGRAM_NAME +
                                          '.pyasn1')))
        elif opt[0] == '--daemonize':
            foregroundFlag = False
        elif opt[0] == '--process-user':
            procUser = opt[1]
        elif opt[0] == '--process-group':
            procGroup = opt[1]
        elif opt[0] == '--pid-file':
            pidFile = opt[1]
        elif opt[0] == '--logging-method':
            loggingMethod = opt[1].split(':')
        elif opt[0] == '--log-level':
            loggingLevel = opt[1]
        elif opt[0] == '--config-file':
            cfgFile = opt[1]

    try:
        log.setLogger(PROGRAM_NAME, *loggingMethod, **dict(force=True))

        if loggingLevel:
            log.setLevel(loggingLevel)

    except SnmpfwdError:
        sys.stderr.write('%s\r\n%s\r\n' % (sys.exc_info()[1], helpMessage))
        return

    try:
        cfgTree = cparser.Config().load(cfgFile)
    except SnmpfwdError:
        log.error('configuration parsing error: %s' % sys.exc_info()[1])
        return

    if cfgTree.getAttrValue('program-name', '', default=None) != PROGRAM_NAME:
        log.error('config file %s does not match program name %s' %
                  (cfgFile, PROGRAM_NAME))
        return

    if cfgTree.getAttrValue('config-version', '',
                            default=None) != CONFIG_VERSION:
        log.error(
            'config file %s version is not compatible with program version %s'
            % (cfgFile, CONFIG_VERSION))
        return

    random.seed()

    gCurrentRequestContext = {}

    credIdMap = {}
    peerIdMap = {}
    contextIdList = []
    contentIdList = []
    pluginIdMap = {}
    trunkIdMap = {}
    engineIdMap = {}

    transportDispatcher = AsynsockDispatcher()
    transportDispatcher.registerRoutingCbFun(lambda td, t, d: td)
    transportDispatcher.setSocketMap()  # use global asyncore socket map

    #
    # Initialize plugin modules
    #

    pluginManager = PluginManager(macro.expandMacros(
        cfgTree.getAttrValue('plugin-modules-path-list',
                             '',
                             default=[],
                             vector=True),
        {'config-dir': os.path.dirname(cfgFile)}),
                                  progId=PROGRAM_NAME,
                                  apiVer=PLUGIN_API_VERSION)

    for pluginCfgPath in cfgTree.getPathsToAttr('plugin-id'):
        pluginId = cfgTree.getAttrValue('plugin-id', *pluginCfgPath)
        pluginMod = cfgTree.getAttrValue('plugin-module', *pluginCfgPath)
        pluginOptions = macro.expandMacros(
            cfgTree.getAttrValue('plugin-options', *pluginCfgPath,
                                 **dict(default=[], vector=True)),
            {'config-dir': os.path.dirname(cfgFile)})

        log.info(
            'configuring plugin ID %s (at %s) from module %s with options %s...'
            % (pluginId, '.'.join(pluginCfgPath), pluginMod,
               ', '.join(pluginOptions) or '<none>'))

        try:
            pluginManager.loadPlugin(pluginId, pluginMod, pluginOptions)

        except SnmpfwdError:
            log.error('plugin %s not loaded: %s' %
                      (pluginId, sys.exc_info()[1]))
            return

    for configEntryPath in cfgTree.getPathsToAttr('snmp-credentials-id'):
        credId = cfgTree.getAttrValue('snmp-credentials-id', *configEntryPath)
        configKey = []
        log.info('configuring snmp-credentials %s (at %s)...' %
                 (credId, '.'.join(configEntryPath)))

        engineId = cfgTree.getAttrValue('snmp-engine-id', *configEntryPath)

        if engineId in engineIdMap:
            snmpEngine, snmpContext, snmpEngineMap = engineIdMap[engineId]
            log.info('using engine-id %s' %
                     snmpEngine.snmpEngineID.prettyPrint())
        else:
            snmpEngine = engine.SnmpEngine(snmpEngineID=engineId)
            snmpContext = context.SnmpContext(snmpEngine)
            snmpEngineMap = {'transportDomain': {}, 'securityName': {}}

            snmpEngine.observer.registerObserver(
                securityAuditObserver,
                'rfc2576.prepareDataElements:sm-failure',
                'rfc3412.prepareDataElements:sm-failure',
                cbCtx=gCurrentRequestContext)

            snmpEngine.observer.registerObserver(
                requestObserver,
                'rfc3412.receiveMessage:request',
                cbCtx=gCurrentRequestContext)

            CommandResponder(snmpEngine, snmpContext)

            NotificationReceiver(snmpEngine, None)

            engineIdMap[engineId] = snmpEngine, snmpContext, snmpEngineMap

            log.info('new engine-id %s' %
                     snmpEngine.snmpEngineID.prettyPrint())

        configKey.append(str(snmpEngine.snmpEngineID))

        transportDomain = cfgTree.getAttrValue('snmp-transport-domain',
                                               *configEntryPath)
        transportDomain = rfc1902.ObjectName(transportDomain)

        if transportDomain in snmpEngineMap['transportDomain']:
            h, p, transportDomain = snmpEngineMap['transportDomain'][
                transportDomain]
            log.info('using transport endpoint %s:%s, transport ID %s' %
                     (h, p, transportDomain))
        else:
            if transportDomain[:len(udp.domainName)] == udp.domainName:
                transport = udp.UdpTransport()
            elif transportDomain[:len(udp6.domainName)] == udp6.domainName:
                transport = udp6.Udp6Transport()
            else:
                log.error('unknown transport domain %s' % (transportDomain, ))
                return

            h, p = cfgTree.getAttrValue('snmp-bind-address',
                                        *configEntryPath).split(':', 1)

            snmpEngine.registerTransportDispatcher(transportDispatcher,
                                                   transportDomain)

            transportOptions = cfgTree.getAttrValue(
                'snmp-transport-options', *configEntryPath,
                **dict(default=[], vector=True))

            t = transport.openServerMode((h, int(p)))

            if 'transparent-proxy' in transportOptions:
                t.enablePktInfo()
                t.enableTransparent()
            elif 'virtual-interface' in transportOptions:
                t.enablePktInfo()

            config.addSocketTransport(snmpEngine, transportDomain, t)

            snmpEngineMap['transportDomain'][
                transportDomain] = h, p, transportDomain

            log.info(
                'new transport endpoint %s:%s, options %s, transport ID %s' %
                (h, p, transportOptions and '/'.join(transportOptions)
                 or '<none>', transportDomain))

        configKey.append(transportDomain)

        securityModel = cfgTree.getAttrValue('snmp-security-model',
                                             *configEntryPath)
        securityModel = rfc1902.Integer(securityModel)
        securityLevel = cfgTree.getAttrValue('snmp-security-level',
                                             *configEntryPath)
        securityLevel = rfc1902.Integer(securityLevel)
        securityName = cfgTree.getAttrValue('snmp-security-name',
                                            *configEntryPath)

        if securityModel in (1, 2):
            if securityName in snmpEngineMap['securityName']:
                if snmpEngineMap['securityName'][
                        securityModel] == securityModel:
                    log.info('using security-name %s' % securityName)
                else:
                    raise SnmpfwdError(
                        'snmp-security-name %s already in use at snmp-security-model %s'
                        % (securityName, securityModel))
            else:
                communityName = cfgTree.getAttrValue('snmp-community-name',
                                                     *configEntryPath)
                config.addV1System(snmpEngine,
                                   securityName,
                                   communityName,
                                   securityName=securityName)
                log.info(
                    'new community-name %s, security-model %s, security-name %s, security-level %s'
                    % (communityName, securityModel, securityName,
                       securityLevel))
                snmpEngineMap['securityName'][securityName] = securityModel

            configKey.append(securityModel)
            configKey.append(securityLevel)
            configKey.append(securityName)

        elif securityModel == 3:
            if securityName in snmpEngineMap['securityName']:
                log.info('using USM security-name: %s' % securityName)
            else:
                usmUser = cfgTree.getAttrValue('snmp-usm-user',
                                               *configEntryPath)
                log.info(
                    'new USM user %s, security-model %s, security-level %s, security-name %s'
                    % (usmUser, securityModel, securityLevel, securityName))

                if securityLevel in (2, 3):
                    usmAuthProto = cfgTree.getAttrValue(
                        'snmp-usm-auth-protocol', *configEntryPath,
                        **dict(default=config.usmHMACMD5AuthProtocol))
                    usmAuthProto = rfc1902.ObjectName(usmAuthProto)
                    usmAuthKey = cfgTree.getAttrValue('snmp-usm-auth-key',
                                                      *configEntryPath)
                    log.info(
                        'new USM authentication key: %s, authentication protocol: %s'
                        % (usmAuthKey, usmAuthProto))

                    if securityLevel == 3:
                        usmPrivProto = cfgTree.getAttrValue(
                            'snmp-usm-priv-protocol', *configEntryPath,
                            **dict(default=config.usmDESPrivProtocol))
                        usmPrivProto = rfc1902.ObjectName(usmPrivProto)
                        usmPrivKey = cfgTree.getAttrValue(
                            'snmp-usm-priv-key', *configEntryPath,
                            **dict(default=None))
                        log.info(
                            'new USM encryption key: %s, encryption protocol: %s'
                            % (usmPrivKey, usmPrivProto))

                        config.addV3User(snmpEngine, usmUser, usmAuthProto,
                                         usmAuthKey, usmPrivProto, usmPrivKey)

                    else:
                        config.addV3User(snmpEngine, usmUser, usmAuthProto,
                                         usmAuthKey)

                else:
                    config.addV3User(snmpEngine, usmUser)

                snmpEngineMap['securityName'][securityName] = securityModel

            configKey.append(securityModel)
            configKey.append(securityLevel)
            configKey.append(securityName)

        else:
            raise SnmpfwdError('unknown snmp-security-model: %s' %
                               securityModel)

        configKey = tuple(configKey)
        if configKey in credIdMap:
            log.error(
                'ambiguous configuration for key snmp-credentials-id=%s at %s'
                % (credId, '.'.join(configEntryPath)))
            return

        credIdMap[configKey] = credId

    duplicates = {}

    for peerCfgPath in cfgTree.getPathsToAttr('snmp-peer-id'):
        peerId = cfgTree.getAttrValue('snmp-peer-id', *peerCfgPath)
        if peerId in duplicates:
            log.error(
                'duplicate snmp-peer-id=%s at %s and %s' %
                (peerId, '.'.join(peerCfgPath), '.'.join(duplicates[peerId])))
            return

        duplicates[peerId] = peerCfgPath

        log.info('configuring peer ID %s (at %s)...' %
                 (peerId, '.'.join(peerCfgPath)))
        transportDomain = cfgTree.getAttrValue('snmp-transport-domain',
                                               *peerCfgPath)
        if transportDomain not in peerIdMap:
            peerIdMap[transportDomain] = []
        for peerAddress in cfgTree.getAttrValue(
                'snmp-peer-address-pattern-list', *peerCfgPath,
                **dict(vector=True)):
            for bindAddress in cfgTree.getAttrValue(
                    'snmp-bind-address-pattern-list', *peerCfgPath,
                    **dict(vector=True)):
                peerIdMap[transportDomain].append(
                    (re.compile(peerAddress + '#' + bindAddress), peerId))

    duplicates = {}

    for contextCfgPath in cfgTree.getPathsToAttr('snmp-context-id'):
        contextId = cfgTree.getAttrValue('snmp-context-id', *contextCfgPath)
        if contextId in duplicates:
            log.error('duplicate snmp-context-id=%s at %s and %s' %
                      (contextId, '.'.join(contextCfgPath), '.'.join(
                          duplicates[contextId])))
            return

        duplicates[contextId] = contextCfgPath

        k = '#'.join((cfgTree.getAttrValue('snmp-context-engine-id-pattern',
                                           *contextCfgPath),
                      cfgTree.getAttrValue('snmp-context-name-pattern',
                                           *contextCfgPath)))

        log.info('configuring context ID %s (at %s), composite key: %s' %
                 (contextId, '.'.join(contextCfgPath), k))

        contextIdList.append((contextId, re.compile(k)))

    duplicates = {}

    for contentCfgPath in cfgTree.getPathsToAttr('snmp-content-id'):
        contentId = cfgTree.getAttrValue('snmp-content-id', *contentCfgPath)
        if contentId in duplicates:
            log.error('duplicate snmp-content-id=%s at %s and %s' %
                      (contentId, '.'.join(contentCfgPath), '.'.join(
                          duplicates[contentId])))
            return

        duplicates[contentId] = contentCfgPath

        for x in cfgTree.getAttrValue('snmp-pdu-oid-prefix-pattern-list',
                                      *contentCfgPath, **dict(vector=True)):
            k = '#'.join([
                cfgTree.getAttrValue('snmp-pdu-type-pattern', *contentCfgPath),
                x
            ])

            log.info('configuring content ID %s (at %s), composite key: %s' %
                     (contentId, '.'.join(contentCfgPath), k))

            contentIdList.append((contentId, re.compile(k)))

    del duplicates

    for pluginCfgPath in cfgTree.getPathsToAttr('using-plugin-id-list'):
        pluginIdList = cfgTree.getAttrValue('using-plugin-id-list',
                                            *pluginCfgPath,
                                            **dict(vector=True))
        log.info('configuring plugin ID(s) %s (at %s)...' %
                 (','.join(pluginIdList), '.'.join(pluginCfgPath)))
        for credId in cfgTree.getAttrValue('matching-snmp-credentials-id-list',
                                           *pluginCfgPath,
                                           **dict(vector=True)):
            for peerId in cfgTree.getAttrValue('matching-snmp-peer-id-list',
                                               *pluginCfgPath,
                                               **dict(vector=True)):
                for contextId in cfgTree.getAttrValue(
                        'matching-snmp-context-id-list', *pluginCfgPath,
                        **dict(vector=True)):
                    for contentId in cfgTree.getAttrValue(
                            'matching-snmp-content-id-list', *pluginCfgPath,
                            **dict(vector=True)):
                        k = credId, contextId, peerId, contentId
                        if k in pluginIdMap:
                            log.error(
                                'duplicate snmp-credentials-id %s, snmp-context-id %s, snmp-peer-id %s, snmp-content-id %s at plugin-id(s) %s'
                                % (credId, contextId, peerId, contentId,
                                   ','.join(pluginIdList)))
                            return
                        else:
                            log.info(
                                'configuring plugin(s) %s (at %s), composite key: %s'
                                % (','.join(pluginIdList),
                                   '.'.join(pluginCfgPath), '/'.join(k)))

                            for pluginId in pluginIdList:
                                if not pluginManager.hasPlugin(pluginId):
                                    log.error(
                                        'undefined plugin ID %s referenced at %s'
                                        % (pluginId, '.'.join(pluginCfgPath)))
                                    return

                            pluginIdMap[k] = pluginIdList

    for routeCfgPath in cfgTree.getPathsToAttr('using-trunk-id-list'):
        trunkIdList = cfgTree.getAttrValue('using-trunk-id-list',
                                           *routeCfgPath, **dict(vector=True))
        log.info('configuring destination trunk ID(s) %s (at %s)...' %
                 (','.join(trunkIdList), '.'.join(routeCfgPath)))
        for credId in cfgTree.getAttrValue('matching-snmp-credentials-id-list',
                                           *routeCfgPath, **dict(vector=True)):
            for peerId in cfgTree.getAttrValue('matching-snmp-peer-id-list',
                                               *routeCfgPath,
                                               **dict(vector=True)):
                for contextId in cfgTree.getAttrValue(
                        'matching-snmp-context-id-list', *routeCfgPath,
                        **dict(vector=True)):
                    for contentId in cfgTree.getAttrValue(
                            'matching-snmp-content-id-list', *routeCfgPath,
                            **dict(vector=True)):
                        k = credId, contextId, peerId, contentId
                        if k in trunkIdMap:
                            log.error(
                                'duplicate snmp-credentials-id %s, snmp-context-id %s, snmp-peer-id %s, snmp-content-id %s at trunk-id(s) %s'
                                % (credId, contextId, peerId, contentId,
                                   ','.join(trunkIdList)))
                            return
                        else:
                            trunkIdMap[k] = trunkIdList

                        log.info(
                            'configuring trunk routing to %s (at %s), composite key: %s'
                            % (','.join(trunkIdList), '.'.join(routeCfgPath),
                               '/'.join(k)))

    def dataCbFun(trunkId, msgId, msg):
        log.debug('message ID %s received from trunk %s' % (msgId, trunkId))

    trunkingManager = TrunkingManager(dataCbFun)

    def getTrunkAddr(a, port=0):
        f = lambda h, p=port: (h, int(p))
        try:
            return f(*a.split(':'))

        except Exception:
            raise SnmpfwdError('improper IPv4 endpoint %s' % a)

    for trunkCfgPath in cfgTree.getPathsToAttr('trunk-id'):
        trunkId = cfgTree.getAttrValue('trunk-id', *trunkCfgPath)
        secret = cfgTree.getAttrValue('trunk-crypto-key', *trunkCfgPath,
                                      **dict(default=''))
        secret = secret and (secret * ((16 // len(secret)) + 1))[:16]
        log.info('configuring trunk ID %s (at %s)...' %
                 (trunkId, '.'.join(trunkCfgPath)))
        connectionMode = cfgTree.getAttrValue('trunk-connection-mode',
                                              *trunkCfgPath)
        if connectionMode == 'client':
            trunkingManager.addClient(
                trunkId,
                getTrunkAddr(
                    cfgTree.getAttrValue('trunk-bind-address', *trunkCfgPath)),
                getTrunkAddr(
                    cfgTree.getAttrValue('trunk-peer-address', *trunkCfgPath),
                    30201),
                cfgTree.getAttrValue('trunk-ping-period',
                                     *trunkCfgPath,
                                     default=0,
                                     expect=int), secret)
            log.info(
                'new trunking client from %s to %s' %
                (cfgTree.getAttrValue('trunk-bind-address', *trunkCfgPath),
                 cfgTree.getAttrValue('trunk-peer-address', *trunkCfgPath)))
        if connectionMode == 'server':
            trunkingManager.addServer(
                getTrunkAddr(
                    cfgTree.getAttrValue('trunk-bind-address', *trunkCfgPath),
                    30201),
                cfgTree.getAttrValue('trunk-ping-period',
                                     *trunkCfgPath,
                                     default=0,
                                     expect=int), secret)
            log.info(
                'new trunking server at %s' %
                (cfgTree.getAttrValue('trunk-bind-address', *trunkCfgPath)))

    transportDispatcher.registerTimerCbFun(trunkingManager.setupTrunks,
                                           random.randrange(1, 5))
    transportDispatcher.registerTimerCbFun(trunkingManager.monitorTrunks,
                                           random.randrange(1, 5))

    try:
        daemon.dropPrivileges(procUser, procGroup)

    except Exception:
        log.error('can not drop privileges: %s' % sys.exc_info()[1])
        return

    if not foregroundFlag:
        try:
            daemon.daemonize(pidFile)

        except Exception:
            log.error('can not daemonize process: %s' % sys.exc_info()[1])
            return

    # Run mainloop

    log.info('starting I/O engine...')

    transportDispatcher.jobStarted(1)  # server job would never finish

    # Python 2.4 does not support the "finally" clause

    while True:
        try:
            transportDispatcher.runDispatcher()

        except (PySnmpError, SnmpfwdError, socket.error):
            log.error(str(sys.exc_info()[1]))
            continue

        except Exception:
            transportDispatcher.closeDispatcher()
            raise