1 |
|
|
/* $OpenBSD: print-snmp.c,v 1.21 2016/03/15 05:03:11 mmcc Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997 |
5 |
|
|
* John Robert LoVerso. All rights reserved. |
6 |
|
|
* |
7 |
|
|
* Redistribution and use in source and binary forms, with or without |
8 |
|
|
* modification, are permitted provided that the following conditions |
9 |
|
|
* are met: |
10 |
|
|
* |
11 |
|
|
* 1. Redistributions of source code must retain the above copyright |
12 |
|
|
* notice, this list of conditions and the following disclaimer. |
13 |
|
|
* |
14 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
15 |
|
|
* notice, this list of conditions and the following disclaimer in the |
16 |
|
|
* documentation and/or other materials provided with the distribution. |
17 |
|
|
* |
18 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
19 |
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
20 |
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
21 |
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
22 |
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
23 |
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
24 |
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
25 |
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
26 |
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
27 |
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 |
|
|
* |
29 |
|
|
* |
30 |
|
|
* This implementation has been influenced by the CMU SNMP release, |
31 |
|
|
* by Steve Waldbusser. However, this shares no code with that system. |
32 |
|
|
* Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_. |
33 |
|
|
* Earlier forms of this implementation were derived and/or inspired by an |
34 |
|
|
* awk script originally written by C. Philip Wood of LANL (but later |
35 |
|
|
* heavily modified by John Robert LoVerso). The copyright notice for |
36 |
|
|
* that work is preserved below, even though it may not rightly apply |
37 |
|
|
* to this file. |
38 |
|
|
* |
39 |
|
|
* This started out as a very simple program, but the incremental decoding |
40 |
|
|
* (into the BE structure) complicated things. |
41 |
|
|
* |
42 |
|
|
# Los Alamos National Laboratory |
43 |
|
|
# |
44 |
|
|
# Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997 |
45 |
|
|
# This software was produced under a U.S. Government contract |
46 |
|
|
# (W-7405-ENG-36) by Los Alamos National Laboratory, which is |
47 |
|
|
# operated by the University of California for the U.S. Department |
48 |
|
|
# of Energy. The U.S. Government is licensed to use, reproduce, |
49 |
|
|
# and distribute this software. Permission is granted to the |
50 |
|
|
# public to copy and use this software without charge, provided |
51 |
|
|
# that this Notice and any statement of authorship are reproduced |
52 |
|
|
# on all copies. Neither the Government nor the University makes |
53 |
|
|
# any warranty, express or implied, or assumes any liability or |
54 |
|
|
# responsibility for the use of this software. |
55 |
|
|
# @(#)snmp.awk.x 1.1 (LANL) 1/15/90 |
56 |
|
|
*/ |
57 |
|
|
|
58 |
|
|
#include <sys/time.h> |
59 |
|
|
|
60 |
|
|
#include <ctype.h> |
61 |
|
|
#include <stdio.h> |
62 |
|
|
#include <string.h> |
63 |
|
|
|
64 |
|
|
#include "interface.h" |
65 |
|
|
#include "addrtoname.h" |
66 |
|
|
|
67 |
|
|
/* |
68 |
|
|
* Universal ASN.1 types |
69 |
|
|
* (we only care about the tag values for those allowed in the Internet SMI) |
70 |
|
|
*/ |
71 |
|
|
char *Universal[] = { |
72 |
|
|
"U-0", |
73 |
|
|
"Boolean", |
74 |
|
|
"Integer", |
75 |
|
|
#define INTEGER 2 |
76 |
|
|
"Bitstring", |
77 |
|
|
"String", |
78 |
|
|
#define STRING 4 |
79 |
|
|
"Null", |
80 |
|
|
#define ASN_NULL 5 |
81 |
|
|
"ObjID", |
82 |
|
|
#define OBJECTID 6 |
83 |
|
|
"ObjectDes", |
84 |
|
|
"U-8","U-9","U-10","U-11", /* 8-11 */ |
85 |
|
|
"U-12","U-13","U-14","U-15", /* 12-15 */ |
86 |
|
|
"Sequence", |
87 |
|
|
#define SEQUENCE 16 |
88 |
|
|
"Set" |
89 |
|
|
}; |
90 |
|
|
|
91 |
|
|
/* |
92 |
|
|
* Application-wide ASN.1 types from the Internet SMI and their tags |
93 |
|
|
*/ |
94 |
|
|
char *Application[] = { |
95 |
|
|
"IpAddress", |
96 |
|
|
#define IPADDR 0 |
97 |
|
|
"Counter", |
98 |
|
|
#define COUNTER 1 |
99 |
|
|
"Gauge", |
100 |
|
|
#define GAUGE 2 |
101 |
|
|
"TimeTicks", |
102 |
|
|
#define TIMETICKS 3 |
103 |
|
|
"Opaque", |
104 |
|
|
#define OPAQUE 4 |
105 |
|
|
"NsapAddress", |
106 |
|
|
#define NSAPADDR 5 |
107 |
|
|
"Counter64", |
108 |
|
|
#define COUNTER64 6 |
109 |
|
|
"UInteger32" |
110 |
|
|
#define UINTEGER32 7 |
111 |
|
|
}; |
112 |
|
|
|
113 |
|
|
/* |
114 |
|
|
* Context-specific ASN.1 types for the SNMP PDUs and their tags |
115 |
|
|
*/ |
116 |
|
|
char *Context[] = { |
117 |
|
|
"GetRequest", |
118 |
|
|
#define GETREQ 0 |
119 |
|
|
"GetNextRequest", |
120 |
|
|
#define GETNEXTREQ 1 |
121 |
|
|
"GetResponse", |
122 |
|
|
#define GETRESP 2 |
123 |
|
|
"SetRequest", |
124 |
|
|
#define SETREQ 3 |
125 |
|
|
"Trap", |
126 |
|
|
#define TRAP 4 |
127 |
|
|
"GetBulkReq", |
128 |
|
|
#define GETBULKREQ 5 |
129 |
|
|
"InformReq", |
130 |
|
|
#define INFORMREQ 6 |
131 |
|
|
"TrapV2", |
132 |
|
|
#define TRAPV2 7 |
133 |
|
|
"Report" |
134 |
|
|
#define REPORT 8 |
135 |
|
|
}; |
136 |
|
|
|
137 |
|
|
/* |
138 |
|
|
* Private ASN.1 types |
139 |
|
|
* The Internet SMI does not specify any |
140 |
|
|
*/ |
141 |
|
|
char *Private[] = { |
142 |
|
|
"P-0" |
143 |
|
|
}; |
144 |
|
|
|
145 |
|
|
/* |
146 |
|
|
* error-status values for any SNMP PDU |
147 |
|
|
*/ |
148 |
|
|
char *ErrorStatus[] = { |
149 |
|
|
"noError", |
150 |
|
|
"tooBig", |
151 |
|
|
"noSuchName", |
152 |
|
|
"badValue", |
153 |
|
|
"readOnly", |
154 |
|
|
"genErr", |
155 |
|
|
"noAccess", |
156 |
|
|
"wrongType", |
157 |
|
|
"wrongLength", |
158 |
|
|
"wrongEnc", |
159 |
|
|
"wrongValue", |
160 |
|
|
"noCreation", |
161 |
|
|
"inconValue", |
162 |
|
|
"resUnavail", |
163 |
|
|
"commitFailed", |
164 |
|
|
"undoFailed", |
165 |
|
|
"authError", |
166 |
|
|
"notWritable", |
167 |
|
|
"inconName" |
168 |
|
|
}; |
169 |
|
|
#define DECODE_ErrorStatus(e) \ |
170 |
|
|
( e >= 0 && e <= sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \ |
171 |
|
|
? ErrorStatus[e] : (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf)) |
172 |
|
|
|
173 |
|
|
/* |
174 |
|
|
* generic-trap values in the SNMP Trap-PDU |
175 |
|
|
*/ |
176 |
|
|
char *GenericTrap[] = { |
177 |
|
|
"coldStart", |
178 |
|
|
"warmStart", |
179 |
|
|
"linkDown", |
180 |
|
|
"linkUp", |
181 |
|
|
"authenticationFailure", |
182 |
|
|
"egpNeighborLoss", |
183 |
|
|
"enterpriseSpecific" |
184 |
|
|
#define GT_ENTERPRISE 6 |
185 |
|
|
}; |
186 |
|
|
#define DECODE_GenericTrap(t) \ |
187 |
|
|
( t >= 0 && t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \ |
188 |
|
|
? GenericTrap[t] : (snprintf(buf, sizeof(buf), "gt=%d", t), buf)) |
189 |
|
|
|
190 |
|
|
/* |
191 |
|
|
* ASN.1 type class table |
192 |
|
|
* Ties together the preceding Universal, Application, Context, and Private |
193 |
|
|
* type definitions. |
194 |
|
|
*/ |
195 |
|
|
#define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */ |
196 |
|
|
struct { |
197 |
|
|
char *name; |
198 |
|
|
char **Id; |
199 |
|
|
int numIDs; |
200 |
|
|
} Class[] = { |
201 |
|
|
defineCLASS(Universal), |
202 |
|
|
#define UNIVERSAL 0 |
203 |
|
|
defineCLASS(Application), |
204 |
|
|
#define APPLICATION 1 |
205 |
|
|
defineCLASS(Context), |
206 |
|
|
#define CONTEXT 2 |
207 |
|
|
defineCLASS(Private), |
208 |
|
|
#define PRIVATE 3 |
209 |
|
|
}; |
210 |
|
|
|
211 |
|
|
/* |
212 |
|
|
* defined forms for ASN.1 types |
213 |
|
|
*/ |
214 |
|
|
char *Form[] = { |
215 |
|
|
"Primitive", |
216 |
|
|
#define PRIMITIVE 0 |
217 |
|
|
"Constructed", |
218 |
|
|
#define CONSTRUCTED 1 |
219 |
|
|
}; |
220 |
|
|
|
221 |
|
|
/* |
222 |
|
|
* A structure for the OID tree for the compiled-in MIB. |
223 |
|
|
* This is stored as a general-order tree. |
224 |
|
|
*/ |
225 |
|
|
struct obj { |
226 |
|
|
char *desc; /* name of object */ |
227 |
|
|
u_int oid; /* sub-id following parent */ |
228 |
|
|
u_char type; /* object type (unused) */ |
229 |
|
|
struct obj *child, *next; /* child and next sibling pointers */ |
230 |
|
|
} *objp = NULL; |
231 |
|
|
|
232 |
|
|
/* |
233 |
|
|
* Include the compiled in SNMP MIB. "mib.h" is produced by feeding |
234 |
|
|
* RFC-1156 format files into "makemib". "mib.h" MUST define at least |
235 |
|
|
* a value for `mibroot'. |
236 |
|
|
* |
237 |
|
|
* In particular, this is gross, as this is including initialized structures, |
238 |
|
|
* and by right shouldn't be an "include" file. |
239 |
|
|
*/ |
240 |
|
|
#include "mib.h" |
241 |
|
|
|
242 |
|
|
/* |
243 |
|
|
* This defines a list of OIDs which will be abbreviated on output. |
244 |
|
|
* Currently, this includes the prefixes for the Internet MIB, the |
245 |
|
|
* private enterprises tree, and the experimental tree. |
246 |
|
|
*/ |
247 |
|
|
struct obj_abrev { |
248 |
|
|
char *prefix; /* prefix for this abrev */ |
249 |
|
|
struct obj *node; /* pointer into object table */ |
250 |
|
|
char *oid; /* ASN.1 encoded OID */ |
251 |
|
|
} obj_abrev_list[] = { |
252 |
|
|
#ifndef NO_ABREV_MIB |
253 |
|
|
/* .iso.org.dod.internet.mgmt.mib */ |
254 |
|
|
{ "", &_mib_obj, "\53\6\1\2\1" }, |
255 |
|
|
#endif |
256 |
|
|
#ifndef NO_ABREV_ENTER |
257 |
|
|
/* .iso.org.dod.internet.private.enterprises */ |
258 |
|
|
{ "E:", &_enterprises_obj, "\53\6\1\4\1" }, |
259 |
|
|
#endif |
260 |
|
|
#ifndef NO_ABREV_EXPERI |
261 |
|
|
/* .iso.org.dod.internet.experimental */ |
262 |
|
|
{ "X:", &_experimental_obj, "\53\6\1\3" }, |
263 |
|
|
#endif |
264 |
|
|
#ifndef NO_ABREV_SNMPMIBOBJECTS |
265 |
|
|
/* .iso.org.dod.internet.snmpV2.snmpModules.snmpMIB.snmpMIBObjects */ |
266 |
|
|
{ "S:", &_snmpmibobjects_obj, "\53\6\1\6\3\1\1" }, |
267 |
|
|
#endif |
268 |
|
|
{ 0,0,0 } |
269 |
|
|
}; |
270 |
|
|
|
271 |
|
|
/* |
272 |
|
|
* This is used in the OID print routine to walk down the object tree |
273 |
|
|
* rooted at `mibroot'. |
274 |
|
|
*/ |
275 |
|
|
#define OBJ_PRINT(o, suppressdot) \ |
276 |
|
|
{ \ |
277 |
|
|
if (objp) { \ |
278 |
|
|
do { \ |
279 |
|
|
if ((o) == objp->oid) \ |
280 |
|
|
break; \ |
281 |
|
|
} while ((objp = objp->next) != NULL); \ |
282 |
|
|
} \ |
283 |
|
|
if (objp) { \ |
284 |
|
|
printf(suppressdot?"%s":".%s", objp->desc); \ |
285 |
|
|
objp = objp->child; \ |
286 |
|
|
} else \ |
287 |
|
|
printf(suppressdot?"%u":".%u", (o)); \ |
288 |
|
|
} |
289 |
|
|
|
290 |
|
|
/* |
291 |
|
|
* This is the definition for the Any-Data-Type storage used purely for |
292 |
|
|
* temporary internal representation while decoding an ASN.1 data stream. |
293 |
|
|
*/ |
294 |
|
|
struct be { |
295 |
|
|
u_int32_t asnlen; |
296 |
|
|
union { |
297 |
|
|
caddr_t raw; |
298 |
|
|
int32_t integer; |
299 |
|
|
u_int32_t uns; |
300 |
|
|
u_int64_t uns64; |
301 |
|
|
const u_char *str; |
302 |
|
|
} data; |
303 |
|
|
u_short id; |
304 |
|
|
u_char form, class; /* tag info */ |
305 |
|
|
u_char type; |
306 |
|
|
#define BE_ANY 255 |
307 |
|
|
#define BE_NONE 0 |
308 |
|
|
#define BE_NULL 1 |
309 |
|
|
#define BE_OCTET 2 |
310 |
|
|
#define BE_OID 3 |
311 |
|
|
#define BE_INT 4 |
312 |
|
|
#define BE_UNS 5 |
313 |
|
|
#define BE_STR 6 |
314 |
|
|
#define BE_SEQ 7 |
315 |
|
|
#define BE_INETADDR 8 |
316 |
|
|
#define BE_PDU 9 |
317 |
|
|
#define BE_UNS64 10 |
318 |
|
|
}; |
319 |
|
|
|
320 |
|
|
/* |
321 |
|
|
* Defaults for SNMP PDU components |
322 |
|
|
*/ |
323 |
|
|
#define DEF_COMMUNITY "public" |
324 |
|
|
#define DEF_VERSION 1 |
325 |
|
|
|
326 |
|
|
/* |
327 |
|
|
* constants for ASN.1 decoding |
328 |
|
|
*/ |
329 |
|
|
#define OIDMUX 40 |
330 |
|
|
#define ASNLEN_INETADDR 4 |
331 |
|
|
#define ASN_SHIFT7 7 |
332 |
|
|
#define ASN_SHIFT8 8 |
333 |
|
|
#define ASN_BIT8 0x80 |
334 |
|
|
#define ASN_LONGLEN 0x80 |
335 |
|
|
|
336 |
|
|
#define ASN_ID_BITS 0x1f |
337 |
|
|
#define ASN_FORM_BITS 0x20 |
338 |
|
|
#define ASN_FORM_SHIFT 5 |
339 |
|
|
#define ASN_CLASS_BITS 0xc0 |
340 |
|
|
#define ASN_CLASS_SHIFT 6 |
341 |
|
|
|
342 |
|
|
#define ASN_ID_EXT 0x1f /* extension ID in tag field */ |
343 |
|
|
|
344 |
|
|
/* |
345 |
|
|
* truncated==1 means the packet was complete, but we don't have all of |
346 |
|
|
* it to decode. |
347 |
|
|
*/ |
348 |
|
|
static int truncated; |
349 |
|
|
|
350 |
|
|
/* |
351 |
|
|
* This decodes the next ASN.1 object in the stream pointed to by "p" |
352 |
|
|
* (and of real-length "len") and stores the intermediate data in the |
353 |
|
|
* provided BE object. |
354 |
|
|
* |
355 |
|
|
* This returns -l if it fails (i.e., the ASN.1 stream is not valid). |
356 |
|
|
* O/w, this returns the number of bytes parsed from "p". |
357 |
|
|
*/ |
358 |
|
|
static int |
359 |
|
|
asn1_parse(const u_char *p, u_int len, struct be *elem) |
360 |
|
|
{ |
361 |
|
|
u_char form, class, id; |
362 |
|
|
int i, hdr; |
363 |
|
|
|
364 |
|
|
elem->asnlen = 0; |
365 |
|
|
elem->type = BE_ANY; |
366 |
|
|
if (len < 1) { |
367 |
|
|
if (truncated) |
368 |
|
|
fputs("[|snmp]", stdout); |
369 |
|
|
else |
370 |
|
|
fputs("[nothing to parse]", stdout); |
371 |
|
|
return -1; |
372 |
|
|
} |
373 |
|
|
|
374 |
|
|
/* |
375 |
|
|
* it would be nice to use a bit field, but you can't depend on them. |
376 |
|
|
* +---+---+---+---+---+---+---+---+ |
377 |
|
|
* + class |frm| id | |
378 |
|
|
* +---+---+---+---+---+---+---+---+ |
379 |
|
|
* 7 6 5 4 3 2 1 0 |
380 |
|
|
*/ |
381 |
|
|
id = *p & ASN_ID_BITS; /* lower 5 bits, range 00-1f */ |
382 |
|
|
#ifdef notdef |
383 |
|
|
form = (*p & 0xe0) >> 5; /* move upper 3 bits to lower 3 */ |
384 |
|
|
class = form >> 1; /* bits 7&6 -> bits 1&0, range 0-3 */ |
385 |
|
|
form &= 0x1; /* bit 5 -> bit 0, range 0-1 */ |
386 |
|
|
#else |
387 |
|
|
form = (u_char)(*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT; |
388 |
|
|
class = (u_char)(*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT; |
389 |
|
|
#endif |
390 |
|
|
elem->form = form; |
391 |
|
|
elem->class = class; |
392 |
|
|
elem->id = id; |
393 |
|
|
if (vflag) |
394 |
|
|
printf("|%.2x", *p); |
395 |
|
|
p++; len--; hdr = 1; |
396 |
|
|
/* extended tag field */ |
397 |
|
|
if (id == ASN_ID_EXT) { |
398 |
|
|
for (id = 0; *p & ASN_BIT8 && len > 0; len--, hdr++, p++) { |
399 |
|
|
if (vflag) |
400 |
|
|
printf("|%.2x", *p); |
401 |
|
|
id = (id << 7) | (*p & ~ASN_BIT8); |
402 |
|
|
} |
403 |
|
|
if (len == 0 && *p & ASN_BIT8) { |
404 |
|
|
if (truncated) |
405 |
|
|
fputs("[|snmp]", stdout); |
406 |
|
|
else |
407 |
|
|
fputs("[Xtagfield?]", stdout); |
408 |
|
|
return -1; |
409 |
|
|
} |
410 |
|
|
elem->id = id = (id << 7) | *p; |
411 |
|
|
--len; |
412 |
|
|
++hdr; |
413 |
|
|
++p; |
414 |
|
|
} |
415 |
|
|
if (len < 1) { |
416 |
|
|
if (truncated) |
417 |
|
|
fputs("[|snmp]", stdout); |
418 |
|
|
else |
419 |
|
|
fputs("[no asnlen]", stdout); |
420 |
|
|
return -1; |
421 |
|
|
} |
422 |
|
|
elem->asnlen = *p; |
423 |
|
|
if (vflag) |
424 |
|
|
printf("|%.2x", *p); |
425 |
|
|
p++; len--; hdr++; |
426 |
|
|
if (elem->asnlen & ASN_BIT8) { |
427 |
|
|
int noct = elem->asnlen % ASN_BIT8; |
428 |
|
|
elem->asnlen = 0; |
429 |
|
|
if (len < noct) { |
430 |
|
|
if (truncated) |
431 |
|
|
fputs("[|snmp]", stdout); |
432 |
|
|
else |
433 |
|
|
printf("[asnlen? %d<%d]", len, noct); |
434 |
|
|
return -1; |
435 |
|
|
} |
436 |
|
|
for (; noct-- > 0; len--, hdr++) { |
437 |
|
|
if (vflag) |
438 |
|
|
printf("|%.2x", *p); |
439 |
|
|
elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++; |
440 |
|
|
} |
441 |
|
|
} |
442 |
|
|
if (len < elem->asnlen) { |
443 |
|
|
if (!truncated) { |
444 |
|
|
printf("[len%d<asnlen%u]", len, elem->asnlen); |
445 |
|
|
return -1; |
446 |
|
|
} |
447 |
|
|
/* maybe should check at least 4? */ |
448 |
|
|
elem->asnlen = len; |
449 |
|
|
} |
450 |
|
|
if (form >= sizeof(Form)/sizeof(Form[0])) { |
451 |
|
|
if (truncated) |
452 |
|
|
fputs("[|snmp]", stdout); |
453 |
|
|
else |
454 |
|
|
printf("[form?%d]", form); |
455 |
|
|
return -1; |
456 |
|
|
} |
457 |
|
|
if (class >= sizeof(Class)/sizeof(Class[0])) { |
458 |
|
|
if (truncated) |
459 |
|
|
fputs("[|snmp]", stdout); |
460 |
|
|
else |
461 |
|
|
printf("[class?%c/%d]", *Form[form], class); |
462 |
|
|
return -1; |
463 |
|
|
} |
464 |
|
|
if ((int)id >= Class[class].numIDs) { |
465 |
|
|
if (truncated) |
466 |
|
|
fputs("[|snmp]", stdout); |
467 |
|
|
else |
468 |
|
|
printf("[id?%c/%s/%d]", *Form[form], |
469 |
|
|
Class[class].name, id); |
470 |
|
|
return -1; |
471 |
|
|
} |
472 |
|
|
|
473 |
|
|
switch (form) { |
474 |
|
|
case PRIMITIVE: |
475 |
|
|
switch (class) { |
476 |
|
|
case UNIVERSAL: |
477 |
|
|
switch (id) { |
478 |
|
|
case STRING: |
479 |
|
|
elem->type = BE_STR; |
480 |
|
|
elem->data.str = p; |
481 |
|
|
break; |
482 |
|
|
|
483 |
|
|
case INTEGER: { |
484 |
|
|
int32_t data; |
485 |
|
|
elem->type = BE_INT; |
486 |
|
|
data = 0; |
487 |
|
|
|
488 |
|
|
if (*p & ASN_BIT8) /* negative */ |
489 |
|
|
data = -1; |
490 |
|
|
for (i = elem->asnlen; i-- > 0; p++) |
491 |
|
|
data = (data << ASN_SHIFT8) | *p; |
492 |
|
|
elem->data.integer = data; |
493 |
|
|
break; |
494 |
|
|
} |
495 |
|
|
|
496 |
|
|
case OBJECTID: |
497 |
|
|
elem->type = BE_OID; |
498 |
|
|
elem->data.raw = (caddr_t)p; |
499 |
|
|
break; |
500 |
|
|
|
501 |
|
|
case ASN_NULL: |
502 |
|
|
elem->type = BE_NULL; |
503 |
|
|
elem->data.raw = NULL; |
504 |
|
|
break; |
505 |
|
|
|
506 |
|
|
default: |
507 |
|
|
elem->type = BE_OCTET; |
508 |
|
|
elem->data.raw = (caddr_t)p; |
509 |
|
|
printf("[P/U/%s]", |
510 |
|
|
Class[class].Id[id]); |
511 |
|
|
break; |
512 |
|
|
} |
513 |
|
|
break; |
514 |
|
|
|
515 |
|
|
case APPLICATION: |
516 |
|
|
switch (id) { |
517 |
|
|
case IPADDR: |
518 |
|
|
elem->type = BE_INETADDR; |
519 |
|
|
elem->data.raw = (caddr_t)p; |
520 |
|
|
break; |
521 |
|
|
|
522 |
|
|
case COUNTER: |
523 |
|
|
case GAUGE: |
524 |
|
|
case TIMETICKS: |
525 |
|
|
case OPAQUE: |
526 |
|
|
case NSAPADDR: |
527 |
|
|
case UINTEGER32: { |
528 |
|
|
u_int32_t data; |
529 |
|
|
elem->type = BE_UNS; |
530 |
|
|
data = 0; |
531 |
|
|
for (i = elem->asnlen; i-- > 0; p++) |
532 |
|
|
data = (data << 8) + *p; |
533 |
|
|
elem->data.uns = data; |
534 |
|
|
break; |
535 |
|
|
} |
536 |
|
|
|
537 |
|
|
case COUNTER64: { |
538 |
|
|
u_int64_t data; |
539 |
|
|
elem->type = BE_UNS64; |
540 |
|
|
data = 0; |
541 |
|
|
for (i = elem->asnlen; i-- > 0; p++) |
542 |
|
|
data = (data << 8) + *p; |
543 |
|
|
elem->data.uns64 = data; |
544 |
|
|
break; |
545 |
|
|
} |
546 |
|
|
|
547 |
|
|
default: |
548 |
|
|
elem->type = BE_OCTET; |
549 |
|
|
elem->data.raw = (caddr_t)p; |
550 |
|
|
printf("[P/A/%s]", |
551 |
|
|
Class[class].Id[id]); |
552 |
|
|
break; |
553 |
|
|
} |
554 |
|
|
break; |
555 |
|
|
|
556 |
|
|
default: |
557 |
|
|
elem->type = BE_OCTET; |
558 |
|
|
elem->data.raw = (caddr_t)p; |
559 |
|
|
printf("[P/%s/%s]", |
560 |
|
|
Class[class].name, Class[class].Id[id]); |
561 |
|
|
break; |
562 |
|
|
} |
563 |
|
|
break; |
564 |
|
|
|
565 |
|
|
case CONSTRUCTED: |
566 |
|
|
switch (class) { |
567 |
|
|
case UNIVERSAL: |
568 |
|
|
switch (id) { |
569 |
|
|
case SEQUENCE: |
570 |
|
|
elem->type = BE_SEQ; |
571 |
|
|
elem->data.raw = (caddr_t)p; |
572 |
|
|
break; |
573 |
|
|
|
574 |
|
|
default: |
575 |
|
|
elem->type = BE_OCTET; |
576 |
|
|
elem->data.raw = (caddr_t)p; |
577 |
|
|
printf("C/U/%s", Class[class].Id[id]); |
578 |
|
|
break; |
579 |
|
|
} |
580 |
|
|
break; |
581 |
|
|
|
582 |
|
|
case CONTEXT: |
583 |
|
|
elem->type = BE_PDU; |
584 |
|
|
elem->data.raw = (caddr_t)p; |
585 |
|
|
break; |
586 |
|
|
|
587 |
|
|
default: |
588 |
|
|
elem->type = BE_OCTET; |
589 |
|
|
elem->data.raw = (caddr_t)p; |
590 |
|
|
printf("C/%s/%s", |
591 |
|
|
Class[class].name, Class[class].Id[id]); |
592 |
|
|
break; |
593 |
|
|
} |
594 |
|
|
break; |
595 |
|
|
} |
596 |
|
|
p += elem->asnlen; |
597 |
|
|
len -= elem->asnlen; |
598 |
|
|
return elem->asnlen + hdr; |
599 |
|
|
} |
600 |
|
|
|
601 |
|
|
/* |
602 |
|
|
* Display the ASN.1 object represented by the BE object. |
603 |
|
|
* This used to be an integral part of asn1_parse() before the intermediate |
604 |
|
|
* BE form was added. |
605 |
|
|
*/ |
606 |
|
|
static void |
607 |
|
|
asn1_print(struct be *elem) |
608 |
|
|
{ |
609 |
|
|
u_char *p = (u_char *)elem->data.raw; |
610 |
|
|
u_int32_t asnlen = elem->asnlen; |
611 |
|
|
int i; |
612 |
|
|
|
613 |
|
|
switch (elem->type) { |
614 |
|
|
|
615 |
|
|
case BE_OCTET: |
616 |
|
|
for (i = asnlen; i-- > 0; p++) |
617 |
|
|
printf("_%.2x", *p); |
618 |
|
|
break; |
619 |
|
|
|
620 |
|
|
case BE_NULL: |
621 |
|
|
break; |
622 |
|
|
|
623 |
|
|
case BE_OID: { |
624 |
|
|
int o = 0, first = -1, i = asnlen; |
625 |
|
|
|
626 |
|
|
if (!nflag && asnlen > 2) { |
627 |
|
|
struct obj_abrev *a = &obj_abrev_list[0]; |
628 |
|
|
for (; a->node; a++) { |
629 |
|
|
if (!memcmp(a->oid, (char *)p, |
630 |
|
|
strlen(a->oid))) { |
631 |
|
|
objp = a->node->child; |
632 |
|
|
i -= strlen(a->oid); |
633 |
|
|
p += strlen(a->oid); |
634 |
|
|
fputs(a->prefix, stdout); |
635 |
|
|
first = 1; |
636 |
|
|
break; |
637 |
|
|
} |
638 |
|
|
} |
639 |
|
|
} |
640 |
|
|
for (; i-- > 0; p++) { |
641 |
|
|
o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8); |
642 |
|
|
if (*p & ASN_LONGLEN) |
643 |
|
|
continue; |
644 |
|
|
|
645 |
|
|
/* |
646 |
|
|
* first subitem encodes two items with 1st*OIDMUX+2nd |
647 |
|
|
*/ |
648 |
|
|
if (first < 0) { |
649 |
|
|
if (!nflag) |
650 |
|
|
objp = mibroot; |
651 |
|
|
first = 0; |
652 |
|
|
OBJ_PRINT(o/OIDMUX, first); |
653 |
|
|
o %= OIDMUX; |
654 |
|
|
} |
655 |
|
|
OBJ_PRINT(o, first); |
656 |
|
|
if (--first < 0) |
657 |
|
|
first = 0; |
658 |
|
|
o = 0; |
659 |
|
|
} |
660 |
|
|
break; |
661 |
|
|
} |
662 |
|
|
|
663 |
|
|
case BE_INT: |
664 |
|
|
printf("%d", elem->data.integer); |
665 |
|
|
break; |
666 |
|
|
|
667 |
|
|
case BE_UNS: |
668 |
|
|
printf("%d", elem->data.uns); |
669 |
|
|
break; |
670 |
|
|
|
671 |
|
|
case BE_UNS64: |
672 |
|
|
printf("%lld", elem->data.uns64); |
673 |
|
|
break; |
674 |
|
|
|
675 |
|
|
case BE_STR: { |
676 |
|
|
int printable = 1, first = 1; |
677 |
|
|
const u_char *p = elem->data.str; |
678 |
|
|
for (i = asnlen; printable && i-- > 0; p++) |
679 |
|
|
printable = isprint(*p) || isspace(*p); |
680 |
|
|
p = elem->data.str; |
681 |
|
|
if (printable) { |
682 |
|
|
putchar('"'); |
683 |
|
|
(void)fn_print(p, p + asnlen); |
684 |
|
|
putchar('"'); |
685 |
|
|
} else |
686 |
|
|
for (i = asnlen; i-- > 0; p++) { |
687 |
|
|
printf(first ? "%.2x" : "_%.2x", *p); |
688 |
|
|
first = 0; |
689 |
|
|
} |
690 |
|
|
break; |
691 |
|
|
} |
692 |
|
|
|
693 |
|
|
case BE_SEQ: |
694 |
|
|
printf("Seq(%u)", elem->asnlen); |
695 |
|
|
break; |
696 |
|
|
|
697 |
|
|
case BE_INETADDR: { |
698 |
|
|
char sep; |
699 |
|
|
if (asnlen != ASNLEN_INETADDR) |
700 |
|
|
printf("[inetaddr len!=%d]", ASNLEN_INETADDR); |
701 |
|
|
sep='['; |
702 |
|
|
for (i = asnlen; i-- > 0; p++) { |
703 |
|
|
printf("%c%u", sep, *p); |
704 |
|
|
sep='.'; |
705 |
|
|
} |
706 |
|
|
putchar(']'); |
707 |
|
|
break; |
708 |
|
|
} |
709 |
|
|
|
710 |
|
|
case BE_PDU: |
711 |
|
|
printf("%s(%u)", |
712 |
|
|
Class[CONTEXT].Id[elem->id], elem->asnlen); |
713 |
|
|
break; |
714 |
|
|
|
715 |
|
|
case BE_ANY: |
716 |
|
|
fputs("[BE_ANY!?]", stdout); |
717 |
|
|
break; |
718 |
|
|
|
719 |
|
|
default: |
720 |
|
|
fputs("[be!?]", stdout); |
721 |
|
|
break; |
722 |
|
|
} |
723 |
|
|
} |
724 |
|
|
|
725 |
|
|
#ifdef notdef |
726 |
|
|
/* |
727 |
|
|
* This is a brute force ASN.1 printer: recurses to dump an entire structure. |
728 |
|
|
* This will work for any ASN.1 stream, not just an SNMP PDU. |
729 |
|
|
* |
730 |
|
|
* By adding newlines and spaces at the correct places, this would print in |
731 |
|
|
* Rose-Normal-Form. |
732 |
|
|
* |
733 |
|
|
* This is not currently used. |
734 |
|
|
*/ |
735 |
|
|
static void |
736 |
|
|
asn1_decode(u_char *p, u_int length) |
737 |
|
|
{ |
738 |
|
|
struct be elem; |
739 |
|
|
int i = 0; |
740 |
|
|
|
741 |
|
|
while (i >= 0 && length > 0) { |
742 |
|
|
i = asn1_parse(p, length, &elem); |
743 |
|
|
if (i >= 0) { |
744 |
|
|
fputs(" ", stdout); |
745 |
|
|
asn1_print(&elem); |
746 |
|
|
if (elem.type == BE_SEQ || elem.type == BE_PDU) { |
747 |
|
|
fputs(" {", stdout); |
748 |
|
|
asn1_decode(elem.data.raw, elem.asnlen); |
749 |
|
|
fputs(" }", stdout); |
750 |
|
|
} |
751 |
|
|
length -= i; |
752 |
|
|
p += i; |
753 |
|
|
} |
754 |
|
|
} |
755 |
|
|
} |
756 |
|
|
#endif |
757 |
|
|
|
758 |
|
|
/* |
759 |
|
|
* General SNMP header |
760 |
|
|
* SEQUENCE { |
761 |
|
|
* version INTEGER {version-1(0)}, |
762 |
|
|
* community OCTET STRING, |
763 |
|
|
* data ANY -- PDUs |
764 |
|
|
* } |
765 |
|
|
* PDUs for all but Trap: (see rfc1157 from page 15 on) |
766 |
|
|
* SEQUENCE { |
767 |
|
|
* request-id INTEGER, |
768 |
|
|
* error-status INTEGER, |
769 |
|
|
* error-index INTEGER, |
770 |
|
|
* varbindlist SEQUENCE OF |
771 |
|
|
* SEQUENCE { |
772 |
|
|
* name ObjectName, |
773 |
|
|
* value ObjectValue |
774 |
|
|
* } |
775 |
|
|
* } |
776 |
|
|
* PDU for Trap: |
777 |
|
|
* SEQUENCE { |
778 |
|
|
* enterprise OBJECT IDENTIFIER, |
779 |
|
|
* agent-addr NetworkAddress, |
780 |
|
|
* generic-trap INTEGER, |
781 |
|
|
* specific-trap INTEGER, |
782 |
|
|
* time-stamp TimeTicks, |
783 |
|
|
* varbindlist SEQUENCE OF |
784 |
|
|
* SEQUENCE { |
785 |
|
|
* name ObjectName, |
786 |
|
|
* value ObjectValue |
787 |
|
|
* } |
788 |
|
|
* } |
789 |
|
|
*/ |
790 |
|
|
|
791 |
|
|
/* |
792 |
|
|
* Decode SNMP varBind |
793 |
|
|
*/ |
794 |
|
|
static void |
795 |
|
|
varbind_print(u_char pduid, const u_char *np, u_int length, int error) |
796 |
|
|
{ |
797 |
|
|
struct be elem; |
798 |
|
|
int count = 0, ind; |
799 |
|
|
|
800 |
|
|
/* Sequence of varBind */ |
801 |
|
|
if ((count = asn1_parse(np, length, &elem)) < 0) |
802 |
|
|
return; |
803 |
|
|
if (elem.type != BE_SEQ) { |
804 |
|
|
fputs("[!SEQ of varbind]", stdout); |
805 |
|
|
asn1_print(&elem); |
806 |
|
|
return; |
807 |
|
|
} |
808 |
|
|
if (count < length) |
809 |
|
|
printf("[%d extra after SEQ of varbind]", length - count); |
810 |
|
|
/* descend */ |
811 |
|
|
length = elem.asnlen; |
812 |
|
|
np = (u_char *)elem.data.raw; |
813 |
|
|
|
814 |
|
|
for (ind = 1; length > 0; ind++) { |
815 |
|
|
const u_char *vbend; |
816 |
|
|
u_int vblength; |
817 |
|
|
|
818 |
|
|
if (!error || ind == error) |
819 |
|
|
fputs(" ", stdout); |
820 |
|
|
|
821 |
|
|
/* Sequence */ |
822 |
|
|
if ((count = asn1_parse(np, length, &elem)) < 0) |
823 |
|
|
return; |
824 |
|
|
if (elem.type != BE_SEQ) { |
825 |
|
|
fputs("[!varbind]", stdout); |
826 |
|
|
asn1_print(&elem); |
827 |
|
|
return; |
828 |
|
|
} |
829 |
|
|
vbend = np + count; |
830 |
|
|
vblength = length - count; |
831 |
|
|
/* descend */ |
832 |
|
|
length = elem.asnlen; |
833 |
|
|
np = (u_char *)elem.data.raw; |
834 |
|
|
|
835 |
|
|
/* objName (OID) */ |
836 |
|
|
if ((count = asn1_parse(np, length, &elem)) < 0) |
837 |
|
|
return; |
838 |
|
|
if (elem.type != BE_OID) { |
839 |
|
|
fputs("[objName!=OID]", stdout); |
840 |
|
|
asn1_print(&elem); |
841 |
|
|
return; |
842 |
|
|
} |
843 |
|
|
if (!error || ind == error) |
844 |
|
|
asn1_print(&elem); |
845 |
|
|
length -= count; |
846 |
|
|
np += count; |
847 |
|
|
|
848 |
|
|
if (pduid != GETREQ && pduid != GETNEXTREQ && !error) |
849 |
|
|
fputs("=", stdout); |
850 |
|
|
|
851 |
|
|
/* objVal (ANY) */ |
852 |
|
|
if ((count = asn1_parse(np, length, &elem)) < 0) |
853 |
|
|
return; |
854 |
|
|
if (pduid == GETREQ || pduid == GETNEXTREQ || pduid == GETBULKREQ) { |
855 |
|
|
if (elem.type != BE_NULL) { |
856 |
|
|
fputs("[objVal!=NULL]", stdout); |
857 |
|
|
asn1_print(&elem); |
858 |
|
|
} |
859 |
|
|
} else |
860 |
|
|
if (error && ind == error && elem.type != BE_NULL) |
861 |
|
|
fputs("[err objVal!=NULL]", stdout); |
862 |
|
|
if (!error || ind == error) |
863 |
|
|
asn1_print(&elem); |
864 |
|
|
|
865 |
|
|
length = vblength; |
866 |
|
|
np = vbend; |
867 |
|
|
} |
868 |
|
|
} |
869 |
|
|
|
870 |
|
|
/* |
871 |
|
|
* Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, and SetRequest |
872 |
|
|
*/ |
873 |
|
|
static void |
874 |
|
|
snmppdu_print(u_char pduid, const u_char *np, u_int length) |
875 |
|
|
{ |
876 |
|
|
struct be elem; |
877 |
|
|
int count = 0, error; |
878 |
|
|
|
879 |
|
|
/* reqId (Integer) */ |
880 |
|
|
if ((count = asn1_parse(np, length, &elem)) < 0) |
881 |
|
|
return; |
882 |
|
|
if (elem.type != BE_INT) { |
883 |
|
|
fputs("[reqId!=INT]", stdout); |
884 |
|
|
asn1_print(&elem); |
885 |
|
|
return; |
886 |
|
|
} |
887 |
|
|
/* ignore the reqId */ |
888 |
|
|
length -= count; |
889 |
|
|
np += count; |
890 |
|
|
|
891 |
|
|
/* errorStatus (Integer) */ |
892 |
|
|
if ((count = asn1_parse(np, length, &elem)) < 0) |
893 |
|
|
return; |
894 |
|
|
if (elem.type != BE_INT) { |
895 |
|
|
fputs("[errorStatus!=INT]", stdout); |
896 |
|
|
asn1_print(&elem); |
897 |
|
|
return; |
898 |
|
|
} |
899 |
|
|
error = 0; |
900 |
|
|
if ((pduid == GETREQ || pduid == GETNEXTREQ) |
901 |
|
|
&& elem.data.integer != 0) { |
902 |
|
|
char errbuf[20]; |
903 |
|
|
printf("[errorStatus(%s)!=0]", |
904 |
|
|
DECODE_ErrorStatus(elem.data.integer)); |
905 |
|
|
} else if (pduid == GETBULKREQ) |
906 |
|
|
printf(" non-repeaters=%d", elem.data.integer); |
907 |
|
|
else if (elem.data.integer != 0) { |
908 |
|
|
char errbuf[20]; |
909 |
|
|
printf(" %s", DECODE_ErrorStatus(elem.data.integer)); |
910 |
|
|
error = elem.data.integer; |
911 |
|
|
} |
912 |
|
|
length -= count; |
913 |
|
|
np += count; |
914 |
|
|
|
915 |
|
|
/* errorIndex (Integer) */ |
916 |
|
|
if ((count = asn1_parse(np, length, &elem)) < 0) |
917 |
|
|
return; |
918 |
|
|
if (elem.type != BE_INT) { |
919 |
|
|
fputs("[errorIndex!=INT]", stdout); |
920 |
|
|
asn1_print(&elem); |
921 |
|
|
return; |
922 |
|
|
} |
923 |
|
|
if ((pduid == GETREQ || pduid == GETNEXTREQ) |
924 |
|
|
&& elem.data.integer != 0) |
925 |
|
|
printf("[errorIndex(%d)!=0]", elem.data.integer); |
926 |
|
|
else if (pduid == GETBULKREQ) |
927 |
|
|
printf(" max-repetitions=%d", elem.data.integer); |
928 |
|
|
else if (elem.data.integer != 0) { |
929 |
|
|
if (!error) |
930 |
|
|
printf("[errorIndex(%d) w/o errorStatus]", |
931 |
|
|
elem.data.integer); |
932 |
|
|
else { |
933 |
|
|
printf("@%d", elem.data.integer); |
934 |
|
|
error = elem.data.integer; |
935 |
|
|
} |
936 |
|
|
} else if (error) { |
937 |
|
|
fputs("[errorIndex==0]", stdout); |
938 |
|
|
error = 0; |
939 |
|
|
} |
940 |
|
|
length -= count; |
941 |
|
|
np += count; |
942 |
|
|
|
943 |
|
|
varbind_print(pduid, np, length, error); |
944 |
|
|
return; |
945 |
|
|
} |
946 |
|
|
|
947 |
|
|
/* |
948 |
|
|
* Decode SNMP Trap PDU |
949 |
|
|
*/ |
950 |
|
|
static void |
951 |
|
|
trap_print(const u_char *np, u_int length) |
952 |
|
|
{ |
953 |
|
|
struct be elem; |
954 |
|
|
int count = 0, generic; |
955 |
|
|
|
956 |
|
|
putchar(' '); |
957 |
|
|
|
958 |
|
|
/* enterprise (oid) */ |
959 |
|
|
if ((count = asn1_parse(np, length, &elem)) < 0) |
960 |
|
|
return; |
961 |
|
|
if (elem.type != BE_OID) { |
962 |
|
|
fputs("[enterprise!=OID]", stdout); |
963 |
|
|
asn1_print(&elem); |
964 |
|
|
return; |
965 |
|
|
} |
966 |
|
|
asn1_print(&elem); |
967 |
|
|
length -= count; |
968 |
|
|
np += count; |
969 |
|
|
|
970 |
|
|
putchar(' '); |
971 |
|
|
|
972 |
|
|
/* agent-addr (inetaddr) */ |
973 |
|
|
if ((count = asn1_parse(np, length, &elem)) < 0) |
974 |
|
|
return; |
975 |
|
|
if (elem.type != BE_INETADDR) { |
976 |
|
|
fputs("[agent-addr!=INETADDR]", stdout); |
977 |
|
|
asn1_print(&elem); |
978 |
|
|
return; |
979 |
|
|
} |
980 |
|
|
asn1_print(&elem); |
981 |
|
|
length -= count; |
982 |
|
|
np += count; |
983 |
|
|
|
984 |
|
|
/* generic-trap (Integer) */ |
985 |
|
|
if ((count = asn1_parse(np, length, &elem)) < 0) |
986 |
|
|
return; |
987 |
|
|
if (elem.type != BE_INT) { |
988 |
|
|
fputs("[generic-trap!=INT]", stdout); |
989 |
|
|
asn1_print(&elem); |
990 |
|
|
return; |
991 |
|
|
} |
992 |
|
|
generic = elem.data.integer; |
993 |
|
|
{ |
994 |
|
|
char buf[20]; |
995 |
|
|
printf(" %s", DECODE_GenericTrap(generic)); |
996 |
|
|
} |
997 |
|
|
length -= count; |
998 |
|
|
np += count; |
999 |
|
|
|
1000 |
|
|
/* specific-trap (Integer) */ |
1001 |
|
|
if ((count = asn1_parse(np, length, &elem)) < 0) |
1002 |
|
|
return; |
1003 |
|
|
if (elem.type != BE_INT) { |
1004 |
|
|
fputs("[specific-trap!=INT]", stdout); |
1005 |
|
|
asn1_print(&elem); |
1006 |
|
|
return; |
1007 |
|
|
} |
1008 |
|
|
if (generic != GT_ENTERPRISE) { |
1009 |
|
|
if (elem.data.integer != 0) |
1010 |
|
|
printf("[specific-trap(%d)!=0]", elem.data.integer); |
1011 |
|
|
} else |
1012 |
|
|
printf(" s=%d", elem.data.integer); |
1013 |
|
|
length -= count; |
1014 |
|
|
np += count; |
1015 |
|
|
|
1016 |
|
|
putchar(' '); |
1017 |
|
|
|
1018 |
|
|
/* time-stamp (TimeTicks) */ |
1019 |
|
|
if ((count = asn1_parse(np, length, &elem)) < 0) |
1020 |
|
|
return; |
1021 |
|
|
if (elem.type != BE_UNS) { /* XXX */ |
1022 |
|
|
fputs("[time-stamp!=TIMETICKS]", stdout); |
1023 |
|
|
asn1_print(&elem); |
1024 |
|
|
return; |
1025 |
|
|
} |
1026 |
|
|
asn1_print(&elem); |
1027 |
|
|
length -= count; |
1028 |
|
|
np += count; |
1029 |
|
|
|
1030 |
|
|
varbind_print (TRAP, np, length, 0); |
1031 |
|
|
return; |
1032 |
|
|
} |
1033 |
|
|
|
1034 |
|
|
/* |
1035 |
|
|
* Decode SNMP header and pass on to PDU printing routines |
1036 |
|
|
*/ |
1037 |
|
|
void |
1038 |
|
|
snmp_print(const u_char *np, u_int length) |
1039 |
|
|
{ |
1040 |
|
|
struct be elem, pdu; |
1041 |
|
|
int count = 0; |
1042 |
|
|
|
1043 |
|
|
truncated = 0; |
1044 |
|
|
|
1045 |
|
|
/* truncated packet? */ |
1046 |
|
|
if (np + length > snapend) { |
1047 |
|
|
truncated = 1; |
1048 |
|
|
length = snapend - np; |
1049 |
|
|
} |
1050 |
|
|
|
1051 |
|
|
putchar(' '); |
1052 |
|
|
|
1053 |
|
|
/* initial Sequence */ |
1054 |
|
|
if ((count = asn1_parse(np, length, &elem)) < 0) |
1055 |
|
|
return; |
1056 |
|
|
if (elem.type != BE_SEQ) { |
1057 |
|
|
fputs("[!init SEQ]", stdout); |
1058 |
|
|
asn1_print(&elem); |
1059 |
|
|
return; |
1060 |
|
|
} |
1061 |
|
|
if (count < length) |
1062 |
|
|
printf("[%d extra after iSEQ]", length - count); |
1063 |
|
|
/* descend */ |
1064 |
|
|
length = elem.asnlen; |
1065 |
|
|
np = (u_char *)elem.data.raw; |
1066 |
|
|
/* Version (Integer) */ |
1067 |
|
|
if ((count = asn1_parse(np, length, &elem)) < 0) |
1068 |
|
|
return; |
1069 |
|
|
if (elem.type != BE_INT) { |
1070 |
|
|
fputs("[version!=INT]", stdout); |
1071 |
|
|
asn1_print(&elem); |
1072 |
|
|
return; |
1073 |
|
|
} |
1074 |
|
|
/* only handle version 1 and 2 */ |
1075 |
|
|
if (elem.data.integer > DEF_VERSION) { |
1076 |
|
|
printf("[version(%d)>%d]", elem.data.integer, DEF_VERSION); |
1077 |
|
|
return; |
1078 |
|
|
} |
1079 |
|
|
length -= count; |
1080 |
|
|
np += count; |
1081 |
|
|
|
1082 |
|
|
/* Community (String) */ |
1083 |
|
|
if ((count = asn1_parse(np, length, &elem)) < 0) |
1084 |
|
|
return; |
1085 |
|
|
if (elem.type != BE_STR) { |
1086 |
|
|
fputs("[comm!=STR]", stdout); |
1087 |
|
|
asn1_print(&elem); |
1088 |
|
|
return; |
1089 |
|
|
} |
1090 |
|
|
/* default community */ |
1091 |
|
|
if (strncmp((char *)elem.data.str, DEF_COMMUNITY, |
1092 |
|
|
sizeof(DEF_COMMUNITY) - 1)) |
1093 |
|
|
/* ! "public" */ |
1094 |
|
|
printf("C=%.*s ", (int)elem.asnlen, elem.data.str); |
1095 |
|
|
length -= count; |
1096 |
|
|
np += count; |
1097 |
|
|
|
1098 |
|
|
/* PDU (Context) */ |
1099 |
|
|
if ((count = asn1_parse(np, length, &pdu)) < 0) |
1100 |
|
|
return; |
1101 |
|
|
if (pdu.type != BE_PDU) { |
1102 |
|
|
fputs("[no PDU]", stdout); |
1103 |
|
|
return; |
1104 |
|
|
} |
1105 |
|
|
if (count < length) |
1106 |
|
|
printf("[%d extra after PDU]", length - count); |
1107 |
|
|
asn1_print(&pdu); |
1108 |
|
|
/* descend into PDU */ |
1109 |
|
|
length = pdu.asnlen; |
1110 |
|
|
np = (u_char *)pdu.data.raw; |
1111 |
|
|
|
1112 |
|
|
switch (pdu.id) { |
1113 |
|
|
case TRAP: |
1114 |
|
|
trap_print(np, length); |
1115 |
|
|
break; |
1116 |
|
|
case GETREQ: |
1117 |
|
|
case GETNEXTREQ: |
1118 |
|
|
case GETRESP: |
1119 |
|
|
case SETREQ: |
1120 |
|
|
case GETBULKREQ: |
1121 |
|
|
case INFORMREQ: |
1122 |
|
|
case TRAPV2: |
1123 |
|
|
case REPORT: |
1124 |
|
|
snmppdu_print(pdu.id, np, length); |
1125 |
|
|
break; |
1126 |
|
|
} |
1127 |
|
|
return; |
1128 |
|
|
} |