1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 __doc__='''zentrap
16
17 Creates events from SNMP Traps.
18
19 $Id$
20 '''
21
22 __version__ = "$Revision$"[11:-2]
23
24 from twisted.python import threadable
25 threadable.init()
26
27 from Queue import Queue
28
29 import time
30 import socket
31
32 import Globals
33
34 from EventServer import EventServer
35 from Event import Event, EventHeartbeat
36
37 from ZenEventClasses import Status_Snmp
38 from Products.ZenModel.IpAddress import findIpAddress
39
40 from twisted.internet import reactor
41 from twisted.internet.protocol import DatagramProtocol
42 from twistedsnmp import snmpprotocol
43
44 TRAP_PORT = 162
45 try:
46 TRAP_PORT = socket.getservbyname('snmptrap', 'udp')
47 except socket.error:
48 pass
49
51 '''Chase an object down to its value.
52
53 Example: getting a timeticks value:
54
55 ticks = obj['value']['application_syntax']['timeticks_value'].get()
56
57 becomes:
58
59 ticks = grind(obj)
60
61 '''
62 if hasattr(obj, 'keys'):
63 return grind(obj.values()[0])
64 return obj.get()
65
67 parts = path.split('/')
68 for p in parts:
69 try:
70 obj = obj[p]
71 except KeyError:
72 return default
73 return obj
74
75
76 -class ZenTrap(EventServer, snmpprotocol.SNMPProtocol):
77 'Listen for SNMP traps and turn them into events'
78
79 totalTime = 0.
80 totalEvents = 0
81 maxTime = 0.
82
83 name = 'zentrap'
84
92
93
95 'Traps are processed asynchronously in a thread'
96 self.q.put( (data, addr, time.time()) )
97
98
114
116 'short hand to get names from oids'
117 return self.dmd.Mibs.oid2name(oid)
118
128
130 eventType = 'unknown'
131 result = {}
132 if data['version'].get() == 1:
133
134 pdu = data['pdu']
135 bindings = extract(data, 'pdu/snmpV2_trap/variable_bindings', [])
136 bindings = extract(data, 'pdu/inform_request/variable_bindings',
137 bindings)
138 for binding in bindings:
139 oid = grind(binding['name'])
140 value = grind(binding['value'])
141
142 if oid.lstrip('.') == '1.3.6.1.6.3.1.1.4.1.0':
143 eventType = self.oid2name(value)
144 result[self.oid2name(oid)] = value
145 else:
146
147 addr = grind(extract(data, 'pdu/trap/agent_addr')), addr[1]
148 enterprise = grind(extract(data, 'pdu/trap/enterprise'))
149 eventType = self.oid2name(enterprise)
150 generic = grind(extract(data, 'pdu/trap/generic_trap'))
151 specific = grind(extract(data, 'pdu/trap/specific_trap'))
152 eventType = { 0 : 'snmp_coldStart',
153 1 : 'snmp_warmStart',
154 2 : 'snmp_linkDown',
155 3 : 'snmp_linkUp',
156 4 : 'snmp_authenticationFailure',
157 5 : 'snmp_egpNeighorLoss',
158 6 : self.oid2name('%s.0.%d' % (enterprise, specific))
159 }.get(generic, eventType + "_%d" % specific)
160 for binding in extract(data, 'pdu/trap/variable_bindings'):
161 oid = grind(binding['name'])
162 value = grind(binding['value'])
163 result[self.oid2name(oid)] = value
164
165 device = self._findDevice(addr)
166 summary = 'snmp trap %s from %s' % (eventType, device)
167 self.log.debug(summary)
168 community = data['community'].get()
169 result.setdefault('agent', 'zentrap')
170 result.setdefault('component', '')
171 result.setdefault('device', device)
172 result.setdefault('eventClassKey', eventType)
173 result.setdefault('eventGroup', 'trap')
174 result.setdefault('rcvtime', ts)
175 result.setdefault('severity', 3)
176 result.setdefault('summary', summary)
177 result.setdefault('community', community)
178 result['ipAddress'] = addr[0]
179 self.sendEvent(result)
180
181 diff = time.time() - ts
182 self.totalTime += diff
183 self.totalEvents += 1
184 self.maxTime = max(diff, self.maxTime)
185
186 if data['pdu'].has_key('inform_request'):
187 r = snmpprotocol.v2c.Response()
188 extract(r, 'pdu/response/request_id').set(
189 extract(data, 'pdu/inform_request/request_id').get())
190 r['community'].set(data['community'].get())
191 reactor.callFromThread(self.informResponse, r.berEncode(), addr)
192
193
196
197
199 EventServer.buildOptions(self)
200 self.parser.add_option('--trapport', '-t',
201 help='Listen for SNMP traps on this port rather than the default',
202 dest='trapport', type='int', default=TRAP_PORT)
203 self.parser.add_option('--useFileDescriptor',
204 dest='useFileDescriptor',
205 type='int',
206 help="Read from an existing connection rather opening a new port.",
207 default=None)
208
209
210 if __name__ == '__main__':
211 z = ZenTrap()
212 z.main()
213