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