]> The Tcpdump Group git mirrors - tcpdump/blob - print-snmp.c
b3ef26c0ac1ea1f3dd479f09440920db1e76ef9d
[tcpdump] / print-snmp.c
1 /*
2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3 * John Robert LoVerso. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 *
28 * This implementation has been influenced by the CMU SNMP release,
29 * by Steve Waldbusser. However, this shares no code with that system.
30 * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_.
31 * Earlier forms of this implementation were derived and/or inspired by an
32 * awk script originally written by C. Philip Wood of LANL (but later
33 * heavily modified by John Robert LoVerso). The copyright notice for
34 * that work is preserved below, even though it may not rightly apply
35 * to this file.
36 *
37 * Support for SNMPv2c/SNMPv3 and the ability to link the module against
38 * the libsmi was added by J. Schoenwaelder, Copyright (c) 1999.
39 *
40 * This started out as a very simple program, but the incremental decoding
41 * (into the BE structure) complicated things.
42 *
43 # Los Alamos National Laboratory
44 #
45 # Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
46 # This software was produced under a U.S. Government contract
47 # (W-7405-ENG-36) by Los Alamos National Laboratory, which is
48 # operated by the University of California for the U.S. Department
49 # of Energy. The U.S. Government is licensed to use, reproduce,
50 # and distribute this software. Permission is granted to the
51 # public to copy and use this software without charge, provided
52 # that this Notice and any statement of authorship are reproduced
53 # on all copies. Neither the Government nor the University makes
54 # any warranty, express or implied, or assumes any liability or
55 # responsibility for the use of this software.
56 # @(#)snmp.awk.x 1.1 (LANL) 1/15/90
57 */
58
59 /* \summary: Simple Network Management Protocol (SNMP) printer */
60
61 #ifdef HAVE_CONFIG_H
62 #include "config.h"
63 #endif
64
65 #include <netdissect-stdinc.h>
66
67 #include <stdio.h>
68 #include <string.h>
69
70 #ifdef USE_LIBSMI
71 #include <smi.h>
72 #endif
73
74 #include "netdissect.h"
75
76 #undef OPAQUE /* defined in <wingdi.h> */
77
78 static const char tstr[] = "[|snmp]";
79
80 /*
81 * Universal ASN.1 types
82 * (we only care about the tag values for those allowed in the Internet SMI)
83 */
84 static const char *Universal[] = {
85 "U-0",
86 "Boolean",
87 "Integer",
88 #define INTEGER 2
89 "Bitstring",
90 "String",
91 #define STRING 4
92 "Null",
93 #define ASN_NULL 5
94 "ObjID",
95 #define OBJECTID 6
96 "ObjectDes",
97 "U-8","U-9","U-10","U-11", /* 8-11 */
98 "U-12","U-13","U-14","U-15", /* 12-15 */
99 "Sequence",
100 #define SEQUENCE 16
101 "Set"
102 };
103
104 /*
105 * Application-wide ASN.1 types from the Internet SMI and their tags
106 */
107 static const char *Application[] = {
108 "IpAddress",
109 #define IPADDR 0
110 "Counter",
111 #define COUNTER 1
112 "Gauge",
113 #define GAUGE 2
114 "TimeTicks",
115 #define TIMETICKS 3
116 "Opaque",
117 #define OPAQUE 4
118 "C-5",
119 "Counter64"
120 #define COUNTER64 6
121 };
122
123 /*
124 * Context-specific ASN.1 types for the SNMP PDUs and their tags
125 */
126 static const char *Context[] = {
127 "GetRequest",
128 #define GETREQ 0
129 "GetNextRequest",
130 #define GETNEXTREQ 1
131 "GetResponse",
132 #define GETRESP 2
133 "SetRequest",
134 #define SETREQ 3
135 "Trap",
136 #define TRAP 4
137 "GetBulk",
138 #define GETBULKREQ 5
139 "Inform",
140 #define INFORMREQ 6
141 "V2Trap",
142 #define V2TRAP 7
143 "Report"
144 #define REPORT 8
145 };
146
147 #define NOTIFY_CLASS(x) (x == TRAP || x == V2TRAP || x == INFORMREQ)
148 #define READ_CLASS(x) (x == GETREQ || x == GETNEXTREQ || x == GETBULKREQ)
149 #define WRITE_CLASS(x) (x == SETREQ)
150 #define RESPONSE_CLASS(x) (x == GETRESP)
151 #define INTERNAL_CLASS(x) (x == REPORT)
152
153 /*
154 * Context-specific ASN.1 types for the SNMP Exceptions and their tags
155 */
156 static const char *Exceptions[] = {
157 "noSuchObject",
158 #define NOSUCHOBJECT 0
159 "noSuchInstance",
160 #define NOSUCHINSTANCE 1
161 "endOfMibView",
162 #define ENDOFMIBVIEW 2
163 };
164
165 /*
166 * Private ASN.1 types
167 * The Internet SMI does not specify any
168 */
169 static const char *Private[] = {
170 "P-0"
171 };
172
173 /*
174 * error-status values for any SNMP PDU
175 */
176 static const char *ErrorStatus[] = {
177 "noError",
178 "tooBig",
179 "noSuchName",
180 "badValue",
181 "readOnly",
182 "genErr",
183 "noAccess",
184 "wrongType",
185 "wrongLength",
186 "wrongEncoding",
187 "wrongValue",
188 "noCreation",
189 "inconsistentValue",
190 "resourceUnavailable",
191 "commitFailed",
192 "undoFailed",
193 "authorizationError",
194 "notWritable",
195 "inconsistentName"
196 };
197 #define DECODE_ErrorStatus(e) \
198 ( e >= 0 && (size_t)e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
199 ? ErrorStatus[e] \
200 : (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf))
201
202 /*
203 * generic-trap values in the SNMP Trap-PDU
204 */
205 static const char *GenericTrap[] = {
206 "coldStart",
207 "warmStart",
208 "linkDown",
209 "linkUp",
210 "authenticationFailure",
211 "egpNeighborLoss",
212 "enterpriseSpecific"
213 #define GT_ENTERPRISE 6
214 };
215 #define DECODE_GenericTrap(t) \
216 ( t >= 0 && (size_t)t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
217 ? GenericTrap[t] \
218 : (snprintf(buf, sizeof(buf), "gt=%d", t), buf))
219
220 /*
221 * ASN.1 type class table
222 * Ties together the preceding Universal, Application, Context, and Private
223 * type definitions.
224 */
225 #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
226 static const struct {
227 const char *name;
228 const char **Id;
229 int numIDs;
230 } Class[] = {
231 defineCLASS(Universal),
232 #define UNIVERSAL 0
233 defineCLASS(Application),
234 #define APPLICATION 1
235 defineCLASS(Context),
236 #define CONTEXT 2
237 defineCLASS(Private),
238 #define PRIVATE 3
239 defineCLASS(Exceptions),
240 #define EXCEPTIONS 4
241 };
242
243 /*
244 * defined forms for ASN.1 types
245 */
246 static const char *Form[] = {
247 "Primitive",
248 #define PRIMITIVE 0
249 "Constructed",
250 #define CONSTRUCTED 1
251 };
252
253 /*
254 * A structure for the OID tree for the compiled-in MIB.
255 * This is stored as a general-order tree.
256 */
257 static struct obj {
258 const char *desc; /* name of object */
259 u_char oid; /* sub-id following parent */
260 u_char type; /* object type (unused) */
261 struct obj *child, *next; /* child and next sibling pointers */
262 } *objp = NULL;
263
264 /*
265 * Include the compiled in SNMP MIB. "mib.h" is produced by feeding
266 * RFC-1156 format files into "makemib". "mib.h" MUST define at least
267 * a value for `mibroot'.
268 *
269 * In particular, this is gross, as this is including initialized structures,
270 * and by right shouldn't be an "include" file.
271 */
272 #include "mib.h"
273
274 /*
275 * This defines a list of OIDs which will be abbreviated on output.
276 * Currently, this includes the prefixes for the Internet MIB, the
277 * private enterprises tree, and the experimental tree.
278 */
279 static const struct obj_abrev {
280 const char *prefix; /* prefix for this abrev */
281 struct obj *node; /* pointer into object table */
282 const char *oid; /* ASN.1 encoded OID */
283 } obj_abrev_list[] = {
284 #ifndef NO_ABREV_MIB
285 /* .iso.org.dod.internet.mgmt.mib */
286 { "", &_mib_obj, "\53\6\1\2\1" },
287 #endif
288 #ifndef NO_ABREV_ENTER
289 /* .iso.org.dod.internet.private.enterprises */
290 { "E:", &_enterprises_obj, "\53\6\1\4\1" },
291 #endif
292 #ifndef NO_ABREV_EXPERI
293 /* .iso.org.dod.internet.experimental */
294 { "X:", &_experimental_obj, "\53\6\1\3" },
295 #endif
296 #ifndef NO_ABBREV_SNMPMODS
297 /* .iso.org.dod.internet.snmpV2.snmpModules */
298 { "S:", &_snmpModules_obj, "\53\6\1\6\3" },
299 #endif
300 { 0,0,0 }
301 };
302
303 /*
304 * This is used in the OID print routine to walk down the object tree
305 * rooted at `mibroot'.
306 */
307 #define OBJ_PRINT(o, suppressdot) \
308 { \
309 if (objp) { \
310 do { \
311 if ((o) == objp->oid) \
312 break; \
313 } while ((objp = objp->next) != NULL); \
314 } \
315 if (objp) { \
316 ND_PRINT((ndo, suppressdot?"%s":".%s", objp->desc)); \
317 objp = objp->child; \
318 } else \
319 ND_PRINT((ndo, suppressdot?"%u":".%u", (o))); \
320 }
321
322 /*
323 * This is the definition for the Any-Data-Type storage used purely for
324 * temporary internal representation while decoding an ASN.1 data stream.
325 */
326 struct be {
327 uint32_t asnlen;
328 union {
329 const uint8_t *raw;
330 int32_t integer;
331 uint32_t uns;
332 const u_char *str;
333 struct {
334 uint32_t high;
335 uint32_t low;
336 } uns64;
337 } data;
338 u_short id;
339 u_char form, class; /* tag info */
340 u_char type;
341 #define BE_ANY 255
342 #define BE_NONE 0
343 #define BE_NULL 1
344 #define BE_OCTET 2
345 #define BE_OID 3
346 #define BE_INT 4
347 #define BE_UNS 5
348 #define BE_STR 6
349 #define BE_SEQ 7
350 #define BE_INETADDR 8
351 #define BE_PDU 9
352 #define BE_UNS64 10
353 #define BE_NOSUCHOBJECT 128
354 #define BE_NOSUCHINST 129
355 #define BE_ENDOFMIBVIEW 130
356 };
357
358 /*
359 * SNMP versions recognized by this module
360 */
361 static const char *SnmpVersion[] = {
362 "SNMPv1",
363 #define SNMP_VERSION_1 0
364 "SNMPv2c",
365 #define SNMP_VERSION_2 1
366 "SNMPv2u",
367 #define SNMP_VERSION_2U 2
368 "SNMPv3"
369 #define SNMP_VERSION_3 3
370 };
371
372 /*
373 * Defaults for SNMP PDU components
374 */
375 #define DEF_COMMUNITY "public"
376
377 /*
378 * constants for ASN.1 decoding
379 */
380 #define OIDMUX 40
381 #define ASNLEN_INETADDR 4
382 #define ASN_SHIFT7 7
383 #define ASN_SHIFT8 8
384 #define ASN_BIT8 0x80
385 #define ASN_LONGLEN 0x80
386
387 #define ASN_ID_BITS 0x1f
388 #define ASN_FORM_BITS 0x20
389 #define ASN_FORM_SHIFT 5
390 #define ASN_CLASS_BITS 0xc0
391 #define ASN_CLASS_SHIFT 6
392
393 #define ASN_ID_EXT 0x1f /* extension ID in tag field */
394
395 /*
396 * This decodes the next ASN.1 object in the stream pointed to by "p"
397 * (and of real-length "len") and stores the intermediate data in the
398 * provided BE object.
399 *
400 * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
401 * O/w, this returns the number of bytes parsed from "p".
402 */
403 static int
404 asn1_parse(netdissect_options *ndo,
405 register const u_char *p, u_int len, struct be *elem)
406 {
407 u_char form, class, id;
408 int i, hdr;
409
410 elem->asnlen = 0;
411 elem->type = BE_ANY;
412 if (len < 1) {
413 ND_PRINT((ndo, "[nothing to parse]"));
414 return -1;
415 }
416 ND_TCHECK(*p);
417
418 /*
419 * it would be nice to use a bit field, but you can't depend on them.
420 * +---+---+---+---+---+---+---+---+
421 * + class |frm| id |
422 * +---+---+---+---+---+---+---+---+
423 * 7 6 5 4 3 2 1 0
424 */
425 id = *p & ASN_ID_BITS; /* lower 5 bits, range 00-1f */
426 #ifdef notdef
427 form = (*p & 0xe0) >> 5; /* move upper 3 bits to lower 3 */
428 class = form >> 1; /* bits 7&6 -> bits 1&0, range 0-3 */
429 form &= 0x1; /* bit 5 -> bit 0, range 0-1 */
430 #else
431 form = (u_char)(*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
432 class = (u_char)(*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
433 #endif
434 elem->form = form;
435 elem->class = class;
436 elem->id = id;
437 p++; len--; hdr = 1;
438 /* extended tag field */
439 if (id == ASN_ID_EXT) {
440 /*
441 * The ID follows, as a sequence of octets with the
442 * 8th bit set and the remaining 7 bits being
443 * the next 7 bits of the value, terminated with
444 * an octet with the 8th bit not set.
445 *
446 * First, assemble all the octets with the 8th
447 * bit set. XXX - this doesn't handle a value
448 * that won't fit in 32 bits.
449 */
450 id = 0;
451 ND_TCHECK(*p);
452 while (*p & ASN_BIT8) {
453 if (len < 1) {
454 ND_PRINT((ndo, "[Xtagfield?]"));
455 return -1;
456 }
457 id = (id << 7) | (*p & ~ASN_BIT8);
458 len--;
459 hdr++;
460 p++;
461 ND_TCHECK(*p);
462 }
463 if (len < 1) {
464 ND_PRINT((ndo, "[Xtagfield?]"));
465 return -1;
466 }
467 ND_TCHECK(*p);
468 elem->id = id = (id << 7) | *p;
469 --len;
470 ++hdr;
471 ++p;
472 }
473 if (len < 1) {
474 ND_PRINT((ndo, "[no asnlen]"));
475 return -1;
476 }
477 ND_TCHECK(*p);
478 elem->asnlen = *p;
479 p++; len--; hdr++;
480 if (elem->asnlen & ASN_BIT8) {
481 uint32_t noct = elem->asnlen % ASN_BIT8;
482 elem->asnlen = 0;
483 if (len < noct) {
484 ND_PRINT((ndo, "[asnlen? %d<%d]", len, noct));
485 return -1;
486 }
487 ND_TCHECK2(*p, noct);
488 for (; noct-- > 0; len--, hdr++)
489 elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++;
490 }
491 if (len < elem->asnlen) {
492 ND_PRINT((ndo, "[len%d<asnlen%u]", len, elem->asnlen));
493 return -1;
494 }
495 if (form >= sizeof(Form)/sizeof(Form[0])) {
496 ND_PRINT((ndo, "[form?%d]", form));
497 return -1;
498 }
499 if (class >= sizeof(Class)/sizeof(Class[0])) {
500 ND_PRINT((ndo, "[class?%c/%d]", *Form[form], class));
501 return -1;
502 }
503 if ((int)id >= Class[class].numIDs) {
504 ND_PRINT((ndo, "[id?%c/%s/%d]", *Form[form], Class[class].name, id));
505 return -1;
506 }
507
508 switch (form) {
509 case PRIMITIVE:
510 switch (class) {
511 case UNIVERSAL:
512 switch (id) {
513 case STRING:
514 elem->type = BE_STR;
515 elem->data.str = p;
516 break;
517
518 case INTEGER: {
519 register int32_t data;
520 elem->type = BE_INT;
521 data = 0;
522
523 ND_TCHECK2(*p, elem->asnlen);
524 if (*p & ASN_BIT8) /* negative */
525 data = -1;
526 for (i = elem->asnlen; i-- > 0; p++)
527 data = (data << ASN_SHIFT8) | *p;
528 elem->data.integer = data;
529 break;
530 }
531
532 case OBJECTID:
533 elem->type = BE_OID;
534 elem->data.raw = (const uint8_t *)p;
535 break;
536
537 case ASN_NULL:
538 elem->type = BE_NULL;
539 elem->data.raw = NULL;
540 break;
541
542 default:
543 elem->type = BE_OCTET;
544 elem->data.raw = (const uint8_t *)p;
545 ND_PRINT((ndo, "[P/U/%s]", Class[class].Id[id]));
546 break;
547 }
548 break;
549
550 case APPLICATION:
551 switch (id) {
552 case IPADDR:
553 elem->type = BE_INETADDR;
554 elem->data.raw = (const uint8_t *)p;
555 break;
556
557 case COUNTER:
558 case GAUGE:
559 case TIMETICKS: {
560 register uint32_t data;
561 ND_TCHECK2(*p, elem->asnlen);
562 elem->type = BE_UNS;
563 data = 0;
564 for (i = elem->asnlen; i-- > 0; p++)
565 data = (data << 8) + *p;
566 elem->data.uns = data;
567 break;
568 }
569
570 case COUNTER64: {
571 register uint32_t high, low;
572 ND_TCHECK2(*p, elem->asnlen);
573 elem->type = BE_UNS64;
574 high = 0, low = 0;
575 for (i = elem->asnlen; i-- > 0; p++) {
576 high = (high << 8) |
577 ((low & 0xFF000000) >> 24);
578 low = (low << 8) | *p;
579 }
580 elem->data.uns64.high = high;
581 elem->data.uns64.low = low;
582 break;
583 }
584
585 default:
586 elem->type = BE_OCTET;
587 elem->data.raw = (const uint8_t *)p;
588 ND_PRINT((ndo, "[P/A/%s]",
589 Class[class].Id[id]));
590 break;
591 }
592 break;
593
594 case CONTEXT:
595 switch (id) {
596 case NOSUCHOBJECT:
597 elem->type = BE_NOSUCHOBJECT;
598 elem->data.raw = NULL;
599 break;
600
601 case NOSUCHINSTANCE:
602 elem->type = BE_NOSUCHINST;
603 elem->data.raw = NULL;
604 break;
605
606 case ENDOFMIBVIEW:
607 elem->type = BE_ENDOFMIBVIEW;
608 elem->data.raw = NULL;
609 break;
610 }
611 break;
612
613 default:
614 ND_PRINT((ndo, "[P/%s/%s]", Class[class].name, Class[class].Id[id]));
615 ND_TCHECK2(*p, elem->asnlen);
616 elem->type = BE_OCTET;
617 elem->data.raw = (const uint8_t *)p;
618 break;
619 }
620 break;
621
622 case CONSTRUCTED:
623 switch (class) {
624 case UNIVERSAL:
625 switch (id) {
626 case SEQUENCE:
627 elem->type = BE_SEQ;
628 elem->data.raw = (const uint8_t *)p;
629 break;
630
631 default:
632 elem->type = BE_OCTET;
633 elem->data.raw = (const uint8_t *)p;
634 ND_PRINT((ndo, "C/U/%s", Class[class].Id[id]));
635 break;
636 }
637 break;
638
639 case CONTEXT:
640 elem->type = BE_PDU;
641 elem->data.raw = (const uint8_t *)p;
642 break;
643
644 default:
645 elem->type = BE_OCTET;
646 elem->data.raw = (const uint8_t *)p;
647 ND_PRINT((ndo, "C/%s/%s", Class[class].name, Class[class].Id[id]));
648 break;
649 }
650 break;
651 }
652 p += elem->asnlen;
653 len -= elem->asnlen;
654 return elem->asnlen + hdr;
655
656 trunc:
657 ND_PRINT((ndo, "%s", tstr));
658 return -1;
659 }
660
661 static int
662 asn1_print_octets(netdissect_options *ndo, struct be *elem)
663 {
664 const u_char *p = (const u_char *)elem->data.raw;
665 uint32_t asnlen = elem->asnlen;
666 uint32_t i;
667
668 ND_TCHECK2(*p, asnlen);
669 for (i = asnlen; i-- > 0; p++)
670 ND_PRINT((ndo, "_%.2x", *p));
671 return 0;
672
673 trunc:
674 ND_PRINT((ndo, "%s", tstr));
675 return -1;
676 }
677
678 static int
679 asn1_print_string(netdissect_options *ndo, struct be *elem)
680 {
681 register int printable = 1, first = 1;
682 const u_char *p;
683 uint32_t asnlen = elem->asnlen;
684 uint32_t i;
685
686 p = elem->data.str;
687 ND_TCHECK2(*p, asnlen);
688 for (i = asnlen; printable && i-- > 0; p++)
689 printable = ND_ISPRINT(*p);
690 p = elem->data.str;
691 if (printable) {
692 ND_PRINT((ndo, "\""));
693 if (fn_printn(ndo, p, asnlen, ndo->ndo_snapend)) {
694 ND_PRINT((ndo, "\""));
695 goto trunc;
696 }
697 ND_PRINT((ndo, "\""));
698 } else {
699 for (i = asnlen; i-- > 0; p++) {
700 ND_PRINT((ndo, first ? "%.2x" : "_%.2x", *p));
701 first = 0;
702 }
703 }
704 return 0;
705
706 trunc:
707 ND_PRINT((ndo, "%s", tstr));
708 return -1;
709 }
710
711 /*
712 * Display the ASN.1 object represented by the BE object.
713 * This used to be an integral part of asn1_parse() before the intermediate
714 * BE form was added.
715 */
716 static int
717 asn1_print(netdissect_options *ndo,
718 struct be *elem)
719 {
720 const u_char *p = (const u_char *)elem->data.raw;
721 uint32_t asnlen = elem->asnlen;
722 uint32_t i;
723
724 switch (elem->type) {
725
726 case BE_OCTET:
727 if (asn1_print_octets(ndo, elem) == -1)
728 return -1;
729 break;
730
731 case BE_NULL:
732 break;
733
734 case BE_OID: {
735 int o = 0, first = -1;
736
737 i = asnlen;
738 if (!nd_smi_module_loaded) {
739 if (!ndo->ndo_nflag && asnlen > 2) {
740 const struct obj_abrev *a = &obj_abrev_list[0];
741 size_t a_len = strlen(a->oid);
742 for (; a->node; a++) {
743 ND_TCHECK2(*p, a_len);
744 if (memcmp(a->oid, p, a_len) == 0) {
745 objp = a->node->child;
746 i -= strlen(a->oid);
747 p += strlen(a->oid);
748 ND_PRINT((ndo, "%s", a->prefix));
749 first = 1;
750 break;
751 }
752 }
753 }
754
755 for (; i-- > 0; p++) {
756 ND_TCHECK(*p);
757 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
758 if (*p & ASN_LONGLEN)
759 continue;
760
761 /*
762 * first subitem encodes two items with
763 * 1st*OIDMUX+2nd
764 * (see X.690:1997 clause 8.19 for the details)
765 */
766 if (first < 0) {
767 int s;
768 if (!ndo->ndo_nflag)
769 objp = mibroot;
770 first = 0;
771 s = o / OIDMUX;
772 if (s > 2) s = 2;
773 OBJ_PRINT(s, first);
774 o -= s * OIDMUX;
775 }
776 OBJ_PRINT(o, first);
777 if (--first < 0)
778 first = 0;
779 o = 0;
780 }
781 }
782 break;
783 }
784
785 case BE_INT:
786 ND_PRINT((ndo, "%d", elem->data.integer));
787 break;
788
789 case BE_UNS:
790 ND_PRINT((ndo, "%u", elem->data.uns));
791 break;
792
793 case BE_UNS64: { /* idea borrowed from by Marshall Rose */
794 double d;
795 int j, carry;
796 char *cpf, *cpl, last[6], first[30];
797 if (elem->data.uns64.high == 0) {
798 ND_PRINT((ndo, "%u", elem->data.uns64.low));
799 break;
800 }
801 d = elem->data.uns64.high * 4294967296.0; /* 2^32 */
802 if (elem->data.uns64.high <= 0x1fffff) {
803 d += elem->data.uns64.low;
804 #if 0 /*is looks illegal, but what is the intention?*/
805 ND_PRINT((ndo, "%.f", d));
806 #else
807 ND_PRINT((ndo, "%f", d));
808 #endif
809 break;
810 }
811 d += (elem->data.uns64.low & 0xfffff000);
812 #if 0 /*is looks illegal, but what is the intention?*/
813 snprintf(first, sizeof(first), "%.f", d);
814 #else
815 snprintf(first, sizeof(first), "%f", d);
816 #endif
817 snprintf(last, sizeof(last), "%5.5d",
818 elem->data.uns64.low & 0xfff);
819 for (carry = 0, cpf = first+strlen(first)-1, cpl = last+4;
820 cpl >= last;
821 cpf--, cpl--) {
822 j = carry + (*cpf - '0') + (*cpl - '0');
823 if (j > 9) {
824 j -= 10;
825 carry = 1;
826 } else {
827 carry = 0;
828 }
829 *cpf = j + '0';
830 }
831 ND_PRINT((ndo, "%s", first));
832 break;
833 }
834
835 case BE_STR:
836 if (asn1_print_string(ndo, elem) == -1)
837 return -1;
838 break;
839
840 case BE_SEQ:
841 ND_PRINT((ndo, "Seq(%u)", elem->asnlen));
842 break;
843
844 case BE_INETADDR:
845 if (asnlen != ASNLEN_INETADDR)
846 ND_PRINT((ndo, "[inetaddr len!=%d]", ASNLEN_INETADDR));
847 ND_TCHECK2(*p, asnlen);
848 for (i = asnlen; i-- != 0; p++) {
849 ND_PRINT((ndo, (i == asnlen-1) ? "%u" : ".%u", *p));
850 }
851 break;
852
853 case BE_NOSUCHOBJECT:
854 case BE_NOSUCHINST:
855 case BE_ENDOFMIBVIEW:
856 ND_PRINT((ndo, "[%s]", Class[EXCEPTIONS].Id[elem->id]));
857 break;
858
859 case BE_PDU:
860 ND_PRINT((ndo, "%s(%u)", Class[CONTEXT].Id[elem->id], elem->asnlen));
861 break;
862
863 case BE_ANY:
864 ND_PRINT((ndo, "[BE_ANY!?]"));
865 break;
866
867 default:
868 ND_PRINT((ndo, "[be!?]"));
869 break;
870 }
871 return 0;
872
873 trunc:
874 ND_PRINT((ndo, "%s", tstr));
875 return -1;
876 }
877
878 #ifdef notdef
879 /*
880 * This is a brute force ASN.1 printer: recurses to dump an entire structure.
881 * This will work for any ASN.1 stream, not just an SNMP PDU.
882 *
883 * By adding newlines and spaces at the correct places, this would print in
884 * Rose-Normal-Form.
885 *
886 * This is not currently used.
887 */
888 static void
889 asn1_decode(u_char *p, u_int length)
890 {
891 struct be elem;
892 int i = 0;
893
894 while (i >= 0 && length > 0) {
895 i = asn1_parse(ndo, p, length, &elem);
896 if (i >= 0) {
897 ND_PRINT((ndo, " "));
898 if (asn1_print(ndo, &elem) < 0)
899 return;
900 if (elem.type == BE_SEQ || elem.type == BE_PDU) {
901 ND_PRINT((ndo, " {"));
902 asn1_decode(elem.data.raw, elem.asnlen);
903 ND_PRINT((ndo, " }"));
904 }
905 length -= i;
906 p += i;
907 }
908 }
909 }
910 #endif
911
912 #ifdef USE_LIBSMI
913
914 struct smi2be {
915 SmiBasetype basetype;
916 int be;
917 };
918
919 static const struct smi2be smi2betab[] = {
920 { SMI_BASETYPE_INTEGER32, BE_INT },
921 { SMI_BASETYPE_OCTETSTRING, BE_STR },
922 { SMI_BASETYPE_OCTETSTRING, BE_INETADDR },
923 { SMI_BASETYPE_OBJECTIDENTIFIER, BE_OID },
924 { SMI_BASETYPE_UNSIGNED32, BE_UNS },
925 { SMI_BASETYPE_INTEGER64, BE_NONE },
926 { SMI_BASETYPE_UNSIGNED64, BE_UNS64 },
927 { SMI_BASETYPE_FLOAT32, BE_NONE },
928 { SMI_BASETYPE_FLOAT64, BE_NONE },
929 { SMI_BASETYPE_FLOAT128, BE_NONE },
930 { SMI_BASETYPE_ENUM, BE_INT },
931 { SMI_BASETYPE_BITS, BE_STR },
932 { SMI_BASETYPE_UNKNOWN, BE_NONE }
933 };
934
935 static int
936 smi_decode_oid(netdissect_options *ndo,
937 struct be *elem, unsigned int *oid,
938 unsigned int oidsize, unsigned int *oidlen)
939 {
940 const u_char *p = (const u_char *)elem->data.raw;
941 uint32_t asnlen = elem->asnlen;
942 int o = 0, first = -1, i = asnlen;
943 unsigned int firstval;
944
945 if (nd_smi_module_loaded) {
946 for (*oidlen = 0; i-- > 0; p++) {
947 ND_TCHECK(*p);
948 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
949 if (*p & ASN_LONGLEN)
950 continue;
951
952 /*
953 * first subitem encodes two items with 1st*OIDMUX+2nd
954 * (see X.690:1997 clause 8.19 for the details)
955 */
956 if (first < 0) {
957 first = 0;
958 firstval = o / OIDMUX;
959 if (firstval > 2) firstval = 2;
960 o -= firstval * OIDMUX;
961 if (*oidlen < oidsize) {
962 oid[(*oidlen)++] = firstval;
963 }
964 }
965 if (*oidlen < oidsize) {
966 oid[(*oidlen)++] = o;
967 }
968 o = 0;
969 }
970 }
971 return 0;
972
973 trunc:
974 ND_PRINT((ndo, "%s", tstr));
975 return -1;
976 }
977
978 static int smi_check_type(SmiBasetype basetype, int be)
979 {
980 int i;
981
982 for (i = 0; smi2betab[i].basetype != SMI_BASETYPE_UNKNOWN; i++) {
983 if (smi2betab[i].basetype == basetype && smi2betab[i].be == be) {
984 return 1;
985 }
986 }
987
988 return 0;
989 }
990
991 static int smi_check_a_range(SmiType *smiType, SmiRange *smiRange,
992 struct be *elem)
993 {
994 int ok = 1;
995
996 switch (smiType->basetype) {
997 case SMI_BASETYPE_OBJECTIDENTIFIER:
998 case SMI_BASETYPE_OCTETSTRING:
999 if (smiRange->minValue.value.unsigned32
1000 == smiRange->maxValue.value.unsigned32) {
1001 ok = (elem->asnlen == smiRange->minValue.value.unsigned32);
1002 } else {
1003 ok = (elem->asnlen >= smiRange->minValue.value.unsigned32
1004 && elem->asnlen <= smiRange->maxValue.value.unsigned32);
1005 }
1006 break;
1007
1008 case SMI_BASETYPE_INTEGER32:
1009 ok = (elem->data.integer >= smiRange->minValue.value.integer32
1010 && elem->data.integer <= smiRange->maxValue.value.integer32);
1011 break;
1012
1013 case SMI_BASETYPE_UNSIGNED32:
1014 ok = (elem->data.uns >= smiRange->minValue.value.unsigned32
1015 && elem->data.uns <= smiRange->maxValue.value.unsigned32);
1016 break;
1017
1018 case SMI_BASETYPE_UNSIGNED64:
1019 /* XXX */
1020 break;
1021
1022 /* case SMI_BASETYPE_INTEGER64: SMIng */
1023 /* case SMI_BASETYPE_FLOAT32: SMIng */
1024 /* case SMI_BASETYPE_FLOAT64: SMIng */
1025 /* case SMI_BASETYPE_FLOAT128: SMIng */
1026
1027 case SMI_BASETYPE_ENUM:
1028 case SMI_BASETYPE_BITS:
1029 case SMI_BASETYPE_UNKNOWN:
1030 ok = 1;
1031 break;
1032
1033 default:
1034 ok = 0;
1035 break;
1036 }
1037
1038 return ok;
1039 }
1040
1041 static int smi_check_range(SmiType *smiType, struct be *elem)
1042 {
1043 SmiRange *smiRange;
1044 int ok = 1;
1045
1046 for (smiRange = smiGetFirstRange(smiType);
1047 smiRange;
1048 smiRange = smiGetNextRange(smiRange)) {
1049
1050 ok = smi_check_a_range(smiType, smiRange, elem);
1051
1052 if (ok) {
1053 break;
1054 }
1055 }
1056
1057 if (ok) {
1058 SmiType *parentType;
1059 parentType = smiGetParentType(smiType);
1060 if (parentType) {
1061 ok = smi_check_range(parentType, elem);
1062 }
1063 }
1064
1065 return ok;
1066 }
1067
1068 static SmiNode *
1069 smi_print_variable(netdissect_options *ndo,
1070 struct be *elem, int *status)
1071 {
1072 unsigned int oid[128], oidlen;
1073 SmiNode *smiNode = NULL;
1074 unsigned int i;
1075
1076 *status = smi_decode_oid(ndo, elem, oid, sizeof(oid) / sizeof(unsigned int),
1077 &oidlen);
1078 if (*status < 0)
1079 return NULL;
1080 smiNode = smiGetNodeByOID(oidlen, oid);
1081 if (! smiNode) {
1082 *status = asn1_print(ndo, elem);
1083 return NULL;
1084 }
1085 if (ndo->ndo_vflag) {
1086 ND_PRINT((ndo, "%s::", smiGetNodeModule(smiNode)->name));
1087 }
1088 ND_PRINT((ndo, "%s", smiNode->name));
1089 if (smiNode->oidlen < oidlen) {
1090 for (i = smiNode->oidlen; i < oidlen; i++) {
1091 ND_PRINT((ndo, ".%u", oid[i]));
1092 }
1093 }
1094 *status = 0;
1095 return smiNode;
1096 }
1097
1098 static int
1099 smi_print_value(netdissect_options *ndo,
1100 SmiNode *smiNode, u_short pduid, struct be *elem)
1101 {
1102 unsigned int i, oid[128], oidlen;
1103 SmiType *smiType;
1104 SmiNamedNumber *nn;
1105 int done = 0;
1106
1107 if (! smiNode || ! (smiNode->nodekind
1108 & (SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN))) {
1109 return asn1_print(ndo, elem);
1110 }
1111
1112 if (elem->type == BE_NOSUCHOBJECT
1113 || elem->type == BE_NOSUCHINST
1114 || elem->type == BE_ENDOFMIBVIEW) {
1115 return asn1_print(ndo, elem);
1116 }
1117
1118 if (NOTIFY_CLASS(pduid) && smiNode->access < SMI_ACCESS_NOTIFY) {
1119 ND_PRINT((ndo, "[notNotifyable]"));
1120 }
1121
1122 if (READ_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_ONLY) {
1123 ND_PRINT((ndo, "[notReadable]"));
1124 }
1125
1126 if (WRITE_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_WRITE) {
1127 ND_PRINT((ndo, "[notWritable]"));
1128 }
1129
1130 if (RESPONSE_CLASS(pduid)
1131 && smiNode->access == SMI_ACCESS_NOT_ACCESSIBLE) {
1132 ND_PRINT((ndo, "[noAccess]"));
1133 }
1134
1135 smiType = smiGetNodeType(smiNode);
1136 if (! smiType) {
1137 return asn1_print(ndo, elem);
1138 }
1139
1140 if (! smi_check_type(smiType->basetype, elem->type)) {
1141 ND_PRINT((ndo, "[wrongType]"));
1142 }
1143
1144 if (! smi_check_range(smiType, elem)) {
1145 ND_PRINT((ndo, "[outOfRange]"));
1146 }
1147
1148 /* resolve bits to named bits */
1149
1150 /* check whether instance identifier is valid */
1151
1152 /* apply display hints (integer, octetstring) */
1153
1154 /* convert instance identifier to index type values */
1155
1156 switch (elem->type) {
1157 case BE_OID:
1158 if (smiType->basetype == SMI_BASETYPE_BITS) {
1159 /* print bit labels */
1160 } else {
1161 smi_decode_oid(ndo, elem, oid,
1162 sizeof(oid)/sizeof(unsigned int),
1163 &oidlen);
1164 smiNode = smiGetNodeByOID(oidlen, oid);
1165 if (smiNode) {
1166 if (ndo->ndo_vflag) {
1167 ND_PRINT((ndo, "%s::", smiGetNodeModule(smiNode)->name));
1168 }
1169 ND_PRINT((ndo, "%s", smiNode->name));
1170 if (smiNode->oidlen < oidlen) {
1171 for (i = smiNode->oidlen;
1172 i < oidlen; i++) {
1173 ND_PRINT((ndo, ".%u", oid[i]));
1174 }
1175 }
1176 done++;
1177 }
1178 }
1179 break;
1180
1181 case BE_INT:
1182 if (smiType->basetype == SMI_BASETYPE_ENUM) {
1183 for (nn = smiGetFirstNamedNumber(smiType);
1184 nn;
1185 nn = smiGetNextNamedNumber(nn)) {
1186 if (nn->value.value.integer32
1187 == elem->data.integer) {
1188 ND_PRINT((ndo, "%s", nn->name));
1189 ND_PRINT((ndo, "(%d)", elem->data.integer));
1190 done++;
1191 break;
1192 }
1193 }
1194 }
1195 break;
1196 }
1197
1198 if (! done) {
1199 return asn1_print(ndo, elem);
1200 }
1201 return 0;
1202 }
1203 #endif
1204
1205 /*
1206 * General SNMP header
1207 * SEQUENCE {
1208 * version INTEGER {version-1(0)},
1209 * community OCTET STRING,
1210 * data ANY -- PDUs
1211 * }
1212 * PDUs for all but Trap: (see rfc1157 from page 15 on)
1213 * SEQUENCE {
1214 * request-id INTEGER,
1215 * error-status INTEGER,
1216 * error-index INTEGER,
1217 * varbindlist SEQUENCE OF
1218 * SEQUENCE {
1219 * name ObjectName,
1220 * value ObjectValue
1221 * }
1222 * }
1223 * PDU for Trap:
1224 * SEQUENCE {
1225 * enterprise OBJECT IDENTIFIER,
1226 * agent-addr NetworkAddress,
1227 * generic-trap INTEGER,
1228 * specific-trap INTEGER,
1229 * time-stamp TimeTicks,
1230 * varbindlist SEQUENCE OF
1231 * SEQUENCE {
1232 * name ObjectName,
1233 * value ObjectValue
1234 * }
1235 * }
1236 */
1237
1238 /*
1239 * Decode SNMP varBind
1240 */
1241 static void
1242 varbind_print(netdissect_options *ndo,
1243 u_short pduid, const u_char *np, u_int length)
1244 {
1245 struct be elem;
1246 int count = 0, ind;
1247 #ifdef USE_LIBSMI
1248 SmiNode *smiNode = NULL;
1249 #endif
1250 int status;
1251
1252 /* Sequence of varBind */
1253 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1254 return;
1255 if (elem.type != BE_SEQ) {
1256 ND_PRINT((ndo, "[!SEQ of varbind]"));
1257 asn1_print(ndo, &elem);
1258 return;
1259 }
1260 if ((u_int)count < length)
1261 ND_PRINT((ndo, "[%d extra after SEQ of varbind]", length - count));
1262 /* descend */
1263 length = elem.asnlen;
1264 np = (const u_char *)elem.data.raw;
1265
1266 for (ind = 1; length > 0; ind++) {
1267 const u_char *vbend;
1268 u_int vblength;
1269
1270 ND_PRINT((ndo, " "));
1271
1272 /* Sequence */
1273 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1274 return;
1275 if (elem.type != BE_SEQ) {
1276 ND_PRINT((ndo, "[!varbind]"));
1277 asn1_print(ndo, &elem);
1278 return;
1279 }
1280 vbend = np + count;
1281 vblength = length - count;
1282 /* descend */
1283 length = elem.asnlen;
1284 np = (const u_char *)elem.data.raw;
1285
1286 /* objName (OID) */
1287 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1288 return;
1289 if (elem.type != BE_OID) {
1290 ND_PRINT((ndo, "[objName!=OID]"));
1291 asn1_print(ndo, &elem);
1292 return;
1293 }
1294 #ifdef USE_LIBSMI
1295 smiNode = smi_print_variable(ndo, &elem, &status);
1296 #else
1297 status = asn1_print(ndo, &elem);
1298 #endif
1299 if (status < 0)
1300 return;
1301 length -= count;
1302 np += count;
1303
1304 if (pduid != GETREQ && pduid != GETNEXTREQ
1305 && pduid != GETBULKREQ)
1306 ND_PRINT((ndo, "="));
1307
1308 /* objVal (ANY) */
1309 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1310 return;
1311 if (pduid == GETREQ || pduid == GETNEXTREQ
1312 || pduid == GETBULKREQ) {
1313 if (elem.type != BE_NULL) {
1314 ND_PRINT((ndo, "[objVal!=NULL]"));
1315 if (asn1_print(ndo, &elem) < 0)
1316 return;
1317 }
1318 } else {
1319 if (elem.type != BE_NULL) {
1320 #ifdef USE_LIBSMI
1321 status = smi_print_value(ndo, smiNode, pduid, &elem);
1322 #else
1323 status = asn1_print(ndo, &elem);
1324 #endif
1325 }
1326 if (status < 0)
1327 return;
1328 }
1329 length = vblength;
1330 np = vbend;
1331 }
1332 }
1333
1334 /*
1335 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
1336 * GetBulk, Inform, V2Trap, and Report
1337 */
1338 static void
1339 snmppdu_print(netdissect_options *ndo,
1340 u_short pduid, const u_char *np, u_int length)
1341 {
1342 struct be elem;
1343 int count = 0, error_status;
1344
1345 /* reqId (Integer) */
1346 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1347 return;
1348 if (elem.type != BE_INT) {
1349 ND_PRINT((ndo, "[reqId!=INT]"));
1350 asn1_print(ndo, &elem);
1351 return;
1352 }
1353 if (ndo->ndo_vflag)
1354 ND_PRINT((ndo, "R=%d ", elem.data.integer));
1355 length -= count;
1356 np += count;
1357
1358 /* errorStatus (Integer) */
1359 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1360 return;
1361 if (elem.type != BE_INT) {
1362 ND_PRINT((ndo, "[errorStatus!=INT]"));
1363 asn1_print(ndo, &elem);
1364 return;
1365 }
1366 error_status = 0;
1367 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1368 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1369 && elem.data.integer != 0) {
1370 char errbuf[20];
1371 ND_PRINT((ndo, "[errorStatus(%s)!=0]",
1372 DECODE_ErrorStatus(elem.data.integer)));
1373 } else if (pduid == GETBULKREQ) {
1374 ND_PRINT((ndo, " N=%d", elem.data.integer));
1375 } else if (elem.data.integer != 0) {
1376 char errbuf[20];
1377 ND_PRINT((ndo, " %s", DECODE_ErrorStatus(elem.data.integer)));
1378 error_status = elem.data.integer;
1379 }
1380 length -= count;
1381 np += count;
1382
1383 /* errorIndex (Integer) */
1384 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1385 return;
1386 if (elem.type != BE_INT) {
1387 ND_PRINT((ndo, "[errorIndex!=INT]"));
1388 asn1_print(ndo, &elem);
1389 return;
1390 }
1391 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1392 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1393 && elem.data.integer != 0)
1394 ND_PRINT((ndo, "[errorIndex(%d)!=0]", elem.data.integer));
1395 else if (pduid == GETBULKREQ)
1396 ND_PRINT((ndo, " M=%d", elem.data.integer));
1397 else if (elem.data.integer != 0) {
1398 if (!error_status)
1399 ND_PRINT((ndo, "[errorIndex(%d) w/o errorStatus]", elem.data.integer));
1400 else
1401 ND_PRINT((ndo, "@%d", elem.data.integer));
1402 } else if (error_status) {
1403 ND_PRINT((ndo, "[errorIndex==0]"));
1404 }
1405 length -= count;
1406 np += count;
1407
1408 varbind_print(ndo, pduid, np, length);
1409 return;
1410 }
1411
1412 /*
1413 * Decode SNMP Trap PDU
1414 */
1415 static void
1416 trappdu_print(netdissect_options *ndo,
1417 const u_char *np, u_int length)
1418 {
1419 struct be elem;
1420 int count = 0, generic;
1421
1422 ND_PRINT((ndo, " "));
1423
1424 /* enterprise (oid) */
1425 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1426 return;
1427 if (elem.type != BE_OID) {
1428 ND_PRINT((ndo, "[enterprise!=OID]"));
1429 asn1_print(ndo, &elem);
1430 return;
1431 }
1432 if (asn1_print(ndo, &elem) < 0)
1433 return;
1434 length -= count;
1435 np += count;
1436
1437 ND_PRINT((ndo, " "));
1438
1439 /* agent-addr (inetaddr) */
1440 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1441 return;
1442 if (elem.type != BE_INETADDR) {
1443 ND_PRINT((ndo, "[agent-addr!=INETADDR]"));
1444 asn1_print(ndo, &elem);
1445 return;
1446 }
1447 if (asn1_print(ndo, &elem) < 0)
1448 return;
1449 length -= count;
1450 np += count;
1451
1452 /* generic-trap (Integer) */
1453 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1454 return;
1455 if (elem.type != BE_INT) {
1456 ND_PRINT((ndo, "[generic-trap!=INT]"));
1457 asn1_print(ndo, &elem);
1458 return;
1459 }
1460 generic = elem.data.integer;
1461 {
1462 char buf[20];
1463 ND_PRINT((ndo, " %s", DECODE_GenericTrap(generic)));
1464 }
1465 length -= count;
1466 np += count;
1467
1468 /* specific-trap (Integer) */
1469 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1470 return;
1471 if (elem.type != BE_INT) {
1472 ND_PRINT((ndo, "[specific-trap!=INT]"));
1473 asn1_print(ndo, &elem);
1474 return;
1475 }
1476 if (generic != GT_ENTERPRISE) {
1477 if (elem.data.integer != 0)
1478 ND_PRINT((ndo, "[specific-trap(%d)!=0]", elem.data.integer));
1479 } else
1480 ND_PRINT((ndo, " s=%d", elem.data.integer));
1481 length -= count;
1482 np += count;
1483
1484 ND_PRINT((ndo, " "));
1485
1486 /* time-stamp (TimeTicks) */
1487 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1488 return;
1489 if (elem.type != BE_UNS) { /* XXX */
1490 ND_PRINT((ndo, "[time-stamp!=TIMETICKS]"));
1491 asn1_print(ndo, &elem);
1492 return;
1493 }
1494 if (asn1_print(ndo, &elem) < 0)
1495 return;
1496 length -= count;
1497 np += count;
1498
1499 varbind_print(ndo, TRAP, np, length);
1500 return;
1501 }
1502
1503 /*
1504 * Decode arbitrary SNMP PDUs.
1505 */
1506 static void
1507 pdu_print(netdissect_options *ndo,
1508 const u_char *np, u_int length, int version)
1509 {
1510 struct be pdu;
1511 int count = 0;
1512
1513 /* PDU (Context) */
1514 if ((count = asn1_parse(ndo, np, length, &pdu)) < 0)
1515 return;
1516 if (pdu.type != BE_PDU) {
1517 ND_PRINT((ndo, "[no PDU]"));
1518 return;
1519 }
1520 if ((u_int)count < length)
1521 ND_PRINT((ndo, "[%d extra after PDU]", length - count));
1522 if (ndo->ndo_vflag) {
1523 ND_PRINT((ndo, "{ "));
1524 }
1525 if (asn1_print(ndo, &pdu) < 0)
1526 return;
1527 ND_PRINT((ndo, " "));
1528 /* descend into PDU */
1529 length = pdu.asnlen;
1530 np = (const u_char *)pdu.data.raw;
1531
1532 if (version == SNMP_VERSION_1 &&
1533 (pdu.id == GETBULKREQ || pdu.id == INFORMREQ ||
1534 pdu.id == V2TRAP || pdu.id == REPORT)) {
1535 ND_PRINT((ndo, "[v2 PDU in v1 message]"));
1536 return;
1537 }
1538
1539 if (version == SNMP_VERSION_2 && pdu.id == TRAP) {
1540 ND_PRINT((ndo, "[v1 PDU in v2 message]"));
1541 return;
1542 }
1543
1544 switch (pdu.id) {
1545 case TRAP:
1546 trappdu_print(ndo, np, length);
1547 break;
1548 case GETREQ:
1549 case GETNEXTREQ:
1550 case GETRESP:
1551 case SETREQ:
1552 case GETBULKREQ:
1553 case INFORMREQ:
1554 case V2TRAP:
1555 case REPORT:
1556 snmppdu_print(ndo, pdu.id, np, length);
1557 break;
1558 }
1559
1560 if (ndo->ndo_vflag) {
1561 ND_PRINT((ndo, " } "));
1562 }
1563 }
1564
1565 /*
1566 * Decode a scoped SNMP PDU.
1567 */
1568 static void
1569 scopedpdu_print(netdissect_options *ndo,
1570 const u_char *np, u_int length, int version)
1571 {
1572 struct be elem;
1573 int count = 0;
1574
1575 /* Sequence */
1576 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1577 return;
1578 if (elem.type != BE_SEQ) {
1579 ND_PRINT((ndo, "[!scoped PDU]"));
1580 asn1_print(ndo, &elem);
1581 return;
1582 }
1583 length = elem.asnlen;
1584 np = (const u_char *)elem.data.raw;
1585
1586 /* contextEngineID (OCTET STRING) */
1587 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1588 return;
1589 if (elem.type != BE_STR) {
1590 ND_PRINT((ndo, "[contextEngineID!=STR]"));
1591 asn1_print(ndo, &elem);
1592 return;
1593 }
1594 length -= count;
1595 np += count;
1596
1597 ND_PRINT((ndo, "E="));
1598 if (asn1_print_octets(ndo, &elem) == -1)
1599 return;
1600 ND_PRINT((ndo, " "));
1601
1602 /* contextName (OCTET STRING) */
1603 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1604 return;
1605 if (elem.type != BE_STR) {
1606 ND_PRINT((ndo, "[contextName!=STR]"));
1607 asn1_print(ndo, &elem);
1608 return;
1609 }
1610 length -= count;
1611 np += count;
1612
1613 ND_PRINT((ndo, "C="));
1614 if (asn1_print_string(ndo, &elem) == -1)
1615 return;
1616 ND_PRINT((ndo, " "));
1617
1618 pdu_print(ndo, np, length, version);
1619 }
1620
1621 /*
1622 * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
1623 */
1624 static void
1625 community_print(netdissect_options *ndo,
1626 const u_char *np, u_int length, int version)
1627 {
1628 struct be elem;
1629 int count = 0;
1630
1631 /* Community (String) */
1632 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1633 return;
1634 if (elem.type != BE_STR) {
1635 ND_PRINT((ndo, "[comm!=STR]"));
1636 asn1_print(ndo, &elem);
1637 return;
1638 }
1639 /* default community */
1640 if (!(elem.asnlen == sizeof(DEF_COMMUNITY) - 1 &&
1641 strncmp((const char *)elem.data.str, DEF_COMMUNITY,
1642 sizeof(DEF_COMMUNITY) - 1) == 0)) {
1643 /* ! "public" */
1644 ND_PRINT((ndo, "C="));
1645 if (asn1_print_string(ndo, &elem) == -1)
1646 return;
1647 ND_PRINT((ndo, " "));
1648 }
1649 length -= count;
1650 np += count;
1651
1652 pdu_print(ndo, np, length, version);
1653 }
1654
1655 /*
1656 * Decode SNMPv3 User-based Security Message Header (SNMPv3)
1657 */
1658 static void
1659 usm_print(netdissect_options *ndo,
1660 const u_char *np, u_int length)
1661 {
1662 struct be elem;
1663 int count = 0;
1664
1665 /* Sequence */
1666 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1667 return;
1668 if (elem.type != BE_SEQ) {
1669 ND_PRINT((ndo, "[!usm]"));
1670 asn1_print(ndo, &elem);
1671 return;
1672 }
1673 length = elem.asnlen;
1674 np = (const u_char *)elem.data.raw;
1675
1676 /* msgAuthoritativeEngineID (OCTET STRING) */
1677 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1678 return;
1679 if (elem.type != BE_STR) {
1680 ND_PRINT((ndo, "[msgAuthoritativeEngineID!=STR]"));
1681 asn1_print(ndo, &elem);
1682 return;
1683 }
1684 length -= count;
1685 np += count;
1686
1687 /* msgAuthoritativeEngineBoots (INTEGER) */
1688 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1689 return;
1690 if (elem.type != BE_INT) {
1691 ND_PRINT((ndo, "[msgAuthoritativeEngineBoots!=INT]"));
1692 asn1_print(ndo, &elem);
1693 return;
1694 }
1695 if (ndo->ndo_vflag)
1696 ND_PRINT((ndo, "B=%d ", elem.data.integer));
1697 length -= count;
1698 np += count;
1699
1700 /* msgAuthoritativeEngineTime (INTEGER) */
1701 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1702 return;
1703 if (elem.type != BE_INT) {
1704 ND_PRINT((ndo, "[msgAuthoritativeEngineTime!=INT]"));
1705 asn1_print(ndo, &elem);
1706 return;
1707 }
1708 if (ndo->ndo_vflag)
1709 ND_PRINT((ndo, "T=%d ", elem.data.integer));
1710 length -= count;
1711 np += count;
1712
1713 /* msgUserName (OCTET STRING) */
1714 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1715 return;
1716 if (elem.type != BE_STR) {
1717 ND_PRINT((ndo, "[msgUserName!=STR]"));
1718 asn1_print(ndo, &elem);
1719 return;
1720 }
1721 length -= count;
1722 np += count;
1723
1724 ND_PRINT((ndo, "U="));
1725 if (asn1_print_string(ndo, &elem) == -1)
1726 return;
1727 ND_PRINT((ndo, " "));
1728
1729 /* msgAuthenticationParameters (OCTET STRING) */
1730 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1731 return;
1732 if (elem.type != BE_STR) {
1733 ND_PRINT((ndo, "[msgAuthenticationParameters!=STR]"));
1734 asn1_print(ndo, &elem);
1735 return;
1736 }
1737 length -= count;
1738 np += count;
1739
1740 /* msgPrivacyParameters (OCTET STRING) */
1741 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1742 return;
1743 if (elem.type != BE_STR) {
1744 ND_PRINT((ndo, "[msgPrivacyParameters!=STR]"));
1745 asn1_print(ndo, &elem);
1746 return;
1747 }
1748 length -= count;
1749 np += count;
1750
1751 if ((u_int)count < length)
1752 ND_PRINT((ndo, "[%d extra after usm SEQ]", length - count));
1753 }
1754
1755 /*
1756 * Decode SNMPv3 Message Header (SNMPv3)
1757 */
1758 static void
1759 v3msg_print(netdissect_options *ndo,
1760 const u_char *np, u_int length)
1761 {
1762 struct be elem;
1763 int count = 0;
1764 u_char flags;
1765 int model;
1766 const u_char *xnp = np;
1767 int xlength = length;
1768
1769 /* Sequence */
1770 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1771 return;
1772 if (elem.type != BE_SEQ) {
1773 ND_PRINT((ndo, "[!message]"));
1774 asn1_print(ndo, &elem);
1775 return;
1776 }
1777 length = elem.asnlen;
1778 np = (const u_char *)elem.data.raw;
1779
1780 if (ndo->ndo_vflag) {
1781 ND_PRINT((ndo, "{ "));
1782 }
1783
1784 /* msgID (INTEGER) */
1785 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1786 return;
1787 if (elem.type != BE_INT) {
1788 ND_PRINT((ndo, "[msgID!=INT]"));
1789 asn1_print(ndo, &elem);
1790 return;
1791 }
1792 length -= count;
1793 np += count;
1794
1795 /* msgMaxSize (INTEGER) */
1796 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1797 return;
1798 if (elem.type != BE_INT) {
1799 ND_PRINT((ndo, "[msgMaxSize!=INT]"));
1800 asn1_print(ndo, &elem);
1801 return;
1802 }
1803 length -= count;
1804 np += count;
1805
1806 /* msgFlags (OCTET STRING) */
1807 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1808 return;
1809 if (elem.type != BE_STR) {
1810 ND_PRINT((ndo, "[msgFlags!=STR]"));
1811 asn1_print(ndo, &elem);
1812 return;
1813 }
1814 if (elem.asnlen != 1) {
1815 ND_PRINT((ndo, "[msgFlags size %d]", elem.asnlen));
1816 return;
1817 }
1818 flags = elem.data.str[0];
1819 if (flags != 0x00 && flags != 0x01 && flags != 0x03
1820 && flags != 0x04 && flags != 0x05 && flags != 0x07) {
1821 ND_PRINT((ndo, "[msgFlags=0x%02X]", flags));
1822 return;
1823 }
1824 length -= count;
1825 np += count;
1826
1827 ND_PRINT((ndo, "F=%s%s%s ",
1828 flags & 0x01 ? "a" : "",
1829 flags & 0x02 ? "p" : "",
1830 flags & 0x04 ? "r" : ""));
1831
1832 /* msgSecurityModel (INTEGER) */
1833 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1834 return;
1835 if (elem.type != BE_INT) {
1836 ND_PRINT((ndo, "[msgSecurityModel!=INT]"));
1837 asn1_print(ndo, &elem);
1838 return;
1839 }
1840 model = elem.data.integer;
1841 length -= count;
1842 np += count;
1843
1844 if ((u_int)count < length)
1845 ND_PRINT((ndo, "[%d extra after message SEQ]", length - count));
1846
1847 if (ndo->ndo_vflag) {
1848 ND_PRINT((ndo, "} "));
1849 }
1850
1851 if (model == 3) {
1852 if (ndo->ndo_vflag) {
1853 ND_PRINT((ndo, "{ USM "));
1854 }
1855 } else {
1856 ND_PRINT((ndo, "[security model %d]", model));
1857 return;
1858 }
1859
1860 np = xnp + (np - xnp);
1861 length = xlength - (np - xnp);
1862
1863 /* msgSecurityParameters (OCTET STRING) */
1864 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1865 return;
1866 if (elem.type != BE_STR) {
1867 ND_PRINT((ndo, "[msgSecurityParameters!=STR]"));
1868 asn1_print(ndo, &elem);
1869 return;
1870 }
1871 length -= count;
1872 np += count;
1873
1874 if (model == 3) {
1875 usm_print(ndo, elem.data.str, elem.asnlen);
1876 if (ndo->ndo_vflag) {
1877 ND_PRINT((ndo, "} "));
1878 }
1879 }
1880
1881 if (ndo->ndo_vflag) {
1882 ND_PRINT((ndo, "{ ScopedPDU "));
1883 }
1884
1885 scopedpdu_print(ndo, np, length, 3);
1886
1887 if (ndo->ndo_vflag) {
1888 ND_PRINT((ndo, "} "));
1889 }
1890 }
1891
1892 /*
1893 * Decode SNMP header and pass on to PDU printing routines
1894 */
1895 void
1896 snmp_print(netdissect_options *ndo,
1897 const u_char *np, u_int length)
1898 {
1899 struct be elem;
1900 int count = 0;
1901 int version = 0;
1902
1903 ND_PRINT((ndo, " "));
1904
1905 /* initial Sequence */
1906 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1907 return;
1908 if (elem.type != BE_SEQ) {
1909 ND_PRINT((ndo, "[!init SEQ]"));
1910 asn1_print(ndo, &elem);
1911 return;
1912 }
1913 if ((u_int)count < length)
1914 ND_PRINT((ndo, "[%d extra after iSEQ]", length - count));
1915 /* descend */
1916 length = elem.asnlen;
1917 np = (const u_char *)elem.data.raw;
1918
1919 /* Version (INTEGER) */
1920 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1921 return;
1922 if (elem.type != BE_INT) {
1923 ND_PRINT((ndo, "[version!=INT]"));
1924 asn1_print(ndo, &elem);
1925 return;
1926 }
1927
1928 switch (elem.data.integer) {
1929 case SNMP_VERSION_1:
1930 case SNMP_VERSION_2:
1931 case SNMP_VERSION_3:
1932 if (ndo->ndo_vflag)
1933 ND_PRINT((ndo, "{ %s ", SnmpVersion[elem.data.integer]));
1934 break;
1935 default:
1936 ND_PRINT((ndo, "[version = %d]", elem.data.integer));
1937 return;
1938 }
1939 version = elem.data.integer;
1940 length -= count;
1941 np += count;
1942
1943 switch (version) {
1944 case SNMP_VERSION_1:
1945 case SNMP_VERSION_2:
1946 community_print(ndo, np, length, version);
1947 break;
1948 case SNMP_VERSION_3:
1949 v3msg_print(ndo, np, length);
1950 break;
1951 default:
1952 ND_PRINT((ndo, "[version = %d]", elem.data.integer));
1953 break;
1954 }
1955
1956 if (ndo->ndo_vflag) {
1957 ND_PRINT((ndo, "} "));
1958 }
1959 }