Merge commit 'crater/master'
[dragonfly.git] / contrib / tcpdump / print-snmp.c
blob728da6beb79ebca0bdeac14455d50173676bd2fa
1 /*
2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3 * John Robert LoVerso. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
37 * Support for SNMPv2c/SNMPv3 and the ability to link the module against
38 * the libsmi was added by J. Schoenwaelder, Copyright (c) 1999.
40 * This started out as a very simple program, but the incremental decoding
41 * (into the BE structure) complicated things.
43 # Los Alamos National Laboratory
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
59 #ifndef lint
60 static const char rcsid[] _U_ =
61 "@(#) $Header: /tcpdump/master/tcpdump/print-snmp.c,v 1.64 2005-05-06 07:56:53 guy Exp $ (LBL)";
62 #endif
64 #ifdef HAVE_CONFIG_H
65 #include "config.h"
66 #endif
68 #include <tcpdump-stdinc.h>
70 #include <stdio.h>
71 #include <string.h>
73 #ifdef HAVE_SMI_H
74 #include <smi.h>
75 #endif
77 #include "interface.h"
78 #include "addrtoname.h"
80 #undef OPAQUE /* defined in <wingdi.h> */
83 * Universal ASN.1 types
84 * (we only care about the tag values for those allowed in the Internet SMI)
86 const char *Universal[] = {
87 "U-0",
88 "Boolean",
89 "Integer",
90 #define INTEGER 2
91 "Bitstring",
92 "String",
93 #define STRING 4
94 "Null",
95 #define ASN_NULL 5
96 "ObjID",
97 #define OBJECTID 6
98 "ObjectDes",
99 "U-8","U-9","U-10","U-11", /* 8-11 */
100 "U-12","U-13","U-14","U-15", /* 12-15 */
101 "Sequence",
102 #define SEQUENCE 16
103 "Set"
107 * Application-wide ASN.1 types from the Internet SMI and their tags
109 const char *Application[] = {
110 "IpAddress",
111 #define IPADDR 0
112 "Counter",
113 #define COUNTER 1
114 "Gauge",
115 #define GAUGE 2
116 "TimeTicks",
117 #define TIMETICKS 3
118 "Opaque",
119 #define OPAQUE 4
120 "C-5",
121 "Counter64"
122 #define COUNTER64 6
126 * Context-specific ASN.1 types for the SNMP PDUs and their tags
128 const char *Context[] = {
129 "GetRequest",
130 #define GETREQ 0
131 "GetNextRequest",
132 #define GETNEXTREQ 1
133 "GetResponse",
134 #define GETRESP 2
135 "SetRequest",
136 #define SETREQ 3
137 "Trap",
138 #define TRAP 4
139 "GetBulk",
140 #define GETBULKREQ 5
141 "Inform",
142 #define INFORMREQ 6
143 "V2Trap",
144 #define V2TRAP 7
145 "Report"
146 #define REPORT 8
149 #define NOTIFY_CLASS(x) (x == TRAP || x == V2TRAP || x == INFORMREQ)
150 #define READ_CLASS(x) (x == GETREQ || x == GETNEXTREQ || x == GETBULKREQ)
151 #define WRITE_CLASS(x) (x == SETREQ)
152 #define RESPONSE_CLASS(x) (x == GETRESP)
153 #define INTERNAL_CLASS(x) (x == REPORT)
156 * Context-specific ASN.1 types for the SNMP Exceptions and their tags
158 const char *Exceptions[] = {
159 "noSuchObject",
160 #define NOSUCHOBJECT 0
161 "noSuchInstance",
162 #define NOSUCHINSTANCE 1
163 "endOfMibView",
164 #define ENDOFMIBVIEW 2
168 * Private ASN.1 types
169 * The Internet SMI does not specify any
171 const char *Private[] = {
172 "P-0"
176 * error-status values for any SNMP PDU
178 const char *ErrorStatus[] = {
179 "noError",
180 "tooBig",
181 "noSuchName",
182 "badValue",
183 "readOnly",
184 "genErr",
185 "noAccess",
186 "wrongType",
187 "wrongLength",
188 "wrongEncoding",
189 "wrongValue",
190 "noCreation",
191 "inconsistentValue",
192 "resourceUnavailable",
193 "commitFailed",
194 "undoFailed",
195 "authorizationError",
196 "notWritable",
197 "inconsistentName"
199 #define DECODE_ErrorStatus(e) \
200 ( e >= 0 && (size_t)e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
201 ? ErrorStatus[e] \
202 : (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf))
205 * generic-trap values in the SNMP Trap-PDU
207 const char *GenericTrap[] = {
208 "coldStart",
209 "warmStart",
210 "linkDown",
211 "linkUp",
212 "authenticationFailure",
213 "egpNeighborLoss",
214 "enterpriseSpecific"
215 #define GT_ENTERPRISE 6
217 #define DECODE_GenericTrap(t) \
218 ( t >= 0 && (size_t)t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
219 ? GenericTrap[t] \
220 : (snprintf(buf, sizeof(buf), "gt=%d", t), buf))
223 * ASN.1 type class table
224 * Ties together the preceding Universal, Application, Context, and Private
225 * type definitions.
227 #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
228 struct {
229 const char *name;
230 const char **Id;
231 int numIDs;
232 } Class[] = {
233 defineCLASS(Universal),
234 #define UNIVERSAL 0
235 defineCLASS(Application),
236 #define APPLICATION 1
237 defineCLASS(Context),
238 #define CONTEXT 2
239 defineCLASS(Private),
240 #define PRIVATE 3
241 defineCLASS(Exceptions),
242 #define EXCEPTIONS 4
246 * defined forms for ASN.1 types
248 const char *Form[] = {
249 "Primitive",
250 #define PRIMITIVE 0
251 "Constructed",
252 #define CONSTRUCTED 1
256 * A structure for the OID tree for the compiled-in MIB.
257 * This is stored as a general-order tree.
259 struct obj {
260 const char *desc; /* name of object */
261 u_char oid; /* sub-id following parent */
262 u_char type; /* object type (unused) */
263 struct obj *child, *next; /* child and next sibling pointers */
264 } *objp = NULL;
267 * Include the compiled in SNMP MIB. "mib.h" is produced by feeding
268 * RFC-1156 format files into "makemib". "mib.h" MUST define at least
269 * a value for `mibroot'.
271 * In particular, this is gross, as this is including initialized structures,
272 * and by right shouldn't be an "include" file.
274 #include "mib.h"
277 * This defines a list of OIDs which will be abbreviated on output.
278 * Currently, this includes the prefixes for the Internet MIB, the
279 * private enterprises tree, and the experimental tree.
281 struct obj_abrev {
282 const char *prefix; /* prefix for this abrev */
283 struct obj *node; /* pointer into object table */
284 const char *oid; /* ASN.1 encoded OID */
285 } obj_abrev_list[] = {
286 #ifndef NO_ABREV_MIB
287 /* .iso.org.dod.internet.mgmt.mib */
288 { "", &_mib_obj, "\53\6\1\2\1" },
289 #endif
290 #ifndef NO_ABREV_ENTER
291 /* .iso.org.dod.internet.private.enterprises */
292 { "E:", &_enterprises_obj, "\53\6\1\4\1" },
293 #endif
294 #ifndef NO_ABREV_EXPERI
295 /* .iso.org.dod.internet.experimental */
296 { "X:", &_experimental_obj, "\53\6\1\3" },
297 #endif
298 #ifndef NO_ABBREV_SNMPMODS
299 /* .iso.org.dod.internet.snmpV2.snmpModules */
300 { "S:", &_snmpModules_obj, "\53\6\1\6\3" },
301 #endif
302 { 0,0,0 }
306 * This is used in the OID print routine to walk down the object tree
307 * rooted at `mibroot'.
309 #define OBJ_PRINT(o, suppressdot) \
311 if (objp) { \
312 do { \
313 if ((o) == objp->oid) \
314 break; \
315 } while ((objp = objp->next) != NULL); \
317 if (objp) { \
318 printf(suppressdot?"%s":".%s", objp->desc); \
319 objp = objp->child; \
320 } else \
321 printf(suppressdot?"%u":".%u", (o)); \
325 * This is the definition for the Any-Data-Type storage used purely for
326 * temporary internal representation while decoding an ASN.1 data stream.
328 struct be {
329 u_int32_t asnlen;
330 union {
331 caddr_t raw;
332 int32_t integer;
333 u_int32_t uns;
334 const u_char *str;
335 struct {
336 u_int32_t high;
337 u_int32_t low;
338 } uns64;
339 } data;
340 u_short id;
341 u_char form, class; /* tag info */
342 u_char type;
343 #define BE_ANY 255
344 #define BE_NONE 0
345 #define BE_NULL 1
346 #define BE_OCTET 2
347 #define BE_OID 3
348 #define BE_INT 4
349 #define BE_UNS 5
350 #define BE_STR 6
351 #define BE_SEQ 7
352 #define BE_INETADDR 8
353 #define BE_PDU 9
354 #define BE_UNS64 10
355 #define BE_NOSUCHOBJECT 128
356 #define BE_NOSUCHINST 129
357 #define BE_ENDOFMIBVIEW 130
361 * SNMP versions recognized by this module
363 const char *SnmpVersion[] = {
364 "SNMPv1",
365 #define SNMP_VERSION_1 0
366 "SNMPv2c",
367 #define SNMP_VERSION_2 1
368 "SNMPv2u",
369 #define SNMP_VERSION_2U 2
370 "SNMPv3"
371 #define SNMP_VERSION_3 3
375 * Defaults for SNMP PDU components
377 #define DEF_COMMUNITY "public"
380 * constants for ASN.1 decoding
382 #define OIDMUX 40
383 #define ASNLEN_INETADDR 4
384 #define ASN_SHIFT7 7
385 #define ASN_SHIFT8 8
386 #define ASN_BIT8 0x80
387 #define ASN_LONGLEN 0x80
389 #define ASN_ID_BITS 0x1f
390 #define ASN_FORM_BITS 0x20
391 #define ASN_FORM_SHIFT 5
392 #define ASN_CLASS_BITS 0xc0
393 #define ASN_CLASS_SHIFT 6
395 #define ASN_ID_EXT 0x1f /* extension ID in tag field */
398 * This decodes the next ASN.1 object in the stream pointed to by "p"
399 * (and of real-length "len") and stores the intermediate data in the
400 * provided BE object.
402 * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
403 * O/w, this returns the number of bytes parsed from "p".
405 static int
406 asn1_parse(register const u_char *p, u_int len, struct be *elem)
408 u_char form, class, id;
409 int i, hdr;
411 elem->asnlen = 0;
412 elem->type = BE_ANY;
413 if (len < 1) {
414 fputs("[nothing to parse]", stdout);
415 return -1;
417 TCHECK(*p);
420 * it would be nice to use a bit field, but you can't depend on them.
421 * +---+---+---+---+---+---+---+---+
422 * + class |frm| id |
423 * +---+---+---+---+---+---+---+---+
424 * 7 6 5 4 3 2 1 0
426 id = *p & ASN_ID_BITS; /* lower 5 bits, range 00-1f */
427 #ifdef notdef
428 form = (*p & 0xe0) >> 5; /* move upper 3 bits to lower 3 */
429 class = form >> 1; /* bits 7&6 -> bits 1&0, range 0-3 */
430 form &= 0x1; /* bit 5 -> bit 0, range 0-1 */
431 #else
432 form = (u_char)(*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
433 class = (u_char)(*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
434 #endif
435 elem->form = form;
436 elem->class = class;
437 elem->id = id;
438 p++; len--; hdr = 1;
439 /* extended tag field */
440 if (id == ASN_ID_EXT) {
442 * The ID follows, as a sequence of octets with the
443 * 8th bit set and the remaining 7 bits being
444 * the next 7 bits of the value, terminated with
445 * an octet with the 8th bit not set.
447 * First, assemble all the octets with the 8th
448 * bit set. XXX - this doesn't handle a value
449 * that won't fit in 32 bits.
451 for (id = 0; *p & ASN_BIT8; len--, hdr++, p++) {
452 if (len < 1) {
453 fputs("[Xtagfield?]", stdout);
454 return -1;
456 TCHECK(*p);
457 id = (id << 7) | (*p & ~ASN_BIT8);
459 if (len < 1) {
460 fputs("[Xtagfield?]", stdout);
461 return -1;
463 TCHECK(*p);
464 elem->id = id = (id << 7) | *p;
465 --len;
466 ++hdr;
467 ++p;
469 if (len < 1) {
470 fputs("[no asnlen]", stdout);
471 return -1;
473 TCHECK(*p);
474 elem->asnlen = *p;
475 p++; len--; hdr++;
476 if (elem->asnlen & ASN_BIT8) {
477 u_int32_t noct = elem->asnlen % ASN_BIT8;
478 elem->asnlen = 0;
479 if (len < noct) {
480 printf("[asnlen? %d<%d]", len, noct);
481 return -1;
483 TCHECK2(*p, noct);
484 for (; noct-- > 0; len--, hdr++)
485 elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++;
487 if (len < elem->asnlen) {
488 printf("[len%d<asnlen%u]", len, elem->asnlen);
489 return -1;
491 if (form >= sizeof(Form)/sizeof(Form[0])) {
492 printf("[form?%d]", form);
493 return -1;
495 if (class >= sizeof(Class)/sizeof(Class[0])) {
496 printf("[class?%c/%d]", *Form[form], class);
497 return -1;
499 if ((int)id >= Class[class].numIDs) {
500 printf("[id?%c/%s/%d]", *Form[form], Class[class].name, id);
501 return -1;
504 switch (form) {
505 case PRIMITIVE:
506 switch (class) {
507 case UNIVERSAL:
508 switch (id) {
509 case STRING:
510 elem->type = BE_STR;
511 elem->data.str = p;
512 break;
514 case INTEGER: {
515 register int32_t data;
516 elem->type = BE_INT;
517 data = 0;
519 TCHECK2(*p, elem->asnlen);
520 if (*p & ASN_BIT8) /* negative */
521 data = -1;
522 for (i = elem->asnlen; i-- > 0; p++)
523 data = (data << ASN_SHIFT8) | *p;
524 elem->data.integer = data;
525 break;
528 case OBJECTID:
529 elem->type = BE_OID;
530 elem->data.raw = (caddr_t)p;
531 break;
533 case ASN_NULL:
534 elem->type = BE_NULL;
535 elem->data.raw = NULL;
536 break;
538 default:
539 elem->type = BE_OCTET;
540 elem->data.raw = (caddr_t)p;
541 printf("[P/U/%s]",
542 Class[class].Id[id]);
543 break;
545 break;
547 case APPLICATION:
548 switch (id) {
549 case IPADDR:
550 elem->type = BE_INETADDR;
551 elem->data.raw = (caddr_t)p;
552 break;
554 case COUNTER:
555 case GAUGE:
556 case TIMETICKS: {
557 register u_int32_t data;
558 TCHECK2(*p, elem->asnlen);
559 elem->type = BE_UNS;
560 data = 0;
561 for (i = elem->asnlen; i-- > 0; p++)
562 data = (data << 8) + *p;
563 elem->data.uns = data;
564 break;
567 case COUNTER64: {
568 register u_int32_t high, low;
569 TCHECK2(*p, elem->asnlen);
570 elem->type = BE_UNS64;
571 high = 0, low = 0;
572 for (i = elem->asnlen; i-- > 0; p++) {
573 high = (high << 8) |
574 ((low & 0xFF000000) >> 24);
575 low = (low << 8) | *p;
577 elem->data.uns64.high = high;
578 elem->data.uns64.low = low;
579 break;
582 default:
583 elem->type = BE_OCTET;
584 elem->data.raw = (caddr_t)p;
585 printf("[P/A/%s]",
586 Class[class].Id[id]);
587 break;
589 break;
591 case CONTEXT:
592 switch (id) {
593 case NOSUCHOBJECT:
594 elem->type = BE_NOSUCHOBJECT;
595 elem->data.raw = NULL;
596 break;
598 case NOSUCHINSTANCE:
599 elem->type = BE_NOSUCHINST;
600 elem->data.raw = NULL;
601 break;
603 case ENDOFMIBVIEW:
604 elem->type = BE_ENDOFMIBVIEW;
605 elem->data.raw = NULL;
606 break;
608 break;
610 default:
611 printf("[P/%s/%s]",
612 Class[class].name, Class[class].Id[id]);
613 TCHECK2(*p, elem->asnlen);
614 elem->type = BE_OCTET;
615 elem->data.raw = (caddr_t)p;
616 break;
618 break;
620 case CONSTRUCTED:
621 switch (class) {
622 case UNIVERSAL:
623 switch (id) {
624 case SEQUENCE:
625 elem->type = BE_SEQ;
626 elem->data.raw = (caddr_t)p;
627 break;
629 default:
630 elem->type = BE_OCTET;
631 elem->data.raw = (caddr_t)p;
632 printf("C/U/%s", Class[class].Id[id]);
633 break;
635 break;
637 case CONTEXT:
638 elem->type = BE_PDU;
639 elem->data.raw = (caddr_t)p;
640 break;
642 default:
643 elem->type = BE_OCTET;
644 elem->data.raw = (caddr_t)p;
645 printf("C/%s/%s",
646 Class[class].name, Class[class].Id[id]);
647 break;
649 break;
651 p += elem->asnlen;
652 len -= elem->asnlen;
653 return elem->asnlen + hdr;
655 trunc:
656 fputs("[|snmp]", stdout);
657 return -1;
661 * Display the ASN.1 object represented by the BE object.
662 * This used to be an integral part of asn1_parse() before the intermediate
663 * BE form was added.
665 static int
666 asn1_print(struct be *elem)
668 u_char *p = (u_char *)elem->data.raw;
669 u_int32_t asnlen = elem->asnlen;
670 u_int32_t i;
672 switch (elem->type) {
674 case BE_OCTET:
675 TCHECK2(*p, asnlen);
676 for (i = asnlen; i-- > 0; p++)
677 printf("_%.2x", *p);
678 break;
680 case BE_NULL:
681 break;
683 case BE_OID: {
684 int o = 0, first = -1, i = asnlen;
686 if (!sflag && !nflag && asnlen > 2) {
687 struct obj_abrev *a = &obj_abrev_list[0];
688 size_t a_len = strlen(a->oid);
689 for (; a->node; a++) {
690 TCHECK2(*p, a_len);
691 if (memcmp(a->oid, (char *)p, a_len) == 0) {
692 objp = a->node->child;
693 i -= strlen(a->oid);
694 p += strlen(a->oid);
695 fputs(a->prefix, stdout);
696 first = 1;
697 break;
702 for (; !sflag && i-- > 0; p++) {
703 TCHECK(*p);
704 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
705 if (*p & ASN_LONGLEN)
706 continue;
709 * first subitem encodes two items with 1st*OIDMUX+2nd
710 * (see X.690:1997 clause 8.19 for the details)
712 if (first < 0) {
713 int s;
714 if (!nflag)
715 objp = mibroot;
716 first = 0;
717 s = o / OIDMUX;
718 if (s > 2) s = 2;
719 OBJ_PRINT(s, first);
720 o -= s * OIDMUX;
722 OBJ_PRINT(o, first);
723 if (--first < 0)
724 first = 0;
725 o = 0;
727 break;
730 case BE_INT:
731 printf("%d", elem->data.integer);
732 break;
734 case BE_UNS:
735 printf("%u", elem->data.uns);
736 break;
738 case BE_UNS64: { /* idea borrowed from by Marshall Rose */
739 double d;
740 int j, carry;
741 char *cpf, *cpl, last[6], first[30];
742 if (elem->data.uns64.high == 0) {
743 printf("%u", elem->data.uns64.low);
744 break;
746 d = elem->data.uns64.high * 4294967296.0; /* 2^32 */
747 if (elem->data.uns64.high <= 0x1fffff) {
748 d += elem->data.uns64.low;
749 #if 0 /*is looks illegal, but what is the intention?*/
750 printf("%.f", d);
751 #else
752 printf("%f", d);
753 #endif
754 break;
756 d += (elem->data.uns64.low & 0xfffff000);
757 #if 0 /*is looks illegal, but what is the intention?*/
758 snprintf(first, sizeof(first), "%.f", d);
759 #else
760 snprintf(first, sizeof(first), "%f", d);
761 #endif
762 snprintf(last, sizeof(last), "%5.5d",
763 elem->data.uns64.low & 0xfff);
764 for (carry = 0, cpf = first+strlen(first)-1, cpl = last+4;
765 cpl >= last;
766 cpf--, cpl--) {
767 j = carry + (*cpf - '0') + (*cpl - '0');
768 if (j > 9) {
769 j -= 10;
770 carry = 1;
771 } else {
772 carry = 0;
774 *cpf = j + '0';
776 fputs(first, stdout);
777 break;
780 case BE_STR: {
781 register int printable = 1, first = 1;
782 const u_char *p = elem->data.str;
783 TCHECK2(*p, asnlen);
784 for (i = asnlen; printable && i-- > 0; p++)
785 printable = isprint(*p) || isspace(*p);
786 p = elem->data.str;
787 if (printable) {
788 putchar('"');
789 if (fn_printn(p, asnlen, snapend)) {
790 putchar('"');
791 goto trunc;
793 putchar('"');
794 } else
795 for (i = asnlen; i-- > 0; p++) {
796 printf(first ? "%.2x" : "_%.2x", *p);
797 first = 0;
799 break;
802 case BE_SEQ:
803 printf("Seq(%u)", elem->asnlen);
804 break;
806 case BE_INETADDR:
807 if (asnlen != ASNLEN_INETADDR)
808 printf("[inetaddr len!=%d]", ASNLEN_INETADDR);
809 TCHECK2(*p, asnlen);
810 for (i = asnlen; i-- != 0; p++) {
811 printf((i == asnlen-1) ? "%u" : ".%u", *p);
813 break;
815 case BE_NOSUCHOBJECT:
816 case BE_NOSUCHINST:
817 case BE_ENDOFMIBVIEW:
818 printf("[%s]", Class[EXCEPTIONS].Id[elem->id]);
819 break;
821 case BE_PDU:
822 printf("%s(%u)",
823 Class[CONTEXT].Id[elem->id], elem->asnlen);
824 break;
826 case BE_ANY:
827 fputs("[BE_ANY!?]", stdout);
828 break;
830 default:
831 fputs("[be!?]", stdout);
832 break;
834 return 0;
836 trunc:
837 fputs("[|snmp]", stdout);
838 return -1;
841 #ifdef notdef
843 * This is a brute force ASN.1 printer: recurses to dump an entire structure.
844 * This will work for any ASN.1 stream, not just an SNMP PDU.
846 * By adding newlines and spaces at the correct places, this would print in
847 * Rose-Normal-Form.
849 * This is not currently used.
851 static void
852 asn1_decode(u_char *p, u_int length)
854 struct be elem;
855 int i = 0;
857 while (i >= 0 && length > 0) {
858 i = asn1_parse(p, length, &elem);
859 if (i >= 0) {
860 fputs(" ", stdout);
861 if (asn1_print(&elem) < 0)
862 return;
863 if (elem.type == BE_SEQ || elem.type == BE_PDU) {
864 fputs(" {", stdout);
865 asn1_decode(elem.data.raw, elem.asnlen);
866 fputs(" }", stdout);
868 length -= i;
869 p += i;
873 #endif
875 #ifdef LIBSMI
877 struct smi2be {
878 SmiBasetype basetype;
879 int be;
882 static struct smi2be smi2betab[] = {
883 { SMI_BASETYPE_INTEGER32, BE_INT },
884 { SMI_BASETYPE_OCTETSTRING, BE_STR },
885 { SMI_BASETYPE_OCTETSTRING, BE_INETADDR },
886 { SMI_BASETYPE_OBJECTIDENTIFIER, BE_OID },
887 { SMI_BASETYPE_UNSIGNED32, BE_UNS },
888 { SMI_BASETYPE_INTEGER64, BE_NONE },
889 { SMI_BASETYPE_UNSIGNED64, BE_UNS64 },
890 { SMI_BASETYPE_FLOAT32, BE_NONE },
891 { SMI_BASETYPE_FLOAT64, BE_NONE },
892 { SMI_BASETYPE_FLOAT128, BE_NONE },
893 { SMI_BASETYPE_ENUM, BE_INT },
894 { SMI_BASETYPE_BITS, BE_STR },
895 { SMI_BASETYPE_UNKNOWN, BE_NONE }
898 static int
899 smi_decode_oid(struct be *elem, unsigned int *oid,
900 unsigned int oidsize, unsigned int *oidlen)
902 u_char *p = (u_char *)elem->data.raw;
903 u_int32_t asnlen = elem->asnlen;
904 int o = 0, first = -1, i = asnlen;
906 for (*oidlen = 0; sflag && i-- > 0; p++) {
907 TCHECK(*p);
908 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
909 if (*p & ASN_LONGLEN)
910 continue;
913 * first subitem encodes two items with 1st*OIDMUX+2nd
914 * (see X.690:1997 clause 8.19 for the details)
916 if (first < 0) {
917 first = 0;
918 if (*oidlen < oidsize) {
919 oid[*oidlen] = o / OIDMUX;
920 if (oid[*oidlen] > 2) oid[*oidlen] = 2;
922 o -= oid[*oidlen] * OIDMUX;
923 if (*oidlen < oidsize) (*oidlen)++;
925 if (*oidlen < oidsize) {
926 oid[(*oidlen)++] = o;
928 o = 0;
930 return 0;
932 trunc:
933 fputs("[|snmp]", stdout);
934 return -1;
937 static int smi_check_type(SmiBasetype basetype, int be)
939 int i;
941 for (i = 0; smi2betab[i].basetype != SMI_BASETYPE_UNKNOWN; i++) {
942 if (smi2betab[i].basetype == basetype && smi2betab[i].be == be) {
943 return 1;
947 return 0;
950 static int smi_check_a_range(SmiType *smiType, SmiRange *smiRange,
951 struct be *elem)
953 int ok = 1;
955 switch (smiType->basetype) {
956 case SMI_BASETYPE_OBJECTIDENTIFIER:
957 case SMI_BASETYPE_OCTETSTRING:
958 if (smiRange->minValue.value.unsigned32
959 == smiRange->maxValue.value.unsigned32) {
960 ok = (elem->asnlen == smiRange->minValue.value.unsigned32);
961 } else {
962 ok = (elem->asnlen >= smiRange->minValue.value.unsigned32
963 && elem->asnlen <= smiRange->maxValue.value.unsigned32);
965 break;
967 case SMI_BASETYPE_INTEGER32:
968 ok = (elem->data.integer >= smiRange->minValue.value.integer32
969 && elem->data.integer <= smiRange->maxValue.value.integer32);
970 break;
972 case SMI_BASETYPE_UNSIGNED32:
973 ok = (elem->data.uns >= smiRange->minValue.value.unsigned32
974 && elem->data.uns <= smiRange->maxValue.value.unsigned32);
975 break;
977 case SMI_BASETYPE_UNSIGNED64:
978 /* XXX */
979 break;
981 /* case SMI_BASETYPE_INTEGER64: SMIng */
982 /* case SMI_BASETYPE_FLOAT32: SMIng */
983 /* case SMI_BASETYPE_FLOAT64: SMIng */
984 /* case SMI_BASETYPE_FLOAT128: SMIng */
986 case SMI_BASETYPE_ENUM:
987 case SMI_BASETYPE_BITS:
988 case SMI_BASETYPE_UNKNOWN:
989 ok = 1;
990 break;
992 default:
993 ok = 0;
994 break;
997 return ok;
1000 static int smi_check_range(SmiType *smiType, struct be *elem)
1002 SmiRange *smiRange;
1003 int ok = 1;
1005 for (smiRange = smiGetFirstRange(smiType);
1006 smiRange;
1007 smiRange = smiGetNextRange(smiRange)) {
1009 ok = smi_check_a_range(smiType, smiRange, elem);
1011 if (ok) {
1012 break;
1016 if (ok) {
1017 SmiType *parentType;
1018 parentType = smiGetParentType(smiType);
1019 if (parentType) {
1020 ok = smi_check_range(parentType, elem);
1024 return ok;
1027 static SmiNode *smi_print_variable(struct be *elem, int *status)
1029 unsigned int oid[128], oidlen;
1030 SmiNode *smiNode = NULL;
1031 unsigned int i;
1033 *status = smi_decode_oid(elem, oid, sizeof(oid)/sizeof(unsigned int),
1034 &oidlen);
1035 if (*status < 0)
1036 return NULL;
1037 smiNode = smiGetNodeByOID(oidlen, oid);
1038 if (! smiNode) {
1039 *status = asn1_print(elem);
1040 return NULL;
1042 if (vflag) {
1043 fputs(smiGetNodeModule(smiNode)->name, stdout);
1044 fputs("::", stdout);
1046 fputs(smiNode->name, stdout);
1047 if (smiNode->oidlen < oidlen) {
1048 for (i = smiNode->oidlen; i < oidlen; i++) {
1049 printf(".%u", oid[i]);
1052 *status = 0;
1053 return smiNode;
1056 static int
1057 smi_print_value(SmiNode *smiNode, u_char pduid, struct be *elem)
1059 unsigned int i, oid[128], oidlen;
1060 SmiType *smiType;
1061 SmiNamedNumber *nn;
1062 int done = 0;
1064 if (! smiNode || ! (smiNode->nodekind
1065 & (SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN))) {
1066 return asn1_print(elem);
1069 if (elem->type == BE_NOSUCHOBJECT
1070 || elem->type == BE_NOSUCHINST
1071 || elem->type == BE_ENDOFMIBVIEW) {
1072 return asn1_print(elem);
1075 if (NOTIFY_CLASS(pduid) && smiNode->access < SMI_ACCESS_NOTIFY) {
1076 fputs("[notNotifyable]", stdout);
1079 if (READ_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_ONLY) {
1080 fputs("[notReadable]", stdout);
1083 if (WRITE_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_WRITE) {
1084 fputs("[notWritable]", stdout);
1087 if (RESPONSE_CLASS(pduid)
1088 && smiNode->access == SMI_ACCESS_NOT_ACCESSIBLE) {
1089 fputs("[noAccess]", stdout);
1092 smiType = smiGetNodeType(smiNode);
1093 if (! smiType) {
1094 return asn1_print(elem);
1097 if (! smi_check_type(smiType->basetype, elem->type)) {
1098 fputs("[wrongType]", stdout);
1101 if (! smi_check_range(smiType, elem)) {
1102 fputs("[outOfRange]", stdout);
1105 /* resolve bits to named bits */
1107 /* check whether instance identifier is valid */
1109 /* apply display hints (integer, octetstring) */
1111 /* convert instance identifier to index type values */
1113 switch (elem->type) {
1114 case BE_OID:
1115 if (smiType->basetype == SMI_BASETYPE_BITS) {
1116 /* print bit labels */
1117 } else {
1118 smi_decode_oid(elem, oid,
1119 sizeof(oid)/sizeof(unsigned int),
1120 &oidlen);
1121 smiNode = smiGetNodeByOID(oidlen, oid);
1122 if (smiNode) {
1123 if (vflag) {
1124 fputs(smiGetNodeModule(smiNode)->name, stdout);
1125 fputs("::", stdout);
1127 fputs(smiNode->name, stdout);
1128 if (smiNode->oidlen < oidlen) {
1129 for (i = smiNode->oidlen;
1130 i < oidlen; i++) {
1131 printf(".%u", oid[i]);
1134 done++;
1137 break;
1139 case BE_INT:
1140 if (smiType->basetype == SMI_BASETYPE_ENUM) {
1141 for (nn = smiGetFirstNamedNumber(smiType);
1143 nn = smiGetNextNamedNumber(nn)) {
1144 if (nn->value.value.integer32
1145 == elem->data.integer) {
1146 fputs(nn->name, stdout);
1147 printf("(%d)", elem->data.integer);
1148 done++;
1149 break;
1153 break;
1156 if (! done) {
1157 return asn1_print(elem);
1159 return 0;
1161 #endif
1164 * General SNMP header
1165 * SEQUENCE {
1166 * version INTEGER {version-1(0)},
1167 * community OCTET STRING,
1168 * data ANY -- PDUs
1170 * PDUs for all but Trap: (see rfc1157 from page 15 on)
1171 * SEQUENCE {
1172 * request-id INTEGER,
1173 * error-status INTEGER,
1174 * error-index INTEGER,
1175 * varbindlist SEQUENCE OF
1176 * SEQUENCE {
1177 * name ObjectName,
1178 * value ObjectValue
1181 * PDU for Trap:
1182 * SEQUENCE {
1183 * enterprise OBJECT IDENTIFIER,
1184 * agent-addr NetworkAddress,
1185 * generic-trap INTEGER,
1186 * specific-trap INTEGER,
1187 * time-stamp TimeTicks,
1188 * varbindlist SEQUENCE OF
1189 * SEQUENCE {
1190 * name ObjectName,
1191 * value ObjectValue
1197 * Decode SNMP varBind
1199 static void
1200 varbind_print(u_char pduid, const u_char *np, u_int length)
1202 struct be elem;
1203 int count = 0, ind;
1204 #ifdef LIBSMI
1205 SmiNode *smiNode = NULL;
1206 #endif
1207 int status;
1209 /* Sequence of varBind */
1210 if ((count = asn1_parse(np, length, &elem)) < 0)
1211 return;
1212 if (elem.type != BE_SEQ) {
1213 fputs("[!SEQ of varbind]", stdout);
1214 asn1_print(&elem);
1215 return;
1217 if ((u_int)count < length)
1218 printf("[%d extra after SEQ of varbind]", length - count);
1219 /* descend */
1220 length = elem.asnlen;
1221 np = (u_char *)elem.data.raw;
1223 for (ind = 1; length > 0; ind++) {
1224 const u_char *vbend;
1225 u_int vblength;
1227 fputs(" ", stdout);
1229 /* Sequence */
1230 if ((count = asn1_parse(np, length, &elem)) < 0)
1231 return;
1232 if (elem.type != BE_SEQ) {
1233 fputs("[!varbind]", stdout);
1234 asn1_print(&elem);
1235 return;
1237 vbend = np + count;
1238 vblength = length - count;
1239 /* descend */
1240 length = elem.asnlen;
1241 np = (u_char *)elem.data.raw;
1243 /* objName (OID) */
1244 if ((count = asn1_parse(np, length, &elem)) < 0)
1245 return;
1246 if (elem.type != BE_OID) {
1247 fputs("[objName!=OID]", stdout);
1248 asn1_print(&elem);
1249 return;
1251 #ifdef LIBSMI
1252 smiNode = smi_print_variable(&elem, &status);
1253 #else
1254 status = asn1_print(&elem);
1255 #endif
1256 if (status < 0)
1257 return;
1258 length -= count;
1259 np += count;
1261 if (pduid != GETREQ && pduid != GETNEXTREQ
1262 && pduid != GETBULKREQ)
1263 fputs("=", stdout);
1265 /* objVal (ANY) */
1266 if ((count = asn1_parse(np, length, &elem)) < 0)
1267 return;
1268 if (pduid == GETREQ || pduid == GETNEXTREQ
1269 || pduid == GETBULKREQ) {
1270 if (elem.type != BE_NULL) {
1271 fputs("[objVal!=NULL]", stdout);
1272 if (asn1_print(&elem) < 0)
1273 return;
1275 } else {
1276 if (elem.type != BE_NULL) {
1277 #ifdef LIBSMI
1278 status = smi_print_value(smiNode, pduid, &elem);
1279 #else
1280 status = asn1_print(&elem);
1281 #endif
1283 if (status < 0)
1284 return;
1286 length = vblength;
1287 np = vbend;
1292 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
1293 * GetBulk, Inform, V2Trap, and Report
1295 static void
1296 snmppdu_print(u_short pduid, const u_char *np, u_int length)
1298 struct be elem;
1299 int count = 0, error;
1301 /* reqId (Integer) */
1302 if ((count = asn1_parse(np, length, &elem)) < 0)
1303 return;
1304 if (elem.type != BE_INT) {
1305 fputs("[reqId!=INT]", stdout);
1306 asn1_print(&elem);
1307 return;
1309 if (vflag)
1310 printf("R=%d ", elem.data.integer);
1311 length -= count;
1312 np += count;
1314 /* errorStatus (Integer) */
1315 if ((count = asn1_parse(np, length, &elem)) < 0)
1316 return;
1317 if (elem.type != BE_INT) {
1318 fputs("[errorStatus!=INT]", stdout);
1319 asn1_print(&elem);
1320 return;
1322 error = 0;
1323 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1324 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1325 && elem.data.integer != 0) {
1326 char errbuf[20];
1327 printf("[errorStatus(%s)!=0]",
1328 DECODE_ErrorStatus(elem.data.integer));
1329 } else if (pduid == GETBULKREQ) {
1330 printf(" N=%d", elem.data.integer);
1331 } else if (elem.data.integer != 0) {
1332 char errbuf[20];
1333 printf(" %s", DECODE_ErrorStatus(elem.data.integer));
1334 error = elem.data.integer;
1336 length -= count;
1337 np += count;
1339 /* errorIndex (Integer) */
1340 if ((count = asn1_parse(np, length, &elem)) < 0)
1341 return;
1342 if (elem.type != BE_INT) {
1343 fputs("[errorIndex!=INT]", stdout);
1344 asn1_print(&elem);
1345 return;
1347 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1348 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1349 && elem.data.integer != 0)
1350 printf("[errorIndex(%d)!=0]", elem.data.integer);
1351 else if (pduid == GETBULKREQ)
1352 printf(" M=%d", elem.data.integer);
1353 else if (elem.data.integer != 0) {
1354 if (!error)
1355 printf("[errorIndex(%d) w/o errorStatus]",
1356 elem.data.integer);
1357 else {
1358 printf("@%d", elem.data.integer);
1359 error = elem.data.integer;
1361 } else if (error) {
1362 fputs("[errorIndex==0]", stdout);
1363 error = 0;
1365 length -= count;
1366 np += count;
1368 varbind_print(pduid, np, length);
1369 return;
1373 * Decode SNMP Trap PDU
1375 static void
1376 trappdu_print(const u_char *np, u_int length)
1378 struct be elem;
1379 int count = 0, generic;
1381 putchar(' ');
1383 /* enterprise (oid) */
1384 if ((count = asn1_parse(np, length, &elem)) < 0)
1385 return;
1386 if (elem.type != BE_OID) {
1387 fputs("[enterprise!=OID]", stdout);
1388 asn1_print(&elem);
1389 return;
1391 if (asn1_print(&elem) < 0)
1392 return;
1393 length -= count;
1394 np += count;
1396 putchar(' ');
1398 /* agent-addr (inetaddr) */
1399 if ((count = asn1_parse(np, length, &elem)) < 0)
1400 return;
1401 if (elem.type != BE_INETADDR) {
1402 fputs("[agent-addr!=INETADDR]", stdout);
1403 asn1_print(&elem);
1404 return;
1406 if (asn1_print(&elem) < 0)
1407 return;
1408 length -= count;
1409 np += count;
1411 /* generic-trap (Integer) */
1412 if ((count = asn1_parse(np, length, &elem)) < 0)
1413 return;
1414 if (elem.type != BE_INT) {
1415 fputs("[generic-trap!=INT]", stdout);
1416 asn1_print(&elem);
1417 return;
1419 generic = elem.data.integer;
1421 char buf[20];
1422 printf(" %s", DECODE_GenericTrap(generic));
1424 length -= count;
1425 np += count;
1427 /* specific-trap (Integer) */
1428 if ((count = asn1_parse(np, length, &elem)) < 0)
1429 return;
1430 if (elem.type != BE_INT) {
1431 fputs("[specific-trap!=INT]", stdout);
1432 asn1_print(&elem);
1433 return;
1435 if (generic != GT_ENTERPRISE) {
1436 if (elem.data.integer != 0)
1437 printf("[specific-trap(%d)!=0]", elem.data.integer);
1438 } else
1439 printf(" s=%d", elem.data.integer);
1440 length -= count;
1441 np += count;
1443 putchar(' ');
1445 /* time-stamp (TimeTicks) */
1446 if ((count = asn1_parse(np, length, &elem)) < 0)
1447 return;
1448 if (elem.type != BE_UNS) { /* XXX */
1449 fputs("[time-stamp!=TIMETICKS]", stdout);
1450 asn1_print(&elem);
1451 return;
1453 if (asn1_print(&elem) < 0)
1454 return;
1455 length -= count;
1456 np += count;
1458 varbind_print (TRAP, np, length);
1459 return;
1463 * Decode arbitrary SNMP PDUs.
1465 static void
1466 pdu_print(const u_char *np, u_int length, int version)
1468 struct be pdu;
1469 int count = 0;
1471 /* PDU (Context) */
1472 if ((count = asn1_parse(np, length, &pdu)) < 0)
1473 return;
1474 if (pdu.type != BE_PDU) {
1475 fputs("[no PDU]", stdout);
1476 return;
1478 if ((u_int)count < length)
1479 printf("[%d extra after PDU]", length - count);
1480 if (vflag) {
1481 fputs("{ ", stdout);
1483 if (asn1_print(&pdu) < 0)
1484 return;
1485 fputs(" ", stdout);
1486 /* descend into PDU */
1487 length = pdu.asnlen;
1488 np = (u_char *)pdu.data.raw;
1490 if (version == SNMP_VERSION_1 &&
1491 (pdu.id == GETBULKREQ || pdu.id == INFORMREQ ||
1492 pdu.id == V2TRAP || pdu.id == REPORT)) {
1493 printf("[v2 PDU in v1 message]");
1494 return;
1497 if (version == SNMP_VERSION_2 && pdu.id == TRAP) {
1498 printf("[v1 PDU in v2 message]");
1499 return;
1502 switch (pdu.id) {
1503 case TRAP:
1504 trappdu_print(np, length);
1505 break;
1506 case GETREQ:
1507 case GETNEXTREQ:
1508 case GETRESP:
1509 case SETREQ:
1510 case GETBULKREQ:
1511 case INFORMREQ:
1512 case V2TRAP:
1513 case REPORT:
1514 snmppdu_print(pdu.id, np, length);
1515 break;
1518 if (vflag) {
1519 fputs(" } ", stdout);
1524 * Decode a scoped SNMP PDU.
1526 static void
1527 scopedpdu_print(const u_char *np, u_int length, int version)
1529 struct be elem;
1530 int i, count = 0;
1532 /* Sequence */
1533 if ((count = asn1_parse(np, length, &elem)) < 0)
1534 return;
1535 if (elem.type != BE_SEQ) {
1536 fputs("[!scoped PDU]", stdout);
1537 asn1_print(&elem);
1538 return;
1540 length = elem.asnlen;
1541 np = (u_char *)elem.data.raw;
1543 /* contextEngineID (OCTET STRING) */
1544 if ((count = asn1_parse(np, length, &elem)) < 0)
1545 return;
1546 if (elem.type != BE_STR) {
1547 fputs("[contextEngineID!=STR]", stdout);
1548 asn1_print(&elem);
1549 return;
1551 length -= count;
1552 np += count;
1554 fputs("E= ", stdout);
1555 for (i = 0; i < (int)elem.asnlen; i++) {
1556 printf("0x%02X", elem.data.str[i]);
1558 fputs(" ", stdout);
1560 /* contextName (OCTET STRING) */
1561 if ((count = asn1_parse(np, length, &elem)) < 0)
1562 return;
1563 if (elem.type != BE_STR) {
1564 fputs("[contextName!=STR]", stdout);
1565 asn1_print(&elem);
1566 return;
1568 length -= count;
1569 np += count;
1571 printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
1573 pdu_print(np, length, version);
1577 * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
1579 static void
1580 community_print(const u_char *np, u_int length, int version)
1582 struct be elem;
1583 int count = 0;
1585 /* Community (String) */
1586 if ((count = asn1_parse(np, length, &elem)) < 0)
1587 return;
1588 if (elem.type != BE_STR) {
1589 fputs("[comm!=STR]", stdout);
1590 asn1_print(&elem);
1591 return;
1593 /* default community */
1594 if (!(elem.asnlen == sizeof(DEF_COMMUNITY) - 1 &&
1595 strncmp((char *)elem.data.str, DEF_COMMUNITY,
1596 sizeof(DEF_COMMUNITY) - 1) == 0))
1597 /* ! "public" */
1598 printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
1599 length -= count;
1600 np += count;
1602 pdu_print(np, length, version);
1606 * Decode SNMPv3 User-based Security Message Header (SNMPv3)
1608 static void
1609 usm_print(const u_char *np, u_int length)
1611 struct be elem;
1612 int count = 0;
1614 /* Sequence */
1615 if ((count = asn1_parse(np, length, &elem)) < 0)
1616 return;
1617 if (elem.type != BE_SEQ) {
1618 fputs("[!usm]", stdout);
1619 asn1_print(&elem);
1620 return;
1622 length = elem.asnlen;
1623 np = (u_char *)elem.data.raw;
1625 /* msgAuthoritativeEngineID (OCTET STRING) */
1626 if ((count = asn1_parse(np, length, &elem)) < 0)
1627 return;
1628 if (elem.type != BE_STR) {
1629 fputs("[msgAuthoritativeEngineID!=STR]", stdout);
1630 asn1_print(&elem);
1631 return;
1633 length -= count;
1634 np += count;
1636 /* msgAuthoritativeEngineBoots (INTEGER) */
1637 if ((count = asn1_parse(np, length, &elem)) < 0)
1638 return;
1639 if (elem.type != BE_INT) {
1640 fputs("[msgAuthoritativeEngineBoots!=INT]", stdout);
1641 asn1_print(&elem);
1642 return;
1644 if (vflag)
1645 printf("B=%d ", elem.data.integer);
1646 length -= count;
1647 np += count;
1649 /* msgAuthoritativeEngineTime (INTEGER) */
1650 if ((count = asn1_parse(np, length, &elem)) < 0)
1651 return;
1652 if (elem.type != BE_INT) {
1653 fputs("[msgAuthoritativeEngineTime!=INT]", stdout);
1654 asn1_print(&elem);
1655 return;
1657 if (vflag)
1658 printf("T=%d ", elem.data.integer);
1659 length -= count;
1660 np += count;
1662 /* msgUserName (OCTET STRING) */
1663 if ((count = asn1_parse(np, length, &elem)) < 0)
1664 return;
1665 if (elem.type != BE_STR) {
1666 fputs("[msgUserName!=STR]", stdout);
1667 asn1_print(&elem);
1668 return;
1670 length -= count;
1671 np += count;
1673 printf("U=%.*s ", (int)elem.asnlen, elem.data.str);
1675 /* msgAuthenticationParameters (OCTET STRING) */
1676 if ((count = asn1_parse(np, length, &elem)) < 0)
1677 return;
1678 if (elem.type != BE_STR) {
1679 fputs("[msgAuthenticationParameters!=STR]", stdout);
1680 asn1_print(&elem);
1681 return;
1683 length -= count;
1684 np += count;
1686 /* msgPrivacyParameters (OCTET STRING) */
1687 if ((count = asn1_parse(np, length, &elem)) < 0)
1688 return;
1689 if (elem.type != BE_STR) {
1690 fputs("[msgPrivacyParameters!=STR]", stdout);
1691 asn1_print(&elem);
1692 return;
1694 length -= count;
1695 np += count;
1697 if ((u_int)count < length)
1698 printf("[%d extra after usm SEQ]", length - count);
1702 * Decode SNMPv3 Message Header (SNMPv3)
1704 static void
1705 v3msg_print(const u_char *np, u_int length)
1707 struct be elem;
1708 int count = 0;
1709 u_char flags;
1710 int model;
1711 const u_char *xnp = np;
1712 int xlength = length;
1714 /* Sequence */
1715 if ((count = asn1_parse(np, length, &elem)) < 0)
1716 return;
1717 if (elem.type != BE_SEQ) {
1718 fputs("[!message]", stdout);
1719 asn1_print(&elem);
1720 return;
1722 length = elem.asnlen;
1723 np = (u_char *)elem.data.raw;
1725 if (vflag) {
1726 fputs("{ ", stdout);
1729 /* msgID (INTEGER) */
1730 if ((count = asn1_parse(np, length, &elem)) < 0)
1731 return;
1732 if (elem.type != BE_INT) {
1733 fputs("[msgID!=INT]", stdout);
1734 asn1_print(&elem);
1735 return;
1737 length -= count;
1738 np += count;
1740 /* msgMaxSize (INTEGER) */
1741 if ((count = asn1_parse(np, length, &elem)) < 0)
1742 return;
1743 if (elem.type != BE_INT) {
1744 fputs("[msgMaxSize!=INT]", stdout);
1745 asn1_print(&elem);
1746 return;
1748 length -= count;
1749 np += count;
1751 /* msgFlags (OCTET STRING) */
1752 if ((count = asn1_parse(np, length, &elem)) < 0)
1753 return;
1754 if (elem.type != BE_STR) {
1755 fputs("[msgFlags!=STR]", stdout);
1756 asn1_print(&elem);
1757 return;
1759 if (elem.asnlen != 1) {
1760 printf("[msgFlags size %d]", elem.asnlen);
1761 return;
1763 flags = elem.data.str[0];
1764 if (flags != 0x00 && flags != 0x01 && flags != 0x03
1765 && flags != 0x04 && flags != 0x05 && flags != 0x07) {
1766 printf("[msgFlags=0x%02X]", flags);
1767 return;
1769 length -= count;
1770 np += count;
1772 fputs("F=", stdout);
1773 if (flags & 0x01) fputs("a", stdout);
1774 if (flags & 0x02) fputs("p", stdout);
1775 if (flags & 0x04) fputs("r", stdout);
1776 fputs(" ", stdout);
1778 /* msgSecurityModel (INTEGER) */
1779 if ((count = asn1_parse(np, length, &elem)) < 0)
1780 return;
1781 if (elem.type != BE_INT) {
1782 fputs("[msgSecurityModel!=INT]", stdout);
1783 asn1_print(&elem);
1784 return;
1786 model = elem.data.integer;
1787 length -= count;
1788 np += count;
1790 if ((u_int)count < length)
1791 printf("[%d extra after message SEQ]", length - count);
1793 if (vflag) {
1794 fputs("} ", stdout);
1797 if (model == 3) {
1798 if (vflag) {
1799 fputs("{ USM ", stdout);
1801 } else {
1802 printf("[security model %d]", model);
1803 return;
1806 np = xnp + (np - xnp);
1807 length = xlength - (np - xnp);
1809 /* msgSecurityParameters (OCTET STRING) */
1810 if ((count = asn1_parse(np, length, &elem)) < 0)
1811 return;
1812 if (elem.type != BE_STR) {
1813 fputs("[msgSecurityParameters!=STR]", stdout);
1814 asn1_print(&elem);
1815 return;
1817 length -= count;
1818 np += count;
1820 if (model == 3) {
1821 usm_print(elem.data.str, elem.asnlen);
1822 if (vflag) {
1823 fputs("} ", stdout);
1827 if (vflag) {
1828 fputs("{ ScopedPDU ", stdout);
1831 scopedpdu_print(np, length, 3);
1833 if (vflag) {
1834 fputs("} ", stdout);
1839 * Decode SNMP header and pass on to PDU printing routines
1841 void
1842 snmp_print(const u_char *np, u_int length)
1844 struct be elem;
1845 int count = 0;
1846 int version = 0;
1848 putchar(' ');
1850 /* initial Sequence */
1851 if ((count = asn1_parse(np, length, &elem)) < 0)
1852 return;
1853 if (elem.type != BE_SEQ) {
1854 fputs("[!init SEQ]", stdout);
1855 asn1_print(&elem);
1856 return;
1858 if ((u_int)count < length)
1859 printf("[%d extra after iSEQ]", length - count);
1860 /* descend */
1861 length = elem.asnlen;
1862 np = (u_char *)elem.data.raw;
1864 /* Version (INTEGER) */
1865 if ((count = asn1_parse(np, length, &elem)) < 0)
1866 return;
1867 if (elem.type != BE_INT) {
1868 fputs("[version!=INT]", stdout);
1869 asn1_print(&elem);
1870 return;
1873 switch (elem.data.integer) {
1874 case SNMP_VERSION_1:
1875 case SNMP_VERSION_2:
1876 case SNMP_VERSION_3:
1877 if (vflag)
1878 printf("{ %s ", SnmpVersion[elem.data.integer]);
1879 break;
1880 default:
1881 printf("[version = %d]", elem.data.integer);
1882 return;
1884 version = elem.data.integer;
1885 length -= count;
1886 np += count;
1888 switch (version) {
1889 case SNMP_VERSION_1:
1890 case SNMP_VERSION_2:
1891 community_print(np, length, version);
1892 break;
1893 case SNMP_VERSION_3:
1894 v3msg_print(np, length);
1895 break;
1896 default:
1897 printf("[version = %d]", elem.data.integer);
1898 break;
1901 if (vflag) {
1902 fputs("} ", stdout);