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 #define NETDISSECT_REWORKED
64 #include <tcpdump-stdinc.h>
73 #include "interface.h"
75 #undef OPAQUE /* defined in <wingdi.h> */
77 static const char tstr[] = "[|snmp]";
80 * Universal ASN.1 types
81 * (we only care about the tag values for those allowed in the Internet SMI)
83 static const char *Universal[] = {
96 "U-8","U-9","U-10","U-11", /* 8-11 */
97 "U-12","U-13","U-14","U-15", /* 12-15 */
104 * Application-wide ASN.1 types from the Internet SMI and their tags
106 static const char *Application[] = {
123 * Context-specific ASN.1 types for the SNMP PDUs and their tags
125 static const char *Context[] = {
146 #define NOTIFY_CLASS(x) (x == TRAP || x == V2TRAP || x == INFORMREQ)
147 #define READ_CLASS(x) (x == GETREQ || x == GETNEXTREQ || x == GETBULKREQ)
148 #define WRITE_CLASS(x) (x == SETREQ)
149 #define RESPONSE_CLASS(x) (x == GETRESP)
150 #define INTERNAL_CLASS(x) (x == REPORT)
153 * Context-specific ASN.1 types for the SNMP Exceptions and their tags
155 static const char *Exceptions[] = {
157 #define NOSUCHOBJECT 0
159 #define NOSUCHINSTANCE 1
161 #define ENDOFMIBVIEW 2
165 * Private ASN.1 types
166 * The Internet SMI does not specify any
168 static const char *Private[] = {
173 * error-status values for any SNMP PDU
175 static const char *ErrorStatus[] = {
189 "resourceUnavailable",
192 "authorizationError",
196 #define DECODE_ErrorStatus(e) \
197 ( e >= 0 && (size_t)e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
199 : (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf))
202 * generic-trap values in the SNMP Trap-PDU
204 static const char *GenericTrap[] = {
209 "authenticationFailure",
212 #define GT_ENTERPRISE 6
214 #define DECODE_GenericTrap(t) \
215 ( t >= 0 && (size_t)t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
217 : (snprintf(buf, sizeof(buf), "gt=%d", t), buf))
220 * ASN.1 type class table
221 * Ties together the preceding Universal, Application, Context, and Private
224 #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
225 static const struct {
230 defineCLASS(Universal),
232 defineCLASS(Application),
233 #define APPLICATION 1
234 defineCLASS(Context),
236 defineCLASS(Private),
238 defineCLASS(Exceptions),
243 * defined forms for ASN.1 types
245 static const char *Form[] = {
249 #define CONSTRUCTED 1
253 * A structure for the OID tree for the compiled-in MIB.
254 * This is stored as a general-order tree.
257 const char *desc; /* name of object */
258 u_char oid; /* sub-id following parent */
259 u_char type; /* object type (unused) */
260 struct obj *child, *next; /* child and next sibling pointers */
264 * Include the compiled in SNMP MIB. "mib.h" is produced by feeding
265 * RFC-1156 format files into "makemib". "mib.h" MUST define at least
266 * a value for `mibroot'.
268 * In particular, this is gross, as this is including initialized structures,
269 * and by right shouldn't be an "include" file.
274 * This defines a list of OIDs which will be abbreviated on output.
275 * Currently, this includes the prefixes for the Internet MIB, the
276 * private enterprises tree, and the experimental tree.
278 static const struct obj_abrev {
279 const char *prefix; /* prefix for this abrev */
280 struct obj *node; /* pointer into object table */
281 const char *oid; /* ASN.1 encoded OID */
282 } obj_abrev_list[] = {
284 /* .iso.org.dod.internet.mgmt.mib */
285 { "", &_mib_obj, "\53\6\1\2\1" },
287 #ifndef NO_ABREV_ENTER
288 /* .iso.org.dod.internet.private.enterprises */
289 { "E:", &_enterprises_obj, "\53\6\1\4\1" },
291 #ifndef NO_ABREV_EXPERI
292 /* .iso.org.dod.internet.experimental */
293 { "X:", &_experimental_obj, "\53\6\1\3" },
295 #ifndef NO_ABBREV_SNMPMODS
296 /* .iso.org.dod.internet.snmpV2.snmpModules */
297 { "S:", &_snmpModules_obj, "\53\6\1\6\3" },
303 * This is used in the OID print routine to walk down the object tree
304 * rooted at `mibroot'.
306 #define OBJ_PRINT(o, suppressdot) \
310 if ((o) == objp->oid) \
312 } while ((objp = objp->next) != NULL); \
315 ND_PRINT((ndo, suppressdot?"%s":".%s", objp->desc)); \
316 objp = objp->child; \
318 ND_PRINT((ndo, suppressdot?"%u":".%u", (o))); \
322 * This is the definition for the Any-Data-Type storage used purely for
323 * temporary internal representation while decoding an ASN.1 data stream.
338 u_char form, class; /* tag info */
349 #define BE_INETADDR 8
352 #define BE_NOSUCHOBJECT 128
353 #define BE_NOSUCHINST 129
354 #define BE_ENDOFMIBVIEW 130
358 * SNMP versions recognized by this module
360 static const char *SnmpVersion[] = {
362 #define SNMP_VERSION_1 0
364 #define SNMP_VERSION_2 1
366 #define SNMP_VERSION_2U 2
368 #define SNMP_VERSION_3 3
372 * Defaults for SNMP PDU components
374 #define DEF_COMMUNITY "public"
377 * constants for ASN.1 decoding
380 #define ASNLEN_INETADDR 4
383 #define ASN_BIT8 0x80
384 #define ASN_LONGLEN 0x80
386 #define ASN_ID_BITS 0x1f
387 #define ASN_FORM_BITS 0x20
388 #define ASN_FORM_SHIFT 5
389 #define ASN_CLASS_BITS 0xc0
390 #define ASN_CLASS_SHIFT 6
392 #define ASN_ID_EXT 0x1f /* extension ID in tag field */
395 * This decodes the next ASN.1 object in the stream pointed to by "p"
396 * (and of real-length "len") and stores the intermediate data in the
397 * provided BE object.
399 * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
400 * O/w, this returns the number of bytes parsed from "p".
403 asn1_parse(netdissect_options *ndo,
404 register const u_char *p, u_int len, struct be *elem)
406 u_char form, class, id;
412 ND_PRINT((ndo, "[nothing to parse]"));
418 * it would be nice to use a bit field, but you can't depend on them.
419 * +---+---+---+---+---+---+---+---+
421 * +---+---+---+---+---+---+---+---+
424 id = *p & ASN_ID_BITS; /* lower 5 bits, range 00-1f */
426 form = (*p & 0xe0) >> 5; /* move upper 3 bits to lower 3 */
427 class = form >> 1; /* bits 7&6 -> bits 1&0, range 0-3 */
428 form &= 0x1; /* bit 5 -> bit 0, range 0-1 */
430 form = (u_char)(*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
431 class = (u_char)(*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
437 /* extended tag field */
438 if (id == ASN_ID_EXT) {
440 * The ID follows, as a sequence of octets with the
441 * 8th bit set and the remaining 7 bits being
442 * the next 7 bits of the value, terminated with
443 * an octet with the 8th bit not set.
445 * First, assemble all the octets with the 8th
446 * bit set. XXX - this doesn't handle a value
447 * that won't fit in 32 bits.
449 for (id = 0; *p & ASN_BIT8; len--, hdr++, p++) {
451 ND_PRINT((ndo, "[Xtagfield?]"));
455 id = (id << 7) | (*p & ~ASN_BIT8);
458 ND_PRINT((ndo, "[Xtagfield?]"));
462 elem->id = id = (id << 7) | *p;
468 ND_PRINT((ndo, "[no asnlen]"));
474 if (elem->asnlen & ASN_BIT8) {
475 uint32_t noct = elem->asnlen % ASN_BIT8;
478 ND_PRINT((ndo, "[asnlen? %d<%d]", len, noct));
481 ND_TCHECK2(*p, noct);
482 for (; noct-- > 0; len--, hdr++)
483 elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++;
485 if (len < elem->asnlen) {
486 ND_PRINT((ndo, "[len%d<asnlen%u]", len, elem->asnlen));
489 if (form >= sizeof(Form)/sizeof(Form[0])) {
490 ND_PRINT((ndo, "[form?%d]", form));
493 if (class >= sizeof(Class)/sizeof(Class[0])) {
494 ND_PRINT((ndo, "[class?%c/%d]", *Form[form], class));
497 if ((int)id >= Class[class].numIDs) {
498 ND_PRINT((ndo, "[id?%c/%s/%d]", *Form[form], Class[class].name, id));
513 register int32_t data;
517 ND_TCHECK2(*p, elem->asnlen);
518 if (*p & ASN_BIT8) /* negative */
520 for (i = elem->asnlen; i-- > 0; p++)
521 data = (data << ASN_SHIFT8) | *p;
522 elem->data.integer = data;
528 elem->data.raw = (caddr_t)p;
532 elem->type = BE_NULL;
533 elem->data.raw = NULL;
537 elem->type = BE_OCTET;
538 elem->data.raw = (caddr_t)p;
539 ND_PRINT((ndo, "[P/U/%s]", Class[class].Id[id]));
547 elem->type = BE_INETADDR;
548 elem->data.raw = (caddr_t)p;
554 register uint32_t data;
555 ND_TCHECK2(*p, elem->asnlen);
558 for (i = elem->asnlen; i-- > 0; p++)
559 data = (data << 8) + *p;
560 elem->data.uns = data;
565 register uint32_t high, low;
566 ND_TCHECK2(*p, elem->asnlen);
567 elem->type = BE_UNS64;
569 for (i = elem->asnlen; i-- > 0; p++) {
571 ((low & 0xFF000000) >> 24);
572 low = (low << 8) | *p;
574 elem->data.uns64.high = high;
575 elem->data.uns64.low = low;
580 elem->type = BE_OCTET;
581 elem->data.raw = (caddr_t)p;
582 ND_PRINT((ndo, "[P/A/%s]",
583 Class[class].Id[id]));
591 elem->type = BE_NOSUCHOBJECT;
592 elem->data.raw = NULL;
596 elem->type = BE_NOSUCHINST;
597 elem->data.raw = NULL;
601 elem->type = BE_ENDOFMIBVIEW;
602 elem->data.raw = NULL;
608 ND_PRINT((ndo, "[P/%s/%s]", Class[class].name, Class[class].Id[id]));
609 ND_TCHECK2(*p, elem->asnlen);
610 elem->type = BE_OCTET;
611 elem->data.raw = (caddr_t)p;
622 elem->data.raw = (caddr_t)p;
626 elem->type = BE_OCTET;
627 elem->data.raw = (caddr_t)p;
628 ND_PRINT((ndo, "C/U/%s", Class[class].Id[id]));
635 elem->data.raw = (caddr_t)p;
639 elem->type = BE_OCTET;
640 elem->data.raw = (caddr_t)p;
641 ND_PRINT((ndo, "C/%s/%s", Class[class].name, Class[class].Id[id]));
648 return elem->asnlen + hdr;
651 ND_PRINT((ndo, "%s", tstr));
656 * Display the ASN.1 object represented by the BE object.
657 * This used to be an integral part of asn1_parse() before the intermediate
661 asn1_print(netdissect_options *ndo,
664 u_char *p = (u_char *)elem->data.raw;
665 uint32_t asnlen = elem->asnlen;
668 switch (elem->type) {
671 ND_TCHECK2(*p, asnlen);
672 for (i = asnlen; i-- > 0; p++)
673 ND_PRINT((ndo, "_%.2x", *p));
680 int o = 0, first = -1, i = asnlen;
682 if (!ndo->ndo_sflag && !ndo->ndo_nflag && asnlen > 2) {
683 const struct obj_abrev *a = &obj_abrev_list[0];
684 size_t a_len = strlen(a->oid);
685 for (; a->node; a++) {
686 ND_TCHECK2(*p, a_len);
687 if (memcmp(a->oid, (char *)p, a_len) == 0) {
688 objp = a->node->child;
691 ND_PRINT((ndo, "%s", a->prefix));
698 for (; !ndo->ndo_sflag && i-- > 0; p++) {
700 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
701 if (*p & ASN_LONGLEN)
705 * first subitem encodes two items with 1st*OIDMUX+2nd
706 * (see X.690:1997 clause 8.19 for the details)
727 ND_PRINT((ndo, "%d", elem->data.integer));
731 ND_PRINT((ndo, "%u", elem->data.uns));
734 case BE_UNS64: { /* idea borrowed from by Marshall Rose */
737 char *cpf, *cpl, last[6], first[30];
738 if (elem->data.uns64.high == 0) {
739 ND_PRINT((ndo, "%u", elem->data.uns64.low));
742 d = elem->data.uns64.high * 4294967296.0; /* 2^32 */
743 if (elem->data.uns64.high <= 0x1fffff) {
744 d += elem->data.uns64.low;
745 #if 0 /*is looks illegal, but what is the intention?*/
746 ND_PRINT((ndo, "%.f", d));
748 ND_PRINT((ndo, "%f", d));
752 d += (elem->data.uns64.low & 0xfffff000);
753 #if 0 /*is looks illegal, but what is the intention?*/
754 snprintf(first, sizeof(first), "%.f", d);
756 snprintf(first, sizeof(first), "%f", d);
758 snprintf(last, sizeof(last), "%5.5d",
759 elem->data.uns64.low & 0xfff);
760 for (carry = 0, cpf = first+strlen(first)-1, cpl = last+4;
763 j = carry + (*cpf - '0') + (*cpl - '0');
772 ND_PRINT((ndo, "%s", first));
777 register int printable = 1, first = 1;
778 const u_char *p = elem->data.str;
779 ND_TCHECK2(*p, asnlen);
780 for (i = asnlen; printable && i-- > 0; p++)
781 printable = ND_ISPRINT(*p);
784 ND_PRINT((ndo, "\""));
785 if (fn_printn(ndo, p, asnlen, ndo->ndo_snapend)) {
786 ND_PRINT((ndo, "\""));
789 ND_PRINT((ndo, "\""));
791 for (i = asnlen; i-- > 0; p++) {
792 ND_PRINT((ndo, first ? "%.2x" : "_%.2x", *p));
799 ND_PRINT((ndo, "Seq(%u)", elem->asnlen));
803 if (asnlen != ASNLEN_INETADDR)
804 ND_PRINT((ndo, "[inetaddr len!=%d]", ASNLEN_INETADDR));
805 ND_TCHECK2(*p, asnlen);
806 for (i = asnlen; i-- != 0; p++) {
807 ND_PRINT((ndo, (i == asnlen-1) ? "%u" : ".%u", *p));
811 case BE_NOSUCHOBJECT:
813 case BE_ENDOFMIBVIEW:
814 ND_PRINT((ndo, "[%s]", Class[EXCEPTIONS].Id[elem->id]));
818 ND_PRINT((ndo, "%s(%u)", Class[CONTEXT].Id[elem->id], elem->asnlen));
822 ND_PRINT((ndo, "[BE_ANY!?]"));
826 ND_PRINT((ndo, "[be!?]"));
832 ND_PRINT((ndo, "%s", tstr));
838 * This is a brute force ASN.1 printer: recurses to dump an entire structure.
839 * This will work for any ASN.1 stream, not just an SNMP PDU.
841 * By adding newlines and spaces at the correct places, this would print in
844 * This is not currently used.
847 asn1_decode(u_char *p, u_int length)
852 while (i >= 0 && length > 0) {
853 i = asn1_parse(ndo, p, length, &elem);
855 ND_PRINT((ndo, " "));
856 if (asn1_print(ndo, &elem) < 0)
858 if (elem.type == BE_SEQ || elem.type == BE_PDU) {
859 ND_PRINT((ndo, " {"));
860 asn1_decode(elem.data.raw, elem.asnlen);
861 ND_PRINT((ndo, " }"));
873 SmiBasetype basetype;
877 static const struct smi2be smi2betab[] = {
878 { SMI_BASETYPE_INTEGER32, BE_INT },
879 { SMI_BASETYPE_OCTETSTRING, BE_STR },
880 { SMI_BASETYPE_OCTETSTRING, BE_INETADDR },
881 { SMI_BASETYPE_OBJECTIDENTIFIER, BE_OID },
882 { SMI_BASETYPE_UNSIGNED32, BE_UNS },
883 { SMI_BASETYPE_INTEGER64, BE_NONE },
884 { SMI_BASETYPE_UNSIGNED64, BE_UNS64 },
885 { SMI_BASETYPE_FLOAT32, BE_NONE },
886 { SMI_BASETYPE_FLOAT64, BE_NONE },
887 { SMI_BASETYPE_FLOAT128, BE_NONE },
888 { SMI_BASETYPE_ENUM, BE_INT },
889 { SMI_BASETYPE_BITS, BE_STR },
890 { SMI_BASETYPE_UNKNOWN, BE_NONE }
894 smi_decode_oid(netdissect_options *ndo,
895 struct be *elem, unsigned int *oid,
896 unsigned int oidsize, unsigned int *oidlen)
898 u_char *p = (u_char *)elem->data.raw;
899 uint32_t asnlen = elem->asnlen;
900 int o = 0, first = -1, i = asnlen;
901 unsigned int firstval;
903 for (*oidlen = 0; ndo->ndo_sflag && i-- > 0; p++) {
905 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
906 if (*p & ASN_LONGLEN)
910 * first subitem encodes two items with 1st*OIDMUX+2nd
911 * (see X.690:1997 clause 8.19 for the details)
915 firstval = o / OIDMUX;
916 if (firstval > 2) firstval = 2;
917 o -= firstval * OIDMUX;
918 if (*oidlen < oidsize) {
919 oid[(*oidlen)++] = firstval;
922 if (*oidlen < oidsize) {
923 oid[(*oidlen)++] = o;
930 ND_PRINT((ndo, "%s", tstr));
934 static int smi_check_type(SmiBasetype basetype, int be)
938 for (i = 0; smi2betab[i].basetype != SMI_BASETYPE_UNKNOWN; i++) {
939 if (smi2betab[i].basetype == basetype && smi2betab[i].be == be) {
947 static int smi_check_a_range(SmiType *smiType, SmiRange *smiRange,
952 switch (smiType->basetype) {
953 case SMI_BASETYPE_OBJECTIDENTIFIER:
954 case SMI_BASETYPE_OCTETSTRING:
955 if (smiRange->minValue.value.unsigned32
956 == smiRange->maxValue.value.unsigned32) {
957 ok = (elem->asnlen == smiRange->minValue.value.unsigned32);
959 ok = (elem->asnlen >= smiRange->minValue.value.unsigned32
960 && elem->asnlen <= smiRange->maxValue.value.unsigned32);
964 case SMI_BASETYPE_INTEGER32:
965 ok = (elem->data.integer >= smiRange->minValue.value.integer32
966 && elem->data.integer <= smiRange->maxValue.value.integer32);
969 case SMI_BASETYPE_UNSIGNED32:
970 ok = (elem->data.uns >= smiRange->minValue.value.unsigned32
971 && elem->data.uns <= smiRange->maxValue.value.unsigned32);
974 case SMI_BASETYPE_UNSIGNED64:
978 /* case SMI_BASETYPE_INTEGER64: SMIng */
979 /* case SMI_BASETYPE_FLOAT32: SMIng */
980 /* case SMI_BASETYPE_FLOAT64: SMIng */
981 /* case SMI_BASETYPE_FLOAT128: SMIng */
983 case SMI_BASETYPE_ENUM:
984 case SMI_BASETYPE_BITS:
985 case SMI_BASETYPE_UNKNOWN:
997 static int smi_check_range(SmiType *smiType, struct be *elem)
1002 for (smiRange = smiGetFirstRange(smiType);
1004 smiRange = smiGetNextRange(smiRange)) {
1006 ok = smi_check_a_range(smiType, smiRange, elem);
1014 SmiType *parentType;
1015 parentType = smiGetParentType(smiType);
1017 ok = smi_check_range(parentType, elem);
1025 smi_print_variable(netdissect_options *ndo,
1026 struct be *elem, int *status)
1028 unsigned int oid[128], oidlen;
1029 SmiNode *smiNode = NULL;
1032 *status = smi_decode_oid(ndo, elem, oid, sizeof(oid) / sizeof(unsigned int),
1036 smiNode = smiGetNodeByOID(oidlen, oid);
1038 *status = asn1_print(ndo, elem);
1041 if (ndo->ndo_vflag) {
1042 ND_PRINT((ndo, "%s::", smiGetNodeModule(smiNode)->name));
1044 ND_PRINT((ndo, "%s", smiNode->name));
1045 if (smiNode->oidlen < oidlen) {
1046 for (i = smiNode->oidlen; i < oidlen; i++) {
1047 ND_PRINT((ndo, ".%u", oid[i]));
1055 smi_print_value(netdissect_options *ndo,
1056 SmiNode *smiNode, u_char pduid, struct be *elem)
1058 unsigned int i, oid[128], oidlen;
1063 if (! smiNode || ! (smiNode->nodekind
1064 & (SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN))) {
1065 return asn1_print(ndo, elem);
1068 if (elem->type == BE_NOSUCHOBJECT
1069 || elem->type == BE_NOSUCHINST
1070 || elem->type == BE_ENDOFMIBVIEW) {
1071 return asn1_print(ndo, elem);
1074 if (NOTIFY_CLASS(pduid) && smiNode->access < SMI_ACCESS_NOTIFY) {
1075 ND_PRINT((ndo, "[notNotifyable]"));
1078 if (READ_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_ONLY) {
1079 ND_PRINT((ndo, "[notReadable]"));
1082 if (WRITE_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_WRITE) {
1083 ND_PRINT((ndo, "[notWritable]"));
1086 if (RESPONSE_CLASS(pduid)
1087 && smiNode->access == SMI_ACCESS_NOT_ACCESSIBLE) {
1088 ND_PRINT((ndo, "[noAccess]"));
1091 smiType = smiGetNodeType(smiNode);
1093 return asn1_print(ndo, elem);
1096 if (! smi_check_type(smiType->basetype, elem->type)) {
1097 ND_PRINT((ndo, "[wrongType]"));
1100 if (! smi_check_range(smiType, elem)) {
1101 ND_PRINT((ndo, "[outOfRange]"));
1104 /* resolve bits to named bits */
1106 /* check whether instance identifier is valid */
1108 /* apply display hints (integer, octetstring) */
1110 /* convert instance identifier to index type values */
1112 switch (elem->type) {
1114 if (smiType->basetype == SMI_BASETYPE_BITS) {
1115 /* print bit labels */
1117 smi_decode_oid(ndo, elem, oid,
1118 sizeof(oid)/sizeof(unsigned int),
1120 smiNode = smiGetNodeByOID(oidlen, oid);
1122 if (ndo->ndo_vflag) {
1123 ND_PRINT((ndo, "%s::", smiGetNodeModule(smiNode)->name));
1125 ND_PRINT((ndo, "%s", smiNode->name));
1126 if (smiNode->oidlen < oidlen) {
1127 for (i = smiNode->oidlen;
1129 ND_PRINT((ndo, ".%u", oid[i]));
1138 if (smiType->basetype == SMI_BASETYPE_ENUM) {
1139 for (nn = smiGetFirstNamedNumber(smiType);
1141 nn = smiGetNextNamedNumber(nn)) {
1142 if (nn->value.value.integer32
1143 == elem->data.integer) {
1144 ND_PRINT((ndo, "%s", nn->name));
1145 ND_PRINT((ndo, "(%d)", elem->data.integer));
1155 return asn1_print(ndo, elem);
1162 * General SNMP header
1164 * version INTEGER {version-1(0)},
1165 * community OCTET STRING,
1168 * PDUs for all but Trap: (see rfc1157 from page 15 on)
1170 * request-id INTEGER,
1171 * error-status INTEGER,
1172 * error-index INTEGER,
1173 * varbindlist SEQUENCE OF
1181 * enterprise OBJECT IDENTIFIER,
1182 * agent-addr NetworkAddress,
1183 * generic-trap INTEGER,
1184 * specific-trap INTEGER,
1185 * time-stamp TimeTicks,
1186 * varbindlist SEQUENCE OF
1195 * Decode SNMP varBind
1198 varbind_print(netdissect_options *ndo,
1199 u_char pduid, const u_char *np, u_int length)
1204 SmiNode *smiNode = NULL;
1208 /* Sequence of varBind */
1209 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1211 if (elem.type != BE_SEQ) {
1212 ND_PRINT((ndo, "[!SEQ of varbind]"));
1213 asn1_print(ndo, &elem);
1216 if ((u_int)count < length)
1217 ND_PRINT((ndo, "[%d extra after SEQ of varbind]", length - count));
1219 length = elem.asnlen;
1220 np = (u_char *)elem.data.raw;
1222 for (ind = 1; length > 0; ind++) {
1223 const u_char *vbend;
1226 ND_PRINT((ndo, " "));
1229 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1231 if (elem.type != BE_SEQ) {
1232 ND_PRINT((ndo, "[!varbind]"));
1233 asn1_print(ndo, &elem);
1237 vblength = length - count;
1239 length = elem.asnlen;
1240 np = (u_char *)elem.data.raw;
1243 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1245 if (elem.type != BE_OID) {
1246 ND_PRINT((ndo, "[objName!=OID]"));
1247 asn1_print(ndo, &elem);
1251 smiNode = smi_print_variable(ndo, &elem, &status);
1253 status = asn1_print(ndo, &elem);
1260 if (pduid != GETREQ && pduid != GETNEXTREQ
1261 && pduid != GETBULKREQ)
1262 ND_PRINT((ndo, "="));
1265 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1267 if (pduid == GETREQ || pduid == GETNEXTREQ
1268 || pduid == GETBULKREQ) {
1269 if (elem.type != BE_NULL) {
1270 ND_PRINT((ndo, "[objVal!=NULL]"));
1271 if (asn1_print(ndo, &elem) < 0)
1275 if (elem.type != BE_NULL) {
1277 status = smi_print_value(ndo, smiNode, pduid, &elem);
1279 status = asn1_print(ndo, &elem);
1291 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
1292 * GetBulk, Inform, V2Trap, and Report
1295 snmppdu_print(netdissect_options *ndo,
1296 u_short pduid, const u_char *np, u_int length)
1299 int count = 0, error;
1301 /* reqId (Integer) */
1302 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1304 if (elem.type != BE_INT) {
1305 ND_PRINT((ndo, "[reqId!=INT]"));
1306 asn1_print(ndo, &elem);
1310 ND_PRINT((ndo, "R=%d ", elem.data.integer));
1314 /* errorStatus (Integer) */
1315 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1317 if (elem.type != BE_INT) {
1318 ND_PRINT((ndo, "[errorStatus!=INT]"));
1319 asn1_print(ndo, &elem);
1323 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1324 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1325 && elem.data.integer != 0) {
1327 ND_PRINT((ndo, "[errorStatus(%s)!=0]",
1328 DECODE_ErrorStatus(elem.data.integer)));
1329 } else if (pduid == GETBULKREQ) {
1330 ND_PRINT((ndo, " N=%d", elem.data.integer));
1331 } else if (elem.data.integer != 0) {
1333 ND_PRINT((ndo, " %s", DECODE_ErrorStatus(elem.data.integer)));
1334 error = elem.data.integer;
1339 /* errorIndex (Integer) */
1340 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1342 if (elem.type != BE_INT) {
1343 ND_PRINT((ndo, "[errorIndex!=INT]"));
1344 asn1_print(ndo, &elem);
1347 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1348 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1349 && elem.data.integer != 0)
1350 ND_PRINT((ndo, "[errorIndex(%d)!=0]", elem.data.integer));
1351 else if (pduid == GETBULKREQ)
1352 ND_PRINT((ndo, " M=%d", elem.data.integer));
1353 else if (elem.data.integer != 0) {
1355 ND_PRINT((ndo, "[errorIndex(%d) w/o errorStatus]", elem.data.integer));
1357 ND_PRINT((ndo, "@%d", elem.data.integer));
1358 error = elem.data.integer;
1361 ND_PRINT((ndo, "[errorIndex==0]"));
1367 varbind_print(ndo, pduid, np, length);
1372 * Decode SNMP Trap PDU
1375 trappdu_print(netdissect_options *ndo,
1376 const u_char *np, u_int length)
1379 int count = 0, generic;
1381 ND_PRINT((ndo, " "));
1383 /* enterprise (oid) */
1384 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1386 if (elem.type != BE_OID) {
1387 ND_PRINT((ndo, "[enterprise!=OID]"));
1388 asn1_print(ndo, &elem);
1391 if (asn1_print(ndo, &elem) < 0)
1396 ND_PRINT((ndo, " "));
1398 /* agent-addr (inetaddr) */
1399 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1401 if (elem.type != BE_INETADDR) {
1402 ND_PRINT((ndo, "[agent-addr!=INETADDR]"));
1403 asn1_print(ndo, &elem);
1406 if (asn1_print(ndo, &elem) < 0)
1411 /* generic-trap (Integer) */
1412 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1414 if (elem.type != BE_INT) {
1415 ND_PRINT((ndo, "[generic-trap!=INT]"));
1416 asn1_print(ndo, &elem);
1419 generic = elem.data.integer;
1422 ND_PRINT((ndo, " %s", DECODE_GenericTrap(generic)));
1427 /* specific-trap (Integer) */
1428 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1430 if (elem.type != BE_INT) {
1431 ND_PRINT((ndo, "[specific-trap!=INT]"));
1432 asn1_print(ndo, &elem);
1435 if (generic != GT_ENTERPRISE) {
1436 if (elem.data.integer != 0)
1437 ND_PRINT((ndo, "[specific-trap(%d)!=0]", elem.data.integer));
1439 ND_PRINT((ndo, " s=%d", elem.data.integer));
1443 ND_PRINT((ndo, " "));
1445 /* time-stamp (TimeTicks) */
1446 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1448 if (elem.type != BE_UNS) { /* XXX */
1449 ND_PRINT((ndo, "[time-stamp!=TIMETICKS]"));
1450 asn1_print(ndo, &elem);
1453 if (asn1_print(ndo, &elem) < 0)
1458 varbind_print(ndo, TRAP, np, length);
1463 * Decode arbitrary SNMP PDUs.
1466 pdu_print(netdissect_options *ndo,
1467 const u_char *np, u_int length, int version)
1473 if ((count = asn1_parse(ndo, np, length, &pdu)) < 0)
1475 if (pdu.type != BE_PDU) {
1476 ND_PRINT((ndo, "[no PDU]"));
1479 if ((u_int)count < length)
1480 ND_PRINT((ndo, "[%d extra after PDU]", length - count));
1481 if (ndo->ndo_vflag) {
1482 ND_PRINT((ndo, "{ "));
1484 if (asn1_print(ndo, &pdu) < 0)
1486 ND_PRINT((ndo, " "));
1487 /* descend into PDU */
1488 length = pdu.asnlen;
1489 np = (u_char *)pdu.data.raw;
1491 if (version == SNMP_VERSION_1 &&
1492 (pdu.id == GETBULKREQ || pdu.id == INFORMREQ ||
1493 pdu.id == V2TRAP || pdu.id == REPORT)) {
1494 ND_PRINT((ndo, "[v2 PDU in v1 message]"));
1498 if (version == SNMP_VERSION_2 && pdu.id == TRAP) {
1499 ND_PRINT((ndo, "[v1 PDU in v2 message]"));
1505 trappdu_print(ndo, np, length);
1515 snmppdu_print(ndo, pdu.id, np, length);
1519 if (ndo->ndo_vflag) {
1520 ND_PRINT((ndo, " } "));
1525 * Decode a scoped SNMP PDU.
1528 scopedpdu_print(netdissect_options *ndo,
1529 const u_char *np, u_int length, int version)
1535 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1537 if (elem.type != BE_SEQ) {
1538 ND_PRINT((ndo, "[!scoped PDU]"));
1539 asn1_print(ndo, &elem);
1542 length = elem.asnlen;
1543 np = (u_char *)elem.data.raw;
1545 /* contextEngineID (OCTET STRING) */
1546 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1548 if (elem.type != BE_STR) {
1549 ND_PRINT((ndo, "[contextEngineID!=STR]"));
1550 asn1_print(ndo, &elem);
1556 ND_PRINT((ndo, "E= "));
1557 for (i = 0; i < (int)elem.asnlen; i++) {
1558 ND_PRINT((ndo, "0x%02X", elem.data.str[i]));
1560 ND_PRINT((ndo, " "));
1562 /* contextName (OCTET STRING) */
1563 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1565 if (elem.type != BE_STR) {
1566 ND_PRINT((ndo, "[contextName!=STR]"));
1567 asn1_print(ndo, &elem);
1573 ND_PRINT((ndo, "C=%.*s ", (int)elem.asnlen, elem.data.str));
1575 pdu_print(ndo, np, length, version);
1579 * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
1582 community_print(netdissect_options *ndo,
1583 const u_char *np, u_int length, int version)
1588 /* Community (String) */
1589 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1591 if (elem.type != BE_STR) {
1592 ND_PRINT((ndo, "[comm!=STR]"));
1593 asn1_print(ndo, &elem);
1596 /* default community */
1597 if (!(elem.asnlen == sizeof(DEF_COMMUNITY) - 1 &&
1598 strncmp((char *)elem.data.str, DEF_COMMUNITY,
1599 sizeof(DEF_COMMUNITY) - 1) == 0))
1601 ND_PRINT((ndo, "C=%.*s ", (int)elem.asnlen, elem.data.str));
1605 pdu_print(ndo, np, length, version);
1609 * Decode SNMPv3 User-based Security Message Header (SNMPv3)
1612 usm_print(netdissect_options *ndo,
1613 const u_char *np, u_int length)
1619 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1621 if (elem.type != BE_SEQ) {
1622 ND_PRINT((ndo, "[!usm]"));
1623 asn1_print(ndo, &elem);
1626 length = elem.asnlen;
1627 np = (u_char *)elem.data.raw;
1629 /* msgAuthoritativeEngineID (OCTET STRING) */
1630 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1632 if (elem.type != BE_STR) {
1633 ND_PRINT((ndo, "[msgAuthoritativeEngineID!=STR]"));
1634 asn1_print(ndo, &elem);
1640 /* msgAuthoritativeEngineBoots (INTEGER) */
1641 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1643 if (elem.type != BE_INT) {
1644 ND_PRINT((ndo, "[msgAuthoritativeEngineBoots!=INT]"));
1645 asn1_print(ndo, &elem);
1649 ND_PRINT((ndo, "B=%d ", elem.data.integer));
1653 /* msgAuthoritativeEngineTime (INTEGER) */
1654 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1656 if (elem.type != BE_INT) {
1657 ND_PRINT((ndo, "[msgAuthoritativeEngineTime!=INT]"));
1658 asn1_print(ndo, &elem);
1662 ND_PRINT((ndo, "T=%d ", elem.data.integer));
1666 /* msgUserName (OCTET STRING) */
1667 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1669 if (elem.type != BE_STR) {
1670 ND_PRINT((ndo, "[msgUserName!=STR]"));
1671 asn1_print(ndo, &elem);
1677 ND_PRINT((ndo, "U=%.*s ", (int)elem.asnlen, elem.data.str));
1679 /* msgAuthenticationParameters (OCTET STRING) */
1680 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1682 if (elem.type != BE_STR) {
1683 ND_PRINT((ndo, "[msgAuthenticationParameters!=STR]"));
1684 asn1_print(ndo, &elem);
1690 /* msgPrivacyParameters (OCTET STRING) */
1691 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1693 if (elem.type != BE_STR) {
1694 ND_PRINT((ndo, "[msgPrivacyParameters!=STR]"));
1695 asn1_print(ndo, &elem);
1701 if ((u_int)count < length)
1702 ND_PRINT((ndo, "[%d extra after usm SEQ]", length - count));
1706 * Decode SNMPv3 Message Header (SNMPv3)
1709 v3msg_print(netdissect_options *ndo,
1710 const u_char *np, u_int length)
1716 const u_char *xnp = np;
1717 int xlength = length;
1720 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1722 if (elem.type != BE_SEQ) {
1723 ND_PRINT((ndo, "[!message]"));
1724 asn1_print(ndo, &elem);
1727 length = elem.asnlen;
1728 np = (u_char *)elem.data.raw;
1730 if (ndo->ndo_vflag) {
1731 ND_PRINT((ndo, "{ "));
1734 /* msgID (INTEGER) */
1735 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1737 if (elem.type != BE_INT) {
1738 ND_PRINT((ndo, "[msgID!=INT]"));
1739 asn1_print(ndo, &elem);
1745 /* msgMaxSize (INTEGER) */
1746 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1748 if (elem.type != BE_INT) {
1749 ND_PRINT((ndo, "[msgMaxSize!=INT]"));
1750 asn1_print(ndo, &elem);
1756 /* msgFlags (OCTET STRING) */
1757 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1759 if (elem.type != BE_STR) {
1760 ND_PRINT((ndo, "[msgFlags!=STR]"));
1761 asn1_print(ndo, &elem);
1764 if (elem.asnlen != 1) {
1765 ND_PRINT((ndo, "[msgFlags size %d]", elem.asnlen));
1768 flags = elem.data.str[0];
1769 if (flags != 0x00 && flags != 0x01 && flags != 0x03
1770 && flags != 0x04 && flags != 0x05 && flags != 0x07) {
1771 ND_PRINT((ndo, "[msgFlags=0x%02X]", flags));
1777 ND_PRINT((ndo, "F=%s%s%s ",
1778 flags & 0x01 ? "a" : "",
1779 flags & 0x02 ? "p" : "",
1780 flags & 0x04 ? "r" : ""));
1782 /* msgSecurityModel (INTEGER) */
1783 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1785 if (elem.type != BE_INT) {
1786 ND_PRINT((ndo, "[msgSecurityModel!=INT]"));
1787 asn1_print(ndo, &elem);
1790 model = elem.data.integer;
1794 if ((u_int)count < length)
1795 ND_PRINT((ndo, "[%d extra after message SEQ]", length - count));
1797 if (ndo->ndo_vflag) {
1798 ND_PRINT((ndo, "} "));
1802 if (ndo->ndo_vflag) {
1803 ND_PRINT((ndo, "{ USM "));
1806 ND_PRINT((ndo, "[security model %d]", model));
1810 np = xnp + (np - xnp);
1811 length = xlength - (np - xnp);
1813 /* msgSecurityParameters (OCTET STRING) */
1814 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1816 if (elem.type != BE_STR) {
1817 ND_PRINT((ndo, "[msgSecurityParameters!=STR]"));
1818 asn1_print(ndo, &elem);
1825 usm_print(ndo, elem.data.str, elem.asnlen);
1826 if (ndo->ndo_vflag) {
1827 ND_PRINT((ndo, "} "));
1831 if (ndo->ndo_vflag) {
1832 ND_PRINT((ndo, "{ ScopedPDU "));
1835 scopedpdu_print(ndo, np, length, 3);
1837 if (ndo->ndo_vflag) {
1838 ND_PRINT((ndo, "} "));
1843 * Decode SNMP header and pass on to PDU printing routines
1846 snmp_print(netdissect_options *ndo,
1847 const u_char *np, u_int length)
1853 ND_PRINT((ndo, " "));
1855 /* initial Sequence */
1856 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1858 if (elem.type != BE_SEQ) {
1859 ND_PRINT((ndo, "[!init SEQ]"));
1860 asn1_print(ndo, &elem);
1863 if ((u_int)count < length)
1864 ND_PRINT((ndo, "[%d extra after iSEQ]", length - count));
1866 length = elem.asnlen;
1867 np = (u_char *)elem.data.raw;
1869 /* Version (INTEGER) */
1870 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1872 if (elem.type != BE_INT) {
1873 ND_PRINT((ndo, "[version!=INT]"));
1874 asn1_print(ndo, &elem);
1878 switch (elem.data.integer) {
1879 case SNMP_VERSION_1:
1880 case SNMP_VERSION_2:
1881 case SNMP_VERSION_3:
1883 ND_PRINT((ndo, "{ %s ", SnmpVersion[elem.data.integer]));
1886 ND_PRINT((ndo, "[version = %d]", elem.data.integer));
1889 version = elem.data.integer;
1894 case SNMP_VERSION_1:
1895 case SNMP_VERSION_2:
1896 community_print(ndo, np, length, version);
1898 case SNMP_VERSION_3:
1899 v3msg_print(ndo, np, length);
1902 ND_PRINT((ndo, "[version = %d]", elem.data.integer));
1906 if (ndo->ndo_vflag) {
1907 ND_PRINT((ndo, "} "));