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
59 /* \summary: Simple Network Management Protocol (SNMP) printer */
65 #include <netdissect-stdinc.h>
74 #include "netdissect.h"
76 #undef OPAQUE /* defined in <wingdi.h> */
78 static const char tstr[] = "[|snmp]";
81 * Universal ASN.1 types
82 * (we only care about the tag values for those allowed in the Internet SMI)
84 static const char *Universal[] = {
97 "U-8","U-9","U-10","U-11", /* 8-11 */
98 "U-12","U-13","U-14","U-15", /* 12-15 */
105 * Application-wide ASN.1 types from the Internet SMI and their tags
107 static const char *Application[] = {
124 * Context-specific ASN.1 types for the SNMP PDUs and their tags
126 static const char *Context[] = {
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 static const char *Exceptions[] = {
158 #define NOSUCHOBJECT 0
160 #define NOSUCHINSTANCE 1
162 #define ENDOFMIBVIEW 2
166 * Private ASN.1 types
167 * The Internet SMI does not specify any
169 static const char *Private[] = {
174 * error-status values for any SNMP PDU
176 static const char *ErrorStatus[] = {
190 "resourceUnavailable",
193 "authorizationError",
197 #define DECODE_ErrorStatus(e) \
198 ( e >= 0 && (size_t)e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
200 : (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf))
203 * generic-trap values in the SNMP Trap-PDU
205 static const char *GenericTrap[] = {
210 "authenticationFailure",
213 #define GT_ENTERPRISE 6
215 #define DECODE_GenericTrap(t) \
216 ( t >= 0 && (size_t)t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
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
225 #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
226 static const struct {
231 defineCLASS(Universal),
233 defineCLASS(Application),
234 #define APPLICATION 1
235 defineCLASS(Context),
237 defineCLASS(Private),
239 defineCLASS(Exceptions),
244 * defined forms for ASN.1 types
246 static const char *Form[] = {
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.
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 */
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.
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 #define OID_FIRST_OCTET(x, y) (((x)*40) + (y)) /* X.690 8.19.4 */
282 static const uint8_t mib_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 2, 1 };
284 #ifndef NO_ABREV_ENTER
285 static const uint8_t enterprises_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 4, 1 };
287 #ifndef NO_ABREV_EXPERI
288 static const uint8_t experimental_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 3 };
290 #ifndef NO_ABBREV_SNMPMODS
291 static const uint8_t snmpModules_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 6, 3 };
294 #define OBJ_ABBREV_ENTRY(prefix, obj) \
295 { prefix, &_ ## obj ## _obj, obj ## _oid, sizeof (obj ## _oid) }
296 static const struct obj_abrev {
297 const char *prefix; /* prefix for this abrev */
298 struct obj *node; /* pointer into object table */
299 const uint8_t *oid; /* ASN.1 encoded OID */
300 size_t oid_len; /* length of OID */
301 } obj_abrev_list[] = {
303 /* .iso.org.dod.internet.mgmt.mib */
304 OBJ_ABBREV_ENTRY("", mib),
306 #ifndef NO_ABREV_ENTER
307 /* .iso.org.dod.internet.private.enterprises */
308 OBJ_ABBREV_ENTRY("E:", enterprises),
310 #ifndef NO_ABREV_EXPERI
311 /* .iso.org.dod.internet.experimental */
312 OBJ_ABBREV_ENTRY("X:", experimental),
314 #ifndef NO_ABBREV_SNMPMODS
315 /* .iso.org.dod.internet.snmpV2.snmpModules */
316 OBJ_ABBREV_ENTRY("S:", snmpModules),
322 * This is used in the OID print routine to walk down the object tree
323 * rooted at `mibroot'.
325 #define OBJ_PRINT(o, suppressdot) \
329 if ((o) == objp->oid) \
331 } while ((objp = objp->next) != NULL); \
334 ND_PRINT((ndo, suppressdot?"%s":".%s", objp->desc)); \
335 objp = objp->child; \
337 ND_PRINT((ndo, suppressdot?"%u":".%u", (o))); \
341 * This is the definition for the Any-Data-Type storage used purely for
342 * temporary internal representation while decoding an ASN.1 data stream.
354 u_char form, class; /* tag info */
365 #define BE_INETADDR 8
368 #define BE_NOSUCHOBJECT 128
369 #define BE_NOSUCHINST 129
370 #define BE_ENDOFMIBVIEW 130
374 * SNMP versions recognized by this module
376 static const char *SnmpVersion[] = {
378 #define SNMP_VERSION_1 0
380 #define SNMP_VERSION_2 1
382 #define SNMP_VERSION_2U 2
384 #define SNMP_VERSION_3 3
388 * Defaults for SNMP PDU components
390 #define DEF_COMMUNITY "public"
393 * constants for ASN.1 decoding
396 #define ASNLEN_INETADDR 4
399 #define ASN_BIT8 0x80
400 #define ASN_LONGLEN 0x80
402 #define ASN_ID_BITS 0x1f
403 #define ASN_FORM_BITS 0x20
404 #define ASN_FORM_SHIFT 5
405 #define ASN_CLASS_BITS 0xc0
406 #define ASN_CLASS_SHIFT 6
408 #define ASN_ID_EXT 0x1f /* extension ID in tag field */
411 * This decodes the next ASN.1 object in the stream pointed to by "p"
412 * (and of real-length "len") and stores the intermediate data in the
413 * provided BE object.
415 * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
416 * O/w, this returns the number of bytes parsed from "p".
419 asn1_parse(netdissect_options *ndo,
420 register const u_char *p, u_int len, struct be *elem)
422 u_char form, class, id;
428 ND_PRINT((ndo, "[nothing to parse]"));
434 * it would be nice to use a bit field, but you can't depend on them.
435 * +---+---+---+---+---+---+---+---+
437 * +---+---+---+---+---+---+---+---+
440 id = *p & ASN_ID_BITS; /* lower 5 bits, range 00-1f */
442 form = (*p & 0xe0) >> 5; /* move upper 3 bits to lower 3 */
443 class = form >> 1; /* bits 7&6 -> bits 1&0, range 0-3 */
444 form &= 0x1; /* bit 5 -> bit 0, range 0-1 */
446 form = (u_char)(*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
447 class = (u_char)(*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
453 /* extended tag field */
454 if (id == ASN_ID_EXT) {
456 * The ID follows, as a sequence of octets with the
457 * 8th bit set and the remaining 7 bits being
458 * the next 7 bits of the value, terminated with
459 * an octet with the 8th bit not set.
461 * First, assemble all the octets with the 8th
462 * bit set. XXX - this doesn't handle a value
463 * that won't fit in 32 bits.
467 while (*p & ASN_BIT8) {
469 ND_PRINT((ndo, "[Xtagfield?]"));
472 id = (id << 7) | (*p & ~ASN_BIT8);
479 ND_PRINT((ndo, "[Xtagfield?]"));
483 elem->id = id = (id << 7) | *p;
489 ND_PRINT((ndo, "[no asnlen]"));
495 if (elem->asnlen & ASN_BIT8) {
496 uint32_t noct = elem->asnlen % ASN_BIT8;
499 ND_PRINT((ndo, "[asnlen? %d<%d]", len, noct));
502 ND_TCHECK2(*p, noct);
503 for (; noct-- > 0; len--, hdr++)
504 elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++;
506 if (len < elem->asnlen) {
507 ND_PRINT((ndo, "[len%d<asnlen%u]", len, elem->asnlen));
510 if (form >= sizeof(Form)/sizeof(Form[0])) {
511 ND_PRINT((ndo, "[form?%d]", form));
514 if (class >= sizeof(Class)/sizeof(Class[0])) {
515 ND_PRINT((ndo, "[class?%c/%d]", *Form[form], class));
518 if ((int)id >= Class[class].numIDs) {
519 ND_PRINT((ndo, "[id?%c/%s/%d]", *Form[form], Class[class].name, id));
522 ND_TCHECK2(*p, elem->asnlen);
535 register int32_t data;
539 if (elem->asnlen == 0) {
540 ND_PRINT((ndo, "[asnlen=0]"));
543 if (*p & ASN_BIT8) /* negative */
545 for (i = elem->asnlen; i-- > 0; p++)
546 data = (data << ASN_SHIFT8) | *p;
547 elem->data.integer = data;
553 elem->data.raw = (const uint8_t *)p;
557 elem->type = BE_NULL;
558 elem->data.raw = NULL;
562 elem->type = BE_OCTET;
563 elem->data.raw = (const uint8_t *)p;
564 ND_PRINT((ndo, "[P/U/%s]", Class[class].Id[id]));
572 elem->type = BE_INETADDR;
573 elem->data.raw = (const uint8_t *)p;
579 register uint32_t data;
582 for (i = elem->asnlen; i-- > 0; p++)
583 data = (data << 8) + *p;
584 elem->data.uns = data;
589 register uint64_t data64;
590 elem->type = BE_UNS64;
592 for (i = elem->asnlen; i-- > 0; p++)
593 data64 = (data64 << 8) + *p;
594 elem->data.uns64 = data64;
599 elem->type = BE_OCTET;
600 elem->data.raw = (const uint8_t *)p;
601 ND_PRINT((ndo, "[P/A/%s]",
602 Class[class].Id[id]));
610 elem->type = BE_NOSUCHOBJECT;
611 elem->data.raw = NULL;
615 elem->type = BE_NOSUCHINST;
616 elem->data.raw = NULL;
620 elem->type = BE_ENDOFMIBVIEW;
621 elem->data.raw = NULL;
627 ND_PRINT((ndo, "[P/%s/%s]", Class[class].name, Class[class].Id[id]));
628 elem->type = BE_OCTET;
629 elem->data.raw = (const uint8_t *)p;
640 elem->data.raw = (const uint8_t *)p;
644 elem->type = BE_OCTET;
645 elem->data.raw = (const uint8_t *)p;
646 ND_PRINT((ndo, "C/U/%s", Class[class].Id[id]));
653 elem->data.raw = (const uint8_t *)p;
657 elem->type = BE_OCTET;
658 elem->data.raw = (const uint8_t *)p;
659 ND_PRINT((ndo, "C/%s/%s", Class[class].name, Class[class].Id[id]));
666 return elem->asnlen + hdr;
669 ND_PRINT((ndo, "%s", tstr));
674 asn1_print_octets(netdissect_options *ndo, struct be *elem)
676 const u_char *p = (const u_char *)elem->data.raw;
677 uint32_t asnlen = elem->asnlen;
680 ND_TCHECK2(*p, asnlen);
681 for (i = asnlen; i-- > 0; p++)
682 ND_PRINT((ndo, "_%.2x", *p));
686 ND_PRINT((ndo, "%s", tstr));
691 asn1_print_string(netdissect_options *ndo, struct be *elem)
693 register int printable = 1, first = 1;
695 uint32_t asnlen = elem->asnlen;
699 ND_TCHECK2(*p, asnlen);
700 for (i = asnlen; printable && i-- > 0; p++)
701 printable = ND_ISPRINT(*p);
704 ND_PRINT((ndo, "\""));
705 if (fn_printn(ndo, p, asnlen, ndo->ndo_snapend)) {
706 ND_PRINT((ndo, "\""));
709 ND_PRINT((ndo, "\""));
711 for (i = asnlen; i-- > 0; p++) {
712 ND_PRINT((ndo, first ? "%.2x" : "_%.2x", *p));
719 ND_PRINT((ndo, "%s", tstr));
724 * Display the ASN.1 object represented by the BE object.
725 * This used to be an integral part of asn1_parse() before the intermediate
729 asn1_print(netdissect_options *ndo,
733 uint32_t asnlen = elem->asnlen;
736 switch (elem->type) {
739 if (asn1_print_octets(ndo, elem) == -1)
747 int o = 0, first = -1;
749 p = (const u_char *)elem->data.raw;
751 if (!ndo->ndo_nflag && asnlen > 2) {
752 const struct obj_abrev *a = &obj_abrev_list[0];
753 for (; a->node; a++) {
756 if (!ND_TTEST2(*p, a->oid_len))
758 if (memcmp(a->oid, p, a->oid_len) == 0) {
759 objp = a->node->child;
762 ND_PRINT((ndo, "%s", a->prefix));
769 for (; i-- > 0; p++) {
771 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
772 if (*p & ASN_LONGLEN)
776 * first subitem encodes two items with
778 * (see X.690:1997 clause 8.19 for the details)
799 ND_PRINT((ndo, "%d", elem->data.integer));
803 ND_PRINT((ndo, "%u", elem->data.uns));
807 ND_PRINT((ndo, "%" PRIu64, elem->data.uns64));
811 if (asn1_print_string(ndo, elem) == -1)
816 ND_PRINT((ndo, "Seq(%u)", elem->asnlen));
820 if (asnlen != ASNLEN_INETADDR)
821 ND_PRINT((ndo, "[inetaddr len!=%d]", ASNLEN_INETADDR));
822 p = (const u_char *)elem->data.raw;
823 ND_TCHECK2(*p, asnlen);
824 for (i = asnlen; i-- != 0; p++) {
825 ND_PRINT((ndo, (i == asnlen-1) ? "%u" : ".%u", *p));
829 case BE_NOSUCHOBJECT:
831 case BE_ENDOFMIBVIEW:
832 ND_PRINT((ndo, "[%s]", Class[EXCEPTIONS].Id[elem->id]));
836 ND_PRINT((ndo, "%s(%u)", Class[CONTEXT].Id[elem->id], elem->asnlen));
840 ND_PRINT((ndo, "[BE_ANY!?]"));
844 ND_PRINT((ndo, "[be!?]"));
850 ND_PRINT((ndo, "%s", tstr));
856 * This is a brute force ASN.1 printer: recurses to dump an entire structure.
857 * This will work for any ASN.1 stream, not just an SNMP PDU.
859 * By adding newlines and spaces at the correct places, this would print in
862 * This is not currently used.
865 asn1_decode(u_char *p, u_int length)
870 while (i >= 0 && length > 0) {
871 i = asn1_parse(ndo, p, length, &elem);
873 ND_PRINT((ndo, " "));
874 if (asn1_print(ndo, &elem) < 0)
876 if (elem.type == BE_SEQ || elem.type == BE_PDU) {
877 ND_PRINT((ndo, " {"));
878 asn1_decode(elem.data.raw, elem.asnlen);
879 ND_PRINT((ndo, " }"));
891 SmiBasetype basetype;
895 static const struct smi2be smi2betab[] = {
896 { SMI_BASETYPE_INTEGER32, BE_INT },
897 { SMI_BASETYPE_OCTETSTRING, BE_STR },
898 { SMI_BASETYPE_OCTETSTRING, BE_INETADDR },
899 { SMI_BASETYPE_OBJECTIDENTIFIER, BE_OID },
900 { SMI_BASETYPE_UNSIGNED32, BE_UNS },
901 { SMI_BASETYPE_INTEGER64, BE_NONE },
902 { SMI_BASETYPE_UNSIGNED64, BE_UNS64 },
903 { SMI_BASETYPE_FLOAT32, BE_NONE },
904 { SMI_BASETYPE_FLOAT64, BE_NONE },
905 { SMI_BASETYPE_FLOAT128, BE_NONE },
906 { SMI_BASETYPE_ENUM, BE_INT },
907 { SMI_BASETYPE_BITS, BE_STR },
908 { SMI_BASETYPE_UNKNOWN, BE_NONE }
912 smi_decode_oid(netdissect_options *ndo,
913 struct be *elem, unsigned int *oid,
914 unsigned int oidsize, unsigned int *oidlen)
916 const u_char *p = (const u_char *)elem->data.raw;
917 uint32_t asnlen = elem->asnlen;
918 int o = 0, first = -1, i = asnlen;
919 unsigned int firstval;
921 for (*oidlen = 0; i-- > 0; p++) {
923 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
924 if (*p & ASN_LONGLEN)
928 * first subitem encodes two items with 1st*OIDMUX+2nd
929 * (see X.690:1997 clause 8.19 for the details)
933 firstval = o / OIDMUX;
934 if (firstval > 2) firstval = 2;
935 o -= firstval * OIDMUX;
936 if (*oidlen < oidsize) {
937 oid[(*oidlen)++] = firstval;
940 if (*oidlen < oidsize) {
941 oid[(*oidlen)++] = o;
948 ND_PRINT((ndo, "%s", tstr));
952 static int smi_check_type(SmiBasetype basetype, int be)
956 for (i = 0; smi2betab[i].basetype != SMI_BASETYPE_UNKNOWN; i++) {
957 if (smi2betab[i].basetype == basetype && smi2betab[i].be == be) {
965 static int smi_check_a_range(SmiType *smiType, SmiRange *smiRange,
970 switch (smiType->basetype) {
971 case SMI_BASETYPE_OBJECTIDENTIFIER:
972 case SMI_BASETYPE_OCTETSTRING:
973 if (smiRange->minValue.value.unsigned32
974 == smiRange->maxValue.value.unsigned32) {
975 ok = (elem->asnlen == smiRange->minValue.value.unsigned32);
977 ok = (elem->asnlen >= smiRange->minValue.value.unsigned32
978 && elem->asnlen <= smiRange->maxValue.value.unsigned32);
982 case SMI_BASETYPE_INTEGER32:
983 ok = (elem->data.integer >= smiRange->minValue.value.integer32
984 && elem->data.integer <= smiRange->maxValue.value.integer32);
987 case SMI_BASETYPE_UNSIGNED32:
988 ok = (elem->data.uns >= smiRange->minValue.value.unsigned32
989 && elem->data.uns <= smiRange->maxValue.value.unsigned32);
992 case SMI_BASETYPE_UNSIGNED64:
996 /* case SMI_BASETYPE_INTEGER64: SMIng */
997 /* case SMI_BASETYPE_FLOAT32: SMIng */
998 /* case SMI_BASETYPE_FLOAT64: SMIng */
999 /* case SMI_BASETYPE_FLOAT128: SMIng */
1001 case SMI_BASETYPE_ENUM:
1002 case SMI_BASETYPE_BITS:
1003 case SMI_BASETYPE_UNKNOWN:
1015 static int smi_check_range(SmiType *smiType, struct be *elem)
1020 for (smiRange = smiGetFirstRange(smiType);
1022 smiRange = smiGetNextRange(smiRange)) {
1024 ok = smi_check_a_range(smiType, smiRange, elem);
1032 SmiType *parentType;
1033 parentType = smiGetParentType(smiType);
1035 ok = smi_check_range(parentType, elem);
1043 smi_print_variable(netdissect_options *ndo,
1044 struct be *elem, int *status)
1046 unsigned int oid[128], oidlen;
1047 SmiNode *smiNode = NULL;
1050 if (!nd_smi_module_loaded) {
1051 *status = asn1_print(ndo, elem);
1054 *status = smi_decode_oid(ndo, elem, oid, sizeof(oid) / sizeof(unsigned int),
1058 smiNode = smiGetNodeByOID(oidlen, oid);
1060 *status = asn1_print(ndo, elem);
1063 if (ndo->ndo_vflag) {
1064 ND_PRINT((ndo, "%s::", smiGetNodeModule(smiNode)->name));
1066 ND_PRINT((ndo, "%s", smiNode->name));
1067 if (smiNode->oidlen < oidlen) {
1068 for (i = smiNode->oidlen; i < oidlen; i++) {
1069 ND_PRINT((ndo, ".%u", oid[i]));
1077 smi_print_value(netdissect_options *ndo,
1078 SmiNode *smiNode, u_short pduid, struct be *elem)
1080 unsigned int i, oid[128], oidlen;
1085 if (! smiNode || ! (smiNode->nodekind
1086 & (SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN))) {
1087 return asn1_print(ndo, elem);
1090 if (elem->type == BE_NOSUCHOBJECT
1091 || elem->type == BE_NOSUCHINST
1092 || elem->type == BE_ENDOFMIBVIEW) {
1093 return asn1_print(ndo, elem);
1096 if (NOTIFY_CLASS(pduid) && smiNode->access < SMI_ACCESS_NOTIFY) {
1097 ND_PRINT((ndo, "[notNotifyable]"));
1100 if (READ_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_ONLY) {
1101 ND_PRINT((ndo, "[notReadable]"));
1104 if (WRITE_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_WRITE) {
1105 ND_PRINT((ndo, "[notWritable]"));
1108 if (RESPONSE_CLASS(pduid)
1109 && smiNode->access == SMI_ACCESS_NOT_ACCESSIBLE) {
1110 ND_PRINT((ndo, "[noAccess]"));
1113 smiType = smiGetNodeType(smiNode);
1115 return asn1_print(ndo, elem);
1118 if (! smi_check_type(smiType->basetype, elem->type)) {
1119 ND_PRINT((ndo, "[wrongType]"));
1122 if (! smi_check_range(smiType, elem)) {
1123 ND_PRINT((ndo, "[outOfRange]"));
1126 /* resolve bits to named bits */
1128 /* check whether instance identifier is valid */
1130 /* apply display hints (integer, octetstring) */
1132 /* convert instance identifier to index type values */
1134 switch (elem->type) {
1136 if (smiType->basetype == SMI_BASETYPE_BITS) {
1137 /* print bit labels */
1139 if (nd_smi_module_loaded &&
1140 smi_decode_oid(ndo, elem, oid,
1141 sizeof(oid)/sizeof(unsigned int),
1143 smiNode = smiGetNodeByOID(oidlen, oid);
1145 if (ndo->ndo_vflag) {
1146 ND_PRINT((ndo, "%s::", smiGetNodeModule(smiNode)->name));
1148 ND_PRINT((ndo, "%s", smiNode->name));
1149 if (smiNode->oidlen < oidlen) {
1150 for (i = smiNode->oidlen;
1152 ND_PRINT((ndo, ".%u", oid[i]));
1162 if (smiType->basetype == SMI_BASETYPE_ENUM) {
1163 for (nn = smiGetFirstNamedNumber(smiType);
1165 nn = smiGetNextNamedNumber(nn)) {
1166 if (nn->value.value.integer32
1167 == elem->data.integer) {
1168 ND_PRINT((ndo, "%s", nn->name));
1169 ND_PRINT((ndo, "(%d)", elem->data.integer));
1179 return asn1_print(ndo, elem);
1186 * General SNMP header
1188 * version INTEGER {version-1(0)},
1189 * community OCTET STRING,
1192 * PDUs for all but Trap: (see rfc1157 from page 15 on)
1194 * request-id INTEGER,
1195 * error-status INTEGER,
1196 * error-index INTEGER,
1197 * varbindlist SEQUENCE OF
1205 * enterprise OBJECT IDENTIFIER,
1206 * agent-addr NetworkAddress,
1207 * generic-trap INTEGER,
1208 * specific-trap INTEGER,
1209 * time-stamp TimeTicks,
1210 * varbindlist SEQUENCE OF
1219 * Decode SNMP varBind
1222 varbind_print(netdissect_options *ndo,
1223 u_short pduid, const u_char *np, u_int length)
1228 SmiNode *smiNode = NULL;
1232 /* Sequence of varBind */
1233 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1235 if (elem.type != BE_SEQ) {
1236 ND_PRINT((ndo, "[!SEQ of varbind]"));
1237 asn1_print(ndo, &elem);
1240 if ((u_int)count < length)
1241 ND_PRINT((ndo, "[%d extra after SEQ of varbind]", length - count));
1243 length = elem.asnlen;
1244 np = (const u_char *)elem.data.raw;
1246 for (ind = 1; length > 0; ind++) {
1247 const u_char *vbend;
1250 ND_PRINT((ndo, " "));
1253 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1255 if (elem.type != BE_SEQ) {
1256 ND_PRINT((ndo, "[!varbind]"));
1257 asn1_print(ndo, &elem);
1261 vblength = length - count;
1263 length = elem.asnlen;
1264 np = (const u_char *)elem.data.raw;
1267 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1269 if (elem.type != BE_OID) {
1270 ND_PRINT((ndo, "[objName!=OID]"));
1271 asn1_print(ndo, &elem);
1275 smiNode = smi_print_variable(ndo, &elem, &status);
1277 status = asn1_print(ndo, &elem);
1284 if (pduid != GETREQ && pduid != GETNEXTREQ
1285 && pduid != GETBULKREQ)
1286 ND_PRINT((ndo, "="));
1289 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1291 if (pduid == GETREQ || pduid == GETNEXTREQ
1292 || pduid == GETBULKREQ) {
1293 if (elem.type != BE_NULL) {
1294 ND_PRINT((ndo, "[objVal!=NULL]"));
1295 if (asn1_print(ndo, &elem) < 0)
1299 if (elem.type != BE_NULL) {
1301 status = smi_print_value(ndo, smiNode, pduid, &elem);
1303 status = asn1_print(ndo, &elem);
1315 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
1316 * GetBulk, Inform, V2Trap, and Report
1319 snmppdu_print(netdissect_options *ndo,
1320 u_short pduid, const u_char *np, u_int length)
1323 int count = 0, error_status;
1325 /* reqId (Integer) */
1326 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1328 if (elem.type != BE_INT) {
1329 ND_PRINT((ndo, "[reqId!=INT]"));
1330 asn1_print(ndo, &elem);
1334 ND_PRINT((ndo, "R=%d ", elem.data.integer));
1338 /* errorStatus (Integer) */
1339 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1341 if (elem.type != BE_INT) {
1342 ND_PRINT((ndo, "[errorStatus!=INT]"));
1343 asn1_print(ndo, &elem);
1347 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1348 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1349 && elem.data.integer != 0) {
1351 ND_PRINT((ndo, "[errorStatus(%s)!=0]",
1352 DECODE_ErrorStatus(elem.data.integer)));
1353 } else if (pduid == GETBULKREQ) {
1354 ND_PRINT((ndo, " N=%d", elem.data.integer));
1355 } else if (elem.data.integer != 0) {
1357 ND_PRINT((ndo, " %s", DECODE_ErrorStatus(elem.data.integer)));
1358 error_status = elem.data.integer;
1363 /* errorIndex (Integer) */
1364 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1366 if (elem.type != BE_INT) {
1367 ND_PRINT((ndo, "[errorIndex!=INT]"));
1368 asn1_print(ndo, &elem);
1371 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1372 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1373 && elem.data.integer != 0)
1374 ND_PRINT((ndo, "[errorIndex(%d)!=0]", elem.data.integer));
1375 else if (pduid == GETBULKREQ)
1376 ND_PRINT((ndo, " M=%d", elem.data.integer));
1377 else if (elem.data.integer != 0) {
1379 ND_PRINT((ndo, "[errorIndex(%d) w/o errorStatus]", elem.data.integer));
1381 ND_PRINT((ndo, "@%d", elem.data.integer));
1382 } else if (error_status) {
1383 ND_PRINT((ndo, "[errorIndex==0]"));
1388 varbind_print(ndo, pduid, np, length);
1393 * Decode SNMP Trap PDU
1396 trappdu_print(netdissect_options *ndo,
1397 const u_char *np, u_int length)
1400 int count = 0, generic;
1402 ND_PRINT((ndo, " "));
1404 /* enterprise (oid) */
1405 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1407 if (elem.type != BE_OID) {
1408 ND_PRINT((ndo, "[enterprise!=OID]"));
1409 asn1_print(ndo, &elem);
1412 if (asn1_print(ndo, &elem) < 0)
1417 ND_PRINT((ndo, " "));
1419 /* agent-addr (inetaddr) */
1420 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1422 if (elem.type != BE_INETADDR) {
1423 ND_PRINT((ndo, "[agent-addr!=INETADDR]"));
1424 asn1_print(ndo, &elem);
1427 if (asn1_print(ndo, &elem) < 0)
1432 /* generic-trap (Integer) */
1433 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1435 if (elem.type != BE_INT) {
1436 ND_PRINT((ndo, "[generic-trap!=INT]"));
1437 asn1_print(ndo, &elem);
1440 generic = elem.data.integer;
1443 ND_PRINT((ndo, " %s", DECODE_GenericTrap(generic)));
1448 /* specific-trap (Integer) */
1449 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1451 if (elem.type != BE_INT) {
1452 ND_PRINT((ndo, "[specific-trap!=INT]"));
1453 asn1_print(ndo, &elem);
1456 if (generic != GT_ENTERPRISE) {
1457 if (elem.data.integer != 0)
1458 ND_PRINT((ndo, "[specific-trap(%d)!=0]", elem.data.integer));
1460 ND_PRINT((ndo, " s=%d", elem.data.integer));
1464 ND_PRINT((ndo, " "));
1466 /* time-stamp (TimeTicks) */
1467 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1469 if (elem.type != BE_UNS) { /* XXX */
1470 ND_PRINT((ndo, "[time-stamp!=TIMETICKS]"));
1471 asn1_print(ndo, &elem);
1474 if (asn1_print(ndo, &elem) < 0)
1479 varbind_print(ndo, TRAP, np, length);
1484 * Decode arbitrary SNMP PDUs.
1487 pdu_print(netdissect_options *ndo,
1488 const u_char *np, u_int length, int version)
1494 if ((count = asn1_parse(ndo, np, length, &pdu)) < 0)
1496 if (pdu.type != BE_PDU) {
1497 ND_PRINT((ndo, "[no PDU]"));
1500 if ((u_int)count < length)
1501 ND_PRINT((ndo, "[%d extra after PDU]", length - count));
1502 if (ndo->ndo_vflag) {
1503 ND_PRINT((ndo, "{ "));
1505 if (asn1_print(ndo, &pdu) < 0)
1507 ND_PRINT((ndo, " "));
1508 /* descend into PDU */
1509 length = pdu.asnlen;
1510 np = (const u_char *)pdu.data.raw;
1512 if (version == SNMP_VERSION_1 &&
1513 (pdu.id == GETBULKREQ || pdu.id == INFORMREQ ||
1514 pdu.id == V2TRAP || pdu.id == REPORT)) {
1515 ND_PRINT((ndo, "[v2 PDU in v1 message]"));
1519 if (version == SNMP_VERSION_2 && pdu.id == TRAP) {
1520 ND_PRINT((ndo, "[v1 PDU in v2 message]"));
1526 trappdu_print(ndo, np, length);
1536 snmppdu_print(ndo, pdu.id, np, length);
1540 if (ndo->ndo_vflag) {
1541 ND_PRINT((ndo, " } "));
1546 * Decode a scoped SNMP PDU.
1549 scopedpdu_print(netdissect_options *ndo,
1550 const u_char *np, u_int length, int version)
1556 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1558 if (elem.type != BE_SEQ) {
1559 ND_PRINT((ndo, "[!scoped PDU]"));
1560 asn1_print(ndo, &elem);
1563 length = elem.asnlen;
1564 np = (const u_char *)elem.data.raw;
1566 /* contextEngineID (OCTET STRING) */
1567 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1569 if (elem.type != BE_STR) {
1570 ND_PRINT((ndo, "[contextEngineID!=STR]"));
1571 asn1_print(ndo, &elem);
1577 ND_PRINT((ndo, "E="));
1578 if (asn1_print_octets(ndo, &elem) == -1)
1580 ND_PRINT((ndo, " "));
1582 /* contextName (OCTET STRING) */
1583 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1585 if (elem.type != BE_STR) {
1586 ND_PRINT((ndo, "[contextName!=STR]"));
1587 asn1_print(ndo, &elem);
1593 ND_PRINT((ndo, "C="));
1594 if (asn1_print_string(ndo, &elem) == -1)
1596 ND_PRINT((ndo, " "));
1598 pdu_print(ndo, np, length, version);
1602 * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
1605 community_print(netdissect_options *ndo,
1606 const u_char *np, u_int length, int version)
1611 /* Community (String) */
1612 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1614 if (elem.type != BE_STR) {
1615 ND_PRINT((ndo, "[comm!=STR]"));
1616 asn1_print(ndo, &elem);
1619 /* default community */
1620 if (!(elem.asnlen == sizeof(DEF_COMMUNITY) - 1 &&
1621 strncmp((const char *)elem.data.str, DEF_COMMUNITY,
1622 sizeof(DEF_COMMUNITY) - 1) == 0)) {
1624 ND_PRINT((ndo, "C="));
1625 if (asn1_print_string(ndo, &elem) == -1)
1627 ND_PRINT((ndo, " "));
1632 pdu_print(ndo, np, length, version);
1636 * Decode SNMPv3 User-based Security Message Header (SNMPv3)
1639 usm_print(netdissect_options *ndo,
1640 const u_char *np, u_int length)
1646 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1648 if (elem.type != BE_SEQ) {
1649 ND_PRINT((ndo, "[!usm]"));
1650 asn1_print(ndo, &elem);
1653 length = elem.asnlen;
1654 np = (const u_char *)elem.data.raw;
1656 /* msgAuthoritativeEngineID (OCTET STRING) */
1657 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1659 if (elem.type != BE_STR) {
1660 ND_PRINT((ndo, "[msgAuthoritativeEngineID!=STR]"));
1661 asn1_print(ndo, &elem);
1667 /* msgAuthoritativeEngineBoots (INTEGER) */
1668 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1670 if (elem.type != BE_INT) {
1671 ND_PRINT((ndo, "[msgAuthoritativeEngineBoots!=INT]"));
1672 asn1_print(ndo, &elem);
1676 ND_PRINT((ndo, "B=%d ", elem.data.integer));
1680 /* msgAuthoritativeEngineTime (INTEGER) */
1681 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1683 if (elem.type != BE_INT) {
1684 ND_PRINT((ndo, "[msgAuthoritativeEngineTime!=INT]"));
1685 asn1_print(ndo, &elem);
1689 ND_PRINT((ndo, "T=%d ", elem.data.integer));
1693 /* msgUserName (OCTET STRING) */
1694 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1696 if (elem.type != BE_STR) {
1697 ND_PRINT((ndo, "[msgUserName!=STR]"));
1698 asn1_print(ndo, &elem);
1704 ND_PRINT((ndo, "U="));
1705 if (asn1_print_string(ndo, &elem) == -1)
1707 ND_PRINT((ndo, " "));
1709 /* msgAuthenticationParameters (OCTET STRING) */
1710 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1712 if (elem.type != BE_STR) {
1713 ND_PRINT((ndo, "[msgAuthenticationParameters!=STR]"));
1714 asn1_print(ndo, &elem);
1720 /* msgPrivacyParameters (OCTET STRING) */
1721 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1723 if (elem.type != BE_STR) {
1724 ND_PRINT((ndo, "[msgPrivacyParameters!=STR]"));
1725 asn1_print(ndo, &elem);
1731 if ((u_int)count < length)
1732 ND_PRINT((ndo, "[%d extra after usm SEQ]", length - count));
1736 * Decode SNMPv3 Message Header (SNMPv3)
1739 v3msg_print(netdissect_options *ndo,
1740 const u_char *np, u_int length)
1746 const u_char *xnp = np;
1747 int xlength = length;
1750 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1752 if (elem.type != BE_SEQ) {
1753 ND_PRINT((ndo, "[!message]"));
1754 asn1_print(ndo, &elem);
1757 length = elem.asnlen;
1758 np = (const u_char *)elem.data.raw;
1760 if (ndo->ndo_vflag) {
1761 ND_PRINT((ndo, "{ "));
1764 /* msgID (INTEGER) */
1765 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1767 if (elem.type != BE_INT) {
1768 ND_PRINT((ndo, "[msgID!=INT]"));
1769 asn1_print(ndo, &elem);
1775 /* msgMaxSize (INTEGER) */
1776 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1778 if (elem.type != BE_INT) {
1779 ND_PRINT((ndo, "[msgMaxSize!=INT]"));
1780 asn1_print(ndo, &elem);
1786 /* msgFlags (OCTET STRING) */
1787 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1789 if (elem.type != BE_STR) {
1790 ND_PRINT((ndo, "[msgFlags!=STR]"));
1791 asn1_print(ndo, &elem);
1794 if (elem.asnlen != 1) {
1795 ND_PRINT((ndo, "[msgFlags size %d]", elem.asnlen));
1798 flags = elem.data.str[0];
1799 if (flags != 0x00 && flags != 0x01 && flags != 0x03
1800 && flags != 0x04 && flags != 0x05 && flags != 0x07) {
1801 ND_PRINT((ndo, "[msgFlags=0x%02X]", flags));
1807 ND_PRINT((ndo, "F=%s%s%s ",
1808 flags & 0x01 ? "a" : "",
1809 flags & 0x02 ? "p" : "",
1810 flags & 0x04 ? "r" : ""));
1812 /* msgSecurityModel (INTEGER) */
1813 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1815 if (elem.type != BE_INT) {
1816 ND_PRINT((ndo, "[msgSecurityModel!=INT]"));
1817 asn1_print(ndo, &elem);
1820 model = elem.data.integer;
1824 if ((u_int)count < length)
1825 ND_PRINT((ndo, "[%d extra after message SEQ]", length - count));
1827 if (ndo->ndo_vflag) {
1828 ND_PRINT((ndo, "} "));
1832 if (ndo->ndo_vflag) {
1833 ND_PRINT((ndo, "{ USM "));
1836 ND_PRINT((ndo, "[security model %d]", model));
1840 np = xnp + (np - xnp);
1841 length = xlength - (np - xnp);
1843 /* msgSecurityParameters (OCTET STRING) */
1844 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1846 if (elem.type != BE_STR) {
1847 ND_PRINT((ndo, "[msgSecurityParameters!=STR]"));
1848 asn1_print(ndo, &elem);
1855 usm_print(ndo, elem.data.str, elem.asnlen);
1856 if (ndo->ndo_vflag) {
1857 ND_PRINT((ndo, "} "));
1861 if (ndo->ndo_vflag) {
1862 ND_PRINT((ndo, "{ ScopedPDU "));
1865 scopedpdu_print(ndo, np, length, 3);
1867 if (ndo->ndo_vflag) {
1868 ND_PRINT((ndo, "} "));
1873 * Decode SNMP header and pass on to PDU printing routines
1876 snmp_print(netdissect_options *ndo,
1877 const u_char *np, u_int length)
1883 ND_PRINT((ndo, " "));
1885 /* initial Sequence */
1886 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1888 if (elem.type != BE_SEQ) {
1889 ND_PRINT((ndo, "[!init SEQ]"));
1890 asn1_print(ndo, &elem);
1893 if ((u_int)count < length)
1894 ND_PRINT((ndo, "[%d extra after iSEQ]", length - count));
1896 length = elem.asnlen;
1897 np = (const u_char *)elem.data.raw;
1899 /* Version (INTEGER) */
1900 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1902 if (elem.type != BE_INT) {
1903 ND_PRINT((ndo, "[version!=INT]"));
1904 asn1_print(ndo, &elem);
1908 switch (elem.data.integer) {
1909 case SNMP_VERSION_1:
1910 case SNMP_VERSION_2:
1911 case SNMP_VERSION_3:
1913 ND_PRINT((ndo, "{ %s ", SnmpVersion[elem.data.integer]));
1916 ND_PRINT((ndo, "SNMP [version = %d]", elem.data.integer));
1919 version = elem.data.integer;
1924 case SNMP_VERSION_1:
1925 case SNMP_VERSION_2:
1926 community_print(ndo, np, length, version);
1928 case SNMP_VERSION_3:
1929 v3msg_print(ndo, np, length);
1932 ND_PRINT((ndo, "[version = %d]", elem.data.integer));
1936 if (ndo->ndo_vflag) {
1937 ND_PRINT((ndo, "} "));