4 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
5 * John Robert LoVerso. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * This implementation has been influenced by the CMU SNMP release,
31 * by Steve Waldbusser. However, this shares no code with that system.
32 * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_.
33 * Earlier forms of this implementation were derived and/or inspired by an
34 * awk script originally written by C. Philip Wood of LANL (but later
35 * heavily modified by John Robert LoVerso). The copyright notice for
36 * that work is preserved below, even though it may not rightly apply
39 * Support for SNMPv2c/SNMPv3 and the ability to link the module against
40 * the libsmi was added by J. Schoenwaelder, Copyright (c) 1999.
42 * This started out as a very simple program, but the incremental decoding
43 * (into the BE structure) complicated things.
45 # Los Alamos National Laboratory
47 # Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
48 # This software was produced under a U.S. Government contract
49 # (W-7405-ENG-36) by Los Alamos National Laboratory, which is
50 # operated by the University of California for the U.S. Department
51 # of Energy. The U.S. Government is licensed to use, reproduce,
52 # and distribute this software. Permission is granted to the
53 # public to copy and use this software without charge, provided
54 # that this Notice and any statement of authorship are reproduced
55 # on all copies. Neither the Government nor the University makes
56 # any warranty, express or implied, or assumes any liability or
57 # responsibility for the use of this software.
58 # @(#)snmp.awk.x 1.1 (LANL) 1/15/90
61 #include <sys/cdefs.h>
64 static const char rcsid
[] _U_
=
65 "@(#) Header: /tcpdump/master/tcpdump/print-snmp.c,v 1.62.2.2 2005/05/06 07:57:19 guy Exp (LBL)";
67 __RCSID("$NetBSD: tcpdump2rcsid.ex,v 1.1 2001/06/25 20:09:58 itojun Exp $");
75 #include <tcpdump-stdinc.h>
84 #include "interface.h"
85 #include "addrtoname.h"
87 #undef OPAQUE /* defined in <wingdi.h> */
90 * Universal ASN.1 types
91 * (we only care about the tag values for those allowed in the Internet SMI)
93 const char *Universal
[] = {
106 "U-8","U-9","U-10","U-11", /* 8-11 */
107 "U-12","U-13","U-14","U-15", /* 12-15 */
114 * Application-wide ASN.1 types from the Internet SMI and their tags
116 const char *Application
[] = {
133 * Context-specific ASN.1 types for the SNMP PDUs and their tags
135 const char *Context
[] = {
156 #define NOTIFY_CLASS(x) (x == TRAP || x == V2TRAP || x == INFORMREQ)
157 #define READ_CLASS(x) (x == GETREQ || x == GETNEXTREQ || x == GETBULKREQ)
158 #define WRITE_CLASS(x) (x == SETREQ)
159 #define RESPONSE_CLASS(x) (x == GETRESP)
160 #define INTERNAL_CLASS(x) (x == REPORT)
163 * Context-specific ASN.1 types for the SNMP Exceptions and their tags
165 const char *Exceptions
[] = {
167 #define NOSUCHOBJECT 0
169 #define NOSUCHINSTANCE 1
171 #define ENDOFMIBVIEW 2
175 * Private ASN.1 types
176 * The Internet SMI does not specify any
178 const char *Private
[] = {
183 * error-status values for any SNMP PDU
185 const char *ErrorStatus
[] = {
199 "resourceUnavailable",
202 "authorizationError",
206 #define DECODE_ErrorStatus(e) \
207 ( e >= 0 && (size_t)e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
209 : (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf))
212 * generic-trap values in the SNMP Trap-PDU
214 const char *GenericTrap
[] = {
219 "authenticationFailure",
222 #define GT_ENTERPRISE 6
224 #define DECODE_GenericTrap(t) \
225 ( t >= 0 && (size_t)t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
227 : (snprintf(buf, sizeof(buf), "gt=%d", t), buf))
230 * ASN.1 type class table
231 * Ties together the preceding Universal, Application, Context, and Private
234 #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
240 defineCLASS(Universal
),
242 defineCLASS(Application
),
243 #define APPLICATION 1
244 defineCLASS(Context
),
246 defineCLASS(Private
),
248 defineCLASS(Exceptions
),
253 * defined forms for ASN.1 types
255 const char *Form
[] = {
259 #define CONSTRUCTED 1
263 * A structure for the OID tree for the compiled-in MIB.
264 * This is stored as a general-order tree.
267 const char *desc
; /* name of object */
268 u_char oid
; /* sub-id following parent */
269 u_char type
; /* object type (unused) */
270 struct obj
*child
, *next
; /* child and next sibling pointers */
274 * Include the compiled in SNMP MIB. "mib.h" is produced by feeding
275 * RFC-1156 format files into "makemib". "mib.h" MUST define at least
276 * a value for `mibroot'.
278 * In particular, this is gross, as this is including initialized structures,
279 * and by right shouldn't be an "include" file.
284 * This defines a list of OIDs which will be abbreviated on output.
285 * Currently, this includes the prefixes for the Internet MIB, the
286 * private enterprises tree, and the experimental tree.
289 const char *prefix
; /* prefix for this abrev */
290 struct obj
*node
; /* pointer into object table */
291 const char *oid
; /* ASN.1 encoded OID */
292 } obj_abrev_list
[] = {
294 /* .iso.org.dod.internet.mgmt.mib */
295 { "", &_mib_obj
, "\53\6\1\2\1" },
297 #ifndef NO_ABREV_ENTER
298 /* .iso.org.dod.internet.private.enterprises */
299 { "E:", &_enterprises_obj
, "\53\6\1\4\1" },
301 #ifndef NO_ABREV_EXPERI
302 /* .iso.org.dod.internet.experimental */
303 { "X:", &_experimental_obj
, "\53\6\1\3" },
305 #ifndef NO_ABBREV_SNMPMODS
306 /* .iso.org.dod.internet.snmpV2.snmpModules */
307 { "S:", &_snmpModules_obj
, "\53\6\1\6\3" },
313 * This is used in the OID print routine to walk down the object tree
314 * rooted at `mibroot'.
316 #define OBJ_PRINT(o, suppressdot) \
320 if ((o) == objp->oid) \
322 } while ((objp = objp->next) != NULL); \
325 printf(suppressdot?"%s":".%s", objp->desc); \
326 objp = objp->child; \
328 printf(suppressdot?"%u":".%u", (o)); \
332 * This is the definition for the Any-Data-Type storage used purely for
333 * temporary internal representation while decoding an ASN.1 data stream.
348 u_char form
, class; /* tag info */
359 #define BE_INETADDR 8
362 #define BE_NOSUCHOBJECT 128
363 #define BE_NOSUCHINST 129
364 #define BE_ENDOFMIBVIEW 130
368 * SNMP versions recognized by this module
370 const char *SnmpVersion
[] = {
372 #define SNMP_VERSION_1 0
374 #define SNMP_VERSION_2 1
376 #define SNMP_VERSION_2U 2
378 #define SNMP_VERSION_3 3
382 * Defaults for SNMP PDU components
384 #define DEF_COMMUNITY "public"
387 * constants for ASN.1 decoding
390 #define ASNLEN_INETADDR 4
393 #define ASN_BIT8 0x80
394 #define ASN_LONGLEN 0x80
396 #define ASN_ID_BITS 0x1f
397 #define ASN_FORM_BITS 0x20
398 #define ASN_FORM_SHIFT 5
399 #define ASN_CLASS_BITS 0xc0
400 #define ASN_CLASS_SHIFT 6
402 #define ASN_ID_EXT 0x1f /* extension ID in tag field */
405 * This decodes the next ASN.1 object in the stream pointed to by "p"
406 * (and of real-length "len") and stores the intermediate data in the
407 * provided BE object.
409 * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
410 * O/w, this returns the number of bytes parsed from "p".
413 asn1_parse(register const u_char
*p
, u_int len
, struct be
*elem
)
415 u_char form
, class, id
;
421 fputs("[nothing to parse]", stdout
);
427 * it would be nice to use a bit field, but you can't depend on them.
428 * +---+---+---+---+---+---+---+---+
430 * +---+---+---+---+---+---+---+---+
433 id
= *p
& ASN_ID_BITS
; /* lower 5 bits, range 00-1f */
435 form
= (*p
& 0xe0) >> 5; /* move upper 3 bits to lower 3 */
436 class = form
>> 1; /* bits 7&6 -> bits 1&0, range 0-3 */
437 form
&= 0x1; /* bit 5 -> bit 0, range 0-1 */
439 form
= (u_char
)(*p
& ASN_FORM_BITS
) >> ASN_FORM_SHIFT
;
440 class = (u_char
)(*p
& ASN_CLASS_BITS
) >> ASN_CLASS_SHIFT
;
446 /* extended tag field */
447 if (id
== ASN_ID_EXT
) {
449 * The ID follows, as a sequence of octets with the
450 * 8th bit set and the remaining 7 bits being
451 * the next 7 bits of the value, terminated with
452 * an octet with the 8th bit not set.
454 * First, assemble all the octets with the 8th
455 * bit set. XXX - this doesn't handle a value
456 * that won't fit in 32 bits.
458 for (id
= 0; *p
& ASN_BIT8
; len
--, hdr
++, p
++) {
460 fputs("[Xtagfield?]", stdout
);
464 id
= (id
<< 7) | (*p
& ~ASN_BIT8
);
467 fputs("[Xtagfield?]", stdout
);
471 elem
->id
= id
= (id
<< 7) | *p
;
477 fputs("[no asnlen]", stdout
);
483 if (elem
->asnlen
& ASN_BIT8
) {
484 u_int32_t noct
= elem
->asnlen
% ASN_BIT8
;
487 printf("[asnlen? %d<%d]", len
, noct
);
491 for (; noct
-- > 0; len
--, hdr
++)
492 elem
->asnlen
= (elem
->asnlen
<< ASN_SHIFT8
) | *p
++;
494 if (len
< elem
->asnlen
) {
495 printf("[len%d<asnlen%u]", len
, elem
->asnlen
);
498 if (form
>= sizeof(Form
)/sizeof(Form
[0])) {
499 printf("[form?%d]", form
);
502 if (class >= sizeof(Class
)/sizeof(Class
[0])) {
503 printf("[class?%c/%d]", *Form
[form
], class);
506 if ((int)id
>= Class
[class].numIDs
) {
507 printf("[id?%c/%s/%d]", *Form
[form
], Class
[class].name
, id
);
522 register int32_t data
;
526 TCHECK2(*p
, elem
->asnlen
);
527 if (*p
& ASN_BIT8
) /* negative */
529 for (i
= elem
->asnlen
; i
-- > 0; p
++)
530 data
= (data
<< ASN_SHIFT8
) | *p
;
531 elem
->data
.integer
= data
;
537 elem
->data
.raw
= (caddr_t
)p
;
541 elem
->type
= BE_NULL
;
542 elem
->data
.raw
= NULL
;
546 elem
->type
= BE_OCTET
;
547 elem
->data
.raw
= (caddr_t
)p
;
549 Class
[class].Id
[id
]);
557 elem
->type
= BE_INETADDR
;
558 elem
->data
.raw
= (caddr_t
)p
;
564 register u_int32_t data
;
565 TCHECK2(*p
, elem
->asnlen
);
568 for (i
= elem
->asnlen
; i
-- > 0; p
++)
569 data
= (data
<< 8) + *p
;
570 elem
->data
.uns
= data
;
575 register u_int32_t high
, low
;
576 TCHECK2(*p
, elem
->asnlen
);
577 elem
->type
= BE_UNS64
;
579 for (i
= elem
->asnlen
; i
-- > 0; p
++) {
581 ((low
& 0xFF000000) >> 24);
582 low
= (low
<< 8) | *p
;
584 elem
->data
.uns64
.high
= high
;
585 elem
->data
.uns64
.low
= low
;
590 elem
->type
= BE_OCTET
;
591 elem
->data
.raw
= (caddr_t
)p
;
593 Class
[class].Id
[id
]);
601 elem
->type
= BE_NOSUCHOBJECT
;
602 elem
->data
.raw
= NULL
;
606 elem
->type
= BE_NOSUCHINST
;
607 elem
->data
.raw
= NULL
;
611 elem
->type
= BE_ENDOFMIBVIEW
;
612 elem
->data
.raw
= NULL
;
619 Class
[class].name
, Class
[class].Id
[id
]);
620 TCHECK2(*p
, elem
->asnlen
);
621 elem
->type
= BE_OCTET
;
622 elem
->data
.raw
= (caddr_t
)p
;
633 elem
->data
.raw
= (caddr_t
)p
;
637 elem
->type
= BE_OCTET
;
638 elem
->data
.raw
= (caddr_t
)p
;
639 printf("C/U/%s", Class
[class].Id
[id
]);
646 elem
->data
.raw
= (caddr_t
)p
;
650 elem
->type
= BE_OCTET
;
651 elem
->data
.raw
= (caddr_t
)p
;
653 Class
[class].name
, Class
[class].Id
[id
]);
660 return elem
->asnlen
+ hdr
;
663 fputs("[|snmp]", stdout
);
668 * Display the ASN.1 object represented by the BE object.
669 * This used to be an integral part of asn1_parse() before the intermediate
673 asn1_print(struct be
*elem
)
675 u_char
*p
= (u_char
*)elem
->data
.raw
;
676 u_int32_t asnlen
= elem
->asnlen
;
679 switch (elem
->type
) {
683 for (i
= asnlen
; i
-- > 0; p
++)
691 int o
= 0, first
= -1, i
= asnlen
;
693 if (!sflag
&& !nflag
&& asnlen
> 2) {
694 struct obj_abrev
*a
= &obj_abrev_list
[0];
695 size_t a_len
= strlen(a
->oid
);
696 for (; a
->node
; a
++) {
698 if (memcmp(a
->oid
, (char *)p
, a_len
) == 0) {
699 objp
= a
->node
->child
;
702 fputs(a
->prefix
, stdout
);
709 for (; !sflag
&& i
-- > 0; p
++) {
711 o
= (o
<< ASN_SHIFT7
) + (*p
& ~ASN_BIT8
);
712 if (*p
& ASN_LONGLEN
)
716 * first subitem encodes two items with 1st*OIDMUX+2nd
717 * (see X.690:1997 clause 8.19 for the details)
738 printf("%d", elem
->data
.integer
);
742 printf("%u", elem
->data
.uns
);
745 case BE_UNS64
: { /* idea borrowed from by Marshall Rose */
748 char *cpf
, *cpl
, last
[6], first
[30];
749 if (elem
->data
.uns64
.high
== 0) {
750 printf("%u", elem
->data
.uns64
.low
);
753 d
= elem
->data
.uns64
.high
* 4294967296.0; /* 2^32 */
754 if (elem
->data
.uns64
.high
<= 0x1fffff) {
755 d
+= elem
->data
.uns64
.low
;
756 #if 0 /*is looks illegal, but what is the intention?*/
763 d
+= (elem
->data
.uns64
.low
& 0xfffff000);
764 #if 0 /*is looks illegal, but what is the intention?*/
765 snprintf(first
, sizeof(first
), "%.f", d
);
767 snprintf(first
, sizeof(first
), "%f", d
);
769 snprintf(last
, sizeof(last
), "%5.5d",
770 elem
->data
.uns64
.low
& 0xfff);
771 for (carry
= 0, cpf
= first
+strlen(first
)-1, cpl
= last
+4;
774 j
= carry
+ (*cpf
- '0') + (*cpl
- '0');
783 fputs(first
, stdout
);
788 register int printable
= 1, first
= 1;
789 const u_char
*p
= elem
->data
.str
;
791 for (i
= asnlen
; printable
&& i
-- > 0; p
++)
792 printable
= isprint(*p
) || isspace(*p
);
796 if (fn_printn(p
, asnlen
, snapend
)) {
802 for (i
= asnlen
; i
-- > 0; p
++) {
803 printf(first
? "%.2x" : "_%.2x", *p
);
810 printf("Seq(%u)", elem
->asnlen
);
814 if (asnlen
!= ASNLEN_INETADDR
)
815 printf("[inetaddr len!=%d]", ASNLEN_INETADDR
);
817 for (i
= asnlen
; i
-- != 0; p
++) {
818 printf((i
== asnlen
-1) ? "%u" : ".%u", *p
);
822 case BE_NOSUCHOBJECT
:
824 case BE_ENDOFMIBVIEW
:
825 printf("[%s]", Class
[EXCEPTIONS
].Id
[elem
->id
]);
830 Class
[CONTEXT
].Id
[elem
->id
], elem
->asnlen
);
834 fputs("[BE_ANY!?]", stdout
);
838 fputs("[be!?]", stdout
);
844 fputs("[|snmp]", stdout
);
850 * This is a brute force ASN.1 printer: recurses to dump an entire structure.
851 * This will work for any ASN.1 stream, not just an SNMP PDU.
853 * By adding newlines and spaces at the correct places, this would print in
856 * This is not currently used.
859 asn1_decode(u_char
*p
, u_int length
)
864 while (i
>= 0 && length
> 0) {
865 i
= asn1_parse(p
, length
, &elem
);
868 if (asn1_print(&elem
) < 0)
870 if (elem
.type
== BE_SEQ
|| elem
.type
== BE_PDU
) {
872 asn1_decode(elem
.data
.raw
, elem
.asnlen
);
885 SmiBasetype basetype
;
889 static struct smi2be smi2betab
[] = {
890 { SMI_BASETYPE_INTEGER32
, BE_INT
},
891 { SMI_BASETYPE_OCTETSTRING
, BE_STR
},
892 { SMI_BASETYPE_OCTETSTRING
, BE_INETADDR
},
893 { SMI_BASETYPE_OBJECTIDENTIFIER
, BE_OID
},
894 { SMI_BASETYPE_UNSIGNED32
, BE_UNS
},
895 { SMI_BASETYPE_INTEGER64
, BE_NONE
},
896 { SMI_BASETYPE_UNSIGNED64
, BE_UNS64
},
897 { SMI_BASETYPE_FLOAT32
, BE_NONE
},
898 { SMI_BASETYPE_FLOAT64
, BE_NONE
},
899 { SMI_BASETYPE_FLOAT128
, BE_NONE
},
900 { SMI_BASETYPE_ENUM
, BE_INT
},
901 { SMI_BASETYPE_BITS
, BE_STR
},
902 { SMI_BASETYPE_UNKNOWN
, BE_NONE
}
906 smi_decode_oid(struct be
*elem
, unsigned int *oid
,
907 unsigned int oidsize
, unsigned int *oidlen
)
909 u_char
*p
= (u_char
*)elem
->data
.raw
;
910 u_int32_t asnlen
= elem
->asnlen
;
911 int o
= 0, first
= -1, i
= asnlen
;
913 for (*oidlen
= 0; sflag
&& i
-- > 0; p
++) {
915 o
= (o
<< ASN_SHIFT7
) + (*p
& ~ASN_BIT8
);
916 if (*p
& ASN_LONGLEN
)
920 * first subitem encodes two items with 1st*OIDMUX+2nd
921 * (see X.690:1997 clause 8.19 for the details)
925 if (*oidlen
< oidsize
) {
926 oid
[*oidlen
] = o
/ OIDMUX
;
927 if (oid
[*oidlen
] > 2) oid
[*oidlen
] = 2;
929 o
-= oid
[*oidlen
] * OIDMUX
;
930 if (*oidlen
< oidsize
) (*oidlen
)++;
932 if (*oidlen
< oidsize
) {
933 oid
[(*oidlen
)++] = o
;
940 fputs("[|snmp]", stdout
);
944 static int smi_check_type(SmiBasetype basetype
, int be
)
948 for (i
= 0; smi2betab
[i
].basetype
!= SMI_BASETYPE_UNKNOWN
; i
++) {
949 if (smi2betab
[i
].basetype
== basetype
&& smi2betab
[i
].be
== be
) {
957 static int smi_check_a_range(SmiType
*smiType
, SmiRange
*smiRange
,
962 switch (smiType
->basetype
) {
963 case SMI_BASETYPE_OBJECTIDENTIFIER
:
964 case SMI_BASETYPE_OCTETSTRING
:
965 if (smiRange
->minValue
.value
.unsigned32
966 == smiRange
->maxValue
.value
.unsigned32
) {
967 ok
= (elem
->asnlen
== smiRange
->minValue
.value
.unsigned32
);
969 ok
= (elem
->asnlen
>= smiRange
->minValue
.value
.unsigned32
970 && elem
->asnlen
<= smiRange
->maxValue
.value
.unsigned32
);
974 case SMI_BASETYPE_INTEGER32
:
975 ok
= (elem
->data
.integer
>= smiRange
->minValue
.value
.integer32
976 && elem
->data
.integer
<= smiRange
->maxValue
.value
.integer32
);
979 case SMI_BASETYPE_UNSIGNED32
:
980 ok
= (elem
->data
.uns
>= smiRange
->minValue
.value
.unsigned32
981 && elem
->data
.uns
<= smiRange
->maxValue
.value
.unsigned32
);
984 case SMI_BASETYPE_UNSIGNED64
:
988 /* case SMI_BASETYPE_INTEGER64: SMIng */
989 /* case SMI_BASETYPE_FLOAT32: SMIng */
990 /* case SMI_BASETYPE_FLOAT64: SMIng */
991 /* case SMI_BASETYPE_FLOAT128: SMIng */
993 case SMI_BASETYPE_ENUM
:
994 case SMI_BASETYPE_BITS
:
995 case SMI_BASETYPE_UNKNOWN
:
1007 static int smi_check_range(SmiType
*smiType
, struct be
*elem
)
1012 for (smiRange
= smiGetFirstRange(smiType
);
1014 smiRange
= smiGetNextRange(smiRange
)) {
1016 ok
= smi_check_a_range(smiType
, smiRange
, elem
);
1024 SmiType
*parentType
;
1025 parentType
= smiGetParentType(smiType
);
1027 ok
= smi_check_range(parentType
, elem
);
1034 static SmiNode
*smi_print_variable(struct be
*elem
, int *status
)
1036 unsigned int oid
[128], oidlen
;
1037 SmiNode
*smiNode
= NULL
;
1040 *status
= smi_decode_oid(elem
, oid
, sizeof(oid
)/sizeof(unsigned int),
1044 smiNode
= smiGetNodeByOID(oidlen
, oid
);
1046 *status
= asn1_print(elem
);
1050 fputs(smiGetNodeModule(smiNode
)->name
, stdout
);
1051 fputs("::", stdout
);
1053 fputs(smiNode
->name
, stdout
);
1054 if (smiNode
->oidlen
< oidlen
) {
1055 for (i
= smiNode
->oidlen
; i
< oidlen
; i
++) {
1056 printf(".%u", oid
[i
]);
1064 smi_print_value(SmiNode
*smiNode
, u_char pduid
, struct be
*elem
)
1066 unsigned int i
, oid
[128], oidlen
;
1071 if (! smiNode
|| ! (smiNode
->nodekind
1072 & (SMI_NODEKIND_SCALAR
| SMI_NODEKIND_COLUMN
))) {
1073 return asn1_print(elem
);
1076 if (elem
->type
== BE_NOSUCHOBJECT
1077 || elem
->type
== BE_NOSUCHINST
1078 || elem
->type
== BE_ENDOFMIBVIEW
) {
1079 return asn1_print(elem
);
1082 if (NOTIFY_CLASS(pduid
) && smiNode
->access
< SMI_ACCESS_NOTIFY
) {
1083 fputs("[notNotifyable]", stdout
);
1086 if (READ_CLASS(pduid
) && smiNode
->access
< SMI_ACCESS_READ_ONLY
) {
1087 fputs("[notReadable]", stdout
);
1090 if (WRITE_CLASS(pduid
) && smiNode
->access
< SMI_ACCESS_READ_WRITE
) {
1091 fputs("[notWritable]", stdout
);
1094 if (RESPONSE_CLASS(pduid
)
1095 && smiNode
->access
== SMI_ACCESS_NOT_ACCESSIBLE
) {
1096 fputs("[noAccess]", stdout
);
1099 smiType
= smiGetNodeType(smiNode
);
1101 return asn1_print(elem
);
1104 if (! smi_check_type(smiType
->basetype
, elem
->type
)) {
1105 fputs("[wrongType]", stdout
);
1108 if (! smi_check_range(smiType
, elem
)) {
1109 fputs("[outOfRange]", stdout
);
1112 /* resolve bits to named bits */
1114 /* check whether instance identifier is valid */
1116 /* apply display hints (integer, octetstring) */
1118 /* convert instance identifier to index type values */
1120 switch (elem
->type
) {
1122 if (smiType
->basetype
== SMI_BASETYPE_BITS
) {
1123 /* print bit labels */
1125 smi_decode_oid(elem
, oid
,
1126 sizeof(oid
)/sizeof(unsigned int),
1128 smiNode
= smiGetNodeByOID(oidlen
, oid
);
1131 fputs(smiGetNodeModule(smiNode
)->name
, stdout
);
1132 fputs("::", stdout
);
1134 fputs(smiNode
->name
, stdout
);
1135 if (smiNode
->oidlen
< oidlen
) {
1136 for (i
= smiNode
->oidlen
;
1138 printf(".%u", oid
[i
]);
1147 if (smiType
->basetype
== SMI_BASETYPE_ENUM
) {
1148 for (nn
= smiGetFirstNamedNumber(smiType
);
1150 nn
= smiGetNextNamedNumber(nn
)) {
1151 if (nn
->value
.value
.integer32
1152 == elem
->data
.integer
) {
1153 fputs(nn
->name
, stdout
);
1154 printf("(%d)", elem
->data
.integer
);
1164 return asn1_print(elem
);
1171 * General SNMP header
1173 * version INTEGER {version-1(0)},
1174 * community OCTET STRING,
1177 * PDUs for all but Trap: (see rfc1157 from page 15 on)
1179 * request-id INTEGER,
1180 * error-status INTEGER,
1181 * error-index INTEGER,
1182 * varbindlist SEQUENCE OF
1190 * enterprise OBJECT IDENTIFIER,
1191 * agent-addr NetworkAddress,
1192 * generic-trap INTEGER,
1193 * specific-trap INTEGER,
1194 * time-stamp TimeTicks,
1195 * varbindlist SEQUENCE OF
1204 * Decode SNMP varBind
1207 varbind_print(u_char pduid
, const u_char
*np
, u_int length
)
1212 SmiNode
*smiNode
= NULL
;
1216 /* Sequence of varBind */
1217 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1219 if (elem
.type
!= BE_SEQ
) {
1220 fputs("[!SEQ of varbind]", stdout
);
1224 if ((u_int
)count
< length
)
1225 printf("[%d extra after SEQ of varbind]", length
- count
);
1227 length
= elem
.asnlen
;
1228 np
= (u_char
*)elem
.data
.raw
;
1230 for (ind
= 1; length
> 0; ind
++) {
1231 const u_char
*vbend
;
1237 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1239 if (elem
.type
!= BE_SEQ
) {
1240 fputs("[!varbind]", stdout
);
1245 vblength
= length
- count
;
1247 length
= elem
.asnlen
;
1248 np
= (u_char
*)elem
.data
.raw
;
1251 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1253 if (elem
.type
!= BE_OID
) {
1254 fputs("[objName!=OID]", stdout
);
1259 smiNode
= smi_print_variable(&elem
, &status
);
1261 status
= asn1_print(&elem
);
1268 if (pduid
!= GETREQ
&& pduid
!= GETNEXTREQ
1269 && pduid
!= GETBULKREQ
)
1273 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1275 if (pduid
== GETREQ
|| pduid
== GETNEXTREQ
1276 || pduid
== GETBULKREQ
) {
1277 if (elem
.type
!= BE_NULL
) {
1278 fputs("[objVal!=NULL]", stdout
);
1279 if (asn1_print(&elem
) < 0)
1283 if (elem
.type
!= BE_NULL
) {
1285 status
= smi_print_value(smiNode
, pduid
, &elem
);
1287 status
= asn1_print(&elem
);
1299 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
1300 * GetBulk, Inform, V2Trap, and Report
1303 snmppdu_print(u_short pduid
, const u_char
*np
, u_int length
)
1306 int count
= 0, error
;
1308 /* reqId (Integer) */
1309 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1311 if (elem
.type
!= BE_INT
) {
1312 fputs("[reqId!=INT]", stdout
);
1317 printf("R=%d ", elem
.data
.integer
);
1321 /* errorStatus (Integer) */
1322 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1324 if (elem
.type
!= BE_INT
) {
1325 fputs("[errorStatus!=INT]", stdout
);
1330 if ((pduid
== GETREQ
|| pduid
== GETNEXTREQ
|| pduid
== SETREQ
1331 || pduid
== INFORMREQ
|| pduid
== V2TRAP
|| pduid
== REPORT
)
1332 && elem
.data
.integer
!= 0) {
1334 printf("[errorStatus(%s)!=0]",
1335 DECODE_ErrorStatus(elem
.data
.integer
));
1336 } else if (pduid
== GETBULKREQ
) {
1337 printf(" N=%d", elem
.data
.integer
);
1338 } else if (elem
.data
.integer
!= 0) {
1340 printf(" %s", DECODE_ErrorStatus(elem
.data
.integer
));
1341 error
= elem
.data
.integer
;
1346 /* errorIndex (Integer) */
1347 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1349 if (elem
.type
!= BE_INT
) {
1350 fputs("[errorIndex!=INT]", stdout
);
1354 if ((pduid
== GETREQ
|| pduid
== GETNEXTREQ
|| pduid
== SETREQ
1355 || pduid
== INFORMREQ
|| pduid
== V2TRAP
|| pduid
== REPORT
)
1356 && elem
.data
.integer
!= 0)
1357 printf("[errorIndex(%d)!=0]", elem
.data
.integer
);
1358 else if (pduid
== GETBULKREQ
)
1359 printf(" M=%d", elem
.data
.integer
);
1360 else if (elem
.data
.integer
!= 0) {
1362 printf("[errorIndex(%d) w/o errorStatus]",
1365 printf("@%d", elem
.data
.integer
);
1366 error
= elem
.data
.integer
;
1369 fputs("[errorIndex==0]", stdout
);
1375 varbind_print(pduid
, np
, length
);
1380 * Decode SNMP Trap PDU
1383 trappdu_print(const u_char
*np
, u_int length
)
1386 int count
= 0, generic
;
1390 /* enterprise (oid) */
1391 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1393 if (elem
.type
!= BE_OID
) {
1394 fputs("[enterprise!=OID]", stdout
);
1398 if (asn1_print(&elem
) < 0)
1405 /* agent-addr (inetaddr) */
1406 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1408 if (elem
.type
!= BE_INETADDR
) {
1409 fputs("[agent-addr!=INETADDR]", stdout
);
1413 if (asn1_print(&elem
) < 0)
1418 /* generic-trap (Integer) */
1419 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1421 if (elem
.type
!= BE_INT
) {
1422 fputs("[generic-trap!=INT]", stdout
);
1426 generic
= elem
.data
.integer
;
1429 printf(" %s", DECODE_GenericTrap(generic
));
1434 /* specific-trap (Integer) */
1435 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1437 if (elem
.type
!= BE_INT
) {
1438 fputs("[specific-trap!=INT]", stdout
);
1442 if (generic
!= GT_ENTERPRISE
) {
1443 if (elem
.data
.integer
!= 0)
1444 printf("[specific-trap(%d)!=0]", elem
.data
.integer
);
1446 printf(" s=%d", elem
.data
.integer
);
1452 /* time-stamp (TimeTicks) */
1453 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1455 if (elem
.type
!= BE_UNS
) { /* XXX */
1456 fputs("[time-stamp!=TIMETICKS]", stdout
);
1460 if (asn1_print(&elem
) < 0)
1465 varbind_print (TRAP
, np
, length
);
1470 * Decode arbitrary SNMP PDUs.
1473 pdu_print(const u_char
*np
, u_int length
, int version
)
1479 if ((count
= asn1_parse(np
, length
, &pdu
)) < 0)
1481 if (pdu
.type
!= BE_PDU
) {
1482 fputs("[no PDU]", stdout
);
1485 if ((u_int
)count
< length
)
1486 printf("[%d extra after PDU]", length
- count
);
1488 fputs("{ ", stdout
);
1490 if (asn1_print(&pdu
) < 0)
1493 /* descend into PDU */
1494 length
= pdu
.asnlen
;
1495 np
= (u_char
*)pdu
.data
.raw
;
1497 if (version
== SNMP_VERSION_1
&&
1498 (pdu
.id
== GETBULKREQ
|| pdu
.id
== INFORMREQ
||
1499 pdu
.id
== V2TRAP
|| pdu
.id
== REPORT
)) {
1500 printf("[v2 PDU in v1 message]");
1504 if (version
== SNMP_VERSION_2
&& pdu
.id
== TRAP
) {
1505 printf("[v1 PDU in v2 message]");
1511 trappdu_print(np
, length
);
1521 snmppdu_print(pdu
.id
, np
, length
);
1526 fputs(" } ", stdout
);
1531 * Decode a scoped SNMP PDU.
1534 scopedpdu_print(const u_char
*np
, u_int length
, int version
)
1540 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1542 if (elem
.type
!= BE_SEQ
) {
1543 fputs("[!scoped PDU]", stdout
);
1547 length
= elem
.asnlen
;
1548 np
= (u_char
*)elem
.data
.raw
;
1550 /* contextEngineID (OCTET STRING) */
1551 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1553 if (elem
.type
!= BE_STR
) {
1554 fputs("[contextEngineID!=STR]", stdout
);
1561 fputs("E= ", stdout
);
1562 for (i
= 0; i
< (int)elem
.asnlen
; i
++) {
1563 printf("0x%02X", elem
.data
.str
[i
]);
1567 /* contextName (OCTET STRING) */
1568 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1570 if (elem
.type
!= BE_STR
) {
1571 fputs("[contextName!=STR]", stdout
);
1578 printf("C=%.*s ", (int)elem
.asnlen
, elem
.data
.str
);
1580 pdu_print(np
, length
, version
);
1584 * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
1587 community_print(const u_char
*np
, u_int length
, int version
)
1592 /* Community (String) */
1593 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1595 if (elem
.type
!= BE_STR
) {
1596 fputs("[comm!=STR]", stdout
);
1600 /* default community */
1601 if (!(elem
.asnlen
== sizeof(DEF_COMMUNITY
) - 1 &&
1602 strncmp((char *)elem
.data
.str
, DEF_COMMUNITY
,
1603 sizeof(DEF_COMMUNITY
) - 1) == 0))
1605 printf("C=%.*s ", (int)elem
.asnlen
, elem
.data
.str
);
1609 pdu_print(np
, length
, version
);
1613 * Decode SNMPv3 User-based Security Message Header (SNMPv3)
1616 usm_print(const u_char
*np
, u_int length
)
1622 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1624 if (elem
.type
!= BE_SEQ
) {
1625 fputs("[!usm]", stdout
);
1629 length
= elem
.asnlen
;
1630 np
= (u_char
*)elem
.data
.raw
;
1632 /* msgAuthoritativeEngineID (OCTET STRING) */
1633 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1635 if (elem
.type
!= BE_STR
) {
1636 fputs("[msgAuthoritativeEngineID!=STR]", stdout
);
1643 /* msgAuthoritativeEngineBoots (INTEGER) */
1644 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1646 if (elem
.type
!= BE_INT
) {
1647 fputs("[msgAuthoritativeEngineBoots!=INT]", stdout
);
1652 printf("B=%d ", elem
.data
.integer
);
1656 /* msgAuthoritativeEngineTime (INTEGER) */
1657 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1659 if (elem
.type
!= BE_INT
) {
1660 fputs("[msgAuthoritativeEngineTime!=INT]", stdout
);
1665 printf("T=%d ", elem
.data
.integer
);
1669 /* msgUserName (OCTET STRING) */
1670 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1672 if (elem
.type
!= BE_STR
) {
1673 fputs("[msgUserName!=STR]", stdout
);
1680 printf("U=%.*s ", (int)elem
.asnlen
, elem
.data
.str
);
1682 /* msgAuthenticationParameters (OCTET STRING) */
1683 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1685 if (elem
.type
!= BE_STR
) {
1686 fputs("[msgAuthenticationParameters!=STR]", stdout
);
1693 /* msgPrivacyParameters (OCTET STRING) */
1694 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1696 if (elem
.type
!= BE_STR
) {
1697 fputs("[msgPrivacyParameters!=STR]", stdout
);
1704 if ((u_int
)count
< length
)
1705 printf("[%d extra after usm SEQ]", length
- count
);
1709 * Decode SNMPv3 Message Header (SNMPv3)
1712 v3msg_print(const u_char
*np
, u_int length
)
1718 const u_char
*xnp
= np
;
1719 int xlength
= length
;
1722 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1724 if (elem
.type
!= BE_SEQ
) {
1725 fputs("[!message]", stdout
);
1729 length
= elem
.asnlen
;
1730 np
= (u_char
*)elem
.data
.raw
;
1733 fputs("{ ", stdout
);
1736 /* msgID (INTEGER) */
1737 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1739 if (elem
.type
!= BE_INT
) {
1740 fputs("[msgID!=INT]", stdout
);
1747 /* msgMaxSize (INTEGER) */
1748 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1750 if (elem
.type
!= BE_INT
) {
1751 fputs("[msgMaxSize!=INT]", stdout
);
1758 /* msgFlags (OCTET STRING) */
1759 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1761 if (elem
.type
!= BE_STR
) {
1762 fputs("[msgFlags!=STR]", stdout
);
1766 if (elem
.asnlen
!= 1) {
1767 printf("[msgFlags size %d]", elem
.asnlen
);
1770 flags
= elem
.data
.str
[0];
1771 if (flags
!= 0x00 && flags
!= 0x01 && flags
!= 0x03
1772 && flags
!= 0x04 && flags
!= 0x05 && flags
!= 0x07) {
1773 printf("[msgFlags=0x%02X]", flags
);
1779 fputs("F=", stdout
);
1780 if (flags
& 0x01) fputs("a", stdout
);
1781 if (flags
& 0x02) fputs("p", stdout
);
1782 if (flags
& 0x04) fputs("r", stdout
);
1785 /* msgSecurityModel (INTEGER) */
1786 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1788 if (elem
.type
!= BE_INT
) {
1789 fputs("[msgSecurityModel!=INT]", stdout
);
1793 model
= elem
.data
.integer
;
1797 if ((u_int
)count
< length
)
1798 printf("[%d extra after message SEQ]", length
- count
);
1801 fputs("} ", stdout
);
1806 fputs("{ USM ", stdout
);
1809 printf("[security model %d]", model
);
1813 np
= xnp
+ (np
- xnp
);
1814 length
= xlength
- (np
- xnp
);
1816 /* msgSecurityParameters (OCTET STRING) */
1817 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1819 if (elem
.type
!= BE_STR
) {
1820 fputs("[msgSecurityParameters!=STR]", stdout
);
1828 usm_print(elem
.data
.str
, elem
.asnlen
);
1830 fputs("} ", stdout
);
1835 fputs("{ ScopedPDU ", stdout
);
1838 scopedpdu_print(np
, length
, 3);
1841 fputs("} ", stdout
);
1846 * Decode SNMP header and pass on to PDU printing routines
1849 snmp_print(const u_char
*np
, u_int length
)
1857 /* initial Sequence */
1858 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1860 if (elem
.type
!= BE_SEQ
) {
1861 fputs("[!init SEQ]", stdout
);
1865 if ((u_int
)count
< length
)
1866 printf("[%d extra after iSEQ]", length
- count
);
1868 length
= elem
.asnlen
;
1869 np
= (u_char
*)elem
.data
.raw
;
1871 /* Version (INTEGER) */
1872 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1874 if (elem
.type
!= BE_INT
) {
1875 fputs("[version!=INT]", stdout
);
1880 switch (elem
.data
.integer
) {
1881 case SNMP_VERSION_1
:
1882 case SNMP_VERSION_2
:
1883 case SNMP_VERSION_3
:
1885 printf("{ %s ", SnmpVersion
[elem
.data
.integer
]);
1888 printf("[version = %d]", elem
.data
.integer
);
1891 version
= elem
.data
.integer
;
1896 case SNMP_VERSION_1
:
1897 case SNMP_VERSION_2
:
1898 community_print(np
, length
, version
);
1900 case SNMP_VERSION_3
:
1901 v3msg_print(np
, length
);
1904 printf("[version = %d]", elem
.data
.integer
);
1909 fputs("} ", stdout
);