SNMP (Simple Network Management Protocol-簡單網絡管理協議)


前言

在運維工作中我們通常借助SNMP協議,以get/walk  oid到網絡設備返回結果的方式,對網絡設備進行被動監控。

但是這種監控方式有如下缺陷:

監控觸發時機無法精確把握

可監控項比較有限

Trap是在網絡設備上設置各種trap,一旦網絡設備(交換機、防火牆、路由器、AC、AP)發生故障時立即觸發已設置的trap時,網絡設備主動把trap報文匯報到trap-server。(報警全面、及時)

 

最終目標是可以做1個類似 H3C的IMC(Intelligent management center)智能管理中心。

 

 

 

SNMP協議介紹

什么是SNMP協議?

Simple Network Management Protocol (SNMP是一種基於UDP協議的,簡單的網絡管理協議):

The core of SNMP is a simple set of  operations that gives administrators the ability to get or change the sate of some SNMP-based devive.

管理員通過1組操作(

  • Get:讀取網絡設備的狀態信息。

  • Set:遠程配置設備參數。

  • Trap:被監控設備主動 發送SNMP trap報文。 

)  去獲取和改變基於SNMP設備的狀態。

  

 

SMI和MIB是什么?

SMI:The Structure of Management Infomaton.管理信息結構

SMI defines how management information is grouped and named;allowed operations、permitted data type and synatax for specifying MIBs.

SMI是一種用於描述單個管理信息節點的數據結構:包含管理節點的oid名稱、數據類型、語法。

 VarBind:
  name=1.3.6.1.4.1.2011.5.25.207.1.2.1.1.4.34
  =_BindValue:
   value=ObjectSyntax:
    simple=SimpleSyntax:
     string-value=VTY0

 

MIB(妹播):Management Information Base 管理信息庫。

The Management Infromation Base(MIB) can be thought of a database of managed object that the agent tracks

如果我們采用倒置樹結構,使用1個全球唯一的數字把每1個被管理節點的名稱標識出來,並保證標識每個被管理節點的數字不重復,這樣就組成了1個類似DNS的管理信息庫,所以MIB就是1個管理對象名稱和oid關系 映射表。

 

A agent may implement many MIBs(NMS端)

but all agents implement a particular MIB called MIB-II.(從上圖可知:MIb2的從1.3.6.1.2.1開頭)

不管是華為交換機還是什么思科路由器只要它支持SNMP協議,廠家都都會實現了1個MIB庫這就是:MIB2

不同的是每個網絡設備廠商都會在1.3.6.1.2.1.N.后面申請1個Enterprise ID例如華為是2011,用來標識自己生產的設備中被管理對象的oid.

ps:以下是華為交換機的oid信息S2700 V100R006C05

from pysnmp.entity.rfc3413.oneliner import cmdgen
cg=cmdgen.CommandGenerator()
#,安全名稱my-agent、社區名public、snmp協議版本,之間用逗號隔開。(snmp協議版本:0代表 snmpv1版本,1代表snmpV2c版本)
ret=cg.getCmd(cmdgen.CommunityData('xxxxx','xxxx',1), 
        cmdgen.UdpTransportTarget(('10.44.4.48',161)),'1.3.6.1.2.1.1.1.0')   #ip 端口 OID,一個OID對應一種設備(比如網卡、磁盤等,在不同機器上同種設備的OID是一樣的)
            #1.3.6.1.2.1.1.1.0#獲取系統基本信息
            #1.3.6.1.2.1.1.2.0#獲取enterprises.2011.2.23.224
            #1.3.6.1.2.1.1.3.0#系統運行時間
            #1.3.6.1.2.1.1.4.0#系統聯系人
            #1.3.6.1.2.1.1.5.0#機器名稱
            #1.3.6.1.2.1.1.6.0#機器坐在位置
            #1.3.6.1.4.1.2011.5.25.31.1.1.1.1.5.67108873 CPU使用率
            #1.3.6.1.4.1.2011.5.25.31.1.1.1.1.7.67108873內存使用率
            #1.3.6.1.4.1.2011.5.25.31.1.1.1.1.11.67108873機器溫度
            #(1,3,6,1,2,1,1,5,0)

            #(1,3,6,1,4,1,2011,6,3,4,1,2,0,0,0) 5秒鍾
            #(1,3,6,1,4,1,2011,6,3,4,1,3,0,0,0) 1分鍾
            #1.3.6.1.4.1.2011.6.3.4.1,
            #(1,3,6,1,4,1,2011,6,3,4,1,4,0,0,0)  5分鍾
# print(ret[-1])

 

SNMP架構

 

1.NMS向Agent發送Get/Set請求

2.Agent接收請求,獲取請求報文中攜帶的oid

3.從Agent端的MIB中解析oid,執行命令。

4.講命令的結果返回NMS

 

SNMP的版本

V1:

The inital version of SNMP protocol 

SNMPv1's security is based on communities,which are nothing more than password:plain-text strings that allow any SNMP-based application that knows the strings to gain access to a devive's management infomation.

SNMP協議的安全主要基於社區,社區就是一個明文字符串,只要監控端(NMS)和被監控端(Agent)之間都使用同了1個明文字符串,就說明他們屬於同一社區,所以監控端(NMS)就可以獲取、設置被監控設備(Agent)上的管理信息。

There are typically these communities in SNMPV1:read-only、read-write、trap

V2/V2C:

It is often referred to as community-string-based SNMPv2

The version of SNMP is technically called SNMPV2C 

SNMPV2版本仍然使用基於社區字符串的方式進行傳輸數據,當擴展了SNMPv1版本的功能,SNMPv2也被稱為SNMPV2C。

V3:

It adds support for strong authentication and private comminication between managed entities.

v3版本在SNMP在NMS(監控端)和Agent(被監控端)之間增加了認證和私有社區字符串。

ps:截止目前最流行的版本仍然是V1因為v1版本簡單,還有就是網絡設備更新迭代慢。

 

 

snmpd安裝(Agent端)

在Linux上關於snmp的軟件包有2個

net-snmp:snmp的Agent也就是(被監端)

net-snmp-utills:NetworkManagement System (NMS監控別人端)

想要支持trap功能:net-snmp+net-snmp-utills全部安裝,因為只有安裝了net-snmp包才能監聽在UDP的162端口上接收trap報文。

 

安裝(agent+NMS)

yum install net-snmp net-snmp-utils

 

啟動snmpd(agent)

[root@zhanggen snmp]# systemctl restart snmpd
[root@zhanggen snmp]# netstat -unlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name         
udp        0      0 0.0.0.0:161             0.0.0.0:*                           3506/snmpd   

 

tcpdump抓包

[root@4 trap_server]# tcpdump udp port 162 and host 10.44.14.64

 

獲取監控信息

[root@zhanggen snmp]# snmpwalk -v 2c -c public localhost
SNMPv2-MIB::sysDescr.0 = STRING: Linux zhanggen 3.10.0-514.el7.x86_64 #1 SMP Tue Nov 22 16:42:41 UTC 2016 x86_64
SNMPv2-MIB::sysObjectID.0 = OID: NET-SNMP-MIB::netSnmpAgentOIDs.10
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (63840) 0:10:38.40
SNMPv2-MIB::sysContact.0 = STRING: Root <root@localhost> (configure /etc/snmp/snmp.local.conf)
SNMPv2-MIB::sysName.0 = STRING: zhanggen
SNMPv2-MIB::sysLocation.0 = STRING: Unknown (edit /etc/snmp/snmpd.conf)
SNMPv2-MIB::sysORLastChange.0 = Timeticks: (2) 0:00:00.02
SNMPv2-MIB::sysORID.1 = OID: SNMP-MPD-MIB::snmpMPDCompliance
SNMPv2-MIB::sysORID.2 = OID: SNMP-USER-BASED-SM-MIB::usmMIBCompliance
SNMPv2-MIB::sysORID.3 = OID: SNMP-FRAMEWORK-MIB::snmpFrameworkMIBCompliance
SNMPv2-MIB::sysORID.4 = OID: SNMPv2-MIB::snmpMIB
SNMPv2-MIB::sysORID.5 = OID: TCP-MIB::tcpMIB
SNMPv2-MIB::sysORID.6 = OID: IP-MIB::ip
SNMPv2-MIB::sysORID.7 = OID: UDP-MIB::udpMIB
SNMPv2-MIB::sysORID.8 = OID: SNMP-VIEW-BASED-ACM-MIB::vacmBasicGroup
SNMPv2-MIB::sysORID.9 = OID: SNMP-NOTIFICATION-MIB::snmpNotifyFullCompliance
SNMPv2-MIB::sysORID.10 = OID: NOTIFICATION-LOG-MIB::notificationLogMIB
SNMPv2-MIB::sysORDescr.1 = STRING: The MIB for Message Processing and Dispatching.
SNMPv2-MIB::sysORDescr.2 = STRING: The management information definitions for the SNMP User-based Security Model.
SNMPv2-MIB::sysORDescr.3 = STRING: The SNMP Management Architecture MIB.
SNMPv2-MIB::sysORDescr.4 = STRING: The MIB module for SNMPv2 entities
SNMPv2-MIB::sysORDescr.5 = STRING: The MIB module for managing TCP implementations
SNMPv2-MIB::sysORDescr.6 = STRING: The MIB module for managing IP and ICMP implementations
SNMPv2-MIB::sysORDescr.7 = STRING: The MIB module for managing UDP implementations
SNMPv2-MIB::sysORDescr.8 = STRING: View-based Access Control Model for SNMP.
SNMPv2-MIB::sysORDescr.9 = STRING: The MIB modules for managing SNMP Notification, plus filtering.
SNMPv2-MIB::sysORDescr.10 = STRING: The MIB module for logging SNMP Notifications.
SNMPv2-MIB::sysORUpTime.1 = Timeticks: (2) 0:00:00.02
SNMPv2-MIB::sysORUpTime.2 = Timeticks: (2) 0:00:00.02
SNMPv2-MIB::sysORUpTime.3 = Timeticks: (2) 0:00:00.02
SNMPv2-MIB::sysORUpTime.4 = Timeticks: (2) 0:00:00.02
SNMPv2-MIB::sysORUpTime.5 = Timeticks: (2) 0:00:00.02
SNMPv2-MIB::sysORUpTime.6 = Timeticks: (2) 0:00:00.02
SNMPv2-MIB::sysORUpTime.7 = Timeticks: (2) 0:00:00.02
SNMPv2-MIB::sysORUpTime.8 = Timeticks: (2) 0:00:00.02
SNMPv2-MIB::sysORUpTime.9 = Timeticks: (2) 0:00:00.02
SNMPv2-MIB::sysORUpTime.10 = Timeticks: (2) 0:00:00.02
HOST-RESOURCES-MIB::hrSystemUptime.0 = Timeticks: (121940) 0:20:19.40
HOST-RESOURCES-MIB::hrSystemUptime.0 = No more variables left in this MIB View (It is past the end of the MIB tree)
[root@zhanggen snmp]# 

 獲取主機名

[root@zhanggen long]# snmpget -v 2c -c public 127.0.0.1 .1.3.6.1.2.1.1.5.0
SNMPv2-MIB::sysName.0 = STRING: zhanggen

 

后台啟動snmptrapd

[root@zhanggen snmp]# systemctl restart snmptrapd
[root@zhanggen snmp]# netstat -unlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name         
udp        0      0 0.0.0.0:161             0.0.0.0:*                           3506/snmpd          
udp        0      0 0.0.0.0:162             0.0.0.0:*                           4304/snmptrapd         
[root@zhanggen snmp]# 

 

前台啟動snmptrapd

[root@zhanggen bin]# snmptrapd -C -c/etc/snmp/snmptrapd.conf -df -Lo
NET-SNMP version 5.7.2

Received 72 byte packet from UDP: [127.0.0.1]:56573->[127.0.0.1]:162
0000: 30 46 02 01  01 04 06 70  75 62 6C 69  63 A7 39 02    0F.....public.9.
0016: 04 29 A7 B1  EC 02 01 00  02 01 00 30  2B 30 18 06    .).........0+0..
0032: 0A 2B 06 01  06 03 01 01  04 01 00 06  0A 2B 06 01    .+...........+..
0048: 04 01 8F 65  81 7B 01 30  0F 06 08 2B  06 01 02 01    ...e.{.0...+....
0064: 01 06 00 04  03 65 65 65                              .....eee

2020-06-12 01:18:49 localhost [UDP: [127.0.0.1]:54044->[127.0.0.1]:162]:
SNMPv2-MIB::snmpTrapOID.0 = OID: SNMPv2-SMI::enterprises.2345 SNMPv2-MIB::sysLocation.0 = STRING: just here

-C : 表示不使用net-snmp默認路徑下的配置文件snmptrapd.conf;
-c : 指定snmptrapd.conf文件;
-d : 顯示收到和發送的數據報,通過這個選項可以看到數據報文;
-f  : 默認情況下,snmptrapd是在后台中運行的,加上這個選項,表示在前台運行;
-L : 指定日志記錄在哪里,后面的o表示直接輸出到屏幕上,如果是跟着f表示日志記錄到指定的文件中;

 

 

snmp utills使用(NMS端)

如果有snmpd工作在161端口,那我么就可以使用snmp utills發送各種SNMP操作了。

發送snmptrap報文

[root@zhanggen nginx]# snmptrap -v 2c -c public 10.44.14.146 "zhanggen" 1.3.6.1.4.1.2345567 SNMPv2-MIB::sysLocation.0 s "this is a trap pud please load oid-->1.3.6.1.4.1.2345 in SNMPv2-MIB::sysLocation.0"
[root@zhanggen nginx]# 

接收trap server
2020-06-12 18:23:51 localhost [UDP: [127.0.0.1]:55926->[127.0.0.1]:162]:
SNMPv2-MIB::snmpTrapOID.0 = OID: SNMPv2-SMI::enterprises.2345    SNMPv2-MIB::sysLocation.0 = STRING: this is a trap pud please load oid-->1.3.6.1.4.1.2345 in SNMPv2-MIB::sysLocation.0

 發送v1版本

[root@zhanggen zhanggen]# snmptrap -v1 -c public 172.31.240.253 1.3.6.1.4.1.1 10.10.12.219 2 3 1000 1.3.6.1.9.9.44.1.2.1 i 12 1.3.4.1.2.3.1 s test_snmptrap 

 

 

 

參數說明:

-v 1|2c|3 specifies SNMP version to use(指定SNMP協議版本)

127.0.0.1:162 “zhanggen”:Trap server的IP、主機名,主機名稱可以為空;

-c COMMUNITY set the community string(設置社區名稱:agent和nms的之間通過社區建立信任)

.3.6.1.4.1.2345:企業OID,Enterprise-OID;

-m MIB[:...] load given list of MIBs (ALL loads everything)(Trap消息使用MIB庫解析oid和object name, 指定mib庫文件)

-M DIR[:...] look in given list of directories for MIBs(指定mib庫所在目錄)

SNMPv2-MIB::sysLocation.0 s “just here”:SNMPv2-MIB::sysLocation.0 觸發SNMPv2-MIB庫下sysLocation.0對象(oid對應的objectname)的報警、s:數據類型、數據值。

just her:說明

 

Trap PDU結構 ( SNMP v1 )

字段

類型

說明

PDU Type

 

PDU類型,Trap為4

Enterprise

Object Identifier

產生該Trap的網絡管理子系統,基於sysObjectID。如果是企業自定義Trap,此值為企業在enterprise子樹下的注冊子樹。

Agent-addr

NetworkAddress

產生Trap的SNMP實體地址,一般為代理地址

Generic-trap

Integer

通用trap類型,取值為coldStart、warmStart、linkDown、linkUp、authenticationFailure、egpNeihborLoss、enterpriseSpecific

Specific-trap

Integer

當Generic-trap為enterpriseSpecific時,specific-trap指明具體的企業自定義Trap類型,specific-trap跟在enterprise后面,組成了Trap的標識

Time-stamp

TimeTicks

上次初始化網絡實體和產生Trap的時間間隔,包含sysUpTime值

Variable-bindings

Sequences of

和Trap相關的附加信息

 

PDU結構(SNMP v2c)

字段

類型

說明

PDU Type

 

PDU類型

request-id

Integer

發送實體通過給每個PDU賦一個id使每一個到同一代理的請求能夠被唯一識別,代理應答時原封不動返回request-id值,使發送方可以將應答和請求匹配,也可以使雙方有能力處理UDP中可能產生的重復發送的消息

Error-status

Integer

用於表示在處理請求時出現的異常,對於trap數據包該字段為0。

Error-index

Integer

錯誤索引,對於trap數據包該字段為0。

variableBindings

Sequences of

所要求的實例列表

 

接收trap報文

python的pysnmp實現了對snmp協議的封裝,我們既可以使用這個模塊發送 trap/get/walk消息,還可以使用它作為trap-server接收trap報文。

#!/usr/bin/python3
#encoding=utf8
import datetime,requests,json
from pysnmp.carrier.asynsock.dispatch import AsynsockDispatcher
from pysnmp.carrier.asynsock.dgram import udp, udp6
from pyasn1.codec.ber import decoder
from pysnmp.proto import api


class TrapServer(object):
    def __init__(self,transfer_server):
        self.trap_server=transfer_server

    def run_trap_server(self):
        transportDispatcher = AsynsockDispatcher()
        #回調函數
        transportDispatcher.registerRecvCbFun(self.recive_trapPDU)
        # UDP/IPv4
        transportDispatcher.registerTransport(
            udp.domainName, udp.UdpSocketTransport().openServerMode(('0.0.0.0', 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
            transportDispatcher.runDispatcher()
        except:
            transportDispatcher.closeDispatcher()
            raise

    def recive_trapPDU(self, transportDispatcher, transportDomain, transportAddress, wholeMsg):
        while wholeMsg:
            # 解析消息版本
            msgVersion = int(api.decodeMessageVersion(wholeMsg))
            print("消息SNMP版本:0:v1, v1:v2c", msgVersion, datetime.datetime.now())
            ##根據snmp版本選擇protoModules模塊
            if msgVersion in api.protoModules:
                pMod = api.protoModules[msgVersion]
            else:
                print('不支持的 SNMP 版本 %s' % msgVersion)
                return
            # 根據protoModules解碼snmp的消息
            reqMsg, wholeMsg = decoder.decode(
                wholeMsg, asn1Spec=pMod.Message(),
            )
            # SNMPv2TrapPDU:
            reqPDU = pMod.apiMessage.getPDU(reqMsg)
            # 判斷是否為Mod.TrapPDU
            if reqPDU.isSameTypeWith(pMod.TrapPDU()):
                trapPDU_metadata={}
                if msgVersion == api.protoVersion1:
                    trapPDU_metadata["up_time"] =  pMod.apiTrapPDU.getTimeStamp(reqPDU).prettyPrint()
                    trapPDU_metadata["agent_address"] = pMod.apiTrapPDU.getAgentAddr(reqPDU).prettyPrint()
                    trapPDU_metadata["trap_generic"] = pMod.apiTrapPDU.getGenericTrap(reqPDU).prettyPrint()
                    trapPDU_metadata["trap_OID"] =pMod.apiTrapPDU.getEnterprise(reqPDU).prettyPrint()+'.'+pMod.apiTrapPDU.getSpecificTrap(reqPDU).prettyPrint()
                    #self.analy_trapPDU(trapPDU_metadata)
                    varBinds = pMod.apiTrapPDU.getVarBindList(reqPDU)
                else:
                    varBinds = pMod.apiPDU.getVarBindList(reqPDU)
                bind_info = ''
                for bind in varBinds:
                    for line in bind.values():
                        line=str(line)
                        '''
                    === 1.3.6.1.4.1.2011.6.122.62.1.4.0
                    === ObjectSyntax:
                        simple=SimpleSyntax:
                        string=ssh
                    '''
                        if line.startswith("1.3.6.1"):
                            line="[%s]"%line
                        bind_info+=line
                trapPDU_metadata["trap_details"]=bind_info
                self.trap_transfer(trapPDU_metadata)
                return

    def trap_transfer(self,data):
        data=json.dumps(data,ensure_ascii=False)
        headers = {'Content-Type':'application/json'}
        requests.post(url=self.trap_server, headers=headers, data=data)

if __name__ == '__main__':
    trapserver=TrapServer("http://127.0.0.1:8001/IToperation/trap/receive/API/")
    trapserver.run_trap_server()
經典版

經典版trap-server無法獲取snmp v2c版本報文的up_time、agent_address、trap_generic。

 

那就使用snmpv1版本把,可以當 AC發送報文過來時獲取的agent_address是127.0.1.1。我中途研究了snmp 報文的編碼規則 ASN1,試圖通過ASN1進行解碼。

from socket import *
from pysnmp.proto import api
from pyasn1.codec.der.decoder import decode
server = socket(AF_INET, SOCK_DGRAM)
server.bind(('10.44.13.73', 162))
while True:
    data1, addr = server.recvfrom(1024)
    msgVer = int(api.decodeMessageVersion(data1))
    pMod = api.protoModules[msgVer]
    reqMsg, wholeMsg =decode(data1,asn1Spec=pMod.Message())
    reqPDU = pMod.apiMessage.getPDU(reqMsg)
    varBinds = pMod.apiPDU.getVarBindList(reqPDU)
    print(addr)
    print('--------')
    print(varBinds)
    print('--------')
pyasn1自己解碼

 

在研究如何對發送到udp:162的trap報文進行ASN解碼的時候,我發現pysnmp模塊的官網。

可以同時監聽在多個port上,支持snmp v1和v2c版本trap/infro報文。

from pysnmp.entity import engine, config
from pysnmp.carrier.asyncore.dgram import udp
from pysnmp.entity.rfc3413 import ntfrcv

# Create SNMP engine with autogenernated engineID and pre-bound
# to socket transport dispatcher
snmpEngine = engine.SnmpEngine()

# Transport setup

# UDP over IPv4, first listening interface/port
config.addTransport(
    snmpEngine,
    udp.domainName + (1,),
    udp.UdpTransport().openServerMode(('127.0.0.1', 162))
)

# UDP over IPv4, second listening interface/port
config.addTransport(
    snmpEngine,
    udp.domainName + (2,),
    udp.UdpTransport().openServerMode(('127.0.0.1', 2162))
)

# SNMPv1/2c setup

# SecurityName <-> CommunityName mapping
config.addV1System(snmpEngine, 'my-area', 'public')


# Callback function for receiving notifications
# noinspection PyUnusedLocal,PyUnusedLocal,PyUnusedLocal
def cbFun(snmpEngine, stateReference, contextEngineId, contextName,
          varBinds, cbCtx):
    print('Notification from ContextEngineId "%s", ContextName "%s"' % (contextEngineId.prettyPrint(),
                                                                        contextName.prettyPrint()))
    for name, val in varBinds:
        print('%s = %s' % (name.prettyPrint(), val.prettyPrint()))


# Register SNMP Application at the SNMP engine
ntfrcv.NotificationReceiver(snmpEngine, cbFun)

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

# Run I/O dispatcher which would receive queries and send confirmations
try:
    snmpEngine.transportDispatcher.runDispatcher()
except:
    snmpEngine.transportDispatcher.closeDispatcher()
    raise
Serving multiple network interfaces

可以監聽在ipv4和ipv6上,支持snmp v1和v2c版本trap/infro報文。

from pysnmp.entity import engine, config
from pysnmp.carrier.asyncore.dgram import udp, udp6
from pysnmp.entity.rfc3413 import ntfrcv

# Create SNMP engine with autogenernated engineID and pre-bound
# to socket transport dispatcher
snmpEngine = engine.SnmpEngine()

# Transport setup

# UDP over IPv4
config.addTransport(
    snmpEngine,
    udp.domainName,
    udp.UdpTransport().openServerMode(('127.0.0.1', 162))
)

# UDP over IPv6
config.addTransport(
    snmpEngine,
    udp6.domainName,
    udp6.Udp6Transport().openServerMode(('::1', 162))
)

# SNMPv1/2c setup

# SecurityName <-> CommunityName mapping
config.addV1System(snmpEngine, 'my-area', 'public')


# Callback function for receiving notifications
# noinspection PyUnusedLocal,PyUnusedLocal,PyUnusedLocal
def cbFun(snmpEngine, stateReference, contextEngineId, contextName,
          varBinds, cbCtx):
    print('Notification from ContextEngineId "%s", ContextName "%s"' % (contextEngineId.prettyPrint(),
                                                                        contextName.prettyPrint()))
    for name, val in varBinds:
        print('%s = %s' % (name.prettyPrint(), val.prettyPrint()))


# Register SNMP Application at the SNMP engine
ntfrcv.NotificationReceiver(snmpEngine, cbFun)

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

# Run I/O dispatcher which would receive queries and send confirmations
try:
    snmpEngine.transportDispatcher.runDispatcher()
except:
    snmpEngine.transportDispatcher.closeDispatcher()
    raise
Using multiple network transports

監聽在ipv4 ip地址的162端口

from pysnmp.entity import engine, config
from pysnmp.carrier.asyncore.dgram import udp
from pysnmp.entity.rfc3413 import ntfrcv

# Create SNMP engine with autogenernated engineID and pre-bound
# to socket transport dispatcher
snmpEngine = engine.SnmpEngine()

# Transport setup

# UDP over IPv4, first listening interface/port
config.addTransport(
    snmpEngine,
    udp.domainName + (1,),
    udp.UdpTransport().openServerMode(('127.0.0.1', 162))
)

# SNMPv1/2c setup

# SecurityName <-> CommunityName mapping
config.addV1System(snmpEngine, 'my-area', 'public')


# Callback function for receiving notifications
# noinspection PyUnusedLocal,PyUnusedLocal
def cbFun(snmpEngine, stateReference, contextEngineId, contextName,
          varBinds, cbCtx):
    # Get an execution context...
    execContext = snmpEngine.observer.getExecutionContext(
        'rfc3412.receiveMessage:request'
    )

    # ... and use inner SNMP engine data to figure out peer address
    print('Notification from %s, ContextEngineId "%s", ContextName "%s"' % ('@'.join([str(x) for x in execContext['transportAddress']]),
                                                                            contextEngineId.prettyPrint(),
                                                                            contextName.prettyPrint()))
    for name, val in varBinds:
        print('%s = %s' % (name.prettyPrint(), val.prettyPrint()))


# Register SNMP Application at the SNMP engine
ntfrcv.NotificationReceiver(snmpEngine, cbFun)

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

# Run I/O dispatcher which would receive queries and send confirmations
try:
    snmpEngine.transportDispatcher.runDispatcher()
except:
    snmpEngine.transportDispatcher.closeDispatcher()
    raise
Receive notifications noting peer address

 

1個完整trap報文

以下是pysnmp 接收到的一個完整的trap報文,由

  • transportDomain
  • transportAddress
  • wholeMsg
  • messageProcessingModel
  • securityModel
  • securityName
  • securityLevel
  • contextEngineId
  • contextName
  • pdu

構成。

 

transportDomain ----------- (1, 3, 6, 1, 6, 1, 1, 1)
transportAddress ----------- ('10.8.193.10', 32774)
wholeMsg ----------- b"0\x82\x01H\x02\x01\x00\x04\x08hbit@618\xa4\x82\x017\x06\n+\x06\x01\x04\x01\x83\x042\x00\x0b@\x04\x7f\x00\x01\x01\x02\x01\x06\x02\x01\x14C\x04rQ\xa6\xa40\x82\x01\x150#\x06\x0c+\x06\x01\x04\x01\x83\x042\x01\x02\x01\x01\x04\x13EAP_OPP_CACHED_KEYS0\x15\x06\x0c+\x06\x01\x04\x01\x83\x042\x01\x02\x01\x02\x04\x05DOT110\x11\x06\x0c+\x06\x01\x04\x01\x83\x042\x01\x02\x01\x03\x02\x01\x060\x81\x88\x06\x0c+\x06\x01\x04\x01\x83\x042\x01\x02\x01\x04\x04xOpportunistic Key Cache used for client 'F8-DA-0C-54-29-79' on wlan 'JD' radio 'XH-6F01-AP03-5708:R1'. Skipping 802.1x. 0\x16\x06\x0c+\x06\x01\x04\x01\x83\x042\x01\x02\x01\x05\x04\x06\x84$\x8d\x87W\x080!\x06\x0c+\x06\x01\x04\x01\x83\x042\x01\x02\x01\x06\x04\x11XH-6F01-AP03-5708"
messageProcessingModel ----------- 0
securityModel ----------- 1
securityName ----------- my-area
securityLevel ----------- 1
contextEngineId ----------- O¸4$¥H
contextName ----------- 
pdu ----------- TrapPDU:
 enterprise=1.3.6.1.4.1.388.50.0.11
 agent-addr=NetworkAddress:
  internet=127.0.1.1

 generic-trap=enterpriseSpecific
 specific-trap=20
 time-stamp=1917953700
 variable-bindings=VarBindList:
  VarBind:
   name=1.3.6.1.4.1.388.50.1.2.1.1
   value=ObjectSyntax:
    simple=SimpleSyntax:
     string=EAP_OPP_CACHED_KEYS


  VarBind:
   name=1.3.6.1.4.1.388.50.1.2.1.2
   value=ObjectSyntax:
    simple=SimpleSyntax:
     string=DOT11


  VarBind:
   name=1.3.6.1.4.1.388.50.1.2.1.3
   value=ObjectSyntax:
    simple=SimpleSyntax:
     number=6


  VarBind:
   name=1.3.6.1.4.1.388.50.1.2.1.4
   value=ObjectSyntax:
    simple=SimpleSyntax:
     string=Opportunistic Key Cache used for client 'F8-DA-0C-54-29-79' on wlan 'JD' radio 'XH-6F01-AP03-5708:R1'. Skipping 802.1x. 


  VarBind:
   name=1.3.6.1.4.1.388.50.1.2.1.5
   value=ObjectSyntax:
    simple=SimpleSyntax:
     string=0x84248d875708


  VarBind:
   name=1.3.6.1.4.1.388.50.1.2.1.6
   value=ObjectSyntax:
    simple=SimpleSyntax:
     string=XH-6F01-AP03-5708
trap報文格式

 

 

發送snmpget

查看1個具體的oid節點

[root@zhanggen long]# snmpget -v 2c -c 社區名稱 10.44.4.48 1.3.6.1.4.1.2011.5.2.1.4.1.1.14.51.54.48.98.117.121.97.100.46.108.111.99.97.108
SNMPv2-SMI::enterprises.2011.5.2.1.4.1.1.14.51.54.48.98.117.121.97.100.46.108.111.99.97.108 = STRING: "360.local"
[root@zhanggen long]# snmpget -v 2c -c 社區名稱 10.44.4.48 1.3.6.1.4.1.2011.5.2.1.4.1.1.14.51.54.48.98.117.121.97.100.46.108.111.99.97.108

 

發送snmpwalk

如果對某個葉子節點的OID值做walk遍歷

[root@zhanggen]# snmpwalk -v 2c -c 社區名稱  10.44.4.48 1.3.6.1.4.1.2011.5
SNMPv2-SMI::enterprises.2011.5.2.1.1.1.1.4.97.117.116.104 = STRING: "auth"
SNMPv2-SMI::enterprises.2011.5.2.1.1.1.1.6.114.97.100.105.117.115 = STRING: "radius"
SNMPv2-SMI::enterprises.2011.5.2.1.1.1.1.7.100.101.102.97.117.108.116 = STRING: "default"
SNMPv2-SMI::enterprises.2011.5.2.1.1.1.2.4.97.117.116.104 = INTEGER: 5
SNMPv2-SMI::enterprises.2011.5.2.1.1.1.2.6.114.97.100.105.117.115 = INTEGER: 3
SNMPv2-SMI::enterprises.2011.5.2.1.1.1.2.7.100.101.102.97.117.108.116 = INTEGER: 1
SNMPv2-SMI::enterprises.2011.5.2.1.1.1.3.4.97.117.116.104 = INTEGER: 1
SNMPv2-SMI::enterprises.2011.5.2.1.1.1.3.6.114.97.100.105.117.115 = INTEGER: 1
SNMPv2-SMI::enterprises.2011.5.2.1.1.1.3.7.100.101.102.97.117.108.116 = INTEGER: 1
SNMPv2-SMI::enterprises.2011.5.2.1.2.1.1.7.100.101.102.97.117.108.116 = STRING: "default"
SNMPv2-SMI::enterprises.2011.5.2.1.2.1.2.7.100.101.102.97.117.108.116 = INTEGER: 2
SNMPv2-SMI::enterprises.2011.5.2.1.2.1.3.7.100.101.102.97.117.108.116 = INTEGER: 2
SNMPv2-SMI::enterprises.2011.5.2.1.2.1.4.7.100.101.102.97.117.108.116 = INTEGER: 1
SNMPv2-SMI::enterprises.2011.5.2.1.2.1.5.7.100.101.102.97.117.108.116 = INTEGER: 0
SNMPv2-SMI::enterprises.2011.5.2.1.2.1.6.7.100.101.102.97.117.108.116 = INTEGER: 1
SNMPv2-SMI::enterprises.2011.5.2.1.4.1.1.7.100.101.102.97.117.108.116 = STRING: "default"
SNMPv2-SMI::enterprises.2011.5.2.1.4.1.1.13.100.101.102.97.117.108.116.95.97.100.109.105.110 = STRING: "sss"
SNMPv2-SMI::enterprises.2011.5.2.1.4.1.1.14.51.54.48.98.117.121.97.100.46.108.111.99.97.108 = STRING: "ssss"
SNMPv2-SMI::enterprises.2011.5.2.1.4.1.2.7.100.101.102.97.117.108.116 = STRING: "ssss"
SNMPv2-SMI::enterprises.2011.5.2.1.4.1.2.13.100.101.102.97.117.108.116.95.97.100.109.105.110 = STRING: "default"
SNMPv2-SMI::enterprises.2011.5.2.1.4.1.2.14.51.54.48.98.117.121.97.100.46.108.111.99.97.108 = STRING: "auth"
SNMPv2-SMI::enterprises.2011.5.2.1.4.1.3.7.100.101.102.97.117.108.116 = STRING: "default"
SNMPv2-SMI::enterprises.2011.5.2.1.4.1.3.13.100.101.102.97.117.108.116.95.97.100.109.105.110 = STRING: "default"
SNMPv2-SMI::enterprises.2011.5.2.1.4.1.3.14.51.54.48.98.117.121.97.100.46.108.111.99.97.108 = STRING: "default"

 

 項目部署

#!/usr/bin/python3
# -*- coding:utf-8-*-
import pytz
import logging
import datetime
import sys,os,django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "trap_server.settings")
django.setup()  # 在Django視圖之外,調用Django功能設置環境變量!
from app01 import models
import pymysql
import datetime
import requests
import hashlib
from pysnmp.entity import engine, config
from pysnmp.carrier.asyncore.dgram import udp
from pysnmp.entity.rfc3413 import ntfrcv
import threading
import json
tz = pytz.timezone('Asia/Shanghai')


#記錄錯誤日志
def recordErrors(wrongLog):
    logger = logging.getLogger()
    log_file = './wrongIP.log'
    logger.setLevel(logging.INFO)
    file_handler = logging.FileHandler(log_file)
    file_handler.setLevel(logging.ERROR)
    log_formatter = logging.Formatter('%(asctime)s[%(levelname)s]: %(message)s')
    logger.addHandler(file_handler)
    logger.error(wrongLog)
    file_handler.setFormatter(log_formatter)



#報警推送模塊
class PushTarp():
    def __init__(self):
        self.ddURL="http://wlyw.jd.com/api/notice/dd"
        self.mailURL='http://basics.jd.com/api/write/email_add'
        self.getMailsByERPsURL="http://hn.jdwl.com/v/api/Setting/getMailsByERPs"
        self.mailToken='a2ec38d38fbaae3b3fdc3f98a98c0d8b'
        self.headers = {'content-type': 'application/json'}
        self.key= "vXO9jJRI6E0J"
        self.appid=2

    #獲取陳洋發送咚咚接口的token
    def generate_token(self):
        today = datetime.datetime.now().strftime('%Y-%m-%d')
        m = hashlib.md5()
        m.update(self.key.encode("utf-8"))
        md5key = m.hexdigest()
        m = hashlib.md5()
        m.update((today + md5key).encode("utf-8"))
        token = m.hexdigest()
        return token

    #判斷是否應該推送報警
    def decide_alarm(self,**alarm_data):
        warehouse = alarm_data['warehouse']
        current_policy = models.AlarmsPolicy.objects.filter(warehouse=warehouse).first()
        if current_policy and current_policy.alarm_trigger:
            trap_level = alarm_data['trap_level']
            if trap_level == '嚴重':
                now = datetime.datetime.now()
                AnHourAgo = now - datetime.timedelta(hours=1)
                within_anhour = models.TrapInfo.objects.filter(trap_time__range=[AnHourAgo, now],trap_oid=alarm_data['trap_oid'])
                if within_anhour :
                    return
            elif trap_level=='災難':
                pass
            return current_policy

    #從森偉的接口把erp賬號,轉換成郵箱賬號
    def getMailsByERPs(self,*erpList):
        data = {
            'erpList': json.dumps(list(erpList))
        }
        response = requests.post(url=self.getMailsByERPsURL, params=data)
        return response.json()


    #把報警推送到報警負責人的咚咚和郵箱
    def transfer_media(self,**alarm_data):
        if alarm_data.get('trap_level',) in ['嚴重', "災難"]:
            sentence=self.decide_alarm(**alarm_data)
            if(sentence):
                current_policy=sentence
                receiver=current_policy.notifier.strip(',').split(',')
                try:
                    self.send_email(*receiver,**alarm_data)
                    self.send_dongdong(*receiver, **alarm_data)
                except Exception:
                    print("%s庫房:報警發送給 %s  失敗,請檢查接收者erp賬號是否正確?"%(alarm_data['warehouse'],current_policy.notifier.strip(',')))
                    return
                else:
                    print("推送報警到咚咚和郵件成功")
                    current_policy.notice_time = datetime.datetime.now()
                    current_policy.save()

    def send_dongdong(self,*receiver,**alarm_data):
        msg = '''時間:{trap_time}\r\n預警來源:{brief_position}\r\n設備:{device_type}\r\nip:{agent_IPaddress}\r\n問題:{trap_name}\r\n預警類型:{trap_type}\r\n等級:{trap_level}'''.format(**alarm_data)
        data = {"token": self.generate_token(), "appid": self.appid, "erp":','.join(receiver) , "msg": msg}
        response = requests.post(url=self.ddURL, headers=self.headers, data=data)
        return response.json()

    def send_email(self,*receiver,**alarm_data):
        response_dict=self.getMailsByERPs(*receiver)
        receivers=','.join(list(response_dict['data'].values()))
        content='<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>{trap_name}</title></head><body><h1>{trap_details}</h1></body></html>'.format(**alarm_data)
        emial_title='{brief_position}/{agent_IPaddress}/{trap_name}'.format(**alarm_data)
        data={
            "token":self.mailToken,
            'user':'trap@jd.com',
            'pwd':"HBit@2020.com",
            'name':"預警系統",
            "title":emial_title,
            "content":content,
            "add": receivers,
            "bcc":"zhanggen24@jd.com",#每次發生郵件報警都會抄送
            "add_erp":"zhanggen24"
        }
        response=requests.post(url=self.mailURL,data=data)
        return response.json()


class SqlHelper(object):
    def __init__(self):
        # 讀取配置文件
        self.connect()

    def connect(self):
        self.conn = pymysql.connect(host='172.18.172.13', port=3358, user='lldp_rw', passwd='llDP!20190OO0~',
                                            db='net_detection', charset='utf8')
        # else:
        #     self.conn = pymysql.connect(host='192.168.158.132', port=3358, user='salt', passwd='saltstack',
        #                             db='net_detection', charset='utf8')
        self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)

    def get_list(self,sql,args):
        self.cursor.execute(sql,args)
        result = self.cursor.fetchall()
        return result

    def get_one(self,sql,args):
        self.cursor.execute(sql,args)
        result = self.cursor.fetchone()
        return result

    def modify(self,sql,args):
        self.cursor.execute(sql,args)
        self.conn.commit()

    def multiple_modify(self,sql,args):
        # self.cursor.executemany('insert into bd(id,name)values(%s,%s)',[(1,'alex'),(2,'eric')])
        self.cursor.executemany(sql,args)
        self.conn.commit()

    def create(self,sql,args):
        self.cursor.execute(sql,args)
        self.conn.commit()
        return self.cursor.lastrowid

    def close(self):
        self.cursor.close()
        self.conn.close()

    def ip2long(self,ip):
        ip_list = ip.split('.')
        result = 0
        for i in range(4):  # 0,1,2,3
            result = result + int(ip_list[i]) * 256 ** (3 - i)
        return result

    def ip_info(self, ip):
        self.ipnumber = self.ip2long(ip)
        sql = "SELECT * FROM t_storage_ip_region WHERE %s>= start_ip AND %s<= end_ip" % (self.ipnumber, self.ipnumber)
        ret = self.get_one(sql, [])
        # print(ret)
        sql = "SELECT * FROM t_storage_netinfo WHERE id=%d;" % (ret["storage_id"])
        ret = self.get_one(sql, [])
        sql = "SELECT * FROM t_region WHERE id=%d and is_delete=%d;" % (ret["region_id"], 0)
        ret = self.get_one(sql, [])
        warehouse = ret['region_name']
        sql = "SELECT * FROM t_region WHERE id=%d and is_delete=%d;" % (ret["parent_id"], 0)
        ret = self.get_one(sql, [])
        city = ret['region_name']
        sql = "SELECT * FROM t_region WHERE id=%d and is_delete=%d;" % (ret["parent_id"], 0)
        ret = self.get_one(sql, [])
        province = ret['region_name']
        sql = "SELECT * FROM t_region WHERE id=%d and is_delete=%d;" % (ret["parent_id"], 0)
        ret = self.get_one(sql, [])
        region = ret['region_name']
        return {"agent_IPaddress": ip, "warehouse": warehouse, "city": city, "province": province, "region": region,
                "agent_IPaddress_number": self.ipnumber,"brief_position":'%s-%s-%s-%s'%(region,province,city,warehouse)}

pushDDobj=PushTarp()

#入庫報警信息緩沖區
class MessageBuffer():
    def __init__(self):
        self.buffer=[]
SQLdata_buffer=MessageBuffer()

#報警寫庫、報警推送模塊(線程異步)
class AlarmNotificationThread(threading.Thread):
    def __init__(self,**trapdata):
        threading.Thread.__init__(self)
        self.trapdata=trapdata
    #設置緩沖區2分鍾,push一次緩沖到數據庫
    def transferToDb(self):
        trap_info_obj=models.TrapInfo(**self.trapdata)
        SQLdata_buffer.buffer.append(trap_info_obj)
        # print(len(SQLdata_buffer.buffer))
        if len(SQLdata_buffer.buffer)>=1:
            first_triger_time=SQLdata_buffer.buffer[0].trap_time
            second_delta=(datetime.datetime.now()-first_triger_time).seconds
            if second_delta>120:
                print("push緩沖區%s條數據到MySQL數據庫。"%(len(SQLdata_buffer.buffer)))
                models.TrapInfo.objects.bulk_create(SQLdata_buffer.buffer)
                SQLdata_buffer.buffer=[]

    def transferToReciver(self):
        pushDDobj.transfer_media(**self.trapdata)

    def run(self):
        self.transferToDb() #記錄數據庫
        self.transferToReciver()#發咚咚和郵件


#報警處理模塊
class AlarmHandleThread(threading.Thread):
    def __init__(self,mysqlobj,snmpEngine,trap_message):
        threading.Thread.__init__(self)
        self.mysqlobj=mysqlobj
        self.snmpEngine=snmpEngine
        self.trap_message=trap_message
        self.execContext = self.snmpEngine.observer.getExecutionContext(
            'rfc3412.receiveMessage:request'
        )
        self.agent_address = [str(x) for x in self.execContext['transportAddress']][0]
        print("開局:--------------", self.agent_address)
        self.var_binds =trap_message

    def transformTrap(self):
        # 開始轉換trap報文-----trap報警信息
        trap_data = {}
        # 獲取客戶端的ip地址
        trap_time = datetime.datetime.now()
        trap_data["trap_time"] = trap_time
        try:
            #獲取發送trap的網絡設備網絡的IP信息
            ip_info = self.mysqlobj.ip_info(self.agent_address)
        except Exception:
            #從李勇數據庫中獲取不到IP地址信息
            print('錯誤的IP地址-------%s', self.agent_address)
            # 開啟1個線程異步寫日志到文件
            # wrongipError = 'This is a error ipadress %s' % (self.agent_address)
            # recordErrorsTask = threading.Thread(target=recordErrors, args=(wrongipError,))
            # recordErrorsTask.start()
            return
        trap_data.update(**ip_info)
        trap_pdu_info = ''
        for name, val in self.var_binds:
            # 通過trap報文中固定參數1.3.6.1.6.3.1.1.4.1.0,鎖定trap-oid
            if name.prettyPrint() == "1.3.6.1.6.3.1.1.4.1.0":
                # 1.3:檢查是否存在解析記錄。
                trap_data['trap_oid'] = val.prettyPrint()
                mib_entry = models.MibInfo.objects.filter(trap_oid=val.prettyPrint()).first()
                # 如果報警存在解析記錄
                if mib_entry:
                    # 如果trap-oid存在黑名單
                    if mib_entry.ip_excluded:
                        if mib_entry.ip_excluded == 'all':
                            print("%s被黑名單遮蔽all" % (val.prettyPrint()))
                            return
                        print(val.prettyPrint())
                        excluded_list = mib_entry.ip_excluded.split(',')
                        print(excluded_list)
                        if self.agent_address in excluded_list:
                            print("%s的------%s被黑名單策略" % (self.agent_address, val.prettyPrint()))
                            return
                    # 如果trap-oid存在白名單開始根據解析記錄轉換報警
                    trap_data["trap_name"] = mib_entry.trap_name
                    trap_data["device_type"] = mib_entry.device_type
                    trap_data["trap_type"] = mib_entry.trap_type
                    trap_data["trap_level"] = mib_entry.trap_level
                    trap_data['solution'] = mib_entry.solution
            # 1.6添加trap報文
            each_line = "<p>參數名稱:【%s】   參數值:%s</p>" % (name.prettyPrint(), val.prettyPrint())
            trap_pdu_info += each_line
        trap_data["trap_details"] = '<div>%s</div>' % trap_pdu_info
        # 開啟1個線程,異步推送報警到咚咚和郵件。
        AlarmNotificationTask = AlarmNotificationThread(**trap_data)
        AlarmNotificationTask.start()

    def run(self):
        self.transformTrap()


#報警接收模塊udp
class TrapServer(threading.Thread):
    def __init__(self, ip, port, security_name, community_name):
        threading.Thread.__init__(self)
        self.ip = ip
        self.port = port
        self.security_name = security_name
        self.community_name = community_name
        self.snmp_engine = engine.SnmpEngine()
        self.snmp_config = config
        self.mysqlobj = SqlHelper()
        self.mysqlobj.connect()
        # 初始化snmp-trap-server的配置
        self.snmp_config.addTransport(
            self.snmp_engine,
            udp.domainName + (1,),
            udp.UdpTransport().openServerMode((self.ip, self.port))
        )
        self.snmp_config.addV1System(self.snmp_engine, self.security_name, self.community_name)
        # self.snmp_config.addV1System(self.snmp_engine, self.security_name, "111")

    #trap-server的回調函數
    def callback_function(self, snmpEngine, stateReference, contextEngineId, contextName, varBinds, cbCtx):
        # Get an execution context...獲取執行上下文,包含所有的請求信息。
        #開啟多線程處理trap報文
        handle_Thread=AlarmHandleThread(mysqlobj=self.mysqlobj,snmpEngine=snmpEngine,trap_message=varBinds)
        handle_Thread.start()


    def run_server(self):
        ntfrcv.NotificationReceiver(self.snmp_engine,self.callback_function)
        # this job would never finish
        self.snmp_engine.transportDispatcher.jobStarted(10,20)
        # Run I/O dispatcher which would receive queries and send confirmations
        try:
            self.snmp_engine.transportDispatcher.runDispatcher()
        except:
            self.snmp_engine.transportDispatcher.closeDispatcher()
            print("trap-server錯誤")
            raise


if __name__ == '__main__':
    trap_server = TrapServer("0.0.0.0", 162, "zhanggen", "public")  #public
    trap_server.run_server()
trap-receiver

 

python的GIL鎖限制了python的多線程在同一時刻,只能有1個線程運行在1個CPU之上。

所以我們遇到計算密集型問題、和大數據量導致IO隊列阻塞時。可以使用多進程。

 Nginx也支持對UDP報文進行轉發和負載均衡,這樣我正好啟動多進程監聽在不同的UDP協議端口上,把CPU資源最大限度利用起來。 

# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/

user root;
worker_processes auto;
error_log /var/log/nginx/error.log;

pid /run/nginx.pid;

include /usr/share/nginx/modules/*.conf;
events {
    worker_connections 1024;
}



stream {
    log_format  main  '$remote_addr - [$time_local] 處理主機: $upstream_addr';
    access_log  /var/log/nginx/access.log main;
    upstream trap-server {
      server 192.168.1.101:162;
      server 192.168.1.101:163;
      server 192.168.1.101:164;
    }
 
    server {
      listen  192.168.56.138:162 udp;
      proxy_responses 1;
      proxy_timeout 20s;
      proxy_pass trap-server;
    }
}
nginx.conf

 

鳥槍換炮之后

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

trap接收

S2750常用OID

華為

SNMP MIB


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM