This commit sets new users to see the DragonFly-tips fortunes instead
[dragonfly.git] / contrib / tcpdump-3.8.3 / print-snmp.c
blobe1db2166bc4eaf3c0d0135a2cacc59945cbfdaed
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.56.2.3 2004/03/23 06:59:59 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"
81 * Universal ASN.1 types
82 * (we only care about the tag values for those allowed in the Internet SMI)
84 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"
105 * Application-wide ASN.1 types from the Internet SMI and their tags
107 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
124 * Context-specific ASN.1 types for the SNMP PDUs and their tags
126 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
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)
154 * Context-specific ASN.1 types for the SNMP Exceptions and their tags
156 const char *Exceptions[] = {
157 "noSuchObject",
158 #define NOSUCHOBJECT 0
159 "noSuchInstance",
160 #define NOSUCHINSTANCE 1
161 "endOfMibView",
162 #define ENDOFMIBVIEW 2
166 * Private ASN.1 types
167 * The Internet SMI does not specify any
169 const char *Private[] = {
170 "P-0"
174 * error-status values for any SNMP PDU
176 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"
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))
203 * generic-trap values in the SNMP Trap-PDU
205 const char *GenericTrap[] = {
206 "coldStart",
207 "warmStart",
208 "linkDown",
209 "linkUp",
210 "authenticationFailure",
211 "egpNeighborLoss",
212 "enterpriseSpecific"
213 #define GT_ENTERPRISE 6
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))
221 * ASN.1 type class table
222 * Ties together the preceding Universal, Application, Context, and Private
223 * type definitions.
225 #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
226 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
244 * defined forms for ASN.1 types
246 const char *Form[] = {
247 "Primitive",
248 #define PRIMITIVE 0
249 "Constructed",
250 #define CONSTRUCTED 1
254 * A structure for the OID tree for the compiled-in MIB.
255 * This is stored as a general-order tree.
257 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;
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'.
269 * In particular, this is gross, as this is including initialized structures,
270 * and by right shouldn't be an "include" file.
272 #include "mib.h"
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.
279 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 }
304 * This is used in the OID print routine to walk down the object tree
305 * rooted at `mibroot'.
307 #define OBJ_PRINT(o, suppressdot) \
309 if (objp) { \
310 do { \
311 if ((o) == objp->oid) \
312 break; \
313 } while ((objp = objp->next) != NULL); \
315 if (objp) { \
316 printf(suppressdot?"%s":".%s", objp->desc); \
317 objp = objp->child; \
318 } else \
319 printf(suppressdot?"%u":".%u", (o)); \
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.
326 struct be {
327 u_int32_t asnlen;
328 union {
329 caddr_t raw;
330 int32_t integer;
331 u_int32_t uns;
332 const u_char *str;
333 struct {
334 u_int32_t high;
335 u_int32_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
359 * SNMP versions recognized by this module
361 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
373 * Defaults for SNMP PDU components
375 #define DEF_COMMUNITY "public"
378 * constants for ASN.1 decoding
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
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
393 #define ASN_ID_EXT 0x1f /* extension ID in tag field */
396 * truncated==1 means the packet was complete, but we don't have all of
397 * it to decode.
399 static int truncated;
400 #define ifNotTruncated if (truncated) fputs("[|snmp]", stdout); else
403 * This decodes the next ASN.1 object in the stream pointed to by "p"
404 * (and of real-length "len") and stores the intermediate data in the
405 * provided BE object.
407 * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
408 * O/w, this returns the number of bytes parsed from "p".
410 static int
411 asn1_parse(register const u_char *p, u_int len, struct be *elem)
413 u_char form, class, id;
414 int i, hdr;
416 elem->asnlen = 0;
417 elem->type = BE_ANY;
418 if (len < 1) {
419 ifNotTruncated fputs("[nothing to parse]", stdout);
420 return -1;
424 * it would be nice to use a bit field, but you can't depend on them.
425 * +---+---+---+---+---+---+---+---+
426 * + class |frm| id |
427 * +---+---+---+---+---+---+---+---+
428 * 7 6 5 4 3 2 1 0
430 id = *p & ASN_ID_BITS; /* lower 5 bits, range 00-1f */
431 #ifdef notdef
432 form = (*p & 0xe0) >> 5; /* move upper 3 bits to lower 3 */
433 class = form >> 1; /* bits 7&6 -> bits 1&0, range 0-3 */
434 form &= 0x1; /* bit 5 -> bit 0, range 0-1 */
435 #else
436 form = (u_char)(*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
437 class = (u_char)(*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
438 #endif
439 elem->form = form;
440 elem->class = class;
441 elem->id = id;
442 p++; len--; hdr = 1;
443 /* extended tag field */
444 if (id == ASN_ID_EXT) {
445 for (id = 0; *p & ASN_BIT8 && len > 0; len--, hdr++, p++)
446 id = (id << 7) | (*p & ~ASN_BIT8);
447 if (len == 0 && *p & ASN_BIT8) {
448 ifNotTruncated fputs("[Xtagfield?]", stdout);
449 return -1;
451 elem->id = id = (id << 7) | *p;
452 --len;
453 ++hdr;
454 ++p;
456 if (len < 1) {
457 ifNotTruncated fputs("[no asnlen]", stdout);
458 return -1;
460 elem->asnlen = *p;
461 p++; len--; hdr++;
462 if (elem->asnlen & ASN_BIT8) {
463 u_int32_t noct = elem->asnlen % ASN_BIT8;
464 elem->asnlen = 0;
465 if (len < noct) {
466 ifNotTruncated printf("[asnlen? %d<%d]", len, noct);
467 return -1;
469 for (; noct-- > 0; len--, hdr++)
470 elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++;
472 if (len < elem->asnlen) {
473 if (!truncated) {
474 printf("[len%d<asnlen%u]", len, elem->asnlen);
475 return -1;
477 /* maybe should check at least 4? */
478 elem->asnlen = len;
480 if (form >= sizeof(Form)/sizeof(Form[0])) {
481 ifNotTruncated printf("[form?%d]", form);
482 return -1;
484 if (class >= sizeof(Class)/sizeof(Class[0])) {
485 ifNotTruncated printf("[class?%c/%d]", *Form[form], class);
486 return -1;
488 if ((int)id >= Class[class].numIDs) {
489 ifNotTruncated printf("[id?%c/%s/%d]", *Form[form],
490 Class[class].name, id);
491 return -1;
494 switch (form) {
495 case PRIMITIVE:
496 switch (class) {
497 case UNIVERSAL:
498 switch (id) {
499 case STRING:
500 elem->type = BE_STR;
501 elem->data.str = p;
502 break;
504 case INTEGER: {
505 register int32_t data;
506 elem->type = BE_INT;
507 data = 0;
509 if (*p & ASN_BIT8) /* negative */
510 data = -1;
511 for (i = elem->asnlen; i-- > 0; p++)
512 data = (data << ASN_SHIFT8) | *p;
513 elem->data.integer = data;
514 break;
517 case OBJECTID:
518 elem->type = BE_OID;
519 elem->data.raw = (caddr_t)p;
520 break;
522 case ASN_NULL:
523 elem->type = BE_NULL;
524 elem->data.raw = NULL;
525 break;
527 default:
528 elem->type = BE_OCTET;
529 elem->data.raw = (caddr_t)p;
530 printf("[P/U/%s]",
531 Class[class].Id[id]);
532 break;
534 break;
536 case APPLICATION:
537 switch (id) {
538 case IPADDR:
539 elem->type = BE_INETADDR;
540 elem->data.raw = (caddr_t)p;
541 break;
543 case COUNTER:
544 case GAUGE:
545 case TIMETICKS: {
546 register u_int32_t data;
547 elem->type = BE_UNS;
548 data = 0;
549 for (i = elem->asnlen; i-- > 0; p++)
550 data = (data << 8) + *p;
551 elem->data.uns = data;
552 break;
555 case COUNTER64: {
556 register u_int32_t high, low;
557 elem->type = BE_UNS64;
558 high = 0, low = 0;
559 for (i = elem->asnlen; i-- > 0; p++) {
560 high = (high << 8) |
561 ((low & 0xFF000000) >> 24);
562 low = (low << 8) | *p;
564 elem->data.uns64.high = high;
565 elem->data.uns64.low = low;
566 break;
569 default:
570 elem->type = BE_OCTET;
571 elem->data.raw = (caddr_t)p;
572 printf("[P/A/%s]",
573 Class[class].Id[id]);
574 break;
576 break;
578 case CONTEXT:
579 switch (id) {
580 case NOSUCHOBJECT:
581 elem->type = BE_NOSUCHOBJECT;
582 elem->data.raw = NULL;
583 break;
585 case NOSUCHINSTANCE:
586 elem->type = BE_NOSUCHINST;
587 elem->data.raw = NULL;
588 break;
590 case ENDOFMIBVIEW:
591 elem->type = BE_ENDOFMIBVIEW;
592 elem->data.raw = NULL;
593 break;
595 break;
597 default:
598 elem->type = BE_OCTET;
599 elem->data.raw = (caddr_t)p;
600 printf("[P/%s/%s]",
601 Class[class].name, Class[class].Id[id]);
602 break;
604 break;
606 case CONSTRUCTED:
607 switch (class) {
608 case UNIVERSAL:
609 switch (id) {
610 case SEQUENCE:
611 elem->type = BE_SEQ;
612 elem->data.raw = (caddr_t)p;
613 break;
615 default:
616 elem->type = BE_OCTET;
617 elem->data.raw = (caddr_t)p;
618 printf("C/U/%s", Class[class].Id[id]);
619 break;
621 break;
623 case CONTEXT:
624 elem->type = BE_PDU;
625 elem->data.raw = (caddr_t)p;
626 break;
628 default:
629 elem->type = BE_OCTET;
630 elem->data.raw = (caddr_t)p;
631 printf("C/%s/%s",
632 Class[class].name, Class[class].Id[id]);
633 break;
635 break;
637 p += elem->asnlen;
638 len -= elem->asnlen;
639 return elem->asnlen + hdr;
643 * Display the ASN.1 object represented by the BE object.
644 * This used to be an integral part of asn1_parse() before the intermediate
645 * BE form was added.
647 static void
648 asn1_print(struct be *elem)
650 u_char *p = (u_char *)elem->data.raw;
651 u_int32_t asnlen = elem->asnlen;
652 u_int32_t i;
654 switch (elem->type) {
656 case BE_OCTET:
657 for (i = asnlen; i-- > 0; p++)
658 printf("_%.2x", *p);
659 break;
661 case BE_NULL:
662 break;
664 case BE_OID: {
665 int o = 0, first = -1, i = asnlen;
667 if (!sflag && !nflag && asnlen > 2) {
668 struct obj_abrev *a = &obj_abrev_list[0];
669 for (; a->node; a++) {
670 if (!memcmp(a->oid, (char *)p,
671 strlen(a->oid))) {
672 objp = a->node->child;
673 i -= strlen(a->oid);
674 p += strlen(a->oid);
675 fputs(a->prefix, stdout);
676 first = 1;
677 break;
682 for (; !sflag && i-- > 0; p++) {
683 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
684 if (*p & ASN_LONGLEN)
685 continue;
688 * first subitem encodes two items with 1st*OIDMUX+2nd
689 * (see X.690:1997 clause 8.19 for the details)
691 if (first < 0) {
692 int s;
693 if (!nflag)
694 objp = mibroot;
695 first = 0;
696 s = o / OIDMUX;
697 if (s > 2) s = 2;
698 OBJ_PRINT(s, first);
699 o -= s * OIDMUX;
701 OBJ_PRINT(o, first);
702 if (--first < 0)
703 first = 0;
704 o = 0;
706 break;
709 case BE_INT:
710 printf("%d", elem->data.integer);
711 break;
713 case BE_UNS:
714 printf("%u", elem->data.uns);
715 break;
717 case BE_UNS64: { /* idea borrowed from by Marshall Rose */
718 double d;
719 int j, carry;
720 char *cpf, *cpl, last[6], first[30];
721 if (elem->data.uns64.high == 0) {
722 printf("%u", elem->data.uns64.low);
723 break;
725 d = elem->data.uns64.high * 4294967296.0; /* 2^32 */
726 if (elem->data.uns64.high <= 0x1fffff) {
727 d += elem->data.uns64.low;
728 #if 0 /*is looks illegal, but what is the intention?*/
729 printf("%.f", d);
730 #else
731 printf("%f", d);
732 #endif
733 break;
735 d += (elem->data.uns64.low & 0xfffff000);
736 #if 0 /*is looks illegal, but what is the intention?*/
737 snprintf(first, sizeof(first), "%.f", d);
738 #else
739 snprintf(first, sizeof(first), "%f", d);
740 #endif
741 snprintf(last, sizeof(last), "%5.5d",
742 elem->data.uns64.low & 0xfff);
743 for (carry = 0, cpf = first+strlen(first)-1, cpl = last+4;
744 cpl >= last;
745 cpf--, cpl--) {
746 j = carry + (*cpf - '0') + (*cpl - '0');
747 if (j > 9) {
748 j -= 10;
749 carry = 1;
750 } else {
751 carry = 0;
753 *cpf = j + '0';
755 fputs(first, stdout);
756 break;
759 case BE_STR: {
760 register int printable = 1, first = 1;
761 const u_char *p = elem->data.str;
762 for (i = asnlen; printable && i-- > 0; p++)
763 printable = isprint(*p) || isspace(*p);
764 p = elem->data.str;
765 if (printable) {
766 putchar('"');
767 (void)fn_print(p, p + asnlen);
768 putchar('"');
769 } else
770 for (i = asnlen; i-- > 0; p++) {
771 printf(first ? "%.2x" : "_%.2x", *p);
772 first = 0;
774 break;
777 case BE_SEQ:
778 printf("Seq(%u)", elem->asnlen);
779 break;
781 case BE_INETADDR:
782 if (asnlen != ASNLEN_INETADDR)
783 printf("[inetaddr len!=%d]", ASNLEN_INETADDR);
784 for (i = asnlen; i-- != 0; p++) {
785 printf((i == asnlen-1) ? "%u" : ".%u", *p);
787 break;
789 case BE_NOSUCHOBJECT:
790 case BE_NOSUCHINST:
791 case BE_ENDOFMIBVIEW:
792 printf("[%s]", Class[EXCEPTIONS].Id[elem->id]);
793 break;
795 case BE_PDU:
796 printf("%s(%u)",
797 Class[CONTEXT].Id[elem->id], elem->asnlen);
798 break;
800 case BE_ANY:
801 fputs("[BE_ANY!?]", stdout);
802 break;
804 default:
805 fputs("[be!?]", stdout);
806 break;
810 #ifdef notdef
812 * This is a brute force ASN.1 printer: recurses to dump an entire structure.
813 * This will work for any ASN.1 stream, not just an SNMP PDU.
815 * By adding newlines and spaces at the correct places, this would print in
816 * Rose-Normal-Form.
818 * This is not currently used.
820 static void
821 asn1_decode(u_char *p, u_int length)
823 struct be elem;
824 int i = 0;
826 while (i >= 0 && length > 0) {
827 i = asn1_parse(p, length, &elem);
828 if (i >= 0) {
829 fputs(" ", stdout);
830 asn1_print(&elem);
831 if (elem.type == BE_SEQ || elem.type == BE_PDU) {
832 fputs(" {", stdout);
833 asn1_decode(elem.data.raw, elem.asnlen);
834 fputs(" }", stdout);
836 length -= i;
837 p += i;
841 #endif
843 #ifdef LIBSMI
845 struct smi2be {
846 SmiBasetype basetype;
847 int be;
850 static struct smi2be smi2betab[] = {
851 { SMI_BASETYPE_INTEGER32, BE_INT },
852 { SMI_BASETYPE_OCTETSTRING, BE_STR },
853 { SMI_BASETYPE_OCTETSTRING, BE_INETADDR },
854 { SMI_BASETYPE_OBJECTIDENTIFIER, BE_OID },
855 { SMI_BASETYPE_UNSIGNED32, BE_UNS },
856 { SMI_BASETYPE_INTEGER64, BE_NONE },
857 { SMI_BASETYPE_UNSIGNED64, BE_UNS64 },
858 { SMI_BASETYPE_FLOAT32, BE_NONE },
859 { SMI_BASETYPE_FLOAT64, BE_NONE },
860 { SMI_BASETYPE_FLOAT128, BE_NONE },
861 { SMI_BASETYPE_ENUM, BE_INT },
862 { SMI_BASETYPE_BITS, BE_STR },
863 { SMI_BASETYPE_UNKNOWN, BE_NONE }
866 static void smi_decode_oid(struct be *elem, unsigned int *oid,
867 unsigned int oidsize, unsigned int *oidlen)
869 u_char *p = (u_char *)elem->data.raw;
870 u_int32_t asnlen = elem->asnlen;
871 int o = 0, first = -1, i = asnlen;
873 for (*oidlen = 0; sflag && i-- > 0; p++) {
874 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
875 if (*p & ASN_LONGLEN)
876 continue;
879 * first subitem encodes two items with 1st*OIDMUX+2nd
880 * (see X.690:1997 clause 8.19 for the details)
882 if (first < 0) {
883 first = 0;
884 if (*oidlen < oidsize) {
885 oid[*oidlen] = o / OIDMUX;
886 if (oid[*oidlen] > 2) oid[*oidlen] = 2;
888 o -= oid[*oidlen] * OIDMUX;
889 if (*oidlen < oidsize) (*oidlen)++;
891 if (*oidlen < oidsize) {
892 oid[(*oidlen)++] = o;
894 o = 0;
898 static int smi_check_type(SmiBasetype basetype, int be)
900 int i;
902 for (i = 0; smi2betab[i].basetype != SMI_BASETYPE_UNKNOWN; i++) {
903 if (smi2betab[i].basetype == basetype && smi2betab[i].be == be) {
904 return 1;
908 return 0;
911 static int smi_check_a_range(SmiType *smiType, SmiRange *smiRange,
912 struct be *elem)
914 int ok = 1;
916 switch (smiType->basetype) {
917 case SMI_BASETYPE_OBJECTIDENTIFIER:
918 case SMI_BASETYPE_OCTETSTRING:
919 if (smiRange->minValue.value.unsigned32
920 == smiRange->maxValue.value.unsigned32) {
921 ok = (elem->asnlen == smiRange->minValue.value.unsigned32);
922 } else {
923 ok = (elem->asnlen >= smiRange->minValue.value.unsigned32
924 && elem->asnlen <= smiRange->maxValue.value.unsigned32);
926 break;
928 case SMI_BASETYPE_INTEGER32:
929 ok = (elem->data.integer >= smiRange->minValue.value.integer32
930 && elem->data.integer <= smiRange->maxValue.value.integer32);
931 break;
933 case SMI_BASETYPE_UNSIGNED32:
934 ok = (elem->data.uns >= smiRange->minValue.value.unsigned32
935 && elem->data.uns <= smiRange->maxValue.value.unsigned32);
936 break;
938 case SMI_BASETYPE_UNSIGNED64:
939 /* XXX */
940 break;
942 /* case SMI_BASETYPE_INTEGER64: SMIng */
943 /* case SMI_BASETYPE_FLOAT32: SMIng */
944 /* case SMI_BASETYPE_FLOAT64: SMIng */
945 /* case SMI_BASETYPE_FLOAT128: SMIng */
947 case SMI_BASETYPE_ENUM:
948 case SMI_BASETYPE_BITS:
949 case SMI_BASETYPE_UNKNOWN:
950 ok = 1;
951 break;
954 return ok;
957 static int smi_check_range(SmiType *smiType, struct be *elem)
959 SmiRange *smiRange;
960 int ok = 1;
962 for (smiRange = smiGetFirstRange(smiType);
963 smiRange;
964 smiRange = smiGetNextRange(smiRange)) {
966 ok = smi_check_a_range(smiType, smiRange, elem);
968 if (ok) {
969 break;
973 if (ok) {
974 SmiType *parentType;
975 parentType = smiGetParentType(smiType);
976 if (parentType) {
977 ok = smi_check_range(parentType, elem);
981 return ok;
984 static SmiNode *smi_print_variable(struct be *elem)
986 unsigned int oid[128], oidlen;
987 SmiNode *smiNode = NULL;
988 int i;
990 smi_decode_oid(elem, oid, sizeof(oid)/sizeof(unsigned int), &oidlen);
991 smiNode = smiGetNodeByOID(oidlen, oid);
992 if (! smiNode) {
993 asn1_print(elem);
994 return NULL;
996 if (vflag) {
997 fputs(smiGetNodeModule(smiNode)->name, stdout);
998 fputs("::", stdout);
1000 fputs(smiNode->name, stdout);
1001 if (smiNode->oidlen < oidlen) {
1002 for (i = smiNode->oidlen; i < oidlen; i++) {
1003 printf(".%u", oid[i]);
1006 return smiNode;
1009 static void smi_print_value(SmiNode *smiNode, u_char pduid, struct be *elem)
1011 unsigned int oid[128], oidlen;
1012 SmiType *smiType;
1013 SmiNamedNumber *nn;
1014 int i, done = 0;
1016 if (! smiNode || ! (smiNode->nodekind
1017 & (SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN))) {
1018 asn1_print(elem);
1019 return;
1022 if (elem->type == BE_NOSUCHOBJECT
1023 || elem->type == BE_NOSUCHINST
1024 || elem->type == BE_ENDOFMIBVIEW) {
1025 asn1_print(elem);
1026 return;
1029 if (NOTIFY_CLASS(pduid) && smiNode->access < SMI_ACCESS_NOTIFY) {
1030 fputs("[notNotifyable]", stdout);
1033 if (READ_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_ONLY) {
1034 fputs("[notReadable]", stdout);
1037 if (WRITE_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_WRITE) {
1038 fputs("[notWritable]", stdout);
1041 if (RESPONSE_CLASS(pduid)
1042 && smiNode->access == SMI_ACCESS_NOT_ACCESSIBLE) {
1043 fputs("[noAccess]", stdout);
1046 smiType = smiGetNodeType(smiNode);
1047 if (! smiType) {
1048 asn1_print(elem);
1049 return;
1052 if (! smi_check_type(smiType->basetype, elem->type)) {
1053 fputs("[wrongType]", stdout);
1056 if (! smi_check_range(smiType, elem)) {
1057 fputs("[outOfRange]", stdout);
1060 /* resolve bits to named bits */
1062 /* check whether instance identifier is valid */
1064 /* apply display hints (integer, octetstring) */
1066 /* convert instance identifier to index type values */
1068 switch (elem->type) {
1069 case BE_OID:
1070 if (smiType->basetype == SMI_BASETYPE_BITS) {
1071 /* print bit labels */
1072 } else {
1073 smi_decode_oid(elem, oid,
1074 sizeof(oid)/sizeof(unsigned int),
1075 &oidlen);
1076 smiNode = smiGetNodeByOID(oidlen, oid);
1077 if (smiNode) {
1078 if (vflag) {
1079 fputs(smiGetNodeModule(smiNode)->name, stdout);
1080 fputs("::", stdout);
1082 fputs(smiNode->name, stdout);
1083 if (smiNode->oidlen < oidlen) {
1084 for (i = smiNode->oidlen;
1085 i < oidlen; i++) {
1086 printf(".%u", oid[i]);
1089 done++;
1092 break;
1094 case BE_INT:
1095 if (smiType->basetype == SMI_BASETYPE_ENUM) {
1096 for (nn = smiGetFirstNamedNumber(smiType);
1098 nn = smiGetNextNamedNumber(nn)) {
1099 if (nn->value.value.integer32
1100 == elem->data.integer) {
1101 fputs(nn->name, stdout);
1102 printf("(%d)", elem->data.integer);
1103 done++;
1104 break;
1108 break;
1111 if (! done) {
1112 asn1_print(elem);
1115 #endif
1118 * General SNMP header
1119 * SEQUENCE {
1120 * version INTEGER {version-1(0)},
1121 * community OCTET STRING,
1122 * data ANY -- PDUs
1124 * PDUs for all but Trap: (see rfc1157 from page 15 on)
1125 * SEQUENCE {
1126 * request-id INTEGER,
1127 * error-status INTEGER,
1128 * error-index INTEGER,
1129 * varbindlist SEQUENCE OF
1130 * SEQUENCE {
1131 * name ObjectName,
1132 * value ObjectValue
1135 * PDU for Trap:
1136 * SEQUENCE {
1137 * enterprise OBJECT IDENTIFIER,
1138 * agent-addr NetworkAddress,
1139 * generic-trap INTEGER,
1140 * specific-trap INTEGER,
1141 * time-stamp TimeTicks,
1142 * varbindlist SEQUENCE OF
1143 * SEQUENCE {
1144 * name ObjectName,
1145 * value ObjectValue
1151 * Decode SNMP varBind
1153 static void
1154 varbind_print(u_char pduid, const u_char *np, u_int length)
1156 struct be elem;
1157 int count = 0, ind;
1158 #ifdef LIBSMI
1159 SmiNode *smiNode = NULL;
1160 #endif
1162 /* Sequence of varBind */
1163 if ((count = asn1_parse(np, length, &elem)) < 0)
1164 return;
1165 if (elem.type != BE_SEQ) {
1166 fputs("[!SEQ of varbind]", stdout);
1167 asn1_print(&elem);
1168 return;
1170 if ((u_int)count < length)
1171 printf("[%d extra after SEQ of varbind]", length - count);
1172 /* descend */
1173 length = elem.asnlen;
1174 np = (u_char *)elem.data.raw;
1176 for (ind = 1; length > 0; ind++) {
1177 const u_char *vbend;
1178 u_int vblength;
1180 fputs(" ", stdout);
1182 /* Sequence */
1183 if ((count = asn1_parse(np, length, &elem)) < 0)
1184 return;
1185 if (elem.type != BE_SEQ) {
1186 fputs("[!varbind]", stdout);
1187 asn1_print(&elem);
1188 return;
1190 vbend = np + count;
1191 vblength = length - count;
1192 /* descend */
1193 length = elem.asnlen;
1194 np = (u_char *)elem.data.raw;
1196 /* objName (OID) */
1197 if ((count = asn1_parse(np, length, &elem)) < 0)
1198 return;
1199 if (elem.type != BE_OID) {
1200 fputs("[objName!=OID]", stdout);
1201 asn1_print(&elem);
1202 return;
1204 #ifdef LIBSMI
1205 smiNode = smi_print_variable(&elem);
1206 #else
1207 asn1_print(&elem);
1208 #endif
1209 length -= count;
1210 np += count;
1212 if (pduid != GETREQ && pduid != GETNEXTREQ
1213 && pduid != GETBULKREQ)
1214 fputs("=", stdout);
1216 /* objVal (ANY) */
1217 if ((count = asn1_parse(np, length, &elem)) < 0)
1218 return;
1219 if (pduid == GETREQ || pduid == GETNEXTREQ
1220 || pduid == GETBULKREQ) {
1221 if (elem.type != BE_NULL) {
1222 fputs("[objVal!=NULL]", stdout);
1223 asn1_print(&elem);
1225 } else {
1226 if (elem.type != BE_NULL) {
1227 #ifdef LIBSMI
1228 smi_print_value(smiNode, pduid, &elem);
1229 #else
1230 asn1_print(&elem);
1231 #endif
1234 length = vblength;
1235 np = vbend;
1240 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
1241 * GetBulk, Inform, V2Trap, and Report
1243 static void
1244 snmppdu_print(u_char pduid, const u_char *np, u_int length)
1246 struct be elem;
1247 int count = 0, error;
1249 /* reqId (Integer) */
1250 if ((count = asn1_parse(np, length, &elem)) < 0)
1251 return;
1252 if (elem.type != BE_INT) {
1253 fputs("[reqId!=INT]", stdout);
1254 asn1_print(&elem);
1255 return;
1257 if (vflag)
1258 printf("R=%d ", elem.data.integer);
1259 length -= count;
1260 np += count;
1262 /* errorStatus (Integer) */
1263 if ((count = asn1_parse(np, length, &elem)) < 0)
1264 return;
1265 if (elem.type != BE_INT) {
1266 fputs("[errorStatus!=INT]", stdout);
1267 asn1_print(&elem);
1268 return;
1270 error = 0;
1271 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1272 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1273 && elem.data.integer != 0) {
1274 char errbuf[10];
1275 printf("[errorStatus(%s)!=0]",
1276 DECODE_ErrorStatus(elem.data.integer));
1277 } else if (pduid == GETBULKREQ) {
1278 printf(" N=%d", elem.data.integer);
1279 } else if (elem.data.integer != 0) {
1280 char errbuf[10];
1281 printf(" %s", DECODE_ErrorStatus(elem.data.integer));
1282 error = elem.data.integer;
1284 length -= count;
1285 np += count;
1287 /* errorIndex (Integer) */
1288 if ((count = asn1_parse(np, length, &elem)) < 0)
1289 return;
1290 if (elem.type != BE_INT) {
1291 fputs("[errorIndex!=INT]", stdout);
1292 asn1_print(&elem);
1293 return;
1295 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1296 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1297 && elem.data.integer != 0)
1298 printf("[errorIndex(%d)!=0]", elem.data.integer);
1299 else if (pduid == GETBULKREQ)
1300 printf(" M=%d", elem.data.integer);
1301 else if (elem.data.integer != 0) {
1302 if (!error)
1303 printf("[errorIndex(%d) w/o errorStatus]",
1304 elem.data.integer);
1305 else {
1306 printf("@%d", elem.data.integer);
1307 error = elem.data.integer;
1309 } else if (error) {
1310 fputs("[errorIndex==0]", stdout);
1311 error = 0;
1313 length -= count;
1314 np += count;
1316 varbind_print(pduid, np, length);
1317 return;
1321 * Decode SNMP Trap PDU
1323 static void
1324 trappdu_print(const u_char *np, u_int length)
1326 struct be elem;
1327 int count = 0, generic;
1329 putchar(' ');
1331 /* enterprise (oid) */
1332 if ((count = asn1_parse(np, length, &elem)) < 0)
1333 return;
1334 if (elem.type != BE_OID) {
1335 fputs("[enterprise!=OID]", stdout);
1336 asn1_print(&elem);
1337 return;
1339 asn1_print(&elem);
1340 length -= count;
1341 np += count;
1343 putchar(' ');
1345 /* agent-addr (inetaddr) */
1346 if ((count = asn1_parse(np, length, &elem)) < 0)
1347 return;
1348 if (elem.type != BE_INETADDR) {
1349 fputs("[agent-addr!=INETADDR]", stdout);
1350 asn1_print(&elem);
1351 return;
1353 asn1_print(&elem);
1354 length -= count;
1355 np += count;
1357 /* generic-trap (Integer) */
1358 if ((count = asn1_parse(np, length, &elem)) < 0)
1359 return;
1360 if (elem.type != BE_INT) {
1361 fputs("[generic-trap!=INT]", stdout);
1362 asn1_print(&elem);
1363 return;
1365 generic = elem.data.integer;
1367 char buf[10];
1368 printf(" %s", DECODE_GenericTrap(generic));
1370 length -= count;
1371 np += count;
1373 /* specific-trap (Integer) */
1374 if ((count = asn1_parse(np, length, &elem)) < 0)
1375 return;
1376 if (elem.type != BE_INT) {
1377 fputs("[specific-trap!=INT]", stdout);
1378 asn1_print(&elem);
1379 return;
1381 if (generic != GT_ENTERPRISE) {
1382 if (elem.data.integer != 0)
1383 printf("[specific-trap(%d)!=0]", elem.data.integer);
1384 } else
1385 printf(" s=%d", elem.data.integer);
1386 length -= count;
1387 np += count;
1389 putchar(' ');
1391 /* time-stamp (TimeTicks) */
1392 if ((count = asn1_parse(np, length, &elem)) < 0)
1393 return;
1394 if (elem.type != BE_UNS) { /* XXX */
1395 fputs("[time-stamp!=TIMETICKS]", stdout);
1396 asn1_print(&elem);
1397 return;
1399 asn1_print(&elem);
1400 length -= count;
1401 np += count;
1403 varbind_print (TRAP, np, length);
1404 return;
1408 * Decode arbitrary SNMP PDUs.
1410 static void
1411 pdu_print(const u_char *np, u_int length, int version)
1413 struct be pdu;
1414 int count = 0;
1416 /* PDU (Context) */
1417 if ((count = asn1_parse(np, length, &pdu)) < 0)
1418 return;
1419 if (pdu.type != BE_PDU) {
1420 fputs("[no PDU]", stdout);
1421 return;
1423 if ((u_int)count < length)
1424 printf("[%d extra after PDU]", length - count);
1425 if (vflag) {
1426 fputs("{ ", stdout);
1428 asn1_print(&pdu);
1429 fputs(" ", stdout);
1430 /* descend into PDU */
1431 length = pdu.asnlen;
1432 np = (u_char *)pdu.data.raw;
1434 if (version == SNMP_VERSION_1 &&
1435 (pdu.id == GETBULKREQ || pdu.id == INFORMREQ ||
1436 pdu.id == V2TRAP || pdu.id == REPORT)) {
1437 printf("[v2 PDU in v1 message]");
1438 return;
1441 if (version == SNMP_VERSION_2 && pdu.id == TRAP) {
1442 printf("[v1 PDU in v2 message]");
1443 return;
1446 switch (pdu.id) {
1447 case TRAP:
1448 trappdu_print(np, length);
1449 break;
1450 case GETREQ:
1451 case GETNEXTREQ:
1452 case GETRESP:
1453 case SETREQ:
1454 case GETBULKREQ:
1455 case INFORMREQ:
1456 case V2TRAP:
1457 case REPORT:
1458 snmppdu_print(pdu.id, np, length);
1459 break;
1462 if (vflag) {
1463 fputs(" } ", stdout);
1468 * Decode a scoped SNMP PDU.
1470 static void
1471 scopedpdu_print(const u_char *np, u_int length, int version)
1473 struct be elem;
1474 int i, count = 0;
1476 /* Sequence */
1477 if ((count = asn1_parse(np, length, &elem)) < 0)
1478 return;
1479 if (elem.type != BE_SEQ) {
1480 fputs("[!scoped PDU]", stdout);
1481 asn1_print(&elem);
1482 return;
1484 length = elem.asnlen;
1485 np = (u_char *)elem.data.raw;
1487 /* contextEngineID (OCTET STRING) */
1488 if ((count = asn1_parse(np, length, &elem)) < 0)
1489 return;
1490 if (elem.type != BE_STR) {
1491 fputs("[contextEngineID!=STR]", stdout);
1492 asn1_print(&elem);
1493 return;
1495 length -= count;
1496 np += count;
1498 fputs("E= ", stdout);
1499 for (i = 0; i < (int)elem.asnlen; i++) {
1500 printf("0x%02X", elem.data.str[i]);
1502 fputs(" ", stdout);
1504 /* contextName (OCTET STRING) */
1505 if ((count = asn1_parse(np, length, &elem)) < 0)
1506 return;
1507 if (elem.type != BE_STR) {
1508 fputs("[contextName!=STR]", stdout);
1509 asn1_print(&elem);
1510 return;
1512 length -= count;
1513 np += count;
1515 printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
1517 pdu_print(np, length, version);
1521 * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
1523 static void
1524 community_print(const u_char *np, u_int length, int version)
1526 struct be elem;
1527 int count = 0;
1529 /* Community (String) */
1530 if ((count = asn1_parse(np, length, &elem)) < 0)
1531 return;
1532 if (elem.type != BE_STR) {
1533 fputs("[comm!=STR]", stdout);
1534 asn1_print(&elem);
1535 return;
1537 /* default community */
1538 if (!(elem.asnlen == sizeof(DEF_COMMUNITY) - 1 &&
1539 strncmp((char *)elem.data.str, DEF_COMMUNITY,
1540 sizeof(DEF_COMMUNITY) - 1) == 0))
1541 /* ! "public" */
1542 printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
1543 length -= count;
1544 np += count;
1546 pdu_print(np, length, version);
1550 * Decode SNMPv3 User-based Security Message Header (SNMPv3)
1552 static void
1553 usm_print(const u_char *np, u_int length)
1555 struct be elem;
1556 int count = 0;
1558 /* Sequence */
1559 if ((count = asn1_parse(np, length, &elem)) < 0)
1560 return;
1561 if (elem.type != BE_SEQ) {
1562 fputs("[!usm]", stdout);
1563 asn1_print(&elem);
1564 return;
1566 length = elem.asnlen;
1567 np = (u_char *)elem.data.raw;
1569 /* msgAuthoritativeEngineID (OCTET STRING) */
1570 if ((count = asn1_parse(np, length, &elem)) < 0)
1571 return;
1572 if (elem.type != BE_STR) {
1573 fputs("[msgAuthoritativeEngineID!=STR]", stdout);
1574 asn1_print(&elem);
1575 return;
1577 length -= count;
1578 np += count;
1580 /* msgAuthoritativeEngineBoots (INTEGER) */
1581 if ((count = asn1_parse(np, length, &elem)) < 0)
1582 return;
1583 if (elem.type != BE_INT) {
1584 fputs("[msgAuthoritativeEngineBoots!=INT]", stdout);
1585 asn1_print(&elem);
1586 return;
1588 if (vflag)
1589 printf("B=%d ", elem.data.integer);
1590 length -= count;
1591 np += count;
1593 /* msgAuthoritativeEngineTime (INTEGER) */
1594 if ((count = asn1_parse(np, length, &elem)) < 0)
1595 return;
1596 if (elem.type != BE_INT) {
1597 fputs("[msgAuthoritativeEngineTime!=INT]", stdout);
1598 asn1_print(&elem);
1599 return;
1601 if (vflag)
1602 printf("T=%d ", elem.data.integer);
1603 length -= count;
1604 np += count;
1606 /* msgUserName (OCTET STRING) */
1607 if ((count = asn1_parse(np, length, &elem)) < 0)
1608 return;
1609 if (elem.type != BE_STR) {
1610 fputs("[msgUserName!=STR]", stdout);
1611 asn1_print(&elem);
1612 return;
1614 length -= count;
1615 np += count;
1617 printf("U=%.*s ", (int)elem.asnlen, elem.data.str);
1619 /* msgAuthenticationParameters (OCTET STRING) */
1620 if ((count = asn1_parse(np, length, &elem)) < 0)
1621 return;
1622 if (elem.type != BE_STR) {
1623 fputs("[msgAuthenticationParameters!=STR]", stdout);
1624 asn1_print(&elem);
1625 return;
1627 length -= count;
1628 np += count;
1630 /* msgPrivacyParameters (OCTET STRING) */
1631 if ((count = asn1_parse(np, length, &elem)) < 0)
1632 return;
1633 if (elem.type != BE_STR) {
1634 fputs("[msgPrivacyParameters!=STR]", stdout);
1635 asn1_print(&elem);
1636 return;
1638 length -= count;
1639 np += count;
1641 if ((u_int)count < length)
1642 printf("[%d extra after usm SEQ]", length - count);
1646 * Decode SNMPv3 Message Header (SNMPv3)
1648 static void
1649 v3msg_print(const u_char *np, u_int length)
1651 struct be elem;
1652 int count = 0;
1653 u_char flags;
1654 int model;
1655 const u_char *xnp = np;
1656 int xlength = length;
1658 /* Sequence */
1659 if ((count = asn1_parse(np, length, &elem)) < 0)
1660 return;
1661 if (elem.type != BE_SEQ) {
1662 fputs("[!message]", stdout);
1663 asn1_print(&elem);
1664 return;
1666 length = elem.asnlen;
1667 np = (u_char *)elem.data.raw;
1669 if (vflag) {
1670 fputs("{ ", stdout);
1673 /* msgID (INTEGER) */
1674 if ((count = asn1_parse(np, length, &elem)) < 0)
1675 return;
1676 if (elem.type != BE_INT) {
1677 fputs("[msgID!=INT]", stdout);
1678 asn1_print(&elem);
1679 return;
1681 length -= count;
1682 np += count;
1684 /* msgMaxSize (INTEGER) */
1685 if ((count = asn1_parse(np, length, &elem)) < 0)
1686 return;
1687 if (elem.type != BE_INT) {
1688 fputs("[msgMaxSize!=INT]", stdout);
1689 asn1_print(&elem);
1690 return;
1692 length -= count;
1693 np += count;
1695 /* msgFlags (OCTET STRING) */
1696 if ((count = asn1_parse(np, length, &elem)) < 0)
1697 return;
1698 if (elem.type != BE_STR) {
1699 fputs("[msgFlags!=STR]", stdout);
1700 asn1_print(&elem);
1701 return;
1703 if (elem.asnlen != 1) {
1704 printf("[msgFlags size %d]", elem.asnlen);
1705 return;
1707 flags = elem.data.str[0];
1708 if (flags != 0x00 && flags != 0x01 && flags != 0x03
1709 && flags != 0x04 && flags != 0x05 && flags != 0x07) {
1710 printf("[msgFlags=0x%02X]", flags);
1711 return;
1713 length -= count;
1714 np += count;
1716 fputs("F=", stdout);
1717 if (flags & 0x01) fputs("a", stdout);
1718 if (flags & 0x02) fputs("p", stdout);
1719 if (flags & 0x04) fputs("r", stdout);
1720 fputs(" ", stdout);
1722 /* msgSecurityModel (INTEGER) */
1723 if ((count = asn1_parse(np, length, &elem)) < 0)
1724 return;
1725 if (elem.type != BE_INT) {
1726 fputs("[msgSecurityModel!=INT]", stdout);
1727 asn1_print(&elem);
1728 return;
1730 model = elem.data.integer;
1731 length -= count;
1732 np += count;
1734 if ((u_int)count < length)
1735 printf("[%d extra after message SEQ]", length - count);
1737 if (vflag) {
1738 fputs("} ", stdout);
1741 if (model == 3) {
1742 if (vflag) {
1743 fputs("{ USM ", stdout);
1745 } else {
1746 printf("[security model %d]", model);
1747 return;
1750 np = xnp + (np - xnp);
1751 length = xlength - (np - xnp);
1753 /* msgSecurityParameters (OCTET STRING) */
1754 if ((count = asn1_parse(np, length, &elem)) < 0)
1755 return;
1756 if (elem.type != BE_STR) {
1757 fputs("[msgSecurityParameters!=STR]", stdout);
1758 asn1_print(&elem);
1759 return;
1761 length -= count;
1762 np += count;
1764 if (model == 3) {
1765 usm_print(elem.data.str, elem.asnlen);
1766 if (vflag) {
1767 fputs("} ", stdout);
1771 if (vflag) {
1772 fputs("{ ScopedPDU ", stdout);
1775 scopedpdu_print(np, length, 3);
1777 if (vflag) {
1778 fputs("} ", stdout);
1783 * Decode SNMP header and pass on to PDU printing routines
1785 void
1786 snmp_print(const u_char *np, u_int length)
1788 struct be elem;
1789 int count = 0;
1790 int version = 0;
1792 truncated = 0;
1794 /* truncated packet? */
1795 if (np + length > snapend) {
1796 truncated = 1;
1797 length = snapend - np;
1800 putchar(' ');
1802 /* initial Sequence */
1803 if ((count = asn1_parse(np, length, &elem)) < 0)
1804 return;
1805 if (elem.type != BE_SEQ) {
1806 fputs("[!init SEQ]", stdout);
1807 asn1_print(&elem);
1808 return;
1810 if ((u_int)count < length)
1811 printf("[%d extra after iSEQ]", length - count);
1812 /* descend */
1813 length = elem.asnlen;
1814 np = (u_char *)elem.data.raw;
1816 /* Version (INTEGER) */
1817 if ((count = asn1_parse(np, length, &elem)) < 0)
1818 return;
1819 if (elem.type != BE_INT) {
1820 fputs("[version!=INT]", stdout);
1821 asn1_print(&elem);
1822 return;
1825 switch (elem.data.integer) {
1826 case SNMP_VERSION_1:
1827 case SNMP_VERSION_2:
1828 case SNMP_VERSION_3:
1829 if (vflag)
1830 printf("{ %s ", SnmpVersion[elem.data.integer]);
1831 break;
1832 default:
1833 printf("[version = %d]", elem.data.integer);
1834 return;
1836 version = elem.data.integer;
1837 length -= count;
1838 np += count;
1840 switch (version) {
1841 case SNMP_VERSION_1:
1842 case SNMP_VERSION_2:
1843 community_print(np, length, version);
1844 break;
1845 case SNMP_VERSION_3:
1846 v3msg_print(np, length);
1847 break;
1848 default:
1849 printf("[version = %d]", elem.data.integer);
1850 break;
1853 if (vflag) {
1854 fputs("} ", stdout);