-
Notifications
You must be signed in to change notification settings - Fork 9
/
README.SNMP_util
397 lines (324 loc) · 14.6 KB
/
README.SNMP_util
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
README for SNMP_util.pm
Copyright (c) 1998-2002, Mike Mitchell
All rights reserved
This program is free software; you can redistribute it under the
"Artistic License" included in this distribution (file "Artistic").
Author: Mike Mitchell <[email protected]>
Contributors:
Tobias Oetiker <[email protected]>
Simon Leinen <[email protected]>
Jeff Allen <[email protected]>
Johannes Demel <[email protected]>
Laurent Girod <[email protected]>
Ian Duplisse <[email protected]>
I was using Simon Leinen's SNMP tools in various perl scripts, and I
found that I was using the same functions over and over. I grouped
the common routines into a separate perl module so that I would only
have to make changes in one place, rather than track down all the
different perl scripts that included the code. The result is the
'SNMP_utils.pm' module.
Thanks goes to Tobias Oetiker ([email protected]) of MRTG fame for the
basic layout of the functions.
The SNMP_utils.pm module contains the functions
snmpmapOID(text, OID, [text, OID ...])
snmpMIB_to_OID(filename)
snmpLoad_OID_Cache(filename)
snmpQueue_MIB_File(filename, [filename])
snmpget(community@host:port:timeout:retries:backoff:version, OID, [OID...])
snmpgetnext(community@host:port:timeout:retries:backoff:version, OID,
[OID...])
snmpwalk(community@host:port:timeout:retries:backoff:version, OID, [OID...])
snmpgetbulk(community@host:port:timeout:retries:backoff:version, non_repeat,
max_repeat, OID, [OID...])
snmpset(community@host:port:timeout:retries:backoff:version, OID, type, value,
[OID, type, value ...])
snmptrap(community@host:port:timeout:retries:backoff:version, enterpriseOID,
agent, generalID, specificID, OID, type, value,
[OID, type, value ...])
snmpmaptable(community@host:port:timeout:retries:backoff:version,
function, OID, [OID...])
snmpmaptable4(community@host:port:timeout:retries:backoff:version,
function, max_repetitions, OID, [OID...])
snmpwalkhash(community@host:port:timeout:retries:backoff:version,
function, OID, [OID...], [hash ref])
The functions have a small mapping table for commonly used OIDs. The
OIDs from RFC1213 (MIB-II) and RFC1315 (Frame Relay) are preloaded.
It is much easier to say "ifInOctets.4" instead of "1.3.6.1.2.1.2.2.1.10.4".
The snmpmapOID() function will let you add your own entries to the mapping
table. It doesn't return anything. Be sure to leave off any instance
number from the OID passed to snmpmapOID()! The example above would be
&snmpmapOID("ifInOctets", "1.3.6.1.2.1.2.2.1.10").
Don't use
&snmpmapOID("ifInOctets.4", "1.3.6.1.2.1.2.2.1.10.4").
The trailing ".4" is interpreted as an instance number, and not the entire
OID. The snmpmapOID function will ignore the attempt to add a mapping entry
that includes an instance number. The call
&snmpmapOID("ifInOctets.four", "1.3.6.1.2.1.2.2.1.10.4")
would be accepted, because the text ".four" is interpreted differently
than the number 4.
The snmpMIB_to_OID() function will open the passed-in MIB file name
and read it. It will create text mappings for the appropriate OID
number. It returns the number of text mappings added, so a zero or
negative return indicates an error.
The snmpLoad_OID_Cache() function will open the passed-in file name
and read the file. It is expecting lines with a text string in
the first column and an OID number in the second column, like
ifInOctets 1.3.6.1.2.1.2.2.1.10
ifOutOctets 1.3.6.1.2.1.2.2.1.16
It will add the text to OID mappings in the file to the internal list by
calling the "snmpmapOID()" function. This way the extra overhead of
parsing a MIB file can be avoided if you have a pre-parsed version of
the MIB handy.
The snmpQueue_MIB_File() function queues up file names for use by the
"snmpMIB_to_OID()" function. If there are filenames passed into
"snmpQueue_MIB_File()", when an OID can't be found in the internal
table, the queued MIB files are loaded one after another until the
OID can be found (or the list is exhausted). This delays the MIB
parsing until the OID value is actually needed.
A cache file with the looked up text-to-OID mappings is maintained.
It's name is "OID_cache.txt", and can be changed by setting the
variable $SNMP_util::CacheFile to the name of the file you desire.
This cache file is automatically loaded before the queued MIB files
are parsed. If the OID is found in the cache file, the MIB file
doesn't have to be parsed.
The rest of the functions require a hostname/IP address as the first
argument. The community string, port number, timeout, retries, backoff,
and version parameters are all optional. If the community string isn't
specified, "public" is used. If the port number isn't specified, the
default value from SNMP_Sesssion.pm (port 161) is used for everything but
snmptrap(). snmptrap() uses port 162 as its default.
The port parameter was recently augmented to allow the specification of
the IP address (or hostname) and port of the machine doing the query in
addition to the IP address (or hostname) and port of the machine being
queried. Some machines have additional security features that only allow
SNMP queries to come from certain IP addresses. If the host doing the
query has multiple interface, it may be necessary to specify the interface
the query should come from. The port parameter is further broken down
into "remote_port!local_address!local_port". Here are some examples:
somehost
somehost:161
somehost:161!192.168.2.4!4000 use 192.168.2.4 and port 4000 as source
somehost:!192.168.2.4 use 192.168.2.4 as source
somehost:!!4000 use port 4000 as source
Most people will only need to use the first form ("somehost").
The timeout, retries, and backoff parameters default to whatever
SNMP_Session.pm uses. For SNMP_Session.pm version 0.83 they are 2 seconds,
5 retries, and a 1.0 backoff factor. The backoff factor is used as a
multiplier to increase the timeout after every retry. With a backoff factor
of 1.0 the timeout stays the same for every retry.
The version parameter defaults to SNMP version 1. Some SNMP values such as
64-bit counters have to be queried using SNMP version 2. Specifying "2" or
"2c" as the version parameter will accomplish this. The snmpgetbulk routine
is only supported in SNMP version 2 and higher.
Several parameters internal to SNMP_Session can be set by passing a hash as
the first OID. The keys to the hash are the parameters to modify. Here is
a list of parameters and their default values in SNMP_Session version 0.91:
'community' => "public"
'timeout' => 2.0
'retries' => 5
'backoff' => 1.0
'debug' => 0
'default_max_repetitions' => 12
'use_getbulk' => 1
'lenient_source_address_matching' => 1
'lenient_source_port_matching' => 1
Consult the documentation and/or source code for SNMP_Session for further
information of these parameters.
The snmpget function returns an array with the results of the 'get'
operation. The value associated with each OID is returned as a
separate value in the array.
The snmpgetnext function returns an array with the results of the
'getnext' operation. The OID number is added to the result as a
prefix with a colon separator, like '1.3.6.1.2.1.2.2.1.2.1:ethernet'
The snmpwalk function returns an array with all the OID numbers and values,
like the 'snmpgetnext' function. If only one OID is specified for the walk,
only the instance part of the OID number is added as a prefix. If multiple
OID are specified for the walk, the entire OID number is added as a prefix.
For instance, a walk of just '1.3.6.1.2.1.2.2.1.2' will return values
like '1:ethernet', '2:ethernet', '3:fddi'. A walk multiple OIDs will return
values like '1.3.6.1.2.1.2.2.1.2.1:ethernet'.
The snmpwalk function will use a 'getbulk' query for efficiency if the
SNMP version is 2 or higher.
The snmpgetbulk function, like the snmpgetnext function, returns an array
with the results of the 'getbulk' operation. The OID number is added to the
result as a prefix with a colon separator, like '1.3.6.1.2.1.2.2.1.2.1:ethernet'
The 'non_repeat' argument is the number of OID arguments that should be
retrieved no more than once. The 'max_repeat' argument is the number of
times that other variables beyond those specified by the 'non_repeat'
argument should be retrieved. The getbulk query is only supported at
SNMP version 2 or higher.
The snmpset function is passed OID, type, and value triplets. It
returns an array with the result of the set.
The snmpmaptable function can be used for walking tables. The OID arguments
are the columns of the table sharing the same index, and the passed-in
function is called once per row. The passed-in function will be given
the row index as a partial OID in dotted notation, e.g. "1.3", or
"10.0.1.34", and values of the requested table columns in that row.
The snmpmaptable4 function is just like snmpmaptable, only the third argument
is the number of table rows to request in a single SNMP query. The
snmpmaptable function uses the default of 12 rows.
The snmpwalkhash acts like snmpwalk, but will call the passed-in function
once per returned value. The function is passed a reference to a hash,
the hostname, the textual OID, the dotted-numeric OID, the instance, the
value, and the textual OID you requested. That function can customize the
result you want, in a hash of hashes, so you can extract the value later by
hosts, by oid_names, by oid_numbers, by instances... like these:
$hash{$host}{$name}{$inst} = $value;
$hash{$host}{$oid}{$inst} = $value;
$hash{$name}{$inst} = $value;
$hash{$oid}{$inst} = $value;
$hash{$oid . '.' . $ints} = $value;
$hash{$inst} = $value;
...
If the last argument to snmpwalkhash is a reference to a hash, that hash
reference is passed to the passed-in function instead of a local hash
reference. That way your function can look up other objects unrelated
to the current invocation of snmpwalkhash.
Here is a simple example of using the functions:
#! /usr/local/bin/perl5
BEGIN {
###
# Finally, SNMPGet fully written in PERL5.
# Thanks to Simon Leinen <[email protected]>
# More on: http://www.switch.ch/misc/leinen/snmp/perl/
####
# There older perls tend to behave peculiar with
# large integers ...
require 5.004;
use SNMP_util "0.89";
}
use strict;
sub printfun {
my($ind, $desc, $phy) = @_;
my($a, $b, $c, $d, $e, $f, $mac);
($a, $b, $c, $d, $e, $f) = unpack("C6", $phy);
$mac = sprintf("%02x-%02x-%02x-%02x-%02x-%02x", $a, $b, $c, $d, $e, $f);
print "interface $ind: MAC $mac $desc\n";
}
sub my_hash_with_host {
my($h_ref, $host, $name, $oid, $inst, $value, $tree) = @_;
$inst =~ s/^\.+//;
if ($name =~ /ifPhysAddress/) {
my $mac = '';
map { $mac .= sprintf("%02X", $_) } unpack "CCCCCC", $value;
$value = $mac;
}
$h_ref->{$host}->{$name}->{$inst} = $value;
}
sub main {
my($oid, $host, $response, $cont);
my($desc, @ret, $nrows);
$host = "127.0.0.1";
$cont = "Your Name";
# This snmpmapOID() isn't necessary, as it is already in
# the internal map table. It is just an example...
&snmpmapOID("ifDescr", "1.3.6.1.2.1.2.2.1.2");
print "Trying 'getnext' on $host\n";
@ret = &snmpgetnext($host, "ifDescr");
foreach $desc (@ret) {
($oid, $desc) = split(':', $desc, 2);
print "$oid = $desc\n";
}
print "Trying 'getnext' on $host with different timeout and retries\n";
@ret = &snmpgetnext($host, { 'timeout' => 4, 'retries' => 2 }, "ifDescr");
foreach $desc (@ret) {
($oid, $desc) = split(':', $desc, 2);
print "$oid = $desc\n";
}
print "Trying 'walk' on $host\n";
@ret = &snmpwalk($host, "ifDescr");
foreach $desc (@ret) {
($oid, $desc) = split(':', $desc, 2);
print "$oid = $desc\n";
}
print "Trying 'walkhash' on $host\n";
my %ret_hash = &snmpwalkhash($host, \&my_hash_with_host, "ifEntry");
foreach $oid (sort keys %{$ret_hash{$host}}) {
foreach my $inst (sort { $a <=> $b } keys %{$ret_hash{$host}{$oid}}) {
printf("%20s\t: %-15s %3s = %s\n", $host, $oid, $inst,
$ret_hash{$host}{$oid}{$inst});
}
}
print "Trying 'walkhash' on $host, using own hash\n";
my(%myhash);
%ret_hash = &snmpwalkhash($host, \&my_hash_with_host, "ifEntry", \%myhash);
foreach $oid (sort keys %{$myhash{$host}}) {
foreach my $inst (sort { $a <=> $b } keys %{$myhash{$host}{$oid}}) {
printf("%20s\t: %-15s %3s = %s\n", $host, $oid, $inst,
$myhash{$host}{$oid}{$inst});
}
}
print "Before set:\n";
$oid = "sysContact";
($response) = &snmpget($host, $oid);
if ($response) {
print "GET $oid : $response\n";
} else {
warn "$host did not respond to SNMP query\n";
}
my $oldContact = $response;
print "setting contact to $cont\n";
($response) = &snmpset("security\@$host", $oid, 'string', $cont);
if ($response) {
print "SET: $oid : $response\n";
} else {
die "$host did not respond to SNMP set\n";
}
print "After set:\n";
($response) = &snmpget($host, $oid);
if ($response) {
print "GET $oid : $response\n";
} else {
die "$host did not respond to SNMP query\n";
}
print "Setting contact back to $oldContact\n";
($response) = &snmpset("security\@$host", $oid, 'string', $oldContact);
if ($response) {
print "SET: $oid : $response\n";
} else {
die "$host did not respond to SNMP set\n";
}
print "After 2nd set:\n";
($response) = &snmpget($host, $oid);
if ($response) {
print "GET $oid : $response\n";
} else {
die "$host did not respond to SNMP query\n";
}
print "Walking table of interface description and physical address\n";
$nrows = &snmpmaptable($host, \&printfun, "ifDescr", "ifPhysAddress");
print "walked $nrows rows in the table\n";
}
main;
exit(0);
-----------------------------------------------------
Here is an example using the MIB parsing functions.
First create a file with a simple MIB:
cat > dummy.mib <<EOF
abc OBJECT IDENTIFIER ::= { system 1 }
EOF
#! /usr/local/bin/perl5
BEGIN {
# The older perls tend to behave peculiar with
# large integers ...
require 5.003;
use SNMP_util "0.71";
}
use strict;
sub main {
my ($ret, $arg);
# queue up reading the "dummy.mib" file
&snmpQueue_MIB_File("dummy.mib");
# Override the default cache file ("OID_cache.txt") with "cache_test.txt"
$SNMP_util::CacheFile = "cache_test.txt";
($ret) = &snmpget("127.0.0.1", "abc.0");
print "$ret\n";
}
main;
exit(0);
-----------------------------------------------------
The first time you run the above script, the "dummy.mib" file will be read
and parsed. You should see the "cache_test.txt" file get created with
a single line in it, namely "abc 1.3.6.1.2.1.1.1". The second time you
run the script the "cache_test.txt" file will be loaded instead of the
"dummy.mib" file.