2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by John Robert LoVerso.
11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
12 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
13 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
15 * This implementation has been influenced by the CMU SNMP release,
16 * by Steve Waldbusser. However, this shares no code with that system.
17 * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_.
18 * Earlier forms of this implementation were derived and/or inspired by an
19 * awk script originally written by C. Philip Wood of LANL (but later
20 * heavily modified by John Robert LoVerso). The copyright notice for
21 * that work is preserved below, even though it may not rightly apply
24 * Support for SNMPv2c/SNMPv3 and the ability to link the module against
25 * the libsmi was added by J. Schoenwaelder, Copyright (c) 1999.
27 * This started out as a very simple program, but the incremental decoding
28 * (into the BE structure) complicated things.
30 # Los Alamos National Laboratory
32 # Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
33 # This software was produced under a U.S. Government contract
34 # (W-7405-ENG-36) by Los Alamos National Laboratory, which is
35 # operated by the University of California for the U.S. Department
36 # of Energy. The U.S. Government is licensed to use, reproduce,
37 # and distribute this software. Permission is granted to the
38 # public to copy and use this software without charge, provided
39 # that this Notice and any statement of authorship are reproduced
40 # on all copies. Neither the Government nor the University makes
41 # any warranty, express or implied, or assumes any liability or
42 # responsibility for the use of this software.
43 # @(#)snmp.awk.x 1.1 (LANL) 1/15/90
47 static const char rcsid
[] =
48 "@(#) $Header: /tcpdump/master/tcpdump/print-snmp.c,v 1.44 2000-11-10 17:34:10 fenner Exp $ (LBL)";
55 #include <sys/param.h>
66 #include "interface.h"
67 #include "addrtoname.h"
70 * Universal ASN.1 types
71 * (we only care about the tag values for those allowed in the Internet SMI)
86 "U-8","U-9","U-10","U-11", /* 8-11 */
87 "U-12","U-13","U-14","U-15", /* 12-15 */
94 * Application-wide ASN.1 types from the Internet SMI and their tags
96 char *Application
[] = {
113 * Context-specific ASN.1 types for the SNMP PDUs and their tags
136 #define NOTIFY_CLASS(x) (x == TRAP || x == V2TRAP || x == INFORMREQ)
137 #define READ_CLASS(x) (x == GETREQ || x == GETNEXTREQ || x == GETBULKREQ)
138 #define WRITE_CLASS(x) (x == SETREQ)
139 #define RESPONSE_CLASS(x) (x == GETRESP)
140 #define INTERNAL_CLASS(x) (x == REPORT)
143 * Context-specific ASN.1 types for the SNMP Exceptions and their tags
145 char *Exceptions
[] = {
147 #define NOSUCHOBJECT 0
149 #define NOSUCHINSTANCE 1
151 #define ENDOFMIBVIEW 2
155 * Private ASN.1 types
156 * The Internet SMI does not specify any
163 * error-status values for any SNMP PDU
165 char *ErrorStatus
[] = {
179 "resourceUnavailable",
182 "authorizationError",
186 #define DECODE_ErrorStatus(e) \
187 ( e >= 0 && e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
189 : (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf))
192 * generic-trap values in the SNMP Trap-PDU
194 char *GenericTrap
[] = {
199 "authenticationFailure",
202 #define GT_ENTERPRISE 7
204 #define DECODE_GenericTrap(t) \
205 ( t >= 0 && t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
207 : (snprintf(buf, sizeof(buf), "gt=%d", t), buf))
210 * ASN.1 type class table
211 * Ties together the preceding Universal, Application, Context, and Private
214 #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
220 defineCLASS(Universal
),
222 defineCLASS(Application
),
223 #define APPLICATION 1
224 defineCLASS(Context
),
226 defineCLASS(Private
),
228 defineCLASS(Exceptions
),
233 * defined forms for ASN.1 types
239 #define CONSTRUCTED 1
243 * A structure for the OID tree for the compiled-in MIB.
244 * This is stored as a general-order tree.
247 char *desc
; /* name of object */
248 u_char oid
; /* sub-id following parent */
249 u_char type
; /* object type (unused) */
250 struct obj
*child
, *next
; /* child and next sibling pointers */
254 * Include the compiled in SNMP MIB. "mib.h" is produced by feeding
255 * RFC-1156 format files into "makemib". "mib.h" MUST define at least
256 * a value for `mibroot'.
258 * In particular, this is gross, as this is including initialized structures,
259 * and by right shouldn't be an "include" file.
264 * This defines a list of OIDs which will be abbreviated on output.
265 * Currently, this includes the prefixes for the Internet MIB, the
266 * private enterprises tree, and the experimental tree.
269 char *prefix
; /* prefix for this abrev */
270 struct obj
*node
; /* pointer into object table */
271 char *oid
; /* ASN.1 encoded OID */
272 } obj_abrev_list
[] = {
274 /* .iso.org.dod.internet.mgmt.mib */
275 { "", &_mib_obj
, "\53\6\1\2\1" },
277 #ifndef NO_ABREV_ENTER
278 /* .iso.org.dod.internet.private.enterprises */
279 { "E:", &_enterprises_obj
, "\53\6\1\4\1" },
281 #ifndef NO_ABREV_EXPERI
282 /* .iso.org.dod.internet.experimental */
283 { "X:", &_experimental_obj
, "\53\6\1\3" },
285 #ifndef NO_ABBREV_SNMPMODS
286 /* .iso.org.dod.internet.snmpV2.snmpModules */
287 { "S:", &_snmpModules_obj
, "\53\6\1\6\3" },
293 * This is used in the OID print routine to walk down the object tree
294 * rooted at `mibroot'.
296 #define OBJ_PRINT(o, suppressdot) \
300 if ((o) == objp->oid) \
302 } while ((objp = objp->next) != NULL); \
305 printf(suppressdot?"%s":".%s", objp->desc); \
306 objp = objp->child; \
308 printf(suppressdot?"%u":".%u", (o)); \
312 * This is the definition for the Any-Data-Type storage used purely for
313 * temporary internal representation while decoding an ASN.1 data stream.
328 u_char form
, class; /* tag info */
339 #define BE_INETADDR 8
342 #define BE_NOSUCHOBJECT 128
343 #define BE_NOSUCHINST 129
344 #define BE_ENDOFMIBVIEW 130
348 * SNMP versions recognized by this module
350 char *SnmpVersion
[] = {
352 #define SNMP_VERSION_1 0
354 #define SNMP_VERSION_2 1
356 #define SNMP_VERSION_2U 2
358 #define SNMP_VERSION_3 3
362 * Defaults for SNMP PDU components
364 #define DEF_COMMUNITY "public"
367 * constants for ASN.1 decoding
370 #define ASNLEN_INETADDR 4
373 #define ASN_BIT8 0x80
374 #define ASN_LONGLEN 0x80
376 #define ASN_ID_BITS 0x1f
377 #define ASN_FORM_BITS 0x20
378 #define ASN_FORM_SHIFT 5
379 #define ASN_CLASS_BITS 0xc0
380 #define ASN_CLASS_SHIFT 6
382 #define ASN_ID_EXT 0x1f /* extension ID in tag field */
385 * truncated==1 means the packet was complete, but we don't have all of
388 static int truncated
;
389 #define ifNotTruncated if (truncated) fputs("[|snmp]", stdout); else
392 * This decodes the next ASN.1 object in the stream pointed to by "p"
393 * (and of real-length "len") and stores the intermediate data in the
394 * provided BE object.
396 * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
397 * O/w, this returns the number of bytes parsed from "p".
400 asn1_parse(register const u_char
*p
, u_int len
, struct be
*elem
)
402 u_char form
, class, id
;
408 ifNotTruncated
fputs("[nothing to parse]", stdout
);
413 * it would be nice to use a bit field, but you can't depend on them.
414 * +---+---+---+---+---+---+---+---+
416 * +---+---+---+---+---+---+---+---+
419 id
= *p
& ASN_ID_BITS
; /* lower 5 bits, range 00-1f */
421 form
= (*p
& 0xe0) >> 5; /* move upper 3 bits to lower 3 */
422 class = form
>> 1; /* bits 7&6 -> bits 1&0, range 0-3 */
423 form
&= 0x1; /* bit 5 -> bit 0, range 0-1 */
425 form
= (u_char
)(*p
& ASN_FORM_BITS
) >> ASN_FORM_SHIFT
;
426 class = (u_char
)(*p
& ASN_CLASS_BITS
) >> ASN_CLASS_SHIFT
;
434 /* extended tag field */
435 if (id
== ASN_ID_EXT
) {
436 for (id
= 0; *p
& ASN_BIT8
&& len
> 0; len
--, hdr
++, p
++) {
439 id
= (id
<< 7) | (*p
& ~ASN_BIT8
);
441 if (len
== 0 && *p
& ASN_BIT8
) {
442 ifNotTruncated
fputs("[Xtagfield?]", stdout
);
445 elem
->id
= id
= (id
<< 7) | *p
;
451 ifNotTruncated
fputs("[no asnlen]", stdout
);
458 if (elem
->asnlen
& ASN_BIT8
) {
459 int noct
= elem
->asnlen
% ASN_BIT8
;
462 ifNotTruncated
printf("[asnlen? %d<%d]", len
, noct
);
465 for (; noct
-- > 0; len
--, hdr
++) {
468 elem
->asnlen
= (elem
->asnlen
<< ASN_SHIFT8
) | *p
++;
471 if (len
< elem
->asnlen
) {
473 printf("[len%d<asnlen%u]", len
, elem
->asnlen
);
476 /* maybe should check at least 4? */
479 if (form
>= sizeof(Form
)/sizeof(Form
[0])) {
480 ifNotTruncated
printf("[form?%d]", form
);
483 if (class >= sizeof(Class
)/sizeof(Class
[0])) {
484 ifNotTruncated
printf("[class?%c/%d]", *Form
[form
], class);
487 if ((int)id
>= Class
[class].numIDs
) {
488 ifNotTruncated
printf("[id?%c/%s/%d]", *Form
[form
],
489 Class
[class].name
, id
);
504 register int32_t data
;
508 if (*p
& ASN_BIT8
) /* negative */
510 for (i
= elem
->asnlen
; i
-- > 0; p
++)
511 data
= (data
<< ASN_SHIFT8
) | *p
;
512 elem
->data
.integer
= data
;
518 elem
->data
.raw
= (caddr_t
)p
;
522 elem
->type
= BE_NULL
;
523 elem
->data
.raw
= NULL
;
527 elem
->type
= BE_OCTET
;
528 elem
->data
.raw
= (caddr_t
)p
;
530 Class
[class].Id
[id
]);
538 elem
->type
= BE_INETADDR
;
539 elem
->data
.raw
= (caddr_t
)p
;
545 register u_int32_t data
;
548 for (i
= elem
->asnlen
; i
-- > 0; p
++)
549 data
= (data
<< 8) + *p
;
550 elem
->data
.uns
= data
;
555 register u_int32_t high
, low
;
556 elem
->type
= BE_UNS64
;
558 for (i
= elem
->asnlen
; i
-- > 0; p
++) {
560 ((low
& 0xFF000000) >> 24);
561 low
= (low
<< 8) | *p
;
563 elem
->data
.uns64
.high
= high
;
564 elem
->data
.uns64
.low
= low
;
569 elem
->type
= BE_OCTET
;
570 elem
->data
.raw
= (caddr_t
)p
;
572 Class
[class].Id
[id
]);
580 elem
->type
= BE_NOSUCHOBJECT
;
581 elem
->data
.raw
= NULL
;
585 elem
->type
= BE_NOSUCHINST
;
586 elem
->data
.raw
= NULL
;
590 elem
->type
= BE_ENDOFMIBVIEW
;
591 elem
->data
.raw
= NULL
;
597 elem
->type
= BE_OCTET
;
598 elem
->data
.raw
= (caddr_t
)p
;
600 Class
[class].name
, Class
[class].Id
[id
]);
611 elem
->data
.raw
= (caddr_t
)p
;
615 elem
->type
= BE_OCTET
;
616 elem
->data
.raw
= (caddr_t
)p
;
617 printf("C/U/%s", Class
[class].Id
[id
]);
624 elem
->data
.raw
= (caddr_t
)p
;
628 elem
->type
= BE_OCTET
;
629 elem
->data
.raw
= (caddr_t
)p
;
631 Class
[class].name
, Class
[class].Id
[id
]);
638 return elem
->asnlen
+ hdr
;
642 * Display the ASN.1 object represented by the BE object.
643 * This used to be an integral part of asn1_parse() before the intermediate
647 asn1_print(struct be
*elem
)
649 u_char
*p
= (u_char
*)elem
->data
.raw
;
650 u_int32_t asnlen
= elem
->asnlen
;
653 switch (elem
->type
) {
656 for (i
= asnlen
; i
-- > 0; p
++)
664 int o
= 0, first
= -1, i
= asnlen
;
666 if (!sflag
&& !nflag
&& asnlen
> 2) {
667 struct obj_abrev
*a
= &obj_abrev_list
[0];
668 for (; a
->node
; a
++) {
669 if (!memcmp(a
->oid
, (char *)p
,
671 objp
= a
->node
->child
;
674 fputs(a
->prefix
, stdout
);
681 for (; !sflag
&& i
-- > 0; p
++) {
682 o
= (o
<< ASN_SHIFT7
) + (*p
& ~ASN_BIT8
);
683 if (*p
& ASN_LONGLEN
)
687 * first subitem encodes two items with 1st*OIDMUX+2nd
693 OBJ_PRINT(o
/OIDMUX
, first
);
705 printf("%d", elem
->data
.integer
);
709 printf("%u", elem
->data
.uns
);
712 case BE_UNS64
: { /* idea borrowed from by Marshall Rose */
715 char *cpf
, *cpl
, last
[6], first
[30];
716 if (elem
->data
.uns64
.high
== 0) {
717 printf("%u", elem
->data
.uns64
.low
);
720 d
= elem
->data
.uns64
.high
* 4294967296.0; /* 2^32 */
721 if (elem
->data
.uns64
.high
<= 0x1fffff) {
722 d
+= elem
->data
.uns64
.low
;
723 #if 0 /*is looks illegal, but what is the intention???*/
730 d
+= (elem
->data
.uns64
.low
& 0xfffff000);
731 #if 0 /*is looks illegal, but what is the intention???*/
732 snprintf(first
, sizeof(first
), "%.f", d
);
734 snprintf(first
, sizeof(first
), "%f", d
);
736 snprintf(last
, sizeof(last
), "%5.5d",
737 elem
->data
.uns64
.low
& 0xfff);
738 for (carry
= 0, cpf
= first
+strlen(first
)-1, cpl
= last
+4;
741 j
= carry
+ (*cpf
- '0') + (*cpl
- '0');
750 fputs(first
, stdout
);
755 register int printable
= 1, first
= 1;
756 const u_char
*p
= elem
->data
.str
;
757 for (i
= asnlen
; printable
&& i
-- > 0; p
++)
758 printable
= isprint(*p
) || isspace(*p
);
762 (void)fn_print(p
, p
+ asnlen
);
765 for (i
= asnlen
; i
-- > 0; p
++) {
766 printf(first
? "%.2x" : "_%.2x", *p
);
773 printf("Seq(%u)", elem
->asnlen
);
777 if (asnlen
!= ASNLEN_INETADDR
)
778 printf("[inetaddr len!=%d]", ASNLEN_INETADDR
);
779 for (i
= asnlen
; i
-- > 0; p
++) {
780 printf((i
== asnlen
-1) ? "%u" : ".%u", *p
);
784 case BE_NOSUCHOBJECT
:
786 case BE_ENDOFMIBVIEW
:
787 printf("[%s]", Class
[EXCEPTIONS
].Id
[elem
->id
]);
792 Class
[CONTEXT
].Id
[elem
->id
], elem
->asnlen
);
796 fputs("[BE_ANY!?]", stdout
);
800 fputs("[be!?]", stdout
);
807 * This is a brute force ASN.1 printer: recurses to dump an entire structure.
808 * This will work for any ASN.1 stream, not just an SNMP PDU.
810 * By adding newlines and spaces at the correct places, this would print in
813 * This is not currently used.
816 asn1_decode(u_char
*p
, u_int length
)
821 while (i
>= 0 && length
> 0) {
822 i
= asn1_parse(p
, length
, &elem
);
826 if (elem
.type
== BE_SEQ
|| elem
.type
== BE_PDU
) {
828 asn1_decode(elem
.data
.raw
, elem
.asnlen
);
840 #if (SMI_VERSION_MAJOR == 0 && SMI_VERSION_MINOR >= 2) || (SMI_VERSION_MAJOR > 0)
841 #define LIBSMI_API_V2
843 #define LIBSMI_API_V1
847 /* Some of the API revisions introduced new calls that can be
848 * represented by macros.
850 #define smiGetNodeType(n) smiGetType((n)->typemodule, (n)->typename)
853 /* These calls in the V1 API were removed in V2. */
854 #define smiFreeRange(r)
855 #define smiFreeType(r)
856 #define smiFreeNode(r)
860 SmiBasetype basetype
;
864 static struct smi2be smi2betab
[] = {
865 { SMI_BASETYPE_INTEGER32
, BE_INT
},
866 { SMI_BASETYPE_OCTETSTRING
, BE_STR
},
867 { SMI_BASETYPE_OCTETSTRING
, BE_INETADDR
},
868 { SMI_BASETYPE_OBJECTIDENTIFIER
, BE_OID
},
869 { SMI_BASETYPE_UNSIGNED32
, BE_UNS
},
870 { SMI_BASETYPE_INTEGER64
, BE_NONE
},
871 { SMI_BASETYPE_UNSIGNED64
, BE_UNS64
},
872 { SMI_BASETYPE_FLOAT32
, BE_NONE
},
873 { SMI_BASETYPE_FLOAT64
, BE_NONE
},
874 { SMI_BASETYPE_FLOAT128
, BE_NONE
},
875 { SMI_BASETYPE_ENUM
, BE_INT
},
876 { SMI_BASETYPE_BITS
, BE_STR
},
877 { SMI_BASETYPE_UNKNOWN
, BE_NONE
}
880 static void smi_decode_oid(struct be
*elem
, unsigned int *oid
,
881 unsigned int *oidlen
)
883 u_char
*p
= (u_char
*)elem
->data
.raw
;
884 u_int32_t asnlen
= elem
->asnlen
;
885 int o
= 0, first
= -1, i
= asnlen
;
887 for (*oidlen
= 0; sflag
&& i
-- > 0; p
++) {
888 o
= (o
<< ASN_SHIFT7
) + (*p
& ~ASN_BIT8
);
889 if (*p
& ASN_LONGLEN
)
893 * first subitem encodes two items with 1st*OIDMUX+2nd
897 oid
[(*oidlen
)++] = o
/OIDMUX
;
900 oid
[(*oidlen
)++] = o
;
905 static int smi_check_type(SmiBasetype basetype
, int be
)
909 for (i
= 0; smi2betab
[i
].basetype
!= SMI_BASETYPE_UNKNOWN
; i
++) {
910 if (smi2betab
[i
].basetype
== basetype
&& smi2betab
[i
].be
== be
) {
918 static int smi_check_a_range(SmiType
*smiType
, SmiRange
*smiRange
,
923 switch (smiType
->basetype
) {
924 case SMI_BASETYPE_OBJECTIDENTIFIER
:
925 case SMI_BASETYPE_OCTETSTRING
:
926 if (smiRange
->minValue
.value
.unsigned32
927 == smiRange
->maxValue
.value
.unsigned32
) {
928 ok
= (elem
->asnlen
== smiRange
->minValue
.value
.unsigned32
);
930 ok
= (elem
->asnlen
>= smiRange
->minValue
.value
.unsigned32
931 && elem
->asnlen
<= smiRange
->maxValue
.value
.unsigned32
);
935 case SMI_BASETYPE_INTEGER32
:
936 ok
= (elem
->data
.integer
>= smiRange
->minValue
.value
.integer32
937 && elem
->data
.integer
<= smiRange
->maxValue
.value
.integer32
);
940 case SMI_BASETYPE_UNSIGNED32
:
941 ok
= (elem
->data
.uns
>= smiRange
->minValue
.value
.unsigned32
942 && elem
->data
.uns
<= smiRange
->maxValue
.value
.unsigned32
);
945 case SMI_BASETYPE_UNSIGNED64
:
949 /* case SMI_BASETYPE_INTEGER64: SMIng */
950 /* case SMI_BASETYPE_FLOAT32: SMIng */
951 /* case SMI_BASETYPE_FLOAT64: SMIng */
952 /* case SMI_BASETYPE_FLOAT128: SMIng */
954 case SMI_BASETYPE_ENUM
:
955 case SMI_BASETYPE_BITS
:
956 case SMI_BASETYPE_UNKNOWN
:
964 static int smi_check_range(SmiType
*smiType
, struct be
*elem
)
970 for (smiRange
= smiGetFirstRange(smiType
->module
, smiType
->name
);
972 for (smiRange
= smiGetFirstRange(smiType
);
975 smiRange
= smiGetNextRange(smiRange
)) {
977 ok
= smi_check_a_range(smiType
, smiRange
, elem
);
980 smiFreeRange(smiRange
);
987 && smiType
->parentmodule
&& smiType
->parentname
992 parentType
= smiGetType(smiType
->parentmodule
,
993 smiType
->parentname
);
995 parentType
= smiGetParentType(smiType
);
998 ok
= smi_check_range(parentType
, elem
);
999 smiFreeType(parentType
);
1006 static SmiNode
*smi_print_variable(struct be
*elem
)
1008 unsigned int oid
[128], oidlen
;
1009 SmiNode
*smiNode
= NULL
;
1012 smi_decode_oid(elem
, oid
, &oidlen
);
1013 smiNode
= smiGetNodeByOID(oidlen
, oid
);
1019 #ifdef LIBSMI_API_V1
1020 fputs(smiNode
->module
, stdout
);
1022 fputs(smiGetNodeModule(smiNode
)->name
, stdout
);
1024 fputs("::", stdout
);
1026 fputs(smiNode
->name
, stdout
);
1027 if (smiNode
->oidlen
< oidlen
) {
1028 for (i
= smiNode
->oidlen
; i
< oidlen
; i
++) {
1029 printf(".%u", oid
[i
]);
1035 static void smi_print_value(SmiNode
*smiNode
, u_char pduid
, struct be
*elem
)
1037 unsigned int oid
[128], oidlen
;
1042 if (! smiNode
|| ! (smiNode
->nodekind
1043 & (SMI_NODEKIND_SCALAR
| SMI_NODEKIND_COLUMN
))) {
1048 if (elem
->type
== BE_NOSUCHOBJECT
1049 || elem
->type
== BE_NOSUCHINST
1050 || elem
->type
== BE_ENDOFMIBVIEW
) {
1055 if (NOTIFY_CLASS(pduid
) && smiNode
->access
< SMI_ACCESS_NOTIFY
) {
1056 fputs("[notNotifyable]", stdout
);
1059 if (READ_CLASS(pduid
) && smiNode
->access
< SMI_ACCESS_READ_ONLY
) {
1060 fputs("[notReadable]", stdout
);
1063 if (WRITE_CLASS(pduid
) && smiNode
->access
< SMI_ACCESS_READ_WRITE
) {
1064 fputs("[notWritable]", stdout
);
1067 if (RESPONSE_CLASS(pduid
)
1068 && smiNode
->access
== SMI_ACCESS_NOT_ACCESSIBLE
) {
1069 fputs("[noAccess]", stdout
);
1072 #ifdef LIBSMI_API_V1
1073 smiType
= smiGetType(smiNode
->typemodule
, smiNode
->typename
);
1075 smiType
= smiGetNodeType(smiNode
);
1082 #ifdef LIBSMI_API_V1
1083 if (! smi_check_type(smiNode
->basetype
, elem
->type
)) {
1085 if (! smi_check_type(smiType
->basetype
, elem
->type
)) {
1087 fputs("[wrongType]", stdout
);
1090 if (! smi_check_range(smiType
, elem
)) {
1091 fputs("[wrongLength]", stdout
);
1094 /* resolve bits to named bits */
1096 /* check whether instance identifier is valid */
1098 /* apply display hints (integer, octetstring) */
1100 /* convert instance identifier to index type values */
1102 switch (elem
->type
) {
1104 if (smiType
->basetype
== SMI_BASETYPE_BITS
) {
1105 /* print bit labels */
1107 smi_decode_oid(elem
, oid
, &oidlen
);
1108 smiNode
= smiGetNodeByOID(oidlen
, oid
);
1111 #ifdef LIBSMI_API_V1
1112 fputs(smiNode
->module
, stdout
);
1114 fputs(smiGetNodeModule(smiNode
)->name
, stdout
);
1116 fputs("::", stdout
);
1118 fputs(smiNode
->name
, stdout
);
1119 if (smiNode
->oidlen
< oidlen
) {
1120 for (i
= smiNode
->oidlen
;
1122 printf(".%u", oid
[i
]);
1131 #ifdef LIBSMI_API_V1
1132 if (smiNode
->basetype
== SMI_BASETYPE_ENUM
1133 && smiNode
->typemodule
&& smiNode
->typename
) {
1134 for (nn
= smiGetFirstNamedNumber(smiNode
->typemodule
,
1137 if (smiType
->basetype
== SMI_BASETYPE_ENUM
) {
1138 for (nn
= smiGetFirstNamedNumber(smiType
);
1141 nn
= smiGetNextNamedNumber(nn
)) {
1142 if (nn
->value
.value
.integer32
1143 == elem
->data
.integer
) {
1144 fputs(nn
->name
, stdout
);
1145 printf("(%d)", elem
->data
.integer
);
1159 smiFreeType(smiType
);
1165 * General SNMP header
1167 * version INTEGER {version-1(0)},
1168 * community OCTET STRING,
1171 * PDUs for all but Trap: (see rfc1157 from page 15 on)
1173 * request-id INTEGER,
1174 * error-status INTEGER,
1175 * error-index INTEGER,
1176 * varbindlist SEQUENCE OF
1184 * enterprise OBJECT IDENTIFIER,
1185 * agent-addr NetworkAddress,
1186 * generic-trap INTEGER,
1187 * specific-trap INTEGER,
1188 * time-stamp TimeTicks,
1189 * varbindlist SEQUENCE OF
1198 * Decode SNMP varBind
1201 varbind_print(u_char pduid
, const u_char
*np
, u_int length
)
1206 SmiNode
*smiNode
= NULL
;
1209 /* Sequence of varBind */
1210 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1212 if (elem
.type
!= BE_SEQ
) {
1213 fputs("[!SEQ of varbind]", stdout
);
1218 printf("[%d extra after SEQ of varbind]", length
- count
);
1220 length
= elem
.asnlen
;
1221 np
= (u_char
*)elem
.data
.raw
;
1223 for (ind
= 1; length
> 0; ind
++) {
1224 const u_char
*vbend
;
1230 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1232 if (elem
.type
!= BE_SEQ
) {
1233 fputs("[!varbind]", stdout
);
1238 vblength
= length
- count
;
1240 length
= elem
.asnlen
;
1241 np
= (u_char
*)elem
.data
.raw
;
1244 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1246 if (elem
.type
!= BE_OID
) {
1247 fputs("[objName!=OID]", stdout
);
1252 smiNode
= smi_print_variable(&elem
);
1259 if (pduid
!= GETREQ
&& pduid
!= GETNEXTREQ
1260 && pduid
!= GETBULKREQ
)
1264 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1266 if (pduid
== GETREQ
|| pduid
== GETNEXTREQ
1267 || pduid
== GETBULKREQ
) {
1268 if (elem
.type
!= BE_NULL
) {
1269 fputs("[objVal!=NULL]", stdout
);
1273 if (elem
.type
!= BE_NULL
) {
1275 smi_print_value(smiNode
, pduid
, &elem
);
1276 smiFreeNode(smiNode
);
1288 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
1289 * GetBulk, Inform, V2Trap, and Report
1292 snmppdu_print(u_char pduid
, const u_char
*np
, u_int length
)
1295 int count
= 0, error
;
1297 /* reqId (Integer) */
1298 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1300 if (elem
.type
!= BE_INT
) {
1301 fputs("[reqId!=INT]", stdout
);
1306 printf("R=%d ", elem
.data
.integer
);
1310 /* errorStatus (Integer) */
1311 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1313 if (elem
.type
!= BE_INT
) {
1314 fputs("[errorStatus!=INT]", stdout
);
1319 if ((pduid
== GETREQ
|| pduid
== GETNEXTREQ
|| pduid
== SETREQ
1320 || pduid
== INFORMREQ
|| pduid
== V2TRAP
|| pduid
== REPORT
)
1321 && elem
.data
.integer
!= 0) {
1323 printf("[errorStatus(%s)!=0]",
1324 DECODE_ErrorStatus(elem
.data
.integer
));
1325 } else if (pduid
== GETBULKREQ
) {
1326 printf(" N=%d", elem
.data
.integer
);
1327 } else if (elem
.data
.integer
!= 0) {
1329 printf(" %s", DECODE_ErrorStatus(elem
.data
.integer
));
1330 error
= elem
.data
.integer
;
1335 /* errorIndex (Integer) */
1336 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1338 if (elem
.type
!= BE_INT
) {
1339 fputs("[errorIndex!=INT]", stdout
);
1343 if ((pduid
== GETREQ
|| pduid
== GETNEXTREQ
|| pduid
== SETREQ
1344 || pduid
== INFORMREQ
|| pduid
== V2TRAP
|| pduid
== REPORT
)
1345 && elem
.data
.integer
!= 0)
1346 printf("[errorIndex(%d)!=0]", elem
.data
.integer
);
1347 else if (pduid
== GETBULKREQ
)
1348 printf(" M=%d", elem
.data
.integer
);
1349 else if (elem
.data
.integer
!= 0) {
1351 printf("[errorIndex(%d) w/o errorStatus]",
1354 printf("@%d", elem
.data
.integer
);
1355 error
= elem
.data
.integer
;
1358 fputs("[errorIndex==0]", stdout
);
1364 varbind_print(pduid
, np
, length
);
1369 * Decode SNMP Trap PDU
1372 trappdu_print(const u_char
*np
, u_int length
)
1375 int count
= 0, generic
;
1379 /* enterprise (oid) */
1380 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1382 if (elem
.type
!= BE_OID
) {
1383 fputs("[enterprise!=OID]", stdout
);
1393 /* agent-addr (inetaddr) */
1394 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1396 if (elem
.type
!= BE_INETADDR
) {
1397 fputs("[agent-addr!=INETADDR]", stdout
);
1405 /* generic-trap (Integer) */
1406 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1408 if (elem
.type
!= BE_INT
) {
1409 fputs("[generic-trap!=INT]", stdout
);
1413 generic
= elem
.data
.integer
;
1416 printf(" %s", DECODE_GenericTrap(generic
));
1421 /* specific-trap (Integer) */
1422 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1424 if (elem
.type
!= BE_INT
) {
1425 fputs("[specific-trap!=INT]", stdout
);
1429 if (generic
!= GT_ENTERPRISE
) {
1430 if (elem
.data
.integer
!= 0)
1431 printf("[specific-trap(%d)!=0]", elem
.data
.integer
);
1433 printf(" s=%d", elem
.data
.integer
);
1439 /* time-stamp (TimeTicks) */
1440 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1442 if (elem
.type
!= BE_UNS
) { /* XXX */
1443 fputs("[time-stamp!=TIMETICKS]", stdout
);
1451 varbind_print (TRAP
, np
, length
);
1456 * Decode arbitrary SNMP PDUs.
1459 pdu_print(const u_char
*np
, u_int length
, int version
)
1465 if ((count
= asn1_parse(np
, length
, &pdu
)) < 0)
1467 if (pdu
.type
!= BE_PDU
) {
1468 fputs("[no PDU]", stdout
);
1472 printf("[%d extra after PDU]", length
- count
);
1474 fputs("{ ", stdout
);
1478 /* descend into PDU */
1479 length
= pdu
.asnlen
;
1480 np
= (u_char
*)pdu
.data
.raw
;
1482 if (version
== SNMP_VERSION_1
&&
1483 (pdu
.id
== GETBULKREQ
|| pdu
.id
== INFORMREQ
||
1484 pdu
.id
== V2TRAP
|| pdu
.id
== REPORT
)) {
1485 printf("[v2 PDU in v1 message]");
1489 if (version
== SNMP_VERSION_2
&& pdu
.id
== TRAP
) {
1490 printf("[v1 PDU in v2 message]");
1496 trappdu_print(np
, length
);
1506 snmppdu_print(pdu
.id
, np
, length
);
1511 fputs("} ", stdout
);
1516 * Decode a scoped SNMP PDU.
1519 scopedpdu_print(const u_char
*np
, u_int length
, int version
)
1525 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1527 if (elem
.type
!= BE_SEQ
) {
1528 fputs("[!scoped PDU]", stdout
);
1532 length
= elem
.asnlen
;
1533 np
= (u_char
*)elem
.data
.raw
;
1535 /* contextEngineID (OCTET STRING) */
1536 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1538 if (elem
.type
!= BE_STR
) {
1539 fputs("[contextEngineID!=STR]", stdout
);
1546 fputs("E= ", stdout
);
1547 for (i
= 0; i
< (int)elem
.asnlen
; i
++) {
1548 printf("0x%02X", elem
.data
.str
[i
]);
1552 /* contextName (OCTET STRING) */
1553 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1555 if (elem
.type
!= BE_STR
) {
1556 fputs("[contextName!=STR]", stdout
);
1563 printf("C=%.*s ", (int)elem
.asnlen
, elem
.data
.str
);
1565 pdu_print(np
, length
, version
);
1569 * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
1572 community_print(const u_char
*np
, u_int length
, int version
)
1577 /* Community (String) */
1578 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1580 if (elem
.type
!= BE_STR
) {
1581 fputs("[comm!=STR]", stdout
);
1585 /* default community */
1586 if (strncmp((char *)elem
.data
.str
, DEF_COMMUNITY
,
1587 sizeof(DEF_COMMUNITY
) - 1))
1589 printf("C=%.*s ", (int)elem
.asnlen
, elem
.data
.str
);
1593 pdu_print(np
, length
, version
);
1597 * Decode SNMPv3 User-based Security Message Header (SNMPv3)
1600 usm_print(const u_char
*np
, u_int length
)
1606 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1608 if (elem
.type
!= BE_SEQ
) {
1609 fputs("[!usm]", stdout
);
1613 length
= elem
.asnlen
;
1614 np
= (u_char
*)elem
.data
.raw
;
1616 /* msgAuthoritativeEngineID (OCTET STRING) */
1617 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1619 if (elem
.type
!= BE_STR
) {
1620 fputs("[msgAuthoritativeEngineID!=STR]", stdout
);
1627 /* msgAuthoritativeEngineBoots (INTEGER) */
1628 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1630 if (elem
.type
!= BE_INT
) {
1631 fputs("[msgAuthoritativeEngineBoots!=INT]", stdout
);
1636 printf("B=%d ", elem
.data
.integer
);
1640 /* msgAuthoritativeEngineTime (INTEGER) */
1641 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1643 if (elem
.type
!= BE_INT
) {
1644 fputs("[msgAuthoritativeEngineTime!=INT]", stdout
);
1649 printf("T=%d ", elem
.data
.integer
);
1653 /* msgUserName (OCTET STRING) */
1654 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1656 if (elem
.type
!= BE_STR
) {
1657 fputs("[msgUserName!=STR]", stdout
);
1664 printf("U=%.*s ", (int)elem
.asnlen
, elem
.data
.str
);
1666 /* msgAuthenticationParameters (OCTET STRING) */
1667 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1669 if (elem
.type
!= BE_STR
) {
1670 fputs("[msgAuthenticationParameters!=STR]", stdout
);
1677 /* msgPrivacyParameters (OCTET STRING) */
1678 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1680 if (elem
.type
!= BE_STR
) {
1681 fputs("[msgPrivacyParameters!=STR]", stdout
);
1689 printf("[%d extra after usm SEQ]", length
- count
);
1693 * Decode SNMPv3 Message Header (SNMPv3)
1696 v3msg_print(const u_char
*np
, u_int length
)
1702 const u_char
*xnp
= np
;
1703 int xlength
= length
;
1706 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1708 if (elem
.type
!= BE_SEQ
) {
1709 fputs("[!message]", stdout
);
1713 length
= elem
.asnlen
;
1714 np
= (u_char
*)elem
.data
.raw
;
1717 fputs("{ ", stdout
);
1720 /* msgID (INTEGER) */
1721 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1723 if (elem
.type
!= BE_INT
) {
1724 fputs("[msgID!=INT]", stdout
);
1731 /* msgMaxSize (INTEGER) */
1732 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1734 if (elem
.type
!= BE_INT
) {
1735 fputs("[msgMaxSize!=INT]", stdout
);
1742 /* msgFlags (OCTET STRING) */
1743 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1745 if (elem
.type
!= BE_STR
) {
1746 fputs("[msgFlags!=STR]", stdout
);
1750 if (elem
.asnlen
!= 1) {
1751 printf("[msgFlags size %d]", elem
.asnlen
);
1754 flags
= elem
.data
.str
[0];
1755 if (flags
!= 0x00 && flags
!= 0x01 && flags
!= 0x03
1756 && flags
!= 0x04 && flags
!= 0x05 && flags
!= 0x07) {
1757 printf("[msgFlags=0x%02X]", flags
);
1763 fputs("F=", stdout
);
1764 if (flags
& 0x01) fputs("a", stdout
);
1765 if (flags
& 0x02) fputs("p", stdout
);
1766 if (flags
& 0x04) fputs("r", stdout
);
1769 /* msgSecurityModel (INTEGER) */
1770 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1772 if (elem
.type
!= BE_INT
) {
1773 fputs("[msgSecurityModel!=INT]", stdout
);
1777 model
= elem
.data
.integer
;
1782 printf("[%d extra after message SEQ]", length
- count
);
1785 fputs("} ", stdout
);
1790 fputs("{ USM ", stdout
);
1793 printf("[security model %d]", model
);
1797 np
= xnp
+ (np
- xnp
);
1798 length
= xlength
- (np
- xnp
);
1800 /* msgSecurityParameters (OCTET STRING) */
1801 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1803 if (elem
.type
!= BE_STR
) {
1804 fputs("[msgSecurityParameters!=STR]", stdout
);
1812 usm_print(elem
.data
.str
, elem
.asnlen
);
1814 fputs("} ", stdout
);
1819 fputs("{ ScopedPDU ", stdout
);
1822 scopedpdu_print(np
, length
, 3);
1825 fputs("} ", stdout
);
1830 * Decode SNMP header and pass on to PDU printing routines
1833 snmp_print(const u_char
*np
, u_int length
)
1841 /* truncated packet? */
1842 if (np
+ length
> snapend
) {
1844 length
= snapend
- np
;
1849 /* initial Sequence */
1850 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1852 if (elem
.type
!= BE_SEQ
) {
1853 fputs("[!init SEQ]", stdout
);
1858 printf("[%d extra after iSEQ]", length
- count
);
1860 length
= elem
.asnlen
;
1861 np
= (u_char
*)elem
.data
.raw
;
1863 /* Version (INTEGER) */
1864 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1866 if (elem
.type
!= BE_INT
) {
1867 fputs("[version!=INT]", stdout
);
1872 switch (elem
.data
.integer
) {
1873 case SNMP_VERSION_1
:
1874 case SNMP_VERSION_2
:
1875 case SNMP_VERSION_3
:
1877 printf("{ %s ", SnmpVersion
[elem
.data
.integer
]);
1880 printf("[version = %d]", elem
.data
.integer
);
1883 version
= elem
.data
.integer
;
1888 case SNMP_VERSION_1
:
1889 case SNMP_VERSION_2
:
1890 community_print(np
, length
, version
);
1892 case SNMP_VERSION_3
:
1893 v3msg_print(np
, length
);
1896 printf("[version = %d]", elem
.data
.integer
);
1901 fputs("} ", stdout
);