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
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
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
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)";
68 #include <tcpdump-stdinc.h>
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[] = {
99 "U-8","U-9","U-10","U-11", /* 8-11 */
100 "U-12","U-13","U-14","U-15", /* 12-15 */
107 * Application-wide ASN.1 types from the Internet SMI and their tags
109 const char *Application[] = {
126 * Context-specific ASN.1 types for the SNMP PDUs and their tags
128 const char *Context[] = {
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[] = {
160 #define NOSUCHOBJECT 0
162 #define NOSUCHINSTANCE 1
164 #define ENDOFMIBVIEW 2
168 * Private ASN.1 types
169 * The Internet SMI does not specify any
171 const char *Private[] = {
176 * error-status values for any SNMP PDU
178 const char *ErrorStatus[] = {
192 "resourceUnavailable",
195 "authorizationError",
199 #define DECODE_ErrorStatus(e) \
200 ( e >= 0 && (size_t)e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
202 : (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf))
205 * generic-trap values in the SNMP Trap-PDU
207 const char *GenericTrap[] = {
212 "authenticationFailure",
215 #define GT_ENTERPRISE 6
217 #define DECODE_GenericTrap(t) \
218 ( t >= 0 && (size_t)t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
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
227 #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
233 defineCLASS(Universal),
235 defineCLASS(Application),
236 #define APPLICATION 1
237 defineCLASS(Context),
239 defineCLASS(Private),
241 defineCLASS(Exceptions),
246 * defined forms for ASN.1 types
248 const char *Form[] = {
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.
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 */
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.
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.
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[] = {
287 /* .iso.org.dod.internet.mgmt.mib */
288 { "", &_mib_obj, "\53\6\1\2\1" },
290 #ifndef NO_ABREV_ENTER
291 /* .iso.org.dod.internet.private.enterprises */
292 { "E:", &_enterprises_obj, "\53\6\1\4\1" },
294 #ifndef NO_ABREV_EXPERI
295 /* .iso.org.dod.internet.experimental */
296 { "X:", &_experimental_obj, "\53\6\1\3" },
298 #ifndef NO_ABBREV_SNMPMODS
299 /* .iso.org.dod.internet.snmpV2.snmpModules */
300 { "S:", &_snmpModules_obj, "\53\6\1\6\3" },
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) \
313 if ((o) == objp->oid) \
315 } while ((objp = objp->next) != NULL); \
318 printf(suppressdot?"%s":".%s", objp->desc); \
319 objp = objp->child; \
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.
341 u_char form, class; /* tag info */
352 #define BE_INETADDR 8
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[] = {
365 #define SNMP_VERSION_1 0
367 #define SNMP_VERSION_2 1
369 #define SNMP_VERSION_2U 2
371 #define SNMP_VERSION_3 3
375 * Defaults for SNMP PDU components
377 #define DEF_COMMUNITY "public"
380 * constants for ASN.1 decoding
383 #define ASNLEN_INETADDR 4
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".
406 asn1_parse(register const u_char *p, u_int len, struct be *elem)
408 u_char form, class, id;
414 fputs("[nothing to parse]", stdout);
420 * it would be nice to use a bit field, but you can't depend on them.
421 * +---+---+---+---+---+---+---+---+
423 * +---+---+---+---+---+---+---+---+
426 id = *p & ASN_ID_BITS; /* lower 5 bits, range 00-1f */
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 */
432 form = (u_char)(*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
433 class = (u_char)(*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
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++) {
453 fputs("[Xtagfield?]", stdout);
457 id = (id << 7) | (*p & ~ASN_BIT8);
460 fputs("[Xtagfield?]", stdout);
464 elem->id = id = (id << 7) | *p;
470 fputs("[no asnlen]", stdout);
476 if (elem->asnlen & ASN_BIT8) {
477 u_int32_t noct = elem->asnlen % ASN_BIT8;
480 printf("[asnlen? %d<%d]", len, 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);
491 if (form >= sizeof(Form)/sizeof(Form[0])) {
492 printf("[form?%d]", form);
495 if (class >= sizeof(Class)/sizeof(Class[0])) {
496 printf("[class?%c/%d]", *Form[form], class);
499 if ((int)id >= Class[class].numIDs) {
500 printf("[id?%c/%s/%d]", *Form[form], Class[class].name, id);
515 register int32_t data;
519 TCHECK2(*p, elem->asnlen);
520 if (*p & ASN_BIT8) /* negative */
522 for (i = elem->asnlen; i-- > 0; p++)
523 data = (data << ASN_SHIFT8) | *p;
524 elem->data.integer = data;
530 elem->data.raw = (caddr_t)p;
534 elem->type = BE_NULL;
535 elem->data.raw = NULL;
539 elem->type = BE_OCTET;
540 elem->data.raw = (caddr_t)p;
542 Class[class].Id[id]);
550 elem->type = BE_INETADDR;
551 elem->data.raw = (caddr_t)p;
557 register u_int32_t data;
558 TCHECK2(*p, elem->asnlen);
561 for (i = elem->asnlen; i-- > 0; p++)
562 data = (data << 8) + *p;
563 elem->data.uns = data;
568 register u_int32_t high, low;
569 TCHECK2(*p, elem->asnlen);
570 elem->type = BE_UNS64;
572 for (i = elem->asnlen; i-- > 0; p++) {
574 ((low & 0xFF000000) >> 24);
575 low = (low << 8) | *p;
577 elem->data.uns64.high = high;
578 elem->data.uns64.low = low;
583 elem->type = BE_OCTET;
584 elem->data.raw = (caddr_t)p;
586 Class[class].Id[id]);
594 elem->type = BE_NOSUCHOBJECT;
595 elem->data.raw = NULL;
599 elem->type = BE_NOSUCHINST;
600 elem->data.raw = NULL;
604 elem->type = BE_ENDOFMIBVIEW;
605 elem->data.raw = NULL;
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;
626 elem->data.raw = (caddr_t)p;
630 elem->type = BE_OCTET;
631 elem->data.raw = (caddr_t)p;
632 printf("C/U/%s", Class[class].Id[id]);
639 elem->data.raw = (caddr_t)p;
643 elem->type = BE_OCTET;
644 elem->data.raw = (caddr_t)p;
646 Class[class].name, Class[class].Id[id]);
653 return elem->asnlen + hdr;
656 fputs("[|snmp]", stdout);
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
666 asn1_print(struct be *elem)
668 u_char *p = (u_char *)elem->data.raw;
669 u_int32_t asnlen = elem->asnlen;
672 switch (elem->type) {
676 for (i = asnlen; i-- > 0; p++)
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++) {
691 if (memcmp(a->oid, (char *)p, a_len) == 0) {
692 objp = a->node->child;
695 fputs(a->prefix, stdout);
702 for (; !sflag && i-- > 0; p++) {
704 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
705 if (*p & ASN_LONGLEN)
709 * first subitem encodes two items with 1st*OIDMUX+2nd
710 * (see X.690:1997 clause 8.19 for the details)
731 printf("%d", elem->data.integer);
735 printf("%u", elem->data.uns);
738 case BE_UNS64: { /* idea borrowed from by Marshall Rose */
741 char *cpf, *cpl, last[6], first[30];
742 if (elem->data.uns64.high == 0) {
743 printf("%u", elem->data.uns64.low);
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?*/
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);
760 snprintf(first, sizeof(first), "%f", d);
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;
767 j = carry + (*cpf - '0') + (*cpl - '0');
776 fputs(first, stdout);
781 register int printable = 1, first = 1;
782 const u_char *p = elem->data.str;
784 for (i = asnlen; printable && i-- > 0; p++)
785 printable = isprint(*p) || isspace(*p);
789 if (fn_printn(p, asnlen, snapend)) {
795 for (i = asnlen; i-- > 0; p++) {
796 printf(first ? "%.2x" : "_%.2x", *p);
803 printf("Seq(%u)", elem->asnlen);
807 if (asnlen != ASNLEN_INETADDR)
808 printf("[inetaddr len!=%d]", ASNLEN_INETADDR);
810 for (i = asnlen; i-- != 0; p++) {
811 printf((i == asnlen-1) ? "%u" : ".%u", *p);
815 case BE_NOSUCHOBJECT:
817 case BE_ENDOFMIBVIEW:
818 printf("[%s]", Class[EXCEPTIONS].Id[elem->id]);
823 Class[CONTEXT].Id[elem->id], elem->asnlen);
827 fputs("[BE_ANY!?]", stdout);
831 fputs("[be!?]", stdout);
837 fputs("[|snmp]", stdout);
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
849 * This is not currently used.
852 asn1_decode(u_char *p, u_int length)
857 while (i >= 0 && length > 0) {
858 i = asn1_parse(p, length, &elem);
861 if (asn1_print(&elem) < 0)
863 if (elem.type == BE_SEQ || elem.type == BE_PDU) {
865 asn1_decode(elem.data.raw, elem.asnlen);
878 SmiBasetype basetype;
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 }
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++) {
908 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
909 if (*p & ASN_LONGLEN)
913 * first subitem encodes two items with 1st*OIDMUX+2nd
914 * (see X.690:1997 clause 8.19 for the details)
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;
933 fputs("[|snmp]", stdout);
937 static int smi_check_type(SmiBasetype basetype, int be)
941 for (i = 0; smi2betab[i].basetype != SMI_BASETYPE_UNKNOWN; i++) {
942 if (smi2betab[i].basetype == basetype && smi2betab[i].be == be) {
950 static int smi_check_a_range(SmiType *smiType, SmiRange *smiRange,
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);
962 ok = (elem->asnlen >= smiRange->minValue.value.unsigned32
963 && elem->asnlen <= smiRange->maxValue.value.unsigned32);
967 case SMI_BASETYPE_INTEGER32:
968 ok = (elem->data.integer >= smiRange->minValue.value.integer32
969 && elem->data.integer <= smiRange->maxValue.value.integer32);
972 case SMI_BASETYPE_UNSIGNED32:
973 ok = (elem->data.uns >= smiRange->minValue.value.unsigned32
974 && elem->data.uns <= smiRange->maxValue.value.unsigned32);
977 case SMI_BASETYPE_UNSIGNED64:
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:
1000 static int smi_check_range(SmiType *smiType, struct be *elem)
1005 for (smiRange = smiGetFirstRange(smiType);
1007 smiRange = smiGetNextRange(smiRange)) {
1009 ok = smi_check_a_range(smiType, smiRange, elem);
1017 SmiType *parentType;
1018 parentType = smiGetParentType(smiType);
1020 ok = smi_check_range(parentType, elem);
1027 static SmiNode *smi_print_variable(struct be *elem, int *status)
1029 unsigned int oid[128], oidlen;
1030 SmiNode *smiNode = NULL;
1033 *status = smi_decode_oid(elem, oid, sizeof(oid)/sizeof(unsigned int),
1037 smiNode = smiGetNodeByOID(oidlen, oid);
1039 *status = asn1_print(elem);
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]);
1057 smi_print_value(SmiNode *smiNode, u_char pduid, struct be *elem)
1059 unsigned int i, oid[128], oidlen;
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);
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) {
1115 if (smiType->basetype == SMI_BASETYPE_BITS) {
1116 /* print bit labels */
1118 smi_decode_oid(elem, oid,
1119 sizeof(oid)/sizeof(unsigned int),
1121 smiNode = smiGetNodeByOID(oidlen, oid);
1124 fputs(smiGetNodeModule(smiNode)->name, stdout);
1125 fputs("::", stdout);
1127 fputs(smiNode->name, stdout);
1128 if (smiNode->oidlen < oidlen) {
1129 for (i = smiNode->oidlen;
1131 printf(".%u", oid[i]);
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);
1157 return asn1_print(elem);
1164 * General SNMP header
1166 * version INTEGER {version-1(0)},
1167 * community OCTET STRING,
1170 * PDUs for all but Trap: (see rfc1157 from page 15 on)
1172 * request-id INTEGER,
1173 * error-status INTEGER,
1174 * error-index INTEGER,
1175 * varbindlist SEQUENCE OF
1183 * enterprise OBJECT IDENTIFIER,
1184 * agent-addr NetworkAddress,
1185 * generic-trap INTEGER,
1186 * specific-trap INTEGER,
1187 * time-stamp TimeTicks,
1188 * varbindlist SEQUENCE OF
1197 * Decode SNMP varBind
1200 varbind_print(u_char pduid, const u_char *np, u_int length)
1205 SmiNode *smiNode = NULL;
1209 /* Sequence of varBind */
1210 if ((count = asn1_parse(np, length, &elem)) < 0)
1212 if (elem.type != BE_SEQ) {
1213 fputs("[!SEQ of varbind]", stdout);
1217 if ((u_int)count < length)
1218 printf("[%d extra after SEQ of varbind]", length - count);
1220 length = elem.asnlen;
1221 np = (u_char *)elem.data.raw;
1223 for (ind = 1; length > 0; ind++) {
1224 const u_char *vbend;
1230 if ((count = asn1_parse(np, length, &elem)) < 0)
1232 if (elem.type != BE_SEQ) {
1233 fputs("[!varbind]", stdout);
1238 vblength = length - count;
1240 length = elem.asnlen;
1241 np = (u_char *)elem.data.raw;
1244 if ((count = asn1_parse(np, length, &elem)) < 0)
1246 if (elem.type != BE_OID) {
1247 fputs("[objName!=OID]", stdout);
1252 smiNode = smi_print_variable(&elem, &status);
1254 status = asn1_print(&elem);
1261 if (pduid != GETREQ && pduid != GETNEXTREQ
1262 && pduid != GETBULKREQ)
1266 if ((count = asn1_parse(np, length, &elem)) < 0)
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)
1276 if (elem.type != BE_NULL) {
1278 status = smi_print_value(smiNode, pduid, &elem);
1280 status = asn1_print(&elem);
1292 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
1293 * GetBulk, Inform, V2Trap, and Report
1296 snmppdu_print(u_short pduid, const u_char *np, u_int length)
1299 int count = 0, error;
1301 /* reqId (Integer) */
1302 if ((count = asn1_parse(np, length, &elem)) < 0)
1304 if (elem.type != BE_INT) {
1305 fputs("[reqId!=INT]", stdout);
1310 printf("R=%d ", elem.data.integer);
1314 /* errorStatus (Integer) */
1315 if ((count = asn1_parse(np, length, &elem)) < 0)
1317 if (elem.type != BE_INT) {
1318 fputs("[errorStatus!=INT]", stdout);
1323 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1324 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1325 && elem.data.integer != 0) {
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) {
1333 printf(" %s", DECODE_ErrorStatus(elem.data.integer));
1334 error = elem.data.integer;
1339 /* errorIndex (Integer) */
1340 if ((count = asn1_parse(np, length, &elem)) < 0)
1342 if (elem.type != BE_INT) {
1343 fputs("[errorIndex!=INT]", stdout);
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) {
1355 printf("[errorIndex(%d) w/o errorStatus]",
1358 printf("@%d", elem.data.integer);
1359 error = elem.data.integer;
1362 fputs("[errorIndex==0]", stdout);
1368 varbind_print(pduid, np, length);
1373 * Decode SNMP Trap PDU
1376 trappdu_print(const u_char *np, u_int length)
1379 int count = 0, generic;
1383 /* enterprise (oid) */
1384 if ((count = asn1_parse(np, length, &elem)) < 0)
1386 if (elem.type != BE_OID) {
1387 fputs("[enterprise!=OID]", stdout);
1391 if (asn1_print(&elem) < 0)
1398 /* agent-addr (inetaddr) */
1399 if ((count = asn1_parse(np, length, &elem)) < 0)
1401 if (elem.type != BE_INETADDR) {
1402 fputs("[agent-addr!=INETADDR]", stdout);
1406 if (asn1_print(&elem) < 0)
1411 /* generic-trap (Integer) */
1412 if ((count = asn1_parse(np, length, &elem)) < 0)
1414 if (elem.type != BE_INT) {
1415 fputs("[generic-trap!=INT]", stdout);
1419 generic = elem.data.integer;
1422 printf(" %s", DECODE_GenericTrap(generic));
1427 /* specific-trap (Integer) */
1428 if ((count = asn1_parse(np, length, &elem)) < 0)
1430 if (elem.type != BE_INT) {
1431 fputs("[specific-trap!=INT]", stdout);
1435 if (generic != GT_ENTERPRISE) {
1436 if (elem.data.integer != 0)
1437 printf("[specific-trap(%d)!=0]", elem.data.integer);
1439 printf(" s=%d", elem.data.integer);
1445 /* time-stamp (TimeTicks) */
1446 if ((count = asn1_parse(np, length, &elem)) < 0)
1448 if (elem.type != BE_UNS) { /* XXX */
1449 fputs("[time-stamp!=TIMETICKS]", stdout);
1453 if (asn1_print(&elem) < 0)
1458 varbind_print (TRAP, np, length);
1463 * Decode arbitrary SNMP PDUs.
1466 pdu_print(const u_char *np, u_int length, int version)
1472 if ((count = asn1_parse(np, length, &pdu)) < 0)
1474 if (pdu.type != BE_PDU) {
1475 fputs("[no PDU]", stdout);
1478 if ((u_int)count < length)
1479 printf("[%d extra after PDU]", length - count);
1481 fputs("{ ", stdout);
1483 if (asn1_print(&pdu) < 0)
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]");
1497 if (version == SNMP_VERSION_2 && pdu.id == TRAP) {
1498 printf("[v1 PDU in v2 message]");
1504 trappdu_print(np, length);
1514 snmppdu_print(pdu.id, np, length);
1519 fputs(" } ", stdout);
1524 * Decode a scoped SNMP PDU.
1527 scopedpdu_print(const u_char *np, u_int length, int version)
1533 if ((count = asn1_parse(np, length, &elem)) < 0)
1535 if (elem.type != BE_SEQ) {
1536 fputs("[!scoped PDU]", stdout);
1540 length = elem.asnlen;
1541 np = (u_char *)elem.data.raw;
1543 /* contextEngineID (OCTET STRING) */
1544 if ((count = asn1_parse(np, length, &elem)) < 0)
1546 if (elem.type != BE_STR) {
1547 fputs("[contextEngineID!=STR]", stdout);
1554 fputs("E= ", stdout);
1555 for (i = 0; i < (int)elem.asnlen; i++) {
1556 printf("0x%02X", elem.data.str[i]);
1560 /* contextName (OCTET STRING) */
1561 if ((count = asn1_parse(np, length, &elem)) < 0)
1563 if (elem.type != BE_STR) {
1564 fputs("[contextName!=STR]", stdout);
1571 printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
1573 pdu_print(np, length, version);
1577 * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
1580 community_print(const u_char *np, u_int length, int version)
1585 /* Community (String) */
1586 if ((count = asn1_parse(np, length, &elem)) < 0)
1588 if (elem.type != BE_STR) {
1589 fputs("[comm!=STR]", stdout);
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))
1598 printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
1602 pdu_print(np, length, version);
1606 * Decode SNMPv3 User-based Security Message Header (SNMPv3)
1609 usm_print(const u_char *np, u_int length)
1615 if ((count = asn1_parse(np, length, &elem)) < 0)
1617 if (elem.type != BE_SEQ) {
1618 fputs("[!usm]", stdout);
1622 length = elem.asnlen;
1623 np = (u_char *)elem.data.raw;
1625 /* msgAuthoritativeEngineID (OCTET STRING) */
1626 if ((count = asn1_parse(np, length, &elem)) < 0)
1628 if (elem.type != BE_STR) {
1629 fputs("[msgAuthoritativeEngineID!=STR]", stdout);
1636 /* msgAuthoritativeEngineBoots (INTEGER) */
1637 if ((count = asn1_parse(np, length, &elem)) < 0)
1639 if (elem.type != BE_INT) {
1640 fputs("[msgAuthoritativeEngineBoots!=INT]", stdout);
1645 printf("B=%d ", elem.data.integer);
1649 /* msgAuthoritativeEngineTime (INTEGER) */
1650 if ((count = asn1_parse(np, length, &elem)) < 0)
1652 if (elem.type != BE_INT) {
1653 fputs("[msgAuthoritativeEngineTime!=INT]", stdout);
1658 printf("T=%d ", elem.data.integer);
1662 /* msgUserName (OCTET STRING) */
1663 if ((count = asn1_parse(np, length, &elem)) < 0)
1665 if (elem.type != BE_STR) {
1666 fputs("[msgUserName!=STR]", stdout);
1673 printf("U=%.*s ", (int)elem.asnlen, elem.data.str);
1675 /* msgAuthenticationParameters (OCTET STRING) */
1676 if ((count = asn1_parse(np, length, &elem)) < 0)
1678 if (elem.type != BE_STR) {
1679 fputs("[msgAuthenticationParameters!=STR]", stdout);
1686 /* msgPrivacyParameters (OCTET STRING) */
1687 if ((count = asn1_parse(np, length, &elem)) < 0)
1689 if (elem.type != BE_STR) {
1690 fputs("[msgPrivacyParameters!=STR]", stdout);
1697 if ((u_int)count < length)
1698 printf("[%d extra after usm SEQ]", length - count);
1702 * Decode SNMPv3 Message Header (SNMPv3)
1705 v3msg_print(const u_char *np, u_int length)
1711 const u_char *xnp = np;
1712 int xlength = length;
1715 if ((count = asn1_parse(np, length, &elem)) < 0)
1717 if (elem.type != BE_SEQ) {
1718 fputs("[!message]", stdout);
1722 length = elem.asnlen;
1723 np = (u_char *)elem.data.raw;
1726 fputs("{ ", stdout);
1729 /* msgID (INTEGER) */
1730 if ((count = asn1_parse(np, length, &elem)) < 0)
1732 if (elem.type != BE_INT) {
1733 fputs("[msgID!=INT]", stdout);
1740 /* msgMaxSize (INTEGER) */
1741 if ((count = asn1_parse(np, length, &elem)) < 0)
1743 if (elem.type != BE_INT) {
1744 fputs("[msgMaxSize!=INT]", stdout);
1751 /* msgFlags (OCTET STRING) */
1752 if ((count = asn1_parse(np, length, &elem)) < 0)
1754 if (elem.type != BE_STR) {
1755 fputs("[msgFlags!=STR]", stdout);
1759 if (elem.asnlen != 1) {
1760 printf("[msgFlags size %d]", elem.asnlen);
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);
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);
1778 /* msgSecurityModel (INTEGER) */
1779 if ((count = asn1_parse(np, length, &elem)) < 0)
1781 if (elem.type != BE_INT) {
1782 fputs("[msgSecurityModel!=INT]", stdout);
1786 model = elem.data.integer;
1790 if ((u_int)count < length)
1791 printf("[%d extra after message SEQ]", length - count);
1794 fputs("} ", stdout);
1799 fputs("{ USM ", stdout);
1802 printf("[security model %d]", model);
1806 np = xnp + (np - xnp);
1807 length = xlength - (np - xnp);
1809 /* msgSecurityParameters (OCTET STRING) */
1810 if ((count = asn1_parse(np, length, &elem)) < 0)
1812 if (elem.type != BE_STR) {
1813 fputs("[msgSecurityParameters!=STR]", stdout);
1821 usm_print(elem.data.str, elem.asnlen);
1823 fputs("} ", stdout);
1828 fputs("{ ScopedPDU ", stdout);
1831 scopedpdu_print(np, length, 3);
1834 fputs("} ", stdout);
1839 * Decode SNMP header and pass on to PDU printing routines
1842 snmp_print(const u_char *np, u_int length)
1850 /* initial Sequence */
1851 if ((count = asn1_parse(np, length, &elem)) < 0)
1853 if (elem.type != BE_SEQ) {
1854 fputs("[!init SEQ]", stdout);
1858 if ((u_int)count < length)
1859 printf("[%d extra after iSEQ]", length - count);
1861 length = elem.asnlen;
1862 np = (u_char *)elem.data.raw;
1864 /* Version (INTEGER) */
1865 if ((count = asn1_parse(np, length, &elem)) < 0)
1867 if (elem.type != BE_INT) {
1868 fputs("[version!=INT]", stdout);
1873 switch (elem.data.integer) {
1874 case SNMP_VERSION_1:
1875 case SNMP_VERSION_2:
1876 case SNMP_VERSION_3:
1878 printf("{ %s ", SnmpVersion[elem.data.integer]);
1881 printf("[version = %d]", elem.data.integer);
1884 version = elem.data.integer;
1889 case SNMP_VERSION_1:
1890 case SNMP_VERSION_2:
1891 community_print(np, length, version);
1893 case SNMP_VERSION_3:
1894 v3msg_print(np, length);
1897 printf("[version = %d]", elem.data.integer);
1902 fputs("} ", stdout);