2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3 * John Robert LoVerso. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * This implementation has been influenced by the CMU SNMP release,
29 * by Steve Waldbusser. However, this shares no code with that system.
30 * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_.
31 * Earlier forms of this implementation were derived and/or inspired by an
32 * awk script originally written by C. Philip Wood of LANL (but later
33 * heavily modified by John Robert LoVerso). The copyright notice for
34 * that work is preserved below, even though it may not rightly apply
37 * Support for SNMPv2c/SNMPv3 and the ability to link the module against
38 * the libsmi was added by J. Schoenwaelder, Copyright (c) 1999.
40 * This started out as a very simple program, but the incremental decoding
41 * (into the BE structure) complicated things.
43 # Los Alamos National Laboratory
45 # Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
46 # This software was produced under a U.S. Government contract
47 # (W-7405-ENG-36) by Los Alamos National Laboratory, which is
48 # operated by the University of California for the U.S. Department
49 # of Energy. The U.S. Government is licensed to use, reproduce,
50 # and distribute this software. Permission is granted to the
51 # public to copy and use this software without charge, provided
52 # that this Notice and any statement of authorship are reproduced
53 # on all copies. Neither the Government nor the University makes
54 # any warranty, express or implied, or assumes any liability or
55 # responsibility for the use of this software.
56 # @(#)snmp.awk.x 1.1 (LANL) 1/15/90
60 static const char rcsid
[] _U_
=
61 "@(#) $Header: /tcpdump/master/tcpdump/print-snmp.c,v 1.56.2.3 2004/03/23 06:59:59 guy Exp $ (LBL)";
68 #include <tcpdump-stdinc.h>
77 #include "interface.h"
78 #include "addrtoname.h"
81 * Universal ASN.1 types
82 * (we only care about the tag values for those allowed in the Internet SMI)
84 const char *Universal
[] = {
97 "U-8","U-9","U-10","U-11", /* 8-11 */
98 "U-12","U-13","U-14","U-15", /* 12-15 */
105 * Application-wide ASN.1 types from the Internet SMI and their tags
107 const char *Application
[] = {
124 * Context-specific ASN.1 types for the SNMP PDUs and their tags
126 const char *Context
[] = {
147 #define NOTIFY_CLASS(x) (x == TRAP || x == V2TRAP || x == INFORMREQ)
148 #define READ_CLASS(x) (x == GETREQ || x == GETNEXTREQ || x == GETBULKREQ)
149 #define WRITE_CLASS(x) (x == SETREQ)
150 #define RESPONSE_CLASS(x) (x == GETRESP)
151 #define INTERNAL_CLASS(x) (x == REPORT)
154 * Context-specific ASN.1 types for the SNMP Exceptions and their tags
156 const char *Exceptions
[] = {
158 #define NOSUCHOBJECT 0
160 #define NOSUCHINSTANCE 1
162 #define ENDOFMIBVIEW 2
166 * Private ASN.1 types
167 * The Internet SMI does not specify any
169 const char *Private
[] = {
174 * error-status values for any SNMP PDU
176 const char *ErrorStatus
[] = {
190 "resourceUnavailable",
193 "authorizationError",
197 #define DECODE_ErrorStatus(e) \
198 ( e >= 0 && (size_t)e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
200 : (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf))
203 * generic-trap values in the SNMP Trap-PDU
205 const char *GenericTrap
[] = {
210 "authenticationFailure",
213 #define GT_ENTERPRISE 6
215 #define DECODE_GenericTrap(t) \
216 ( t >= 0 && (size_t)t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
218 : (snprintf(buf, sizeof(buf), "gt=%d", t), buf))
221 * ASN.1 type class table
222 * Ties together the preceding Universal, Application, Context, and Private
225 #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
231 defineCLASS(Universal
),
233 defineCLASS(Application
),
234 #define APPLICATION 1
235 defineCLASS(Context
),
237 defineCLASS(Private
),
239 defineCLASS(Exceptions
),
244 * defined forms for ASN.1 types
246 const char *Form
[] = {
250 #define CONSTRUCTED 1
254 * A structure for the OID tree for the compiled-in MIB.
255 * This is stored as a general-order tree.
258 const char *desc
; /* name of object */
259 u_char oid
; /* sub-id following parent */
260 u_char type
; /* object type (unused) */
261 struct obj
*child
, *next
; /* child and next sibling pointers */
265 * Include the compiled in SNMP MIB. "mib.h" is produced by feeding
266 * RFC-1156 format files into "makemib". "mib.h" MUST define at least
267 * a value for `mibroot'.
269 * In particular, this is gross, as this is including initialized structures,
270 * and by right shouldn't be an "include" file.
275 * This defines a list of OIDs which will be abbreviated on output.
276 * Currently, this includes the prefixes for the Internet MIB, the
277 * private enterprises tree, and the experimental tree.
280 const char *prefix
; /* prefix for this abrev */
281 struct obj
*node
; /* pointer into object table */
282 const char *oid
; /* ASN.1 encoded OID */
283 } obj_abrev_list
[] = {
285 /* .iso.org.dod.internet.mgmt.mib */
286 { "", &_mib_obj
, "\53\6\1\2\1" },
288 #ifndef NO_ABREV_ENTER
289 /* .iso.org.dod.internet.private.enterprises */
290 { "E:", &_enterprises_obj
, "\53\6\1\4\1" },
292 #ifndef NO_ABREV_EXPERI
293 /* .iso.org.dod.internet.experimental */
294 { "X:", &_experimental_obj
, "\53\6\1\3" },
296 #ifndef NO_ABBREV_SNMPMODS
297 /* .iso.org.dod.internet.snmpV2.snmpModules */
298 { "S:", &_snmpModules_obj
, "\53\6\1\6\3" },
304 * This is used in the OID print routine to walk down the object tree
305 * rooted at `mibroot'.
307 #define OBJ_PRINT(o, suppressdot) \
311 if ((o) == objp->oid) \
313 } while ((objp = objp->next) != NULL); \
316 printf(suppressdot?"%s":".%s", objp->desc); \
317 objp = objp->child; \
319 printf(suppressdot?"%u":".%u", (o)); \
323 * This is the definition for the Any-Data-Type storage used purely for
324 * temporary internal representation while decoding an ASN.1 data stream.
339 u_char form
, class; /* tag info */
350 #define BE_INETADDR 8
353 #define BE_NOSUCHOBJECT 128
354 #define BE_NOSUCHINST 129
355 #define BE_ENDOFMIBVIEW 130
359 * SNMP versions recognized by this module
361 const char *SnmpVersion
[] = {
363 #define SNMP_VERSION_1 0
365 #define SNMP_VERSION_2 1
367 #define SNMP_VERSION_2U 2
369 #define SNMP_VERSION_3 3
373 * Defaults for SNMP PDU components
375 #define DEF_COMMUNITY "public"
378 * constants for ASN.1 decoding
381 #define ASNLEN_INETADDR 4
384 #define ASN_BIT8 0x80
385 #define ASN_LONGLEN 0x80
387 #define ASN_ID_BITS 0x1f
388 #define ASN_FORM_BITS 0x20
389 #define ASN_FORM_SHIFT 5
390 #define ASN_CLASS_BITS 0xc0
391 #define ASN_CLASS_SHIFT 6
393 #define ASN_ID_EXT 0x1f /* extension ID in tag field */
396 * truncated==1 means the packet was complete, but we don't have all of
399 static int truncated
;
400 #define ifNotTruncated if (truncated) fputs("[|snmp]", stdout); else
403 * This decodes the next ASN.1 object in the stream pointed to by "p"
404 * (and of real-length "len") and stores the intermediate data in the
405 * provided BE object.
407 * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
408 * O/w, this returns the number of bytes parsed from "p".
411 asn1_parse(register const u_char
*p
, u_int len
, struct be
*elem
)
413 u_char form
, class, id
;
419 ifNotTruncated
fputs("[nothing to parse]", stdout
);
424 * it would be nice to use a bit field, but you can't depend on them.
425 * +---+---+---+---+---+---+---+---+
427 * +---+---+---+---+---+---+---+---+
430 id
= *p
& ASN_ID_BITS
; /* lower 5 bits, range 00-1f */
432 form
= (*p
& 0xe0) >> 5; /* move upper 3 bits to lower 3 */
433 class = form
>> 1; /* bits 7&6 -> bits 1&0, range 0-3 */
434 form
&= 0x1; /* bit 5 -> bit 0, range 0-1 */
436 form
= (u_char
)(*p
& ASN_FORM_BITS
) >> ASN_FORM_SHIFT
;
437 class = (u_char
)(*p
& ASN_CLASS_BITS
) >> ASN_CLASS_SHIFT
;
443 /* extended tag field */
444 if (id
== ASN_ID_EXT
) {
445 for (id
= 0; *p
& ASN_BIT8
&& len
> 0; len
--, hdr
++, p
++)
446 id
= (id
<< 7) | (*p
& ~ASN_BIT8
);
447 if (len
== 0 && *p
& ASN_BIT8
) {
448 ifNotTruncated
fputs("[Xtagfield?]", stdout
);
451 elem
->id
= id
= (id
<< 7) | *p
;
457 ifNotTruncated
fputs("[no asnlen]", stdout
);
462 if (elem
->asnlen
& ASN_BIT8
) {
463 u_int32_t noct
= elem
->asnlen
% ASN_BIT8
;
466 ifNotTruncated
printf("[asnlen? %d<%d]", len
, noct
);
469 for (; noct
-- > 0; len
--, hdr
++)
470 elem
->asnlen
= (elem
->asnlen
<< ASN_SHIFT8
) | *p
++;
472 if (len
< elem
->asnlen
) {
474 printf("[len%d<asnlen%u]", len
, elem
->asnlen
);
477 /* maybe should check at least 4? */
480 if (form
>= sizeof(Form
)/sizeof(Form
[0])) {
481 ifNotTruncated
printf("[form?%d]", form
);
484 if (class >= sizeof(Class
)/sizeof(Class
[0])) {
485 ifNotTruncated
printf("[class?%c/%d]", *Form
[form
], class);
488 if ((int)id
>= Class
[class].numIDs
) {
489 ifNotTruncated
printf("[id?%c/%s/%d]", *Form
[form
],
490 Class
[class].name
, id
);
505 register int32_t data
;
509 if (*p
& ASN_BIT8
) /* negative */
511 for (i
= elem
->asnlen
; i
-- > 0; p
++)
512 data
= (data
<< ASN_SHIFT8
) | *p
;
513 elem
->data
.integer
= data
;
519 elem
->data
.raw
= (caddr_t
)p
;
523 elem
->type
= BE_NULL
;
524 elem
->data
.raw
= NULL
;
528 elem
->type
= BE_OCTET
;
529 elem
->data
.raw
= (caddr_t
)p
;
531 Class
[class].Id
[id
]);
539 elem
->type
= BE_INETADDR
;
540 elem
->data
.raw
= (caddr_t
)p
;
546 register u_int32_t data
;
549 for (i
= elem
->asnlen
; i
-- > 0; p
++)
550 data
= (data
<< 8) + *p
;
551 elem
->data
.uns
= data
;
556 register u_int32_t high
, low
;
557 elem
->type
= BE_UNS64
;
559 for (i
= elem
->asnlen
; i
-- > 0; p
++) {
561 ((low
& 0xFF000000) >> 24);
562 low
= (low
<< 8) | *p
;
564 elem
->data
.uns64
.high
= high
;
565 elem
->data
.uns64
.low
= low
;
570 elem
->type
= BE_OCTET
;
571 elem
->data
.raw
= (caddr_t
)p
;
573 Class
[class].Id
[id
]);
581 elem
->type
= BE_NOSUCHOBJECT
;
582 elem
->data
.raw
= NULL
;
586 elem
->type
= BE_NOSUCHINST
;
587 elem
->data
.raw
= NULL
;
591 elem
->type
= BE_ENDOFMIBVIEW
;
592 elem
->data
.raw
= NULL
;
598 elem
->type
= BE_OCTET
;
599 elem
->data
.raw
= (caddr_t
)p
;
601 Class
[class].name
, Class
[class].Id
[id
]);
612 elem
->data
.raw
= (caddr_t
)p
;
616 elem
->type
= BE_OCTET
;
617 elem
->data
.raw
= (caddr_t
)p
;
618 printf("C/U/%s", Class
[class].Id
[id
]);
625 elem
->data
.raw
= (caddr_t
)p
;
629 elem
->type
= BE_OCTET
;
630 elem
->data
.raw
= (caddr_t
)p
;
632 Class
[class].name
, Class
[class].Id
[id
]);
639 return elem
->asnlen
+ hdr
;
643 * Display the ASN.1 object represented by the BE object.
644 * This used to be an integral part of asn1_parse() before the intermediate
648 asn1_print(struct be
*elem
)
650 u_char
*p
= (u_char
*)elem
->data
.raw
;
651 u_int32_t asnlen
= elem
->asnlen
;
654 switch (elem
->type
) {
657 for (i
= asnlen
; i
-- > 0; p
++)
665 int o
= 0, first
= -1, i
= asnlen
;
667 if (!sflag
&& !nflag
&& asnlen
> 2) {
668 struct obj_abrev
*a
= &obj_abrev_list
[0];
669 for (; a
->node
; a
++) {
670 if (!memcmp(a
->oid
, (char *)p
,
672 objp
= a
->node
->child
;
675 fputs(a
->prefix
, stdout
);
682 for (; !sflag
&& i
-- > 0; p
++) {
683 o
= (o
<< ASN_SHIFT7
) + (*p
& ~ASN_BIT8
);
684 if (*p
& ASN_LONGLEN
)
688 * first subitem encodes two items with 1st*OIDMUX+2nd
689 * (see X.690:1997 clause 8.19 for the details)
710 printf("%d", elem
->data
.integer
);
714 printf("%u", elem
->data
.uns
);
717 case BE_UNS64
: { /* idea borrowed from by Marshall Rose */
720 char *cpf
, *cpl
, last
[6], first
[30];
721 if (elem
->data
.uns64
.high
== 0) {
722 printf("%u", elem
->data
.uns64
.low
);
725 d
= elem
->data
.uns64
.high
* 4294967296.0; /* 2^32 */
726 if (elem
->data
.uns64
.high
<= 0x1fffff) {
727 d
+= elem
->data
.uns64
.low
;
728 #if 0 /*is looks illegal, but what is the intention?*/
735 d
+= (elem
->data
.uns64
.low
& 0xfffff000);
736 #if 0 /*is looks illegal, but what is the intention?*/
737 snprintf(first
, sizeof(first
), "%.f", d
);
739 snprintf(first
, sizeof(first
), "%f", d
);
741 snprintf(last
, sizeof(last
), "%5.5d",
742 elem
->data
.uns64
.low
& 0xfff);
743 for (carry
= 0, cpf
= first
+strlen(first
)-1, cpl
= last
+4;
746 j
= carry
+ (*cpf
- '0') + (*cpl
- '0');
755 fputs(first
, stdout
);
760 register int printable
= 1, first
= 1;
761 const u_char
*p
= elem
->data
.str
;
762 for (i
= asnlen
; printable
&& i
-- > 0; p
++)
763 printable
= isprint(*p
) || isspace(*p
);
767 (void)fn_print(p
, p
+ asnlen
);
770 for (i
= asnlen
; i
-- > 0; p
++) {
771 printf(first
? "%.2x" : "_%.2x", *p
);
778 printf("Seq(%u)", elem
->asnlen
);
782 if (asnlen
!= ASNLEN_INETADDR
)
783 printf("[inetaddr len!=%d]", ASNLEN_INETADDR
);
784 for (i
= asnlen
; i
-- != 0; p
++) {
785 printf((i
== asnlen
-1) ? "%u" : ".%u", *p
);
789 case BE_NOSUCHOBJECT
:
791 case BE_ENDOFMIBVIEW
:
792 printf("[%s]", Class
[EXCEPTIONS
].Id
[elem
->id
]);
797 Class
[CONTEXT
].Id
[elem
->id
], elem
->asnlen
);
801 fputs("[BE_ANY!?]", stdout
);
805 fputs("[be!?]", stdout
);
812 * This is a brute force ASN.1 printer: recurses to dump an entire structure.
813 * This will work for any ASN.1 stream, not just an SNMP PDU.
815 * By adding newlines and spaces at the correct places, this would print in
818 * This is not currently used.
821 asn1_decode(u_char
*p
, u_int length
)
826 while (i
>= 0 && length
> 0) {
827 i
= asn1_parse(p
, length
, &elem
);
831 if (elem
.type
== BE_SEQ
|| elem
.type
== BE_PDU
) {
833 asn1_decode(elem
.data
.raw
, elem
.asnlen
);
846 SmiBasetype basetype
;
850 static struct smi2be smi2betab
[] = {
851 { SMI_BASETYPE_INTEGER32
, BE_INT
},
852 { SMI_BASETYPE_OCTETSTRING
, BE_STR
},
853 { SMI_BASETYPE_OCTETSTRING
, BE_INETADDR
},
854 { SMI_BASETYPE_OBJECTIDENTIFIER
, BE_OID
},
855 { SMI_BASETYPE_UNSIGNED32
, BE_UNS
},
856 { SMI_BASETYPE_INTEGER64
, BE_NONE
},
857 { SMI_BASETYPE_UNSIGNED64
, BE_UNS64
},
858 { SMI_BASETYPE_FLOAT32
, BE_NONE
},
859 { SMI_BASETYPE_FLOAT64
, BE_NONE
},
860 { SMI_BASETYPE_FLOAT128
, BE_NONE
},
861 { SMI_BASETYPE_ENUM
, BE_INT
},
862 { SMI_BASETYPE_BITS
, BE_STR
},
863 { SMI_BASETYPE_UNKNOWN
, BE_NONE
}
866 static void smi_decode_oid(struct be
*elem
, unsigned int *oid
,
867 unsigned int oidsize
, unsigned int *oidlen
)
869 u_char
*p
= (u_char
*)elem
->data
.raw
;
870 u_int32_t asnlen
= elem
->asnlen
;
871 int o
= 0, first
= -1, i
= asnlen
;
873 for (*oidlen
= 0; sflag
&& i
-- > 0; p
++) {
874 o
= (o
<< ASN_SHIFT7
) + (*p
& ~ASN_BIT8
);
875 if (*p
& ASN_LONGLEN
)
879 * first subitem encodes two items with 1st*OIDMUX+2nd
880 * (see X.690:1997 clause 8.19 for the details)
884 if (*oidlen
< oidsize
) {
885 oid
[*oidlen
] = o
/ OIDMUX
;
886 if (oid
[*oidlen
] > 2) oid
[*oidlen
] = 2;
888 o
-= oid
[*oidlen
] * OIDMUX
;
889 if (*oidlen
< oidsize
) (*oidlen
)++;
891 if (*oidlen
< oidsize
) {
892 oid
[(*oidlen
)++] = o
;
898 static int smi_check_type(SmiBasetype basetype
, int be
)
902 for (i
= 0; smi2betab
[i
].basetype
!= SMI_BASETYPE_UNKNOWN
; i
++) {
903 if (smi2betab
[i
].basetype
== basetype
&& smi2betab
[i
].be
== be
) {
911 static int smi_check_a_range(SmiType
*smiType
, SmiRange
*smiRange
,
916 switch (smiType
->basetype
) {
917 case SMI_BASETYPE_OBJECTIDENTIFIER
:
918 case SMI_BASETYPE_OCTETSTRING
:
919 if (smiRange
->minValue
.value
.unsigned32
920 == smiRange
->maxValue
.value
.unsigned32
) {
921 ok
= (elem
->asnlen
== smiRange
->minValue
.value
.unsigned32
);
923 ok
= (elem
->asnlen
>= smiRange
->minValue
.value
.unsigned32
924 && elem
->asnlen
<= smiRange
->maxValue
.value
.unsigned32
);
928 case SMI_BASETYPE_INTEGER32
:
929 ok
= (elem
->data
.integer
>= smiRange
->minValue
.value
.integer32
930 && elem
->data
.integer
<= smiRange
->maxValue
.value
.integer32
);
933 case SMI_BASETYPE_UNSIGNED32
:
934 ok
= (elem
->data
.uns
>= smiRange
->minValue
.value
.unsigned32
935 && elem
->data
.uns
<= smiRange
->maxValue
.value
.unsigned32
);
938 case SMI_BASETYPE_UNSIGNED64
:
942 /* case SMI_BASETYPE_INTEGER64: SMIng */
943 /* case SMI_BASETYPE_FLOAT32: SMIng */
944 /* case SMI_BASETYPE_FLOAT64: SMIng */
945 /* case SMI_BASETYPE_FLOAT128: SMIng */
947 case SMI_BASETYPE_ENUM
:
948 case SMI_BASETYPE_BITS
:
949 case SMI_BASETYPE_UNKNOWN
:
957 static int smi_check_range(SmiType
*smiType
, struct be
*elem
)
962 for (smiRange
= smiGetFirstRange(smiType
);
964 smiRange
= smiGetNextRange(smiRange
)) {
966 ok
= smi_check_a_range(smiType
, smiRange
, elem
);
975 parentType
= smiGetParentType(smiType
);
977 ok
= smi_check_range(parentType
, elem
);
984 static SmiNode
*smi_print_variable(struct be
*elem
)
986 unsigned int oid
[128], oidlen
;
987 SmiNode
*smiNode
= NULL
;
990 smi_decode_oid(elem
, oid
, sizeof(oid
)/sizeof(unsigned int), &oidlen
);
991 smiNode
= smiGetNodeByOID(oidlen
, oid
);
997 fputs(smiGetNodeModule(smiNode
)->name
, stdout
);
1000 fputs(smiNode
->name
, stdout
);
1001 if (smiNode
->oidlen
< oidlen
) {
1002 for (i
= smiNode
->oidlen
; i
< oidlen
; i
++) {
1003 printf(".%u", oid
[i
]);
1009 static void smi_print_value(SmiNode
*smiNode
, u_char pduid
, struct be
*elem
)
1011 unsigned int oid
[128], oidlen
;
1016 if (! smiNode
|| ! (smiNode
->nodekind
1017 & (SMI_NODEKIND_SCALAR
| SMI_NODEKIND_COLUMN
))) {
1022 if (elem
->type
== BE_NOSUCHOBJECT
1023 || elem
->type
== BE_NOSUCHINST
1024 || elem
->type
== BE_ENDOFMIBVIEW
) {
1029 if (NOTIFY_CLASS(pduid
) && smiNode
->access
< SMI_ACCESS_NOTIFY
) {
1030 fputs("[notNotifyable]", stdout
);
1033 if (READ_CLASS(pduid
) && smiNode
->access
< SMI_ACCESS_READ_ONLY
) {
1034 fputs("[notReadable]", stdout
);
1037 if (WRITE_CLASS(pduid
) && smiNode
->access
< SMI_ACCESS_READ_WRITE
) {
1038 fputs("[notWritable]", stdout
);
1041 if (RESPONSE_CLASS(pduid
)
1042 && smiNode
->access
== SMI_ACCESS_NOT_ACCESSIBLE
) {
1043 fputs("[noAccess]", stdout
);
1046 smiType
= smiGetNodeType(smiNode
);
1052 if (! smi_check_type(smiType
->basetype
, elem
->type
)) {
1053 fputs("[wrongType]", stdout
);
1056 if (! smi_check_range(smiType
, elem
)) {
1057 fputs("[outOfRange]", stdout
);
1060 /* resolve bits to named bits */
1062 /* check whether instance identifier is valid */
1064 /* apply display hints (integer, octetstring) */
1066 /* convert instance identifier to index type values */
1068 switch (elem
->type
) {
1070 if (smiType
->basetype
== SMI_BASETYPE_BITS
) {
1071 /* print bit labels */
1073 smi_decode_oid(elem
, oid
,
1074 sizeof(oid
)/sizeof(unsigned int),
1076 smiNode
= smiGetNodeByOID(oidlen
, oid
);
1079 fputs(smiGetNodeModule(smiNode
)->name
, stdout
);
1080 fputs("::", stdout
);
1082 fputs(smiNode
->name
, stdout
);
1083 if (smiNode
->oidlen
< oidlen
) {
1084 for (i
= smiNode
->oidlen
;
1086 printf(".%u", oid
[i
]);
1095 if (smiType
->basetype
== SMI_BASETYPE_ENUM
) {
1096 for (nn
= smiGetFirstNamedNumber(smiType
);
1098 nn
= smiGetNextNamedNumber(nn
)) {
1099 if (nn
->value
.value
.integer32
1100 == elem
->data
.integer
) {
1101 fputs(nn
->name
, stdout
);
1102 printf("(%d)", elem
->data
.integer
);
1118 * General SNMP header
1120 * version INTEGER {version-1(0)},
1121 * community OCTET STRING,
1124 * PDUs for all but Trap: (see rfc1157 from page 15 on)
1126 * request-id INTEGER,
1127 * error-status INTEGER,
1128 * error-index INTEGER,
1129 * varbindlist SEQUENCE OF
1137 * enterprise OBJECT IDENTIFIER,
1138 * agent-addr NetworkAddress,
1139 * generic-trap INTEGER,
1140 * specific-trap INTEGER,
1141 * time-stamp TimeTicks,
1142 * varbindlist SEQUENCE OF
1151 * Decode SNMP varBind
1154 varbind_print(u_char pduid
, const u_char
*np
, u_int length
)
1159 SmiNode
*smiNode
= NULL
;
1162 /* Sequence of varBind */
1163 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1165 if (elem
.type
!= BE_SEQ
) {
1166 fputs("[!SEQ of varbind]", stdout
);
1170 if ((u_int
)count
< length
)
1171 printf("[%d extra after SEQ of varbind]", length
- count
);
1173 length
= elem
.asnlen
;
1174 np
= (u_char
*)elem
.data
.raw
;
1176 for (ind
= 1; length
> 0; ind
++) {
1177 const u_char
*vbend
;
1183 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1185 if (elem
.type
!= BE_SEQ
) {
1186 fputs("[!varbind]", stdout
);
1191 vblength
= length
- count
;
1193 length
= elem
.asnlen
;
1194 np
= (u_char
*)elem
.data
.raw
;
1197 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1199 if (elem
.type
!= BE_OID
) {
1200 fputs("[objName!=OID]", stdout
);
1205 smiNode
= smi_print_variable(&elem
);
1212 if (pduid
!= GETREQ
&& pduid
!= GETNEXTREQ
1213 && pduid
!= GETBULKREQ
)
1217 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1219 if (pduid
== GETREQ
|| pduid
== GETNEXTREQ
1220 || pduid
== GETBULKREQ
) {
1221 if (elem
.type
!= BE_NULL
) {
1222 fputs("[objVal!=NULL]", stdout
);
1226 if (elem
.type
!= BE_NULL
) {
1228 smi_print_value(smiNode
, pduid
, &elem
);
1240 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
1241 * GetBulk, Inform, V2Trap, and Report
1244 snmppdu_print(u_char pduid
, const u_char
*np
, u_int length
)
1247 int count
= 0, error
;
1249 /* reqId (Integer) */
1250 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1252 if (elem
.type
!= BE_INT
) {
1253 fputs("[reqId!=INT]", stdout
);
1258 printf("R=%d ", elem
.data
.integer
);
1262 /* errorStatus (Integer) */
1263 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1265 if (elem
.type
!= BE_INT
) {
1266 fputs("[errorStatus!=INT]", stdout
);
1271 if ((pduid
== GETREQ
|| pduid
== GETNEXTREQ
|| pduid
== SETREQ
1272 || pduid
== INFORMREQ
|| pduid
== V2TRAP
|| pduid
== REPORT
)
1273 && elem
.data
.integer
!= 0) {
1275 printf("[errorStatus(%s)!=0]",
1276 DECODE_ErrorStatus(elem
.data
.integer
));
1277 } else if (pduid
== GETBULKREQ
) {
1278 printf(" N=%d", elem
.data
.integer
);
1279 } else if (elem
.data
.integer
!= 0) {
1281 printf(" %s", DECODE_ErrorStatus(elem
.data
.integer
));
1282 error
= elem
.data
.integer
;
1287 /* errorIndex (Integer) */
1288 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1290 if (elem
.type
!= BE_INT
) {
1291 fputs("[errorIndex!=INT]", stdout
);
1295 if ((pduid
== GETREQ
|| pduid
== GETNEXTREQ
|| pduid
== SETREQ
1296 || pduid
== INFORMREQ
|| pduid
== V2TRAP
|| pduid
== REPORT
)
1297 && elem
.data
.integer
!= 0)
1298 printf("[errorIndex(%d)!=0]", elem
.data
.integer
);
1299 else if (pduid
== GETBULKREQ
)
1300 printf(" M=%d", elem
.data
.integer
);
1301 else if (elem
.data
.integer
!= 0) {
1303 printf("[errorIndex(%d) w/o errorStatus]",
1306 printf("@%d", elem
.data
.integer
);
1307 error
= elem
.data
.integer
;
1310 fputs("[errorIndex==0]", stdout
);
1316 varbind_print(pduid
, np
, length
);
1321 * Decode SNMP Trap PDU
1324 trappdu_print(const u_char
*np
, u_int length
)
1327 int count
= 0, generic
;
1331 /* enterprise (oid) */
1332 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1334 if (elem
.type
!= BE_OID
) {
1335 fputs("[enterprise!=OID]", stdout
);
1345 /* agent-addr (inetaddr) */
1346 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1348 if (elem
.type
!= BE_INETADDR
) {
1349 fputs("[agent-addr!=INETADDR]", stdout
);
1357 /* generic-trap (Integer) */
1358 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1360 if (elem
.type
!= BE_INT
) {
1361 fputs("[generic-trap!=INT]", stdout
);
1365 generic
= elem
.data
.integer
;
1368 printf(" %s", DECODE_GenericTrap(generic
));
1373 /* specific-trap (Integer) */
1374 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1376 if (elem
.type
!= BE_INT
) {
1377 fputs("[specific-trap!=INT]", stdout
);
1381 if (generic
!= GT_ENTERPRISE
) {
1382 if (elem
.data
.integer
!= 0)
1383 printf("[specific-trap(%d)!=0]", elem
.data
.integer
);
1385 printf(" s=%d", elem
.data
.integer
);
1391 /* time-stamp (TimeTicks) */
1392 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1394 if (elem
.type
!= BE_UNS
) { /* XXX */
1395 fputs("[time-stamp!=TIMETICKS]", stdout
);
1403 varbind_print (TRAP
, np
, length
);
1408 * Decode arbitrary SNMP PDUs.
1411 pdu_print(const u_char
*np
, u_int length
, int version
)
1417 if ((count
= asn1_parse(np
, length
, &pdu
)) < 0)
1419 if (pdu
.type
!= BE_PDU
) {
1420 fputs("[no PDU]", stdout
);
1423 if ((u_int
)count
< length
)
1424 printf("[%d extra after PDU]", length
- count
);
1426 fputs("{ ", stdout
);
1430 /* descend into PDU */
1431 length
= pdu
.asnlen
;
1432 np
= (u_char
*)pdu
.data
.raw
;
1434 if (version
== SNMP_VERSION_1
&&
1435 (pdu
.id
== GETBULKREQ
|| pdu
.id
== INFORMREQ
||
1436 pdu
.id
== V2TRAP
|| pdu
.id
== REPORT
)) {
1437 printf("[v2 PDU in v1 message]");
1441 if (version
== SNMP_VERSION_2
&& pdu
.id
== TRAP
) {
1442 printf("[v1 PDU in v2 message]");
1448 trappdu_print(np
, length
);
1458 snmppdu_print(pdu
.id
, np
, length
);
1463 fputs(" } ", stdout
);
1468 * Decode a scoped SNMP PDU.
1471 scopedpdu_print(const u_char
*np
, u_int length
, int version
)
1477 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1479 if (elem
.type
!= BE_SEQ
) {
1480 fputs("[!scoped PDU]", stdout
);
1484 length
= elem
.asnlen
;
1485 np
= (u_char
*)elem
.data
.raw
;
1487 /* contextEngineID (OCTET STRING) */
1488 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1490 if (elem
.type
!= BE_STR
) {
1491 fputs("[contextEngineID!=STR]", stdout
);
1498 fputs("E= ", stdout
);
1499 for (i
= 0; i
< (int)elem
.asnlen
; i
++) {
1500 printf("0x%02X", elem
.data
.str
[i
]);
1504 /* contextName (OCTET STRING) */
1505 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1507 if (elem
.type
!= BE_STR
) {
1508 fputs("[contextName!=STR]", stdout
);
1515 printf("C=%.*s ", (int)elem
.asnlen
, elem
.data
.str
);
1517 pdu_print(np
, length
, version
);
1521 * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
1524 community_print(const u_char
*np
, u_int length
, int version
)
1529 /* Community (String) */
1530 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1532 if (elem
.type
!= BE_STR
) {
1533 fputs("[comm!=STR]", stdout
);
1537 /* default community */
1538 if (!(elem
.asnlen
== sizeof(DEF_COMMUNITY
) - 1 &&
1539 strncmp((char *)elem
.data
.str
, DEF_COMMUNITY
,
1540 sizeof(DEF_COMMUNITY
) - 1) == 0))
1542 printf("C=%.*s ", (int)elem
.asnlen
, elem
.data
.str
);
1546 pdu_print(np
, length
, version
);
1550 * Decode SNMPv3 User-based Security Message Header (SNMPv3)
1553 usm_print(const u_char
*np
, u_int length
)
1559 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1561 if (elem
.type
!= BE_SEQ
) {
1562 fputs("[!usm]", stdout
);
1566 length
= elem
.asnlen
;
1567 np
= (u_char
*)elem
.data
.raw
;
1569 /* msgAuthoritativeEngineID (OCTET STRING) */
1570 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1572 if (elem
.type
!= BE_STR
) {
1573 fputs("[msgAuthoritativeEngineID!=STR]", stdout
);
1580 /* msgAuthoritativeEngineBoots (INTEGER) */
1581 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1583 if (elem
.type
!= BE_INT
) {
1584 fputs("[msgAuthoritativeEngineBoots!=INT]", stdout
);
1589 printf("B=%d ", elem
.data
.integer
);
1593 /* msgAuthoritativeEngineTime (INTEGER) */
1594 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1596 if (elem
.type
!= BE_INT
) {
1597 fputs("[msgAuthoritativeEngineTime!=INT]", stdout
);
1602 printf("T=%d ", elem
.data
.integer
);
1606 /* msgUserName (OCTET STRING) */
1607 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1609 if (elem
.type
!= BE_STR
) {
1610 fputs("[msgUserName!=STR]", stdout
);
1617 printf("U=%.*s ", (int)elem
.asnlen
, elem
.data
.str
);
1619 /* msgAuthenticationParameters (OCTET STRING) */
1620 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1622 if (elem
.type
!= BE_STR
) {
1623 fputs("[msgAuthenticationParameters!=STR]", stdout
);
1630 /* msgPrivacyParameters (OCTET STRING) */
1631 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1633 if (elem
.type
!= BE_STR
) {
1634 fputs("[msgPrivacyParameters!=STR]", stdout
);
1641 if ((u_int
)count
< length
)
1642 printf("[%d extra after usm SEQ]", length
- count
);
1646 * Decode SNMPv3 Message Header (SNMPv3)
1649 v3msg_print(const u_char
*np
, u_int length
)
1655 const u_char
*xnp
= np
;
1656 int xlength
= length
;
1659 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1661 if (elem
.type
!= BE_SEQ
) {
1662 fputs("[!message]", stdout
);
1666 length
= elem
.asnlen
;
1667 np
= (u_char
*)elem
.data
.raw
;
1670 fputs("{ ", stdout
);
1673 /* msgID (INTEGER) */
1674 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1676 if (elem
.type
!= BE_INT
) {
1677 fputs("[msgID!=INT]", stdout
);
1684 /* msgMaxSize (INTEGER) */
1685 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1687 if (elem
.type
!= BE_INT
) {
1688 fputs("[msgMaxSize!=INT]", stdout
);
1695 /* msgFlags (OCTET STRING) */
1696 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1698 if (elem
.type
!= BE_STR
) {
1699 fputs("[msgFlags!=STR]", stdout
);
1703 if (elem
.asnlen
!= 1) {
1704 printf("[msgFlags size %d]", elem
.asnlen
);
1707 flags
= elem
.data
.str
[0];
1708 if (flags
!= 0x00 && flags
!= 0x01 && flags
!= 0x03
1709 && flags
!= 0x04 && flags
!= 0x05 && flags
!= 0x07) {
1710 printf("[msgFlags=0x%02X]", flags
);
1716 fputs("F=", stdout
);
1717 if (flags
& 0x01) fputs("a", stdout
);
1718 if (flags
& 0x02) fputs("p", stdout
);
1719 if (flags
& 0x04) fputs("r", stdout
);
1722 /* msgSecurityModel (INTEGER) */
1723 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1725 if (elem
.type
!= BE_INT
) {
1726 fputs("[msgSecurityModel!=INT]", stdout
);
1730 model
= elem
.data
.integer
;
1734 if ((u_int
)count
< length
)
1735 printf("[%d extra after message SEQ]", length
- count
);
1738 fputs("} ", stdout
);
1743 fputs("{ USM ", stdout
);
1746 printf("[security model %d]", model
);
1750 np
= xnp
+ (np
- xnp
);
1751 length
= xlength
- (np
- xnp
);
1753 /* msgSecurityParameters (OCTET STRING) */
1754 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1756 if (elem
.type
!= BE_STR
) {
1757 fputs("[msgSecurityParameters!=STR]", stdout
);
1765 usm_print(elem
.data
.str
, elem
.asnlen
);
1767 fputs("} ", stdout
);
1772 fputs("{ ScopedPDU ", stdout
);
1775 scopedpdu_print(np
, length
, 3);
1778 fputs("} ", stdout
);
1783 * Decode SNMP header and pass on to PDU printing routines
1786 snmp_print(const u_char
*np
, u_int length
)
1794 /* truncated packet? */
1795 if (np
+ length
> snapend
) {
1797 length
= snapend
- np
;
1802 /* initial Sequence */
1803 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1805 if (elem
.type
!= BE_SEQ
) {
1806 fputs("[!init SEQ]", stdout
);
1810 if ((u_int
)count
< length
)
1811 printf("[%d extra after iSEQ]", length
- count
);
1813 length
= elem
.asnlen
;
1814 np
= (u_char
*)elem
.data
.raw
;
1816 /* Version (INTEGER) */
1817 if ((count
= asn1_parse(np
, length
, &elem
)) < 0)
1819 if (elem
.type
!= BE_INT
) {
1820 fputs("[version!=INT]", stdout
);
1825 switch (elem
.data
.integer
) {
1826 case SNMP_VERSION_1
:
1827 case SNMP_VERSION_2
:
1828 case SNMP_VERSION_3
:
1830 printf("{ %s ", SnmpVersion
[elem
.data
.integer
]);
1833 printf("[version = %d]", elem
.data
.integer
);
1836 version
= elem
.data
.integer
;
1841 case SNMP_VERSION_1
:
1842 case SNMP_VERSION_2
:
1843 community_print(np
, length
, version
);
1845 case SNMP_VERSION_3
:
1846 v3msg_print(np
, length
);
1849 printf("[version = %d]", elem
.data
.integer
);
1854 fputs("} ", stdout
);