2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3 * John Robert LoVerso. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * This implementation has been influenced by the CMU SNMP release,
29 * by Steve Waldbusser. However, this shares no code with that system.
30 * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_.
31 * Earlier forms of this implementation were derived and/or inspired by an
32 * awk script originally written by C. Philip Wood of LANL (but later
33 * heavily modified by John Robert LoVerso). The copyright notice for
34 * that work is preserved below, even though it may not rightly apply
37 * Support for SNMPv2c/SNMPv3 and the ability to link the module against
38 * the libsmi was added by J. Schoenwaelder, Copyright (c) 1999.
40 * This started out as a very simple program, but the incremental decoding
41 * (into the BE structure) complicated things.
43 # Los Alamos National Laboratory
45 # Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
46 # This software was produced under a U.S. Government contract
47 # (W-7405-ENG-36) by Los Alamos National Laboratory, which is
48 # operated by the University of California for the U.S. Department
49 # of Energy. The U.S. Government is licensed to use, reproduce,
50 # and distribute this software. Permission is granted to the
51 # public to copy and use this software without charge, provided
52 # that this Notice and any statement of authorship are reproduced
53 # on all copies. Neither the Government nor the University makes
54 # any warranty, express or implied, or assumes any liability or
55 # responsibility for the use of this software.
56 # @(#)snmp.awk.x 1.1 (LANL) 1/15/90
59 /* \summary: Simple Network Management Protocol (SNMP) printer */
65 #include "netdissect-stdinc.h"
74 #include "netdissect-ctype.h"
76 #include "netdissect.h"
79 #undef OPAQUE /* defined in <wingdi.h> */
83 * Universal ASN.1 types
84 * (we only care about the tag values for those allowed in the Internet SMI)
86 static const char *Universal
[] = {
99 "U-8","U-9","U-10","U-11", /* 8-11 */
100 "U-12","U-13","U-14","U-15", /* 12-15 */
107 * Application-wide ASN.1 types from the Internet SMI and their tags
109 static const char *Application
[] = {
126 * Context-specific ASN.1 types for the SNMP PDUs and their tags
128 static const char *Context
[] = {
149 #define NOTIFY_CLASS(x) (x == TRAP || x == V2TRAP || x == INFORMREQ)
150 #define READ_CLASS(x) (x == GETREQ || x == GETNEXTREQ || x == GETBULKREQ)
151 #define WRITE_CLASS(x) (x == SETREQ)
152 #define RESPONSE_CLASS(x) (x == GETRESP)
153 #define INTERNAL_CLASS(x) (x == REPORT)
156 * Context-specific ASN.1 types for the SNMP Exceptions and their tags
158 static const char *Exceptions
[] = {
160 #define NOSUCHOBJECT 0
162 #define NOSUCHINSTANCE 1
164 #define ENDOFMIBVIEW 2
168 * Private ASN.1 types
169 * The Internet SMI does not specify any
171 static const char *Private
[] = {
176 * error-status values for any SNMP PDU
178 static const char *ErrorStatus
[] = {
192 "resourceUnavailable",
195 "authorizationError",
199 #define DECODE_ErrorStatus(e) \
200 ( e >= 0 && (size_t)e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
202 : (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf))
205 * generic-trap values in the SNMP Trap-PDU
207 static const char *GenericTrap
[] = {
212 "authenticationFailure",
215 #define GT_ENTERPRISE 6
217 #define DECODE_GenericTrap(t) \
218 ( t >= 0 && (size_t)t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
220 : (snprintf(buf, sizeof(buf), "gt=%d", t), buf))
223 * ASN.1 type class table
224 * Ties together the preceding Universal, Application, Context, and Private
227 #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
228 static const struct {
233 defineCLASS(Universal
),
235 defineCLASS(Application
),
236 #define APPLICATION 1
237 defineCLASS(Context
),
239 defineCLASS(Private
),
241 defineCLASS(Exceptions
),
246 * defined forms for ASN.1 types
248 static const char *Form
[] = {
252 #define CONSTRUCTED 1
256 * A structure for the OID tree for the compiled-in MIB.
257 * This is stored as a general-order tree.
260 const char *desc
; /* name of object */
261 u_char oid
; /* sub-id following parent */
262 u_char type
; /* object type (unused) */
263 struct obj
*child
, *next
; /* child and next sibling pointers */
267 * Include the compiled in SNMP MIB. "mib.h" is produced by feeding
268 * RFC-1156 format files into "makemib". "mib.h" MUST define at least
269 * a value for `mibroot'.
271 * In particular, this is gross, as this is including initialized structures,
272 * and by right shouldn't be an "include" file.
277 * This defines a list of OIDs which will be abbreviated on output.
278 * Currently, this includes the prefixes for the Internet MIB, the
279 * private enterprises tree, and the experimental tree.
281 #define OID_FIRST_OCTET(x, y) (((x)*40) + (y)) /* X.690 8.19.4 */
284 static const uint8_t mib_oid
[] = { OID_FIRST_OCTET(1, 3), 6, 1, 2, 1 };
286 #ifndef NO_ABREV_ENTER
287 static const uint8_t enterprises_oid
[] = { OID_FIRST_OCTET(1, 3), 6, 1, 4, 1 };
289 #ifndef NO_ABREV_EXPERI
290 static const uint8_t experimental_oid
[] = { OID_FIRST_OCTET(1, 3), 6, 1, 3 };
292 #ifndef NO_ABBREV_SNMPMODS
293 static const uint8_t snmpModules_oid
[] = { OID_FIRST_OCTET(1, 3), 6, 1, 6, 3 };
296 #define OBJ_ABBREV_ENTRY(prefix, obj) \
297 { prefix, &_ ## obj ## _obj, obj ## _oid, sizeof (obj ## _oid) }
298 static const struct obj_abrev
{
299 const char *prefix
; /* prefix for this abrev */
300 struct obj
*node
; /* pointer into object table */
301 const uint8_t *oid
; /* ASN.1 encoded OID */
302 size_t oid_len
; /* length of OID */
303 } obj_abrev_list
[] = {
305 /* .iso.org.dod.internet.mgmt.mib */
306 OBJ_ABBREV_ENTRY("", mib
),
308 #ifndef NO_ABREV_ENTER
309 /* .iso.org.dod.internet.private.enterprises */
310 OBJ_ABBREV_ENTRY("E:", enterprises
),
312 #ifndef NO_ABREV_EXPERI
313 /* .iso.org.dod.internet.experimental */
314 OBJ_ABBREV_ENTRY("X:", experimental
),
316 #ifndef NO_ABBREV_SNMPMODS
317 /* .iso.org.dod.internet.snmpV2.snmpModules */
318 OBJ_ABBREV_ENTRY("S:", snmpModules
),
324 * This is used in the OID print routine to walk down the object tree
325 * rooted at `mibroot'.
327 #define OBJ_PRINT(o, suppressdot) \
331 if ((o) == objp->oid) \
333 } while ((objp = objp->next) != NULL); \
336 ND_PRINT(suppressdot?"%s":".%s", objp->desc); \
337 objp = objp->child; \
339 ND_PRINT(suppressdot?"%u":".%u", (o)); \
343 * This is the definition for the Any-Data-Type storage used purely for
344 * temporary internal representation while decoding an ASN.1 data stream.
356 u_char form
, class; /* tag info */
367 #define BE_INETADDR 8
370 #define BE_NOSUCHOBJECT 128
371 #define BE_NOSUCHINST 129
372 #define BE_ENDOFMIBVIEW 130
376 * SNMP versions recognized by this module
378 static const char *SnmpVersion
[] = {
380 #define SNMP_VERSION_1 0
382 #define SNMP_VERSION_2 1
384 #define SNMP_VERSION_2U 2
386 #define SNMP_VERSION_3 3
390 * Defaults for SNMP PDU components
392 #define DEF_COMMUNITY "public"
395 * constants for ASN.1 decoding
398 #define ASNLEN_INETADDR 4
401 #define ASN_BIT8 0x80
402 #define ASN_LONGLEN 0x80
404 #define ASN_ID_BITS 0x1f
405 #define ASN_FORM_BITS 0x20
406 #define ASN_FORM_SHIFT 5
407 #define ASN_CLASS_BITS 0xc0
408 #define ASN_CLASS_SHIFT 6
410 #define ASN_ID_EXT 0x1f /* extension ID in tag field */
413 * This decodes the next ASN.1 object in the stream pointed to by "p"
414 * (and of real-length "len") and stores the intermediate data in the
415 * provided BE object.
417 * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
418 * O/w, this returns the number of bytes parsed from "p".
421 asn1_parse(netdissect_options
*ndo
,
422 const u_char
*p
, u_int len
, struct be
*elem
)
424 u_char form
, class, id
;
430 ND_PRINT("[nothing to parse]");
436 * it would be nice to use a bit field, but you can't depend on them.
437 * +---+---+---+---+---+---+---+---+
439 * +---+---+---+---+---+---+---+---+
442 id
= GET_U_1(p
) & ASN_ID_BITS
; /* lower 5 bits, range 00-1f */
444 form
= (GET_U_1(p
) & 0xe0) >> 5; /* move upper 3 bits to lower 3 */
445 class = form
>> 1; /* bits 7&6 -> bits 1&0, range 0-3 */
446 form
&= 0x1; /* bit 5 -> bit 0, range 0-1 */
448 form
= (u_char
)(GET_U_1(p
) & ASN_FORM_BITS
) >> ASN_FORM_SHIFT
;
449 class = (u_char
)(GET_U_1(p
) & ASN_CLASS_BITS
) >> ASN_CLASS_SHIFT
;
455 /* extended tag field */
456 if (id
== ASN_ID_EXT
) {
458 * The ID follows, as a sequence of octets with the
459 * 8th bit set and the remaining 7 bits being
460 * the next 7 bits of the value, terminated with
461 * an octet with the 8th bit not set.
463 * First, assemble all the octets with the 8th
464 * bit set. XXX - this doesn't handle a value
465 * that won't fit in 32 bits.
469 while (GET_U_1(p
) & ASN_BIT8
) {
471 ND_PRINT("[Xtagfield?]");
474 id
= (id
<< 7) | (GET_U_1(p
) & ~ASN_BIT8
);
481 ND_PRINT("[Xtagfield?]");
485 elem
->id
= id
= (id
<< 7) | GET_U_1(p
);
491 ND_PRINT("[no asnlen]");
495 elem
->asnlen
= GET_U_1(p
);
497 if (elem
->asnlen
& ASN_BIT8
) {
498 uint32_t noct
= elem
->asnlen
% ASN_BIT8
;
501 ND_PRINT("[asnlen? %d<%d]", len
, noct
);
504 ND_TCHECK_LEN(p
, noct
);
505 for (; noct
!= 0; len
--, hdr
++, noct
--) {
506 elem
->asnlen
= (elem
->asnlen
<< ASN_SHIFT8
) | GET_U_1(p
);
510 if (len
< elem
->asnlen
) {
511 ND_PRINT("[len%d<asnlen%u]", len
, elem
->asnlen
);
514 if (form
>= sizeof(Form
)/sizeof(Form
[0])) {
515 ND_PRINT("[form?%d]", form
);
518 if (class >= sizeof(Class
)/sizeof(Class
[0])) {
519 ND_PRINT("[class?%c/%d]", *Form
[form
], class);
522 if ((int)id
>= Class
[class].numIDs
) {
523 ND_PRINT("[id?%c/%s/%d]", *Form
[form
], Class
[class].name
, id
);
526 ND_TCHECK_LEN(p
, elem
->asnlen
);
543 if (elem
->asnlen
== 0) {
544 ND_PRINT("[asnlen=0]");
547 if (GET_U_1(p
) & ASN_BIT8
) /* negative */
549 for (i
= elem
->asnlen
; i
!= 0; p
++, i
--)
550 data
= (data
<< ASN_SHIFT8
) | GET_U_1(p
);
551 elem
->data
.integer
= data
;
557 elem
->data
.raw
= (const uint8_t *)p
;
561 elem
->type
= BE_NULL
;
562 elem
->data
.raw
= NULL
;
566 elem
->type
= BE_OCTET
;
567 elem
->data
.raw
= (const uint8_t *)p
;
568 ND_PRINT("[P/U/%s]", Class
[class].Id
[id
]);
576 elem
->type
= BE_INETADDR
;
577 elem
->data
.raw
= (const uint8_t *)p
;
586 for (i
= elem
->asnlen
; i
!= 0; p
++, i
--)
587 data
= (data
<< 8) + GET_U_1(p
);
588 elem
->data
.uns
= data
;
594 elem
->type
= BE_UNS64
;
596 for (i
= elem
->asnlen
; i
!= 0; p
++, i
--)
597 data64
= (data64
<< 8) + GET_U_1(p
);
598 elem
->data
.uns64
= data64
;
603 elem
->type
= BE_OCTET
;
604 elem
->data
.raw
= (const uint8_t *)p
;
606 Class
[class].Id
[id
]);
614 elem
->type
= BE_NOSUCHOBJECT
;
615 elem
->data
.raw
= NULL
;
619 elem
->type
= BE_NOSUCHINST
;
620 elem
->data
.raw
= NULL
;
624 elem
->type
= BE_ENDOFMIBVIEW
;
625 elem
->data
.raw
= NULL
;
631 ND_PRINT("[P/%s/%s]", Class
[class].name
, Class
[class].Id
[id
]);
632 elem
->type
= BE_OCTET
;
633 elem
->data
.raw
= (const uint8_t *)p
;
644 elem
->data
.raw
= (const uint8_t *)p
;
648 elem
->type
= BE_OCTET
;
649 elem
->data
.raw
= (const uint8_t *)p
;
650 ND_PRINT("C/U/%s", Class
[class].Id
[id
]);
657 elem
->data
.raw
= (const uint8_t *)p
;
661 elem
->type
= BE_OCTET
;
662 elem
->data
.raw
= (const uint8_t *)p
;
663 ND_PRINT("C/%s/%s", Class
[class].name
, Class
[class].Id
[id
]);
670 return elem
->asnlen
+ hdr
;
678 asn1_print_octets(netdissect_options
*ndo
, struct be
*elem
)
680 const u_char
*p
= (const u_char
*)elem
->data
.raw
;
681 uint32_t asnlen
= elem
->asnlen
;
684 ND_TCHECK_LEN(p
, asnlen
);
685 for (i
= asnlen
; i
!= 0; p
++, i
--)
686 ND_PRINT("_%.2x", GET_U_1(p
));
695 asn1_print_string(netdissect_options
*ndo
, struct be
*elem
)
697 int printable
= 1, first
= 1;
699 uint32_t asnlen
= elem
->asnlen
;
703 ND_TCHECK_LEN(p
, asnlen
);
704 for (i
= asnlen
; printable
&& i
!= 0; p
++, i
--)
705 printable
= ND_ASCII_ISPRINT(GET_U_1(p
));
709 if (nd_printn(ndo
, p
, asnlen
, ndo
->ndo_snapend
)) {
715 for (i
= asnlen
; i
!= 0; p
++, i
--) {
716 ND_PRINT(first
? "%.2x" : "_%.2x", GET_U_1(p
));
728 * Display the ASN.1 object represented by the BE object.
729 * This used to be an integral part of asn1_parse() before the intermediate
733 asn1_print(netdissect_options
*ndo
,
737 uint32_t asnlen
= elem
->asnlen
;
740 switch (elem
->type
) {
743 if (asn1_print_octets(ndo
, elem
) == -1)
751 int o
= 0, first
= -1;
753 p
= (const u_char
*)elem
->data
.raw
;
755 if (!ndo
->ndo_nflag
&& asnlen
> 2) {
756 const struct obj_abrev
*a
= &obj_abrev_list
[0];
757 for (; a
->node
; a
++) {
760 if (!ND_TTEST_LEN(p
, a
->oid_len
))
762 if (memcmp(a
->oid
, p
, a
->oid_len
) == 0) {
763 objp
= a
->node
->child
;
766 ND_PRINT("%s", a
->prefix
);
773 for (; i
!= 0; p
++, i
--) {
775 o
= (o
<< ASN_SHIFT7
) + (GET_U_1(p
) & ~ASN_BIT8
);
776 if (GET_U_1(p
) & ASN_LONGLEN
)
780 * first subitem encodes two items with
782 * (see X.690:1997 clause 8.19 for the details)
803 ND_PRINT("%d", elem
->data
.integer
);
807 ND_PRINT("%u", elem
->data
.uns
);
811 ND_PRINT("%" PRIu64
, elem
->data
.uns64
);
815 if (asn1_print_string(ndo
, elem
) == -1)
820 ND_PRINT("Seq(%u)", elem
->asnlen
);
824 if (asnlen
!= ASNLEN_INETADDR
)
825 ND_PRINT("[inetaddr len!=%d]", ASNLEN_INETADDR
);
826 p
= (const u_char
*)elem
->data
.raw
;
827 ND_TCHECK_LEN(p
, asnlen
);
828 for (i
= asnlen
; i
!= 0; p
++, i
--) {
829 ND_PRINT((i
== asnlen
) ? "%u" : ".%u", GET_U_1(p
));
833 case BE_NOSUCHOBJECT
:
835 case BE_ENDOFMIBVIEW
:
836 ND_PRINT("[%s]", Class
[EXCEPTIONS
].Id
[elem
->id
]);
840 ND_PRINT("%s(%u)", Class
[CONTEXT
].Id
[elem
->id
], elem
->asnlen
);
844 ND_PRINT("[BE_ANY!?]");
860 * This is a brute force ASN.1 printer: recurses to dump an entire structure.
861 * This will work for any ASN.1 stream, not just an SNMP PDU.
863 * By adding newlines and spaces at the correct places, this would print in
866 * This is not currently used.
869 asn1_decode(u_char
*p
, u_int length
)
874 while (i
>= 0 && length
> 0) {
875 i
= asn1_parse(ndo
, p
, length
, &elem
);
878 if (asn1_print(ndo
, &elem
) < 0)
880 if (elem
.type
== BE_SEQ
|| elem
.type
== BE_PDU
) {
882 asn1_decode(elem
.data
.raw
, elem
.asnlen
);
895 SmiBasetype basetype
;
899 static const struct smi2be smi2betab
[] = {
900 { SMI_BASETYPE_INTEGER32
, BE_INT
},
901 { SMI_BASETYPE_OCTETSTRING
, BE_STR
},
902 { SMI_BASETYPE_OCTETSTRING
, BE_INETADDR
},
903 { SMI_BASETYPE_OBJECTIDENTIFIER
, BE_OID
},
904 { SMI_BASETYPE_UNSIGNED32
, BE_UNS
},
905 { SMI_BASETYPE_INTEGER64
, BE_NONE
},
906 { SMI_BASETYPE_UNSIGNED64
, BE_UNS64
},
907 { SMI_BASETYPE_FLOAT32
, BE_NONE
},
908 { SMI_BASETYPE_FLOAT64
, BE_NONE
},
909 { SMI_BASETYPE_FLOAT128
, BE_NONE
},
910 { SMI_BASETYPE_ENUM
, BE_INT
},
911 { SMI_BASETYPE_BITS
, BE_STR
},
912 { SMI_BASETYPE_UNKNOWN
, BE_NONE
}
916 smi_decode_oid(netdissect_options
*ndo
,
917 struct be
*elem
, unsigned int *oid
,
918 unsigned int oidsize
, unsigned int *oidlen
)
920 const u_char
*p
= (const u_char
*)elem
->data
.raw
;
921 uint32_t asnlen
= elem
->asnlen
;
923 int o
= 0, first
= -1;
924 unsigned int firstval
;
926 for (*oidlen
= 0; i
!= 0; p
++, i
--) {
928 o
= (o
<< ASN_SHIFT7
) + (GET_U_1(p
) & ~ASN_BIT8
);
929 if (GET_U_1(p
) & ASN_LONGLEN
)
933 * first subitem encodes two items with 1st*OIDMUX+2nd
934 * (see X.690:1997 clause 8.19 for the details)
938 firstval
= o
/ OIDMUX
;
939 if (firstval
> 2) firstval
= 2;
940 o
-= firstval
* OIDMUX
;
941 if (*oidlen
< oidsize
) {
942 oid
[(*oidlen
)++] = firstval
;
945 if (*oidlen
< oidsize
) {
946 oid
[(*oidlen
)++] = o
;
957 static int smi_check_type(SmiBasetype basetype
, int be
)
961 for (i
= 0; smi2betab
[i
].basetype
!= SMI_BASETYPE_UNKNOWN
; i
++) {
962 if (smi2betab
[i
].basetype
== basetype
&& smi2betab
[i
].be
== be
) {
970 static int smi_check_a_range(SmiType
*smiType
, SmiRange
*smiRange
,
975 switch (smiType
->basetype
) {
976 case SMI_BASETYPE_OBJECTIDENTIFIER
:
977 case SMI_BASETYPE_OCTETSTRING
:
978 if (smiRange
->minValue
.value
.unsigned32
979 == smiRange
->maxValue
.value
.unsigned32
) {
980 ok
= (elem
->asnlen
== smiRange
->minValue
.value
.unsigned32
);
982 ok
= (elem
->asnlen
>= smiRange
->minValue
.value
.unsigned32
983 && elem
->asnlen
<= smiRange
->maxValue
.value
.unsigned32
);
987 case SMI_BASETYPE_INTEGER32
:
988 ok
= (elem
->data
.integer
>= smiRange
->minValue
.value
.integer32
989 && elem
->data
.integer
<= smiRange
->maxValue
.value
.integer32
);
992 case SMI_BASETYPE_UNSIGNED32
:
993 ok
= (elem
->data
.uns
>= smiRange
->minValue
.value
.unsigned32
994 && elem
->data
.uns
<= smiRange
->maxValue
.value
.unsigned32
);
997 case SMI_BASETYPE_UNSIGNED64
:
1001 /* case SMI_BASETYPE_INTEGER64: SMIng */
1002 /* case SMI_BASETYPE_FLOAT32: SMIng */
1003 /* case SMI_BASETYPE_FLOAT64: SMIng */
1004 /* case SMI_BASETYPE_FLOAT128: SMIng */
1006 case SMI_BASETYPE_ENUM
:
1007 case SMI_BASETYPE_BITS
:
1008 case SMI_BASETYPE_UNKNOWN
:
1020 static int smi_check_range(SmiType
*smiType
, struct be
*elem
)
1025 for (smiRange
= smiGetFirstRange(smiType
);
1027 smiRange
= smiGetNextRange(smiRange
)) {
1029 ok
= smi_check_a_range(smiType
, smiRange
, elem
);
1037 SmiType
*parentType
;
1038 parentType
= smiGetParentType(smiType
);
1040 ok
= smi_check_range(parentType
, elem
);
1048 smi_print_variable(netdissect_options
*ndo
,
1049 struct be
*elem
, int *status
)
1051 unsigned int oid
[128], oidlen
;
1052 SmiNode
*smiNode
= NULL
;
1055 if (!nd_smi_module_loaded
) {
1056 *status
= asn1_print(ndo
, elem
);
1059 *status
= smi_decode_oid(ndo
, elem
, oid
, sizeof(oid
) / sizeof(unsigned int),
1063 smiNode
= smiGetNodeByOID(oidlen
, oid
);
1065 *status
= asn1_print(ndo
, elem
);
1068 if (ndo
->ndo_vflag
) {
1069 ND_PRINT("%s::", smiGetNodeModule(smiNode
)->name
);
1071 ND_PRINT("%s", smiNode
->name
);
1072 if (smiNode
->oidlen
< oidlen
) {
1073 for (i
= smiNode
->oidlen
; i
< oidlen
; i
++) {
1074 ND_PRINT(".%u", oid
[i
]);
1082 smi_print_value(netdissect_options
*ndo
,
1083 SmiNode
*smiNode
, u_short pduid
, struct be
*elem
)
1085 unsigned int i
, oid
[128], oidlen
;
1090 if (! smiNode
|| ! (smiNode
->nodekind
1091 & (SMI_NODEKIND_SCALAR
| SMI_NODEKIND_COLUMN
))) {
1092 return asn1_print(ndo
, elem
);
1095 if (elem
->type
== BE_NOSUCHOBJECT
1096 || elem
->type
== BE_NOSUCHINST
1097 || elem
->type
== BE_ENDOFMIBVIEW
) {
1098 return asn1_print(ndo
, elem
);
1101 if (NOTIFY_CLASS(pduid
) && smiNode
->access
< SMI_ACCESS_NOTIFY
) {
1102 ND_PRINT("[notNotifyable]");
1105 if (READ_CLASS(pduid
) && smiNode
->access
< SMI_ACCESS_READ_ONLY
) {
1106 ND_PRINT("[notReadable]");
1109 if (WRITE_CLASS(pduid
) && smiNode
->access
< SMI_ACCESS_READ_WRITE
) {
1110 ND_PRINT("[notWritable]");
1113 if (RESPONSE_CLASS(pduid
)
1114 && smiNode
->access
== SMI_ACCESS_NOT_ACCESSIBLE
) {
1115 ND_PRINT("[noAccess]");
1118 smiType
= smiGetNodeType(smiNode
);
1120 return asn1_print(ndo
, elem
);
1123 if (! smi_check_type(smiType
->basetype
, elem
->type
)) {
1124 ND_PRINT("[wrongType]");
1127 if (! smi_check_range(smiType
, elem
)) {
1128 ND_PRINT("[outOfRange]");
1131 /* resolve bits to named bits */
1133 /* check whether instance identifier is valid */
1135 /* apply display hints (integer, octetstring) */
1137 /* convert instance identifier to index type values */
1139 switch (elem
->type
) {
1141 if (smiType
->basetype
== SMI_BASETYPE_BITS
) {
1142 /* print bit labels */
1144 if (nd_smi_module_loaded
&&
1145 smi_decode_oid(ndo
, elem
, oid
,
1146 sizeof(oid
)/sizeof(unsigned int),
1148 smiNode
= smiGetNodeByOID(oidlen
, oid
);
1150 if (ndo
->ndo_vflag
) {
1151 ND_PRINT("%s::", smiGetNodeModule(smiNode
)->name
);
1153 ND_PRINT("%s", smiNode
->name
);
1154 if (smiNode
->oidlen
< oidlen
) {
1155 for (i
= smiNode
->oidlen
;
1157 ND_PRINT(".%u", oid
[i
]);
1167 if (smiType
->basetype
== SMI_BASETYPE_ENUM
) {
1168 for (nn
= smiGetFirstNamedNumber(smiType
);
1170 nn
= smiGetNextNamedNumber(nn
)) {
1171 if (nn
->value
.value
.integer32
1172 == elem
->data
.integer
) {
1173 ND_PRINT("%s", nn
->name
);
1174 ND_PRINT("(%d)", elem
->data
.integer
);
1184 return asn1_print(ndo
, elem
);
1191 * General SNMP header
1193 * version INTEGER {version-1(0)},
1194 * community OCTET STRING,
1197 * PDUs for all but Trap: (see rfc1157 from page 15 on)
1199 * request-id INTEGER,
1200 * error-status INTEGER,
1201 * error-index INTEGER,
1202 * varbindlist SEQUENCE OF
1210 * enterprise OBJECT IDENTIFIER,
1211 * agent-addr NetworkAddress,
1212 * generic-trap INTEGER,
1213 * specific-trap INTEGER,
1214 * time-stamp TimeTicks,
1215 * varbindlist SEQUENCE OF
1224 * Decode SNMP varBind
1227 varbind_print(netdissect_options
*ndo
,
1228 u_short pduid
, const u_char
*np
, u_int length
)
1233 SmiNode
*smiNode
= NULL
;
1237 /* Sequence of varBind */
1238 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1240 if (elem
.type
!= BE_SEQ
) {
1241 ND_PRINT("[!SEQ of varbind]");
1242 asn1_print(ndo
, &elem
);
1245 if ((u_int
)count
< length
)
1246 ND_PRINT("[%d extra after SEQ of varbind]", length
- count
);
1248 length
= elem
.asnlen
;
1249 np
= (const u_char
*)elem
.data
.raw
;
1251 for (ind
= 1; length
> 0; ind
++) {
1252 const u_char
*vbend
;
1258 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1260 if (elem
.type
!= BE_SEQ
) {
1261 ND_PRINT("[!varbind]");
1262 asn1_print(ndo
, &elem
);
1266 vblength
= length
- count
;
1268 length
= elem
.asnlen
;
1269 np
= (const u_char
*)elem
.data
.raw
;
1272 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1274 if (elem
.type
!= BE_OID
) {
1275 ND_PRINT("[objName!=OID]");
1276 asn1_print(ndo
, &elem
);
1280 smiNode
= smi_print_variable(ndo
, &elem
, &status
);
1282 status
= asn1_print(ndo
, &elem
);
1289 if (pduid
!= GETREQ
&& pduid
!= GETNEXTREQ
1290 && pduid
!= GETBULKREQ
)
1294 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1296 if (pduid
== GETREQ
|| pduid
== GETNEXTREQ
1297 || pduid
== GETBULKREQ
) {
1298 if (elem
.type
!= BE_NULL
) {
1299 ND_PRINT("[objVal!=NULL]");
1300 if (asn1_print(ndo
, &elem
) < 0)
1304 if (elem
.type
!= BE_NULL
) {
1306 status
= smi_print_value(ndo
, smiNode
, pduid
, &elem
);
1308 status
= asn1_print(ndo
, &elem
);
1320 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
1321 * GetBulk, Inform, V2Trap, and Report
1324 snmppdu_print(netdissect_options
*ndo
,
1325 u_short pduid
, const u_char
*np
, u_int length
)
1328 int count
= 0, error_status
;
1330 /* reqId (Integer) */
1331 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1333 if (elem
.type
!= BE_INT
) {
1334 ND_PRINT("[reqId!=INT]");
1335 asn1_print(ndo
, &elem
);
1339 ND_PRINT("R=%d ", elem
.data
.integer
);
1343 /* errorStatus (Integer) */
1344 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1346 if (elem
.type
!= BE_INT
) {
1347 ND_PRINT("[errorStatus!=INT]");
1348 asn1_print(ndo
, &elem
);
1352 if ((pduid
== GETREQ
|| pduid
== GETNEXTREQ
|| pduid
== SETREQ
1353 || pduid
== INFORMREQ
|| pduid
== V2TRAP
|| pduid
== REPORT
)
1354 && elem
.data
.integer
!= 0) {
1356 ND_PRINT("[errorStatus(%s)!=0]",
1357 DECODE_ErrorStatus(elem
.data
.integer
));
1358 } else if (pduid
== GETBULKREQ
) {
1359 ND_PRINT(" N=%d", elem
.data
.integer
);
1360 } else if (elem
.data
.integer
!= 0) {
1362 ND_PRINT(" %s", DECODE_ErrorStatus(elem
.data
.integer
));
1363 error_status
= elem
.data
.integer
;
1368 /* errorIndex (Integer) */
1369 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1371 if (elem
.type
!= BE_INT
) {
1372 ND_PRINT("[errorIndex!=INT]");
1373 asn1_print(ndo
, &elem
);
1376 if ((pduid
== GETREQ
|| pduid
== GETNEXTREQ
|| pduid
== SETREQ
1377 || pduid
== INFORMREQ
|| pduid
== V2TRAP
|| pduid
== REPORT
)
1378 && elem
.data
.integer
!= 0)
1379 ND_PRINT("[errorIndex(%d)!=0]", elem
.data
.integer
);
1380 else if (pduid
== GETBULKREQ
)
1381 ND_PRINT(" M=%d", elem
.data
.integer
);
1382 else if (elem
.data
.integer
!= 0) {
1384 ND_PRINT("[errorIndex(%d) w/o errorStatus]", elem
.data
.integer
);
1386 ND_PRINT("@%d", elem
.data
.integer
);
1387 } else if (error_status
) {
1388 ND_PRINT("[errorIndex==0]");
1393 varbind_print(ndo
, pduid
, np
, length
);
1398 * Decode SNMP Trap PDU
1401 trappdu_print(netdissect_options
*ndo
,
1402 const u_char
*np
, u_int length
)
1405 int count
= 0, generic
;
1409 /* enterprise (oid) */
1410 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1412 if (elem
.type
!= BE_OID
) {
1413 ND_PRINT("[enterprise!=OID]");
1414 asn1_print(ndo
, &elem
);
1417 if (asn1_print(ndo
, &elem
) < 0)
1424 /* agent-addr (inetaddr) */
1425 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1427 if (elem
.type
!= BE_INETADDR
) {
1428 ND_PRINT("[agent-addr!=INETADDR]");
1429 asn1_print(ndo
, &elem
);
1432 if (asn1_print(ndo
, &elem
) < 0)
1437 /* generic-trap (Integer) */
1438 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1440 if (elem
.type
!= BE_INT
) {
1441 ND_PRINT("[generic-trap!=INT]");
1442 asn1_print(ndo
, &elem
);
1445 generic
= elem
.data
.integer
;
1448 ND_PRINT(" %s", DECODE_GenericTrap(generic
));
1453 /* specific-trap (Integer) */
1454 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1456 if (elem
.type
!= BE_INT
) {
1457 ND_PRINT("[specific-trap!=INT]");
1458 asn1_print(ndo
, &elem
);
1461 if (generic
!= GT_ENTERPRISE
) {
1462 if (elem
.data
.integer
!= 0)
1463 ND_PRINT("[specific-trap(%d)!=0]", elem
.data
.integer
);
1465 ND_PRINT(" s=%d", elem
.data
.integer
);
1471 /* time-stamp (TimeTicks) */
1472 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1474 if (elem
.type
!= BE_UNS
) { /* XXX */
1475 ND_PRINT("[time-stamp!=TIMETICKS]");
1476 asn1_print(ndo
, &elem
);
1479 if (asn1_print(ndo
, &elem
) < 0)
1484 varbind_print(ndo
, TRAP
, np
, length
);
1489 * Decode arbitrary SNMP PDUs.
1492 pdu_print(netdissect_options
*ndo
,
1493 const u_char
*np
, u_int length
, int version
)
1499 if ((count
= asn1_parse(ndo
, np
, length
, &pdu
)) < 0)
1501 if (pdu
.type
!= BE_PDU
) {
1502 ND_PRINT("[no PDU]");
1505 if ((u_int
)count
< length
)
1506 ND_PRINT("[%d extra after PDU]", length
- count
);
1507 if (ndo
->ndo_vflag
) {
1510 if (asn1_print(ndo
, &pdu
) < 0)
1513 /* descend into PDU */
1514 length
= pdu
.asnlen
;
1515 np
= (const u_char
*)pdu
.data
.raw
;
1517 if (version
== SNMP_VERSION_1
&&
1518 (pdu
.id
== GETBULKREQ
|| pdu
.id
== INFORMREQ
||
1519 pdu
.id
== V2TRAP
|| pdu
.id
== REPORT
)) {
1520 ND_PRINT("[v2 PDU in v1 message]");
1524 if (version
== SNMP_VERSION_2
&& pdu
.id
== TRAP
) {
1525 ND_PRINT("[v1 PDU in v2 message]");
1531 trappdu_print(ndo
, np
, length
);
1541 snmppdu_print(ndo
, pdu
.id
, np
, length
);
1545 if (ndo
->ndo_vflag
) {
1551 * Decode a scoped SNMP PDU.
1554 scopedpdu_print(netdissect_options
*ndo
,
1555 const u_char
*np
, u_int length
, int version
)
1561 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1563 if (elem
.type
!= BE_SEQ
) {
1564 ND_PRINT("[!scoped PDU]");
1565 asn1_print(ndo
, &elem
);
1568 length
= elem
.asnlen
;
1569 np
= (const u_char
*)elem
.data
.raw
;
1571 /* contextEngineID (OCTET STRING) */
1572 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1574 if (elem
.type
!= BE_STR
) {
1575 ND_PRINT("[contextEngineID!=STR]");
1576 asn1_print(ndo
, &elem
);
1583 if (asn1_print_octets(ndo
, &elem
) == -1)
1587 /* contextName (OCTET STRING) */
1588 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1590 if (elem
.type
!= BE_STR
) {
1591 ND_PRINT("[contextName!=STR]");
1592 asn1_print(ndo
, &elem
);
1599 if (asn1_print_string(ndo
, &elem
) == -1)
1603 pdu_print(ndo
, np
, length
, version
);
1607 * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
1610 community_print(netdissect_options
*ndo
,
1611 const u_char
*np
, u_int length
, int version
)
1616 /* Community (String) */
1617 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1619 if (elem
.type
!= BE_STR
) {
1620 ND_PRINT("[comm!=STR]");
1621 asn1_print(ndo
, &elem
);
1624 /* default community */
1625 if (!(elem
.asnlen
== sizeof(DEF_COMMUNITY
) - 1 &&
1626 strncmp((const char *)elem
.data
.str
, DEF_COMMUNITY
,
1627 sizeof(DEF_COMMUNITY
) - 1) == 0)) {
1630 if (asn1_print_string(ndo
, &elem
) == -1)
1637 pdu_print(ndo
, np
, length
, version
);
1641 * Decode SNMPv3 User-based Security Message Header (SNMPv3)
1644 usm_print(netdissect_options
*ndo
,
1645 const u_char
*np
, u_int length
)
1651 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1653 if (elem
.type
!= BE_SEQ
) {
1655 asn1_print(ndo
, &elem
);
1658 length
= elem
.asnlen
;
1659 np
= (const u_char
*)elem
.data
.raw
;
1661 /* msgAuthoritativeEngineID (OCTET STRING) */
1662 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1664 if (elem
.type
!= BE_STR
) {
1665 ND_PRINT("[msgAuthoritativeEngineID!=STR]");
1666 asn1_print(ndo
, &elem
);
1672 /* msgAuthoritativeEngineBoots (INTEGER) */
1673 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1675 if (elem
.type
!= BE_INT
) {
1676 ND_PRINT("[msgAuthoritativeEngineBoots!=INT]");
1677 asn1_print(ndo
, &elem
);
1681 ND_PRINT("B=%d ", elem
.data
.integer
);
1685 /* msgAuthoritativeEngineTime (INTEGER) */
1686 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1688 if (elem
.type
!= BE_INT
) {
1689 ND_PRINT("[msgAuthoritativeEngineTime!=INT]");
1690 asn1_print(ndo
, &elem
);
1694 ND_PRINT("T=%d ", elem
.data
.integer
);
1698 /* msgUserName (OCTET STRING) */
1699 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1701 if (elem
.type
!= BE_STR
) {
1702 ND_PRINT("[msgUserName!=STR]");
1703 asn1_print(ndo
, &elem
);
1710 if (asn1_print_string(ndo
, &elem
) == -1)
1714 /* msgAuthenticationParameters (OCTET STRING) */
1715 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1717 if (elem
.type
!= BE_STR
) {
1718 ND_PRINT("[msgAuthenticationParameters!=STR]");
1719 asn1_print(ndo
, &elem
);
1725 /* msgPrivacyParameters (OCTET STRING) */
1726 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1728 if (elem
.type
!= BE_STR
) {
1729 ND_PRINT("[msgPrivacyParameters!=STR]");
1730 asn1_print(ndo
, &elem
);
1736 if ((u_int
)count
< length
)
1737 ND_PRINT("[%d extra after usm SEQ]", length
- count
);
1741 * Decode SNMPv3 Message Header (SNMPv3)
1744 v3msg_print(netdissect_options
*ndo
,
1745 const u_char
*np
, u_int length
)
1751 const u_char
*xnp
= np
;
1752 int xlength
= length
;
1755 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1757 if (elem
.type
!= BE_SEQ
) {
1758 ND_PRINT("[!message]");
1759 asn1_print(ndo
, &elem
);
1762 length
= elem
.asnlen
;
1763 np
= (const u_char
*)elem
.data
.raw
;
1765 if (ndo
->ndo_vflag
) {
1769 /* msgID (INTEGER) */
1770 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1772 if (elem
.type
!= BE_INT
) {
1773 ND_PRINT("[msgID!=INT]");
1774 asn1_print(ndo
, &elem
);
1780 /* msgMaxSize (INTEGER) */
1781 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1783 if (elem
.type
!= BE_INT
) {
1784 ND_PRINT("[msgMaxSize!=INT]");
1785 asn1_print(ndo
, &elem
);
1791 /* msgFlags (OCTET STRING) */
1792 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1794 if (elem
.type
!= BE_STR
) {
1795 ND_PRINT("[msgFlags!=STR]");
1796 asn1_print(ndo
, &elem
);
1799 if (elem
.asnlen
!= 1) {
1800 ND_PRINT("[msgFlags size %d]", elem
.asnlen
);
1803 flags
= GET_U_1(elem
.data
.str
);
1804 if (flags
!= 0x00 && flags
!= 0x01 && flags
!= 0x03
1805 && flags
!= 0x04 && flags
!= 0x05 && flags
!= 0x07) {
1806 ND_PRINT("[msgFlags=0x%02X]", flags
);
1812 ND_PRINT("F=%s%s%s ",
1813 flags
& 0x01 ? "a" : "",
1814 flags
& 0x02 ? "p" : "",
1815 flags
& 0x04 ? "r" : "");
1817 /* msgSecurityModel (INTEGER) */
1818 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1820 if (elem
.type
!= BE_INT
) {
1821 ND_PRINT("[msgSecurityModel!=INT]");
1822 asn1_print(ndo
, &elem
);
1825 model
= elem
.data
.integer
;
1829 if ((u_int
)count
< length
)
1830 ND_PRINT("[%d extra after message SEQ]", length
- count
);
1832 if (ndo
->ndo_vflag
) {
1837 if (ndo
->ndo_vflag
) {
1841 ND_PRINT("[security model %d]", model
);
1845 np
= xnp
+ (np
- xnp
);
1846 length
= xlength
- (np
- xnp
);
1848 /* msgSecurityParameters (OCTET STRING) */
1849 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1851 if (elem
.type
!= BE_STR
) {
1852 ND_PRINT("[msgSecurityParameters!=STR]");
1853 asn1_print(ndo
, &elem
);
1860 usm_print(ndo
, elem
.data
.str
, elem
.asnlen
);
1861 if (ndo
->ndo_vflag
) {
1866 if (ndo
->ndo_vflag
) {
1867 ND_PRINT("{ ScopedPDU ");
1870 scopedpdu_print(ndo
, np
, length
, 3);
1872 if (ndo
->ndo_vflag
) {
1878 * Decode SNMP header and pass on to PDU printing routines
1881 snmp_print(netdissect_options
*ndo
,
1882 const u_char
*np
, u_int length
)
1888 ndo
->ndo_protocol
= "snmp";
1891 /* initial Sequence */
1892 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1894 if (elem
.type
!= BE_SEQ
) {
1895 ND_PRINT("[!init SEQ]");
1896 asn1_print(ndo
, &elem
);
1899 if ((u_int
)count
< length
)
1900 ND_PRINT("[%d extra after iSEQ]", length
- count
);
1902 length
= elem
.asnlen
;
1903 np
= (const u_char
*)elem
.data
.raw
;
1905 /* Version (INTEGER) */
1906 if ((count
= asn1_parse(ndo
, np
, length
, &elem
)) < 0)
1908 if (elem
.type
!= BE_INT
) {
1909 ND_PRINT("[version!=INT]");
1910 asn1_print(ndo
, &elem
);
1914 switch (elem
.data
.integer
) {
1915 case SNMP_VERSION_1
:
1916 case SNMP_VERSION_2
:
1917 case SNMP_VERSION_3
:
1919 ND_PRINT("{ %s ", SnmpVersion
[elem
.data
.integer
]);
1922 ND_PRINT("SNMP [version = %d]", elem
.data
.integer
);
1925 version
= elem
.data
.integer
;
1930 case SNMP_VERSION_1
:
1931 case SNMP_VERSION_2
:
1932 community_print(ndo
, np
, length
, version
);
1934 case SNMP_VERSION_3
:
1935 v3msg_print(ndo
, np
, length
);
1938 ND_PRINT("[version = %d]", elem
.data
.integer
);
1942 if (ndo
->ndo_vflag
) {