1*05b00f60SXin Li /*
2*05b00f60SXin Li * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3*05b00f60SXin Li * John Robert LoVerso. All rights reserved.
4*05b00f60SXin Li *
5*05b00f60SXin Li * Redistribution and use in source and binary forms, with or without
6*05b00f60SXin Li * modification, are permitted provided that the following conditions
7*05b00f60SXin Li * are met:
8*05b00f60SXin Li *
9*05b00f60SXin Li * 1. Redistributions of source code must retain the above copyright
10*05b00f60SXin Li * notice, this list of conditions and the following disclaimer.
11*05b00f60SXin Li *
12*05b00f60SXin Li * 2. Redistributions in binary form must reproduce the above copyright
13*05b00f60SXin Li * notice, this list of conditions and the following disclaimer in the
14*05b00f60SXin Li * documentation and/or other materials provided with the distribution.
15*05b00f60SXin Li *
16*05b00f60SXin Li * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17*05b00f60SXin Li * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18*05b00f60SXin Li * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19*05b00f60SXin Li * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20*05b00f60SXin Li * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21*05b00f60SXin Li * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22*05b00f60SXin Li * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23*05b00f60SXin Li * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24*05b00f60SXin Li * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25*05b00f60SXin Li * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*05b00f60SXin Li *
27*05b00f60SXin Li *
28*05b00f60SXin Li * This implementation has been influenced by the CMU SNMP release,
29*05b00f60SXin Li * by Steve Waldbusser. However, this shares no code with that system.
30*05b00f60SXin Li * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_.
31*05b00f60SXin Li * Earlier forms of this implementation were derived and/or inspired by an
32*05b00f60SXin Li * awk script originally written by C. Philip Wood of LANL (but later
33*05b00f60SXin Li * heavily modified by John Robert LoVerso). The copyright notice for
34*05b00f60SXin Li * that work is preserved below, even though it may not rightly apply
35*05b00f60SXin Li * to this file.
36*05b00f60SXin Li *
37*05b00f60SXin Li * Support for SNMPv2c/SNMPv3 and the ability to link the module against
38*05b00f60SXin Li * the libsmi was added by J. Schoenwaelder, Copyright (c) 1999.
39*05b00f60SXin Li *
40*05b00f60SXin Li * This started out as a very simple program, but the incremental decoding
41*05b00f60SXin Li * (into the BE structure) complicated things.
42*05b00f60SXin Li *
43*05b00f60SXin Li # Los Alamos National Laboratory
44*05b00f60SXin Li #
45*05b00f60SXin Li # Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
46*05b00f60SXin Li # This software was produced under a U.S. Government contract
47*05b00f60SXin Li # (W-7405-ENG-36) by Los Alamos National Laboratory, which is
48*05b00f60SXin Li # operated by the University of California for the U.S. Department
49*05b00f60SXin Li # of Energy. The U.S. Government is licensed to use, reproduce,
50*05b00f60SXin Li # and distribute this software. Permission is granted to the
51*05b00f60SXin Li # public to copy and use this software without charge, provided
52*05b00f60SXin Li # that this Notice and any statement of authorship are reproduced
53*05b00f60SXin Li # on all copies. Neither the Government nor the University makes
54*05b00f60SXin Li # any warranty, express or implied, or assumes any liability or
55*05b00f60SXin Li # responsibility for the use of this software.
56*05b00f60SXin Li # @(#)snmp.awk.x 1.1 (LANL) 1/15/90
57*05b00f60SXin Li */
58*05b00f60SXin Li
59*05b00f60SXin Li /* \summary: Simple Network Management Protocol (SNMP) printer */
60*05b00f60SXin Li
61*05b00f60SXin Li #ifdef HAVE_CONFIG_H
62*05b00f60SXin Li #include <config.h>
63*05b00f60SXin Li #endif
64*05b00f60SXin Li
65*05b00f60SXin Li #include "netdissect-stdinc.h"
66*05b00f60SXin Li
67*05b00f60SXin Li #include <stdio.h>
68*05b00f60SXin Li #include <string.h>
69*05b00f60SXin Li
70*05b00f60SXin Li #ifdef USE_LIBSMI
71*05b00f60SXin Li #include <smi.h>
72*05b00f60SXin Li #endif
73*05b00f60SXin Li
74*05b00f60SXin Li #include "netdissect-ctype.h"
75*05b00f60SXin Li
76*05b00f60SXin Li #include "netdissect.h"
77*05b00f60SXin Li #include "extract.h"
78*05b00f60SXin Li
79*05b00f60SXin Li #undef OPAQUE /* defined in <wingdi.h> */
80*05b00f60SXin Li
81*05b00f60SXin Li
82*05b00f60SXin Li /*
83*05b00f60SXin Li * Universal ASN.1 types
84*05b00f60SXin Li * (we only care about the tag values for those allowed in the Internet SMI)
85*05b00f60SXin Li */
86*05b00f60SXin Li static const char *Universal[] = {
87*05b00f60SXin Li "U-0",
88*05b00f60SXin Li "Boolean",
89*05b00f60SXin Li "Integer",
90*05b00f60SXin Li #define INTEGER 2
91*05b00f60SXin Li "Bitstring",
92*05b00f60SXin Li "String",
93*05b00f60SXin Li #define STRING 4
94*05b00f60SXin Li "Null",
95*05b00f60SXin Li #define ASN_NULL 5
96*05b00f60SXin Li "ObjID",
97*05b00f60SXin Li #define OBJECTID 6
98*05b00f60SXin Li "ObjectDes",
99*05b00f60SXin Li "U-8","U-9","U-10","U-11", /* 8-11 */
100*05b00f60SXin Li "U-12","U-13","U-14","U-15", /* 12-15 */
101*05b00f60SXin Li "Sequence",
102*05b00f60SXin Li #define SEQUENCE 16
103*05b00f60SXin Li "Set"
104*05b00f60SXin Li };
105*05b00f60SXin Li
106*05b00f60SXin Li /*
107*05b00f60SXin Li * Application-wide ASN.1 types from the Internet SMI and their tags
108*05b00f60SXin Li */
109*05b00f60SXin Li static const char *Application[] = {
110*05b00f60SXin Li "IpAddress",
111*05b00f60SXin Li #define IPADDR 0
112*05b00f60SXin Li "Counter",
113*05b00f60SXin Li #define COUNTER 1
114*05b00f60SXin Li "Gauge",
115*05b00f60SXin Li #define GAUGE 2
116*05b00f60SXin Li "TimeTicks",
117*05b00f60SXin Li #define TIMETICKS 3
118*05b00f60SXin Li "Opaque",
119*05b00f60SXin Li #define OPAQUE 4
120*05b00f60SXin Li "C-5",
121*05b00f60SXin Li "Counter64"
122*05b00f60SXin Li #define COUNTER64 6
123*05b00f60SXin Li };
124*05b00f60SXin Li
125*05b00f60SXin Li /*
126*05b00f60SXin Li * Context-specific ASN.1 types for the SNMP PDUs and their tags
127*05b00f60SXin Li */
128*05b00f60SXin Li static const char *Context[] = {
129*05b00f60SXin Li "GetRequest",
130*05b00f60SXin Li #define GETREQ 0
131*05b00f60SXin Li "GetNextRequest",
132*05b00f60SXin Li #define GETNEXTREQ 1
133*05b00f60SXin Li "GetResponse",
134*05b00f60SXin Li #define GETRESP 2
135*05b00f60SXin Li "SetRequest",
136*05b00f60SXin Li #define SETREQ 3
137*05b00f60SXin Li "Trap",
138*05b00f60SXin Li #define TRAP 4
139*05b00f60SXin Li "GetBulk",
140*05b00f60SXin Li #define GETBULKREQ 5
141*05b00f60SXin Li "Inform",
142*05b00f60SXin Li #define INFORMREQ 6
143*05b00f60SXin Li "V2Trap",
144*05b00f60SXin Li #define V2TRAP 7
145*05b00f60SXin Li "Report"
146*05b00f60SXin Li #define REPORT 8
147*05b00f60SXin Li };
148*05b00f60SXin Li
149*05b00f60SXin Li #define NOTIFY_CLASS(x) (x == TRAP || x == V2TRAP || x == INFORMREQ)
150*05b00f60SXin Li #define READ_CLASS(x) (x == GETREQ || x == GETNEXTREQ || x == GETBULKREQ)
151*05b00f60SXin Li #define WRITE_CLASS(x) (x == SETREQ)
152*05b00f60SXin Li #define RESPONSE_CLASS(x) (x == GETRESP)
153*05b00f60SXin Li #define INTERNAL_CLASS(x) (x == REPORT)
154*05b00f60SXin Li
155*05b00f60SXin Li /*
156*05b00f60SXin Li * Context-specific ASN.1 types for the SNMP Exceptions and their tags
157*05b00f60SXin Li */
158*05b00f60SXin Li static const char *Exceptions[] = {
159*05b00f60SXin Li "noSuchObject",
160*05b00f60SXin Li #define NOSUCHOBJECT 0
161*05b00f60SXin Li "noSuchInstance",
162*05b00f60SXin Li #define NOSUCHINSTANCE 1
163*05b00f60SXin Li "endOfMibView",
164*05b00f60SXin Li #define ENDOFMIBVIEW 2
165*05b00f60SXin Li };
166*05b00f60SXin Li
167*05b00f60SXin Li /*
168*05b00f60SXin Li * Private ASN.1 types
169*05b00f60SXin Li * The Internet SMI does not specify any
170*05b00f60SXin Li */
171*05b00f60SXin Li static const char *Private[] = {
172*05b00f60SXin Li "P-0"
173*05b00f60SXin Li };
174*05b00f60SXin Li
175*05b00f60SXin Li /*
176*05b00f60SXin Li * error-status values for any SNMP PDU
177*05b00f60SXin Li */
178*05b00f60SXin Li static const char *ErrorStatus[] = {
179*05b00f60SXin Li "noError",
180*05b00f60SXin Li "tooBig",
181*05b00f60SXin Li "noSuchName",
182*05b00f60SXin Li "badValue",
183*05b00f60SXin Li "readOnly",
184*05b00f60SXin Li "genErr",
185*05b00f60SXin Li "noAccess",
186*05b00f60SXin Li "wrongType",
187*05b00f60SXin Li "wrongLength",
188*05b00f60SXin Li "wrongEncoding",
189*05b00f60SXin Li "wrongValue",
190*05b00f60SXin Li "noCreation",
191*05b00f60SXin Li "inconsistentValue",
192*05b00f60SXin Li "resourceUnavailable",
193*05b00f60SXin Li "commitFailed",
194*05b00f60SXin Li "undoFailed",
195*05b00f60SXin Li "authorizationError",
196*05b00f60SXin Li "notWritable",
197*05b00f60SXin Li "inconsistentName"
198*05b00f60SXin Li };
199*05b00f60SXin Li #define DECODE_ErrorStatus(e) \
200*05b00f60SXin Li ( e >= 0 && (size_t)e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
201*05b00f60SXin Li ? ErrorStatus[e] \
202*05b00f60SXin Li : (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf))
203*05b00f60SXin Li
204*05b00f60SXin Li /*
205*05b00f60SXin Li * generic-trap values in the SNMP Trap-PDU
206*05b00f60SXin Li */
207*05b00f60SXin Li static const char *GenericTrap[] = {
208*05b00f60SXin Li "coldStart",
209*05b00f60SXin Li "warmStart",
210*05b00f60SXin Li "linkDown",
211*05b00f60SXin Li "linkUp",
212*05b00f60SXin Li "authenticationFailure",
213*05b00f60SXin Li "egpNeighborLoss",
214*05b00f60SXin Li "enterpriseSpecific"
215*05b00f60SXin Li #define GT_ENTERPRISE 6
216*05b00f60SXin Li };
217*05b00f60SXin Li #define DECODE_GenericTrap(t) \
218*05b00f60SXin Li ( t >= 0 && (size_t)t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
219*05b00f60SXin Li ? GenericTrap[t] \
220*05b00f60SXin Li : (snprintf(buf, sizeof(buf), "gt=%d", t), buf))
221*05b00f60SXin Li
222*05b00f60SXin Li /*
223*05b00f60SXin Li * ASN.1 type class table
224*05b00f60SXin Li * Ties together the preceding Universal, Application, Context, and Private
225*05b00f60SXin Li * type definitions.
226*05b00f60SXin Li */
227*05b00f60SXin Li #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
228*05b00f60SXin Li static const struct {
229*05b00f60SXin Li const char *name;
230*05b00f60SXin Li const char **Id;
231*05b00f60SXin Li int numIDs;
232*05b00f60SXin Li } Class[] = {
233*05b00f60SXin Li defineCLASS(Universal),
234*05b00f60SXin Li #define UNIVERSAL 0
235*05b00f60SXin Li defineCLASS(Application),
236*05b00f60SXin Li #define APPLICATION 1
237*05b00f60SXin Li defineCLASS(Context),
238*05b00f60SXin Li #define CONTEXT 2
239*05b00f60SXin Li defineCLASS(Private),
240*05b00f60SXin Li #define PRIVATE 3
241*05b00f60SXin Li defineCLASS(Exceptions),
242*05b00f60SXin Li #define EXCEPTIONS 4
243*05b00f60SXin Li };
244*05b00f60SXin Li
245*05b00f60SXin Li /*
246*05b00f60SXin Li * defined forms for ASN.1 types
247*05b00f60SXin Li */
248*05b00f60SXin Li static const char *Form[] = {
249*05b00f60SXin Li "Primitive",
250*05b00f60SXin Li #define PRIMITIVE 0
251*05b00f60SXin Li "Constructed",
252*05b00f60SXin Li #define CONSTRUCTED 1
253*05b00f60SXin Li };
254*05b00f60SXin Li
255*05b00f60SXin Li /*
256*05b00f60SXin Li * A structure for the OID tree for the compiled-in MIB.
257*05b00f60SXin Li * This is stored as a general-order tree.
258*05b00f60SXin Li */
259*05b00f60SXin Li static struct obj {
260*05b00f60SXin Li const char *desc; /* name of object */
261*05b00f60SXin Li u_char oid; /* sub-id following parent */
262*05b00f60SXin Li u_char type; /* object type (unused) */
263*05b00f60SXin Li struct obj *child, *next; /* child and next sibling pointers */
264*05b00f60SXin Li } *objp = NULL;
265*05b00f60SXin Li
266*05b00f60SXin Li /*
267*05b00f60SXin Li * Include the compiled in SNMP MIB. "mib.h" is produced by feeding
268*05b00f60SXin Li * RFC-1156 format files into "makemib". "mib.h" MUST define at least
269*05b00f60SXin Li * a value for `mibroot'.
270*05b00f60SXin Li *
271*05b00f60SXin Li * In particular, this is gross, as this is including initialized structures,
272*05b00f60SXin Li * and by right shouldn't be an "include" file.
273*05b00f60SXin Li */
274*05b00f60SXin Li #include "mib.h"
275*05b00f60SXin Li
276*05b00f60SXin Li /*
277*05b00f60SXin Li * This defines a list of OIDs which will be abbreviated on output.
278*05b00f60SXin Li * Currently, this includes the prefixes for the Internet MIB, the
279*05b00f60SXin Li * private enterprises tree, and the experimental tree.
280*05b00f60SXin Li */
281*05b00f60SXin Li #define OID_FIRST_OCTET(x, y) (((x)*40) + (y)) /* X.690 8.19.4 */
282*05b00f60SXin Li
283*05b00f60SXin Li #ifndef NO_ABREV_MIB
284*05b00f60SXin Li static const uint8_t mib_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 2, 1 };
285*05b00f60SXin Li #endif
286*05b00f60SXin Li #ifndef NO_ABREV_ENTER
287*05b00f60SXin Li static const uint8_t enterprises_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 4, 1 };
288*05b00f60SXin Li #endif
289*05b00f60SXin Li #ifndef NO_ABREV_EXPERI
290*05b00f60SXin Li static const uint8_t experimental_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 3 };
291*05b00f60SXin Li #endif
292*05b00f60SXin Li #ifndef NO_ABBREV_SNMPMODS
293*05b00f60SXin Li static const uint8_t snmpModules_oid[] = { OID_FIRST_OCTET(1, 3), 6, 1, 6, 3 };
294*05b00f60SXin Li #endif
295*05b00f60SXin Li
296*05b00f60SXin Li #define OBJ_ABBREV_ENTRY(prefix, obj) \
297*05b00f60SXin Li { prefix, &_ ## obj ## _obj, obj ## _oid, sizeof (obj ## _oid) }
298*05b00f60SXin Li static const struct obj_abrev {
299*05b00f60SXin Li const char *prefix; /* prefix for this abrev */
300*05b00f60SXin Li struct obj *node; /* pointer into object table */
301*05b00f60SXin Li const uint8_t *oid; /* ASN.1 encoded OID */
302*05b00f60SXin Li size_t oid_len; /* length of OID */
303*05b00f60SXin Li } obj_abrev_list[] = {
304*05b00f60SXin Li #ifndef NO_ABREV_MIB
305*05b00f60SXin Li /* .iso.org.dod.internet.mgmt.mib */
306*05b00f60SXin Li OBJ_ABBREV_ENTRY("", mib),
307*05b00f60SXin Li #endif
308*05b00f60SXin Li #ifndef NO_ABREV_ENTER
309*05b00f60SXin Li /* .iso.org.dod.internet.private.enterprises */
310*05b00f60SXin Li OBJ_ABBREV_ENTRY("E:", enterprises),
311*05b00f60SXin Li #endif
312*05b00f60SXin Li #ifndef NO_ABREV_EXPERI
313*05b00f60SXin Li /* .iso.org.dod.internet.experimental */
314*05b00f60SXin Li OBJ_ABBREV_ENTRY("X:", experimental),
315*05b00f60SXin Li #endif
316*05b00f60SXin Li #ifndef NO_ABBREV_SNMPMODS
317*05b00f60SXin Li /* .iso.org.dod.internet.snmpV2.snmpModules */
318*05b00f60SXin Li OBJ_ABBREV_ENTRY("S:", snmpModules),
319*05b00f60SXin Li #endif
320*05b00f60SXin Li { 0,0,0,0 }
321*05b00f60SXin Li };
322*05b00f60SXin Li
323*05b00f60SXin Li /*
324*05b00f60SXin Li * This is used in the OID print routine to walk down the object tree
325*05b00f60SXin Li * rooted at `mibroot'.
326*05b00f60SXin Li */
327*05b00f60SXin Li #define OBJ_PRINT(o, suppressdot) \
328*05b00f60SXin Li { \
329*05b00f60SXin Li if (objp) { \
330*05b00f60SXin Li do { \
331*05b00f60SXin Li if ((o) == objp->oid) \
332*05b00f60SXin Li break; \
333*05b00f60SXin Li } while ((objp = objp->next) != NULL); \
334*05b00f60SXin Li } \
335*05b00f60SXin Li if (objp) { \
336*05b00f60SXin Li ND_PRINT(suppressdot?"%s":".%s", objp->desc); \
337*05b00f60SXin Li objp = objp->child; \
338*05b00f60SXin Li } else \
339*05b00f60SXin Li ND_PRINT(suppressdot?"%u":".%u", (o)); \
340*05b00f60SXin Li }
341*05b00f60SXin Li
342*05b00f60SXin Li /*
343*05b00f60SXin Li * This is the definition for the Any-Data-Type storage used purely for
344*05b00f60SXin Li * temporary internal representation while decoding an ASN.1 data stream.
345*05b00f60SXin Li */
346*05b00f60SXin Li struct be {
347*05b00f60SXin Li uint32_t asnlen;
348*05b00f60SXin Li union {
349*05b00f60SXin Li const uint8_t *raw;
350*05b00f60SXin Li int32_t integer;
351*05b00f60SXin Li uint32_t uns;
352*05b00f60SXin Li const u_char *str;
353*05b00f60SXin Li uint64_t uns64;
354*05b00f60SXin Li } data;
355*05b00f60SXin Li u_short id;
356*05b00f60SXin Li u_char form, class; /* tag info */
357*05b00f60SXin Li u_char type;
358*05b00f60SXin Li #define BE_ANY 255
359*05b00f60SXin Li #define BE_NONE 0
360*05b00f60SXin Li #define BE_NULL 1
361*05b00f60SXin Li #define BE_OCTET 2
362*05b00f60SXin Li #define BE_OID 3
363*05b00f60SXin Li #define BE_INT 4
364*05b00f60SXin Li #define BE_UNS 5
365*05b00f60SXin Li #define BE_STR 6
366*05b00f60SXin Li #define BE_SEQ 7
367*05b00f60SXin Li #define BE_INETADDR 8
368*05b00f60SXin Li #define BE_PDU 9
369*05b00f60SXin Li #define BE_UNS64 10
370*05b00f60SXin Li #define BE_NOSUCHOBJECT 128
371*05b00f60SXin Li #define BE_NOSUCHINST 129
372*05b00f60SXin Li #define BE_ENDOFMIBVIEW 130
373*05b00f60SXin Li };
374*05b00f60SXin Li
375*05b00f60SXin Li /*
376*05b00f60SXin Li * SNMP versions recognized by this module
377*05b00f60SXin Li */
378*05b00f60SXin Li static const char *SnmpVersion[] = {
379*05b00f60SXin Li "SNMPv1",
380*05b00f60SXin Li #define SNMP_VERSION_1 0
381*05b00f60SXin Li "SNMPv2c",
382*05b00f60SXin Li #define SNMP_VERSION_2 1
383*05b00f60SXin Li "SNMPv2u",
384*05b00f60SXin Li #define SNMP_VERSION_2U 2
385*05b00f60SXin Li "SNMPv3"
386*05b00f60SXin Li #define SNMP_VERSION_3 3
387*05b00f60SXin Li };
388*05b00f60SXin Li
389*05b00f60SXin Li /*
390*05b00f60SXin Li * Defaults for SNMP PDU components
391*05b00f60SXin Li */
392*05b00f60SXin Li #define DEF_COMMUNITY "public"
393*05b00f60SXin Li
394*05b00f60SXin Li /*
395*05b00f60SXin Li * constants for ASN.1 decoding
396*05b00f60SXin Li */
397*05b00f60SXin Li #define OIDMUX 40
398*05b00f60SXin Li #define ASNLEN_INETADDR 4
399*05b00f60SXin Li #define ASN_SHIFT7 7
400*05b00f60SXin Li #define ASN_SHIFT8 8
401*05b00f60SXin Li #define ASN_BIT8 0x80
402*05b00f60SXin Li #define ASN_LONGLEN 0x80
403*05b00f60SXin Li
404*05b00f60SXin Li #define ASN_ID_BITS 0x1f
405*05b00f60SXin Li #define ASN_FORM_BITS 0x20
406*05b00f60SXin Li #define ASN_FORM_SHIFT 5
407*05b00f60SXin Li #define ASN_CLASS_BITS 0xc0
408*05b00f60SXin Li #define ASN_CLASS_SHIFT 6
409*05b00f60SXin Li
410*05b00f60SXin Li #define ASN_ID_EXT 0x1f /* extension ID in tag field */
411*05b00f60SXin Li
412*05b00f60SXin Li /*
413*05b00f60SXin Li * This decodes the next ASN.1 object in the stream pointed to by "p"
414*05b00f60SXin Li * (and of real-length "len") and stores the intermediate data in the
415*05b00f60SXin Li * provided BE object.
416*05b00f60SXin Li *
417*05b00f60SXin Li * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
418*05b00f60SXin Li * O/w, this returns the number of bytes parsed from "p".
419*05b00f60SXin Li */
420*05b00f60SXin Li static int
asn1_parse(netdissect_options * ndo,const u_char * p,u_int len,struct be * elem)421*05b00f60SXin Li asn1_parse(netdissect_options *ndo,
422*05b00f60SXin Li const u_char *p, u_int len, struct be *elem)
423*05b00f60SXin Li {
424*05b00f60SXin Li u_char form, class, id;
425*05b00f60SXin Li u_int i, hdr;
426*05b00f60SXin Li
427*05b00f60SXin Li elem->asnlen = 0;
428*05b00f60SXin Li elem->type = BE_ANY;
429*05b00f60SXin Li if (len < 1) {
430*05b00f60SXin Li ND_PRINT("[nothing to parse]");
431*05b00f60SXin Li return -1;
432*05b00f60SXin Li }
433*05b00f60SXin Li
434*05b00f60SXin Li /*
435*05b00f60SXin Li * it would be nice to use a bit field, but you can't depend on them.
436*05b00f60SXin Li * +---+---+---+---+---+---+---+---+
437*05b00f60SXin Li * + class |frm| id |
438*05b00f60SXin Li * +---+---+---+---+---+---+---+---+
439*05b00f60SXin Li * 7 6 5 4 3 2 1 0
440*05b00f60SXin Li */
441*05b00f60SXin Li id = GET_U_1(p) & ASN_ID_BITS; /* lower 5 bits, range 00-1f */
442*05b00f60SXin Li #ifdef notdef
443*05b00f60SXin Li form = (GET_U_1(p) & 0xe0) >> 5; /* move upper 3 bits to lower 3 */
444*05b00f60SXin Li class = form >> 1; /* bits 7&6 -> bits 1&0, range 0-3 */
445*05b00f60SXin Li form &= 0x1; /* bit 5 -> bit 0, range 0-1 */
446*05b00f60SXin Li #else
447*05b00f60SXin Li form = (u_char)(GET_U_1(p) & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
448*05b00f60SXin Li class = (u_char)(GET_U_1(p) & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
449*05b00f60SXin Li #endif
450*05b00f60SXin Li elem->form = form;
451*05b00f60SXin Li elem->class = class;
452*05b00f60SXin Li elem->id = id;
453*05b00f60SXin Li p++; len--; hdr = 1;
454*05b00f60SXin Li /* extended tag field */
455*05b00f60SXin Li if (id == ASN_ID_EXT) {
456*05b00f60SXin Li /*
457*05b00f60SXin Li * The ID follows, as a sequence of octets with the
458*05b00f60SXin Li * 8th bit set and the remaining 7 bits being
459*05b00f60SXin Li * the next 7 bits of the value, terminated with
460*05b00f60SXin Li * an octet with the 8th bit not set.
461*05b00f60SXin Li *
462*05b00f60SXin Li * First, assemble all the octets with the 8th
463*05b00f60SXin Li * bit set. XXX - this doesn't handle a value
464*05b00f60SXin Li * that won't fit in 32 bits.
465*05b00f60SXin Li */
466*05b00f60SXin Li id = 0;
467*05b00f60SXin Li while (GET_U_1(p) & ASN_BIT8) {
468*05b00f60SXin Li if (len < 1) {
469*05b00f60SXin Li ND_PRINT("[Xtagfield?]");
470*05b00f60SXin Li return -1;
471*05b00f60SXin Li }
472*05b00f60SXin Li id = (id << 7) | (GET_U_1(p) & ~ASN_BIT8);
473*05b00f60SXin Li len--;
474*05b00f60SXin Li hdr++;
475*05b00f60SXin Li p++;
476*05b00f60SXin Li }
477*05b00f60SXin Li if (len < 1) {
478*05b00f60SXin Li ND_PRINT("[Xtagfield?]");
479*05b00f60SXin Li return -1;
480*05b00f60SXin Li }
481*05b00f60SXin Li elem->id = id = (id << 7) | GET_U_1(p);
482*05b00f60SXin Li --len;
483*05b00f60SXin Li ++hdr;
484*05b00f60SXin Li ++p;
485*05b00f60SXin Li }
486*05b00f60SXin Li if (len < 1) {
487*05b00f60SXin Li ND_PRINT("[no asnlen]");
488*05b00f60SXin Li return -1;
489*05b00f60SXin Li }
490*05b00f60SXin Li elem->asnlen = GET_U_1(p);
491*05b00f60SXin Li p++; len--; hdr++;
492*05b00f60SXin Li if (elem->asnlen & ASN_BIT8) {
493*05b00f60SXin Li uint32_t noct = elem->asnlen % ASN_BIT8;
494*05b00f60SXin Li elem->asnlen = 0;
495*05b00f60SXin Li if (len < noct) {
496*05b00f60SXin Li ND_PRINT("[asnlen? %d<%d]", len, noct);
497*05b00f60SXin Li return -1;
498*05b00f60SXin Li }
499*05b00f60SXin Li ND_TCHECK_LEN(p, noct);
500*05b00f60SXin Li for (; noct != 0; len--, hdr++, noct--) {
501*05b00f60SXin Li elem->asnlen = (elem->asnlen << ASN_SHIFT8) | GET_U_1(p);
502*05b00f60SXin Li p++;
503*05b00f60SXin Li }
504*05b00f60SXin Li }
505*05b00f60SXin Li if (len < elem->asnlen) {
506*05b00f60SXin Li ND_PRINT("[len%d<asnlen%u]", len, elem->asnlen);
507*05b00f60SXin Li return -1;
508*05b00f60SXin Li }
509*05b00f60SXin Li if (form >= sizeof(Form)/sizeof(Form[0])) {
510*05b00f60SXin Li ND_PRINT("[form?%d]", form);
511*05b00f60SXin Li return -1;
512*05b00f60SXin Li }
513*05b00f60SXin Li if (class >= sizeof(Class)/sizeof(Class[0])) {
514*05b00f60SXin Li ND_PRINT("[class?%c/%d]", *Form[form], class);
515*05b00f60SXin Li return -1;
516*05b00f60SXin Li }
517*05b00f60SXin Li if ((int)id >= Class[class].numIDs) {
518*05b00f60SXin Li ND_PRINT("[id?%c/%s/%d]", *Form[form], Class[class].name, id);
519*05b00f60SXin Li return -1;
520*05b00f60SXin Li }
521*05b00f60SXin Li ND_TCHECK_LEN(p, elem->asnlen);
522*05b00f60SXin Li
523*05b00f60SXin Li switch (form) {
524*05b00f60SXin Li case PRIMITIVE:
525*05b00f60SXin Li switch (class) {
526*05b00f60SXin Li case UNIVERSAL:
527*05b00f60SXin Li switch (id) {
528*05b00f60SXin Li case STRING:
529*05b00f60SXin Li elem->type = BE_STR;
530*05b00f60SXin Li elem->data.str = p;
531*05b00f60SXin Li break;
532*05b00f60SXin Li
533*05b00f60SXin Li case INTEGER: {
534*05b00f60SXin Li int32_t data;
535*05b00f60SXin Li elem->type = BE_INT;
536*05b00f60SXin Li data = 0;
537*05b00f60SXin Li
538*05b00f60SXin Li if (elem->asnlen == 0) {
539*05b00f60SXin Li ND_PRINT("[asnlen=0]");
540*05b00f60SXin Li return -1;
541*05b00f60SXin Li }
542*05b00f60SXin Li if (GET_U_1(p) & ASN_BIT8) /* negative */
543*05b00f60SXin Li data = -1;
544*05b00f60SXin Li for (i = elem->asnlen; i != 0; p++, i--)
545*05b00f60SXin Li data = (data << ASN_SHIFT8) | GET_U_1(p);
546*05b00f60SXin Li elem->data.integer = data;
547*05b00f60SXin Li break;
548*05b00f60SXin Li }
549*05b00f60SXin Li
550*05b00f60SXin Li case OBJECTID:
551*05b00f60SXin Li elem->type = BE_OID;
552*05b00f60SXin Li elem->data.raw = (const uint8_t *)p;
553*05b00f60SXin Li break;
554*05b00f60SXin Li
555*05b00f60SXin Li case ASN_NULL:
556*05b00f60SXin Li elem->type = BE_NULL;
557*05b00f60SXin Li elem->data.raw = NULL;
558*05b00f60SXin Li break;
559*05b00f60SXin Li
560*05b00f60SXin Li default:
561*05b00f60SXin Li elem->type = BE_OCTET;
562*05b00f60SXin Li elem->data.raw = (const uint8_t *)p;
563*05b00f60SXin Li ND_PRINT("[P/U/%s]", Class[class].Id[id]);
564*05b00f60SXin Li break;
565*05b00f60SXin Li }
566*05b00f60SXin Li break;
567*05b00f60SXin Li
568*05b00f60SXin Li case APPLICATION:
569*05b00f60SXin Li switch (id) {
570*05b00f60SXin Li case IPADDR:
571*05b00f60SXin Li elem->type = BE_INETADDR;
572*05b00f60SXin Li elem->data.raw = (const uint8_t *)p;
573*05b00f60SXin Li break;
574*05b00f60SXin Li
575*05b00f60SXin Li case COUNTER:
576*05b00f60SXin Li case GAUGE:
577*05b00f60SXin Li case TIMETICKS: {
578*05b00f60SXin Li uint32_t data;
579*05b00f60SXin Li elem->type = BE_UNS;
580*05b00f60SXin Li data = 0;
581*05b00f60SXin Li for (i = elem->asnlen; i != 0; p++, i--)
582*05b00f60SXin Li data = (data << 8) + GET_U_1(p);
583*05b00f60SXin Li elem->data.uns = data;
584*05b00f60SXin Li break;
585*05b00f60SXin Li }
586*05b00f60SXin Li
587*05b00f60SXin Li case COUNTER64: {
588*05b00f60SXin Li uint64_t data64;
589*05b00f60SXin Li elem->type = BE_UNS64;
590*05b00f60SXin Li data64 = 0;
591*05b00f60SXin Li for (i = elem->asnlen; i != 0; p++, i--)
592*05b00f60SXin Li data64 = (data64 << 8) + GET_U_1(p);
593*05b00f60SXin Li elem->data.uns64 = data64;
594*05b00f60SXin Li break;
595*05b00f60SXin Li }
596*05b00f60SXin Li
597*05b00f60SXin Li default:
598*05b00f60SXin Li elem->type = BE_OCTET;
599*05b00f60SXin Li elem->data.raw = (const uint8_t *)p;
600*05b00f60SXin Li ND_PRINT("[P/A/%s]",
601*05b00f60SXin Li Class[class].Id[id]);
602*05b00f60SXin Li break;
603*05b00f60SXin Li }
604*05b00f60SXin Li break;
605*05b00f60SXin Li
606*05b00f60SXin Li case CONTEXT:
607*05b00f60SXin Li switch (id) {
608*05b00f60SXin Li case NOSUCHOBJECT:
609*05b00f60SXin Li elem->type = BE_NOSUCHOBJECT;
610*05b00f60SXin Li elem->data.raw = NULL;
611*05b00f60SXin Li break;
612*05b00f60SXin Li
613*05b00f60SXin Li case NOSUCHINSTANCE:
614*05b00f60SXin Li elem->type = BE_NOSUCHINST;
615*05b00f60SXin Li elem->data.raw = NULL;
616*05b00f60SXin Li break;
617*05b00f60SXin Li
618*05b00f60SXin Li case ENDOFMIBVIEW:
619*05b00f60SXin Li elem->type = BE_ENDOFMIBVIEW;
620*05b00f60SXin Li elem->data.raw = NULL;
621*05b00f60SXin Li break;
622*05b00f60SXin Li }
623*05b00f60SXin Li break;
624*05b00f60SXin Li
625*05b00f60SXin Li default:
626*05b00f60SXin Li ND_PRINT("[P/%s/%s]", Class[class].name, Class[class].Id[id]);
627*05b00f60SXin Li elem->type = BE_OCTET;
628*05b00f60SXin Li elem->data.raw = (const uint8_t *)p;
629*05b00f60SXin Li break;
630*05b00f60SXin Li }
631*05b00f60SXin Li break;
632*05b00f60SXin Li
633*05b00f60SXin Li case CONSTRUCTED:
634*05b00f60SXin Li switch (class) {
635*05b00f60SXin Li case UNIVERSAL:
636*05b00f60SXin Li switch (id) {
637*05b00f60SXin Li case SEQUENCE:
638*05b00f60SXin Li elem->type = BE_SEQ;
639*05b00f60SXin Li elem->data.raw = (const uint8_t *)p;
640*05b00f60SXin Li break;
641*05b00f60SXin Li
642*05b00f60SXin Li default:
643*05b00f60SXin Li elem->type = BE_OCTET;
644*05b00f60SXin Li elem->data.raw = (const uint8_t *)p;
645*05b00f60SXin Li ND_PRINT("C/U/%s", Class[class].Id[id]);
646*05b00f60SXin Li break;
647*05b00f60SXin Li }
648*05b00f60SXin Li break;
649*05b00f60SXin Li
650*05b00f60SXin Li case CONTEXT:
651*05b00f60SXin Li elem->type = BE_PDU;
652*05b00f60SXin Li elem->data.raw = (const uint8_t *)p;
653*05b00f60SXin Li break;
654*05b00f60SXin Li
655*05b00f60SXin Li default:
656*05b00f60SXin Li elem->type = BE_OCTET;
657*05b00f60SXin Li elem->data.raw = (const uint8_t *)p;
658*05b00f60SXin Li ND_PRINT("C/%s/%s", Class[class].name, Class[class].Id[id]);
659*05b00f60SXin Li break;
660*05b00f60SXin Li }
661*05b00f60SXin Li break;
662*05b00f60SXin Li }
663*05b00f60SXin Li p += elem->asnlen;
664*05b00f60SXin Li len -= elem->asnlen;
665*05b00f60SXin Li return elem->asnlen + hdr;
666*05b00f60SXin Li
667*05b00f60SXin Li trunc:
668*05b00f60SXin Li nd_print_trunc(ndo);
669*05b00f60SXin Li return -1;
670*05b00f60SXin Li }
671*05b00f60SXin Li
672*05b00f60SXin Li static int
asn1_print_octets(netdissect_options * ndo,struct be * elem)673*05b00f60SXin Li asn1_print_octets(netdissect_options *ndo, struct be *elem)
674*05b00f60SXin Li {
675*05b00f60SXin Li const u_char *p = (const u_char *)elem->data.raw;
676*05b00f60SXin Li uint32_t asnlen = elem->asnlen;
677*05b00f60SXin Li uint32_t i;
678*05b00f60SXin Li
679*05b00f60SXin Li ND_TCHECK_LEN(p, asnlen);
680*05b00f60SXin Li for (i = asnlen; i != 0; p++, i--)
681*05b00f60SXin Li ND_PRINT("_%.2x", GET_U_1(p));
682*05b00f60SXin Li return 0;
683*05b00f60SXin Li
684*05b00f60SXin Li trunc:
685*05b00f60SXin Li nd_print_trunc(ndo);
686*05b00f60SXin Li return -1;
687*05b00f60SXin Li }
688*05b00f60SXin Li
689*05b00f60SXin Li static int
asn1_print_string(netdissect_options * ndo,struct be * elem)690*05b00f60SXin Li asn1_print_string(netdissect_options *ndo, struct be *elem)
691*05b00f60SXin Li {
692*05b00f60SXin Li int printable = 1, first = 1;
693*05b00f60SXin Li const u_char *p;
694*05b00f60SXin Li uint32_t asnlen = elem->asnlen;
695*05b00f60SXin Li uint32_t i;
696*05b00f60SXin Li
697*05b00f60SXin Li p = elem->data.str;
698*05b00f60SXin Li ND_TCHECK_LEN(p, asnlen);
699*05b00f60SXin Li for (i = asnlen; printable && i != 0; p++, i--)
700*05b00f60SXin Li printable = ND_ASCII_ISPRINT(GET_U_1(p));
701*05b00f60SXin Li p = elem->data.str;
702*05b00f60SXin Li if (printable) {
703*05b00f60SXin Li ND_PRINT("\"");
704*05b00f60SXin Li if (nd_printn(ndo, p, asnlen, ndo->ndo_snapend)) {
705*05b00f60SXin Li ND_PRINT("\"");
706*05b00f60SXin Li goto trunc;
707*05b00f60SXin Li }
708*05b00f60SXin Li ND_PRINT("\"");
709*05b00f60SXin Li } else {
710*05b00f60SXin Li for (i = asnlen; i != 0; p++, i--) {
711*05b00f60SXin Li ND_PRINT(first ? "%.2x" : "_%.2x", GET_U_1(p));
712*05b00f60SXin Li first = 0;
713*05b00f60SXin Li }
714*05b00f60SXin Li }
715*05b00f60SXin Li return 0;
716*05b00f60SXin Li
717*05b00f60SXin Li trunc:
718*05b00f60SXin Li nd_print_trunc(ndo);
719*05b00f60SXin Li return -1;
720*05b00f60SXin Li }
721*05b00f60SXin Li
722*05b00f60SXin Li /*
723*05b00f60SXin Li * Display the ASN.1 object represented by the BE object.
724*05b00f60SXin Li * This used to be an integral part of asn1_parse() before the intermediate
725*05b00f60SXin Li * BE form was added.
726*05b00f60SXin Li */
727*05b00f60SXin Li static int
asn1_print(netdissect_options * ndo,struct be * elem)728*05b00f60SXin Li asn1_print(netdissect_options *ndo,
729*05b00f60SXin Li struct be *elem)
730*05b00f60SXin Li {
731*05b00f60SXin Li const u_char *p;
732*05b00f60SXin Li uint32_t asnlen = elem->asnlen;
733*05b00f60SXin Li uint32_t i;
734*05b00f60SXin Li
735*05b00f60SXin Li switch (elem->type) {
736*05b00f60SXin Li
737*05b00f60SXin Li case BE_OCTET:
738*05b00f60SXin Li if (asn1_print_octets(ndo, elem) == -1)
739*05b00f60SXin Li return -1;
740*05b00f60SXin Li break;
741*05b00f60SXin Li
742*05b00f60SXin Li case BE_NULL:
743*05b00f60SXin Li break;
744*05b00f60SXin Li
745*05b00f60SXin Li case BE_OID: {
746*05b00f60SXin Li int o = 0, first = -1;
747*05b00f60SXin Li
748*05b00f60SXin Li p = (const u_char *)elem->data.raw;
749*05b00f60SXin Li i = asnlen;
750*05b00f60SXin Li if (!ndo->ndo_nflag && asnlen > 2) {
751*05b00f60SXin Li const struct obj_abrev *a = &obj_abrev_list[0];
752*05b00f60SXin Li for (; a->node; a++) {
753*05b00f60SXin Li if (i < a->oid_len)
754*05b00f60SXin Li continue;
755*05b00f60SXin Li if (!ND_TTEST_LEN(p, a->oid_len))
756*05b00f60SXin Li continue;
757*05b00f60SXin Li if (memcmp(a->oid, p, a->oid_len) == 0) {
758*05b00f60SXin Li objp = a->node->child;
759*05b00f60SXin Li i -= a->oid_len;
760*05b00f60SXin Li p += a->oid_len;
761*05b00f60SXin Li ND_PRINT("%s", a->prefix);
762*05b00f60SXin Li first = 1;
763*05b00f60SXin Li break;
764*05b00f60SXin Li }
765*05b00f60SXin Li }
766*05b00f60SXin Li }
767*05b00f60SXin Li
768*05b00f60SXin Li for (; i != 0; p++, i--) {
769*05b00f60SXin Li o = (o << ASN_SHIFT7) + (GET_U_1(p) & ~ASN_BIT8);
770*05b00f60SXin Li if (GET_U_1(p) & ASN_LONGLEN)
771*05b00f60SXin Li continue;
772*05b00f60SXin Li
773*05b00f60SXin Li /*
774*05b00f60SXin Li * first subitem encodes two items with
775*05b00f60SXin Li * 1st*OIDMUX+2nd
776*05b00f60SXin Li * (see X.690:1997 clause 8.19 for the details)
777*05b00f60SXin Li */
778*05b00f60SXin Li if (first < 0) {
779*05b00f60SXin Li int s;
780*05b00f60SXin Li if (!ndo->ndo_nflag)
781*05b00f60SXin Li objp = mibroot;
782*05b00f60SXin Li first = 0;
783*05b00f60SXin Li s = o / OIDMUX;
784*05b00f60SXin Li if (s > 2) s = 2;
785*05b00f60SXin Li OBJ_PRINT(s, first);
786*05b00f60SXin Li o -= s * OIDMUX;
787*05b00f60SXin Li }
788*05b00f60SXin Li OBJ_PRINT(o, first);
789*05b00f60SXin Li if (--first < 0)
790*05b00f60SXin Li first = 0;
791*05b00f60SXin Li o = 0;
792*05b00f60SXin Li }
793*05b00f60SXin Li break;
794*05b00f60SXin Li }
795*05b00f60SXin Li
796*05b00f60SXin Li case BE_INT:
797*05b00f60SXin Li ND_PRINT("%d", elem->data.integer);
798*05b00f60SXin Li break;
799*05b00f60SXin Li
800*05b00f60SXin Li case BE_UNS:
801*05b00f60SXin Li ND_PRINT("%u", elem->data.uns);
802*05b00f60SXin Li break;
803*05b00f60SXin Li
804*05b00f60SXin Li case BE_UNS64:
805*05b00f60SXin Li ND_PRINT("%" PRIu64, elem->data.uns64);
806*05b00f60SXin Li break;
807*05b00f60SXin Li
808*05b00f60SXin Li case BE_STR:
809*05b00f60SXin Li if (asn1_print_string(ndo, elem) == -1)
810*05b00f60SXin Li return -1;
811*05b00f60SXin Li break;
812*05b00f60SXin Li
813*05b00f60SXin Li case BE_SEQ:
814*05b00f60SXin Li ND_PRINT("Seq(%u)", elem->asnlen);
815*05b00f60SXin Li break;
816*05b00f60SXin Li
817*05b00f60SXin Li case BE_INETADDR:
818*05b00f60SXin Li if (asnlen != ASNLEN_INETADDR)
819*05b00f60SXin Li ND_PRINT("[inetaddr len!=%d]", ASNLEN_INETADDR);
820*05b00f60SXin Li p = (const u_char *)elem->data.raw;
821*05b00f60SXin Li ND_TCHECK_LEN(p, asnlen);
822*05b00f60SXin Li for (i = asnlen; i != 0; p++, i--) {
823*05b00f60SXin Li ND_PRINT((i == asnlen) ? "%u" : ".%u", GET_U_1(p));
824*05b00f60SXin Li }
825*05b00f60SXin Li break;
826*05b00f60SXin Li
827*05b00f60SXin Li case BE_NOSUCHOBJECT:
828*05b00f60SXin Li case BE_NOSUCHINST:
829*05b00f60SXin Li case BE_ENDOFMIBVIEW:
830*05b00f60SXin Li ND_PRINT("[%s]", Class[EXCEPTIONS].Id[elem->id]);
831*05b00f60SXin Li break;
832*05b00f60SXin Li
833*05b00f60SXin Li case BE_PDU:
834*05b00f60SXin Li ND_PRINT("%s(%u)", Class[CONTEXT].Id[elem->id], elem->asnlen);
835*05b00f60SXin Li break;
836*05b00f60SXin Li
837*05b00f60SXin Li case BE_ANY:
838*05b00f60SXin Li ND_PRINT("[BE_ANY!?]");
839*05b00f60SXin Li break;
840*05b00f60SXin Li
841*05b00f60SXin Li default:
842*05b00f60SXin Li ND_PRINT("[be!?]");
843*05b00f60SXin Li break;
844*05b00f60SXin Li }
845*05b00f60SXin Li return 0;
846*05b00f60SXin Li
847*05b00f60SXin Li trunc:
848*05b00f60SXin Li nd_print_trunc(ndo);
849*05b00f60SXin Li return -1;
850*05b00f60SXin Li }
851*05b00f60SXin Li
852*05b00f60SXin Li #ifdef notdef
853*05b00f60SXin Li /*
854*05b00f60SXin Li * This is a brute force ASN.1 printer: recurses to dump an entire structure.
855*05b00f60SXin Li * This will work for any ASN.1 stream, not just an SNMP PDU.
856*05b00f60SXin Li *
857*05b00f60SXin Li * By adding newlines and spaces at the correct places, this would print in
858*05b00f60SXin Li * Rose-Normal-Form.
859*05b00f60SXin Li *
860*05b00f60SXin Li * This is not currently used.
861*05b00f60SXin Li */
862*05b00f60SXin Li static void
asn1_decode(u_char * p,u_int length)863*05b00f60SXin Li asn1_decode(u_char *p, u_int length)
864*05b00f60SXin Li {
865*05b00f60SXin Li struct be elem;
866*05b00f60SXin Li int i = 0;
867*05b00f60SXin Li
868*05b00f60SXin Li while (i >= 0 && length > 0) {
869*05b00f60SXin Li i = asn1_parse(ndo, p, length, &elem);
870*05b00f60SXin Li if (i >= 0) {
871*05b00f60SXin Li ND_PRINT(" ");
872*05b00f60SXin Li if (asn1_print(ndo, &elem) < 0)
873*05b00f60SXin Li return;
874*05b00f60SXin Li if (elem.type == BE_SEQ || elem.type == BE_PDU) {
875*05b00f60SXin Li ND_PRINT(" {");
876*05b00f60SXin Li asn1_decode(elem.data.raw, elem.asnlen);
877*05b00f60SXin Li ND_PRINT(" }");
878*05b00f60SXin Li }
879*05b00f60SXin Li length -= i;
880*05b00f60SXin Li p += i;
881*05b00f60SXin Li }
882*05b00f60SXin Li }
883*05b00f60SXin Li }
884*05b00f60SXin Li #endif
885*05b00f60SXin Li
886*05b00f60SXin Li #ifdef USE_LIBSMI
887*05b00f60SXin Li
888*05b00f60SXin Li struct smi2be {
889*05b00f60SXin Li SmiBasetype basetype;
890*05b00f60SXin Li int be;
891*05b00f60SXin Li };
892*05b00f60SXin Li
893*05b00f60SXin Li static const struct smi2be smi2betab[] = {
894*05b00f60SXin Li { SMI_BASETYPE_INTEGER32, BE_INT },
895*05b00f60SXin Li { SMI_BASETYPE_OCTETSTRING, BE_STR },
896*05b00f60SXin Li { SMI_BASETYPE_OCTETSTRING, BE_INETADDR },
897*05b00f60SXin Li { SMI_BASETYPE_OBJECTIDENTIFIER, BE_OID },
898*05b00f60SXin Li { SMI_BASETYPE_UNSIGNED32, BE_UNS },
899*05b00f60SXin Li { SMI_BASETYPE_INTEGER64, BE_NONE },
900*05b00f60SXin Li { SMI_BASETYPE_UNSIGNED64, BE_UNS64 },
901*05b00f60SXin Li { SMI_BASETYPE_FLOAT32, BE_NONE },
902*05b00f60SXin Li { SMI_BASETYPE_FLOAT64, BE_NONE },
903*05b00f60SXin Li { SMI_BASETYPE_FLOAT128, BE_NONE },
904*05b00f60SXin Li { SMI_BASETYPE_ENUM, BE_INT },
905*05b00f60SXin Li { SMI_BASETYPE_BITS, BE_STR },
906*05b00f60SXin Li { SMI_BASETYPE_UNKNOWN, BE_NONE }
907*05b00f60SXin Li };
908*05b00f60SXin Li
909*05b00f60SXin Li static int
smi_decode_oid(netdissect_options * ndo,struct be * elem,unsigned int * oid,unsigned int oidsize,unsigned int * oidlen)910*05b00f60SXin Li smi_decode_oid(netdissect_options *ndo,
911*05b00f60SXin Li struct be *elem, unsigned int *oid,
912*05b00f60SXin Li unsigned int oidsize, unsigned int *oidlen)
913*05b00f60SXin Li {
914*05b00f60SXin Li const u_char *p = (const u_char *)elem->data.raw;
915*05b00f60SXin Li uint32_t asnlen = elem->asnlen;
916*05b00f60SXin Li uint32_t i = asnlen;
917*05b00f60SXin Li int o = 0, first = -1;
918*05b00f60SXin Li unsigned int firstval;
919*05b00f60SXin Li
920*05b00f60SXin Li for (*oidlen = 0; i != 0; p++, i--) {
921*05b00f60SXin Li o = (o << ASN_SHIFT7) + (GET_U_1(p) & ~ASN_BIT8);
922*05b00f60SXin Li if (GET_U_1(p) & ASN_LONGLEN)
923*05b00f60SXin Li continue;
924*05b00f60SXin Li
925*05b00f60SXin Li /*
926*05b00f60SXin Li * first subitem encodes two items with 1st*OIDMUX+2nd
927*05b00f60SXin Li * (see X.690:1997 clause 8.19 for the details)
928*05b00f60SXin Li */
929*05b00f60SXin Li if (first < 0) {
930*05b00f60SXin Li first = 0;
931*05b00f60SXin Li firstval = o / OIDMUX;
932*05b00f60SXin Li if (firstval > 2) firstval = 2;
933*05b00f60SXin Li o -= firstval * OIDMUX;
934*05b00f60SXin Li if (*oidlen < oidsize) {
935*05b00f60SXin Li oid[(*oidlen)++] = firstval;
936*05b00f60SXin Li }
937*05b00f60SXin Li }
938*05b00f60SXin Li if (*oidlen < oidsize) {
939*05b00f60SXin Li oid[(*oidlen)++] = o;
940*05b00f60SXin Li }
941*05b00f60SXin Li o = 0;
942*05b00f60SXin Li }
943*05b00f60SXin Li return 0;
944*05b00f60SXin Li }
945*05b00f60SXin Li
smi_check_type(SmiBasetype basetype,int be)946*05b00f60SXin Li static int smi_check_type(SmiBasetype basetype, int be)
947*05b00f60SXin Li {
948*05b00f60SXin Li int i;
949*05b00f60SXin Li
950*05b00f60SXin Li for (i = 0; smi2betab[i].basetype != SMI_BASETYPE_UNKNOWN; i++) {
951*05b00f60SXin Li if (smi2betab[i].basetype == basetype && smi2betab[i].be == be) {
952*05b00f60SXin Li return 1;
953*05b00f60SXin Li }
954*05b00f60SXin Li }
955*05b00f60SXin Li
956*05b00f60SXin Li return 0;
957*05b00f60SXin Li }
958*05b00f60SXin Li
smi_check_a_range(SmiType * smiType,SmiRange * smiRange,struct be * elem)959*05b00f60SXin Li static int smi_check_a_range(SmiType *smiType, SmiRange *smiRange,
960*05b00f60SXin Li struct be *elem)
961*05b00f60SXin Li {
962*05b00f60SXin Li int ok = 1;
963*05b00f60SXin Li
964*05b00f60SXin Li switch (smiType->basetype) {
965*05b00f60SXin Li case SMI_BASETYPE_OBJECTIDENTIFIER:
966*05b00f60SXin Li case SMI_BASETYPE_OCTETSTRING:
967*05b00f60SXin Li if (smiRange->minValue.value.unsigned32
968*05b00f60SXin Li == smiRange->maxValue.value.unsigned32) {
969*05b00f60SXin Li ok = (elem->asnlen == smiRange->minValue.value.unsigned32);
970*05b00f60SXin Li } else {
971*05b00f60SXin Li ok = (elem->asnlen >= smiRange->minValue.value.unsigned32
972*05b00f60SXin Li && elem->asnlen <= smiRange->maxValue.value.unsigned32);
973*05b00f60SXin Li }
974*05b00f60SXin Li break;
975*05b00f60SXin Li
976*05b00f60SXin Li case SMI_BASETYPE_INTEGER32:
977*05b00f60SXin Li ok = (elem->data.integer >= smiRange->minValue.value.integer32
978*05b00f60SXin Li && elem->data.integer <= smiRange->maxValue.value.integer32);
979*05b00f60SXin Li break;
980*05b00f60SXin Li
981*05b00f60SXin Li case SMI_BASETYPE_UNSIGNED32:
982*05b00f60SXin Li ok = (elem->data.uns >= smiRange->minValue.value.unsigned32
983*05b00f60SXin Li && elem->data.uns <= smiRange->maxValue.value.unsigned32);
984*05b00f60SXin Li break;
985*05b00f60SXin Li
986*05b00f60SXin Li case SMI_BASETYPE_UNSIGNED64:
987*05b00f60SXin Li /* XXX */
988*05b00f60SXin Li break;
989*05b00f60SXin Li
990*05b00f60SXin Li /* case SMI_BASETYPE_INTEGER64: SMIng */
991*05b00f60SXin Li /* case SMI_BASETYPE_FLOAT32: SMIng */
992*05b00f60SXin Li /* case SMI_BASETYPE_FLOAT64: SMIng */
993*05b00f60SXin Li /* case SMI_BASETYPE_FLOAT128: SMIng */
994*05b00f60SXin Li
995*05b00f60SXin Li case SMI_BASETYPE_ENUM:
996*05b00f60SXin Li case SMI_BASETYPE_BITS:
997*05b00f60SXin Li case SMI_BASETYPE_UNKNOWN:
998*05b00f60SXin Li ok = 1;
999*05b00f60SXin Li break;
1000*05b00f60SXin Li
1001*05b00f60SXin Li default:
1002*05b00f60SXin Li ok = 0;
1003*05b00f60SXin Li break;
1004*05b00f60SXin Li }
1005*05b00f60SXin Li
1006*05b00f60SXin Li return ok;
1007*05b00f60SXin Li }
1008*05b00f60SXin Li
smi_check_range(SmiType * smiType,struct be * elem)1009*05b00f60SXin Li static int smi_check_range(SmiType *smiType, struct be *elem)
1010*05b00f60SXin Li {
1011*05b00f60SXin Li SmiRange *smiRange;
1012*05b00f60SXin Li int ok = 1;
1013*05b00f60SXin Li
1014*05b00f60SXin Li for (smiRange = smiGetFirstRange(smiType);
1015*05b00f60SXin Li smiRange;
1016*05b00f60SXin Li smiRange = smiGetNextRange(smiRange)) {
1017*05b00f60SXin Li
1018*05b00f60SXin Li ok = smi_check_a_range(smiType, smiRange, elem);
1019*05b00f60SXin Li
1020*05b00f60SXin Li if (ok) {
1021*05b00f60SXin Li break;
1022*05b00f60SXin Li }
1023*05b00f60SXin Li }
1024*05b00f60SXin Li
1025*05b00f60SXin Li if (ok) {
1026*05b00f60SXin Li SmiType *parentType;
1027*05b00f60SXin Li parentType = smiGetParentType(smiType);
1028*05b00f60SXin Li if (parentType) {
1029*05b00f60SXin Li ok = smi_check_range(parentType, elem);
1030*05b00f60SXin Li }
1031*05b00f60SXin Li }
1032*05b00f60SXin Li
1033*05b00f60SXin Li return ok;
1034*05b00f60SXin Li }
1035*05b00f60SXin Li
1036*05b00f60SXin Li static SmiNode *
smi_print_variable(netdissect_options * ndo,struct be * elem,int * status)1037*05b00f60SXin Li smi_print_variable(netdissect_options *ndo,
1038*05b00f60SXin Li struct be *elem, int *status)
1039*05b00f60SXin Li {
1040*05b00f60SXin Li unsigned int oid[128], oidlen;
1041*05b00f60SXin Li SmiNode *smiNode = NULL;
1042*05b00f60SXin Li unsigned int i;
1043*05b00f60SXin Li
1044*05b00f60SXin Li if (!nd_smi_module_loaded) {
1045*05b00f60SXin Li *status = asn1_print(ndo, elem);
1046*05b00f60SXin Li return NULL;
1047*05b00f60SXin Li }
1048*05b00f60SXin Li *status = smi_decode_oid(ndo, elem, oid, sizeof(oid) / sizeof(unsigned int),
1049*05b00f60SXin Li &oidlen);
1050*05b00f60SXin Li if (*status < 0)
1051*05b00f60SXin Li return NULL;
1052*05b00f60SXin Li smiNode = smiGetNodeByOID(oidlen, oid);
1053*05b00f60SXin Li if (! smiNode) {
1054*05b00f60SXin Li *status = asn1_print(ndo, elem);
1055*05b00f60SXin Li return NULL;
1056*05b00f60SXin Li }
1057*05b00f60SXin Li if (ndo->ndo_vflag) {
1058*05b00f60SXin Li ND_PRINT("%s::", smiGetNodeModule(smiNode)->name);
1059*05b00f60SXin Li }
1060*05b00f60SXin Li ND_PRINT("%s", smiNode->name);
1061*05b00f60SXin Li if (smiNode->oidlen < oidlen) {
1062*05b00f60SXin Li for (i = smiNode->oidlen; i < oidlen; i++) {
1063*05b00f60SXin Li ND_PRINT(".%u", oid[i]);
1064*05b00f60SXin Li }
1065*05b00f60SXin Li }
1066*05b00f60SXin Li *status = 0;
1067*05b00f60SXin Li return smiNode;
1068*05b00f60SXin Li }
1069*05b00f60SXin Li
1070*05b00f60SXin Li static int
smi_print_value(netdissect_options * ndo,SmiNode * smiNode,u_short pduid,struct be * elem)1071*05b00f60SXin Li smi_print_value(netdissect_options *ndo,
1072*05b00f60SXin Li SmiNode *smiNode, u_short pduid, struct be *elem)
1073*05b00f60SXin Li {
1074*05b00f60SXin Li unsigned int i, oid[128], oidlen;
1075*05b00f60SXin Li SmiType *smiType;
1076*05b00f60SXin Li SmiNamedNumber *nn;
1077*05b00f60SXin Li int done = 0;
1078*05b00f60SXin Li
1079*05b00f60SXin Li if (! smiNode || ! (smiNode->nodekind
1080*05b00f60SXin Li & (SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN))) {
1081*05b00f60SXin Li return asn1_print(ndo, elem);
1082*05b00f60SXin Li }
1083*05b00f60SXin Li
1084*05b00f60SXin Li if (elem->type == BE_NOSUCHOBJECT
1085*05b00f60SXin Li || elem->type == BE_NOSUCHINST
1086*05b00f60SXin Li || elem->type == BE_ENDOFMIBVIEW) {
1087*05b00f60SXin Li return asn1_print(ndo, elem);
1088*05b00f60SXin Li }
1089*05b00f60SXin Li
1090*05b00f60SXin Li if (NOTIFY_CLASS(pduid) && smiNode->access < SMI_ACCESS_NOTIFY) {
1091*05b00f60SXin Li ND_PRINT("[notNotifyable]");
1092*05b00f60SXin Li }
1093*05b00f60SXin Li
1094*05b00f60SXin Li if (READ_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_ONLY) {
1095*05b00f60SXin Li ND_PRINT("[notReadable]");
1096*05b00f60SXin Li }
1097*05b00f60SXin Li
1098*05b00f60SXin Li if (WRITE_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_WRITE) {
1099*05b00f60SXin Li ND_PRINT("[notWritable]");
1100*05b00f60SXin Li }
1101*05b00f60SXin Li
1102*05b00f60SXin Li if (RESPONSE_CLASS(pduid)
1103*05b00f60SXin Li && smiNode->access == SMI_ACCESS_NOT_ACCESSIBLE) {
1104*05b00f60SXin Li ND_PRINT("[noAccess]");
1105*05b00f60SXin Li }
1106*05b00f60SXin Li
1107*05b00f60SXin Li smiType = smiGetNodeType(smiNode);
1108*05b00f60SXin Li if (! smiType) {
1109*05b00f60SXin Li return asn1_print(ndo, elem);
1110*05b00f60SXin Li }
1111*05b00f60SXin Li
1112*05b00f60SXin Li if (! smi_check_type(smiType->basetype, elem->type)) {
1113*05b00f60SXin Li ND_PRINT("[wrongType]");
1114*05b00f60SXin Li }
1115*05b00f60SXin Li
1116*05b00f60SXin Li if (! smi_check_range(smiType, elem)) {
1117*05b00f60SXin Li ND_PRINT("[outOfRange]");
1118*05b00f60SXin Li }
1119*05b00f60SXin Li
1120*05b00f60SXin Li /* resolve bits to named bits */
1121*05b00f60SXin Li
1122*05b00f60SXin Li /* check whether instance identifier is valid */
1123*05b00f60SXin Li
1124*05b00f60SXin Li /* apply display hints (integer, octetstring) */
1125*05b00f60SXin Li
1126*05b00f60SXin Li /* convert instance identifier to index type values */
1127*05b00f60SXin Li
1128*05b00f60SXin Li switch (elem->type) {
1129*05b00f60SXin Li case BE_OID:
1130*05b00f60SXin Li if (smiType->basetype == SMI_BASETYPE_BITS) {
1131*05b00f60SXin Li /* print bit labels */
1132*05b00f60SXin Li } else {
1133*05b00f60SXin Li if (nd_smi_module_loaded &&
1134*05b00f60SXin Li smi_decode_oid(ndo, elem, oid,
1135*05b00f60SXin Li sizeof(oid)/sizeof(unsigned int),
1136*05b00f60SXin Li &oidlen) == 0) {
1137*05b00f60SXin Li smiNode = smiGetNodeByOID(oidlen, oid);
1138*05b00f60SXin Li if (smiNode) {
1139*05b00f60SXin Li if (ndo->ndo_vflag) {
1140*05b00f60SXin Li ND_PRINT("%s::", smiGetNodeModule(smiNode)->name);
1141*05b00f60SXin Li }
1142*05b00f60SXin Li ND_PRINT("%s", smiNode->name);
1143*05b00f60SXin Li if (smiNode->oidlen < oidlen) {
1144*05b00f60SXin Li for (i = smiNode->oidlen;
1145*05b00f60SXin Li i < oidlen; i++) {
1146*05b00f60SXin Li ND_PRINT(".%u", oid[i]);
1147*05b00f60SXin Li }
1148*05b00f60SXin Li }
1149*05b00f60SXin Li done++;
1150*05b00f60SXin Li }
1151*05b00f60SXin Li }
1152*05b00f60SXin Li }
1153*05b00f60SXin Li break;
1154*05b00f60SXin Li
1155*05b00f60SXin Li case BE_INT:
1156*05b00f60SXin Li if (smiType->basetype == SMI_BASETYPE_ENUM) {
1157*05b00f60SXin Li for (nn = smiGetFirstNamedNumber(smiType);
1158*05b00f60SXin Li nn;
1159*05b00f60SXin Li nn = smiGetNextNamedNumber(nn)) {
1160*05b00f60SXin Li if (nn->value.value.integer32
1161*05b00f60SXin Li == elem->data.integer) {
1162*05b00f60SXin Li ND_PRINT("%s", nn->name);
1163*05b00f60SXin Li ND_PRINT("(%d)", elem->data.integer);
1164*05b00f60SXin Li done++;
1165*05b00f60SXin Li break;
1166*05b00f60SXin Li }
1167*05b00f60SXin Li }
1168*05b00f60SXin Li }
1169*05b00f60SXin Li break;
1170*05b00f60SXin Li }
1171*05b00f60SXin Li
1172*05b00f60SXin Li if (! done) {
1173*05b00f60SXin Li return asn1_print(ndo, elem);
1174*05b00f60SXin Li }
1175*05b00f60SXin Li return 0;
1176*05b00f60SXin Li }
1177*05b00f60SXin Li #endif
1178*05b00f60SXin Li
1179*05b00f60SXin Li /*
1180*05b00f60SXin Li * General SNMP header
1181*05b00f60SXin Li * SEQUENCE {
1182*05b00f60SXin Li * version INTEGER {version-1(0)},
1183*05b00f60SXin Li * community OCTET STRING,
1184*05b00f60SXin Li * data ANY -- PDUs
1185*05b00f60SXin Li * }
1186*05b00f60SXin Li * PDUs for all but Trap: (see rfc1157 from page 15 on)
1187*05b00f60SXin Li * SEQUENCE {
1188*05b00f60SXin Li * request-id INTEGER,
1189*05b00f60SXin Li * error-status INTEGER,
1190*05b00f60SXin Li * error-index INTEGER,
1191*05b00f60SXin Li * varbindlist SEQUENCE OF
1192*05b00f60SXin Li * SEQUENCE {
1193*05b00f60SXin Li * name ObjectName,
1194*05b00f60SXin Li * value ObjectValue
1195*05b00f60SXin Li * }
1196*05b00f60SXin Li * }
1197*05b00f60SXin Li * PDU for Trap:
1198*05b00f60SXin Li * SEQUENCE {
1199*05b00f60SXin Li * enterprise OBJECT IDENTIFIER,
1200*05b00f60SXin Li * agent-addr NetworkAddress,
1201*05b00f60SXin Li * generic-trap INTEGER,
1202*05b00f60SXin Li * specific-trap INTEGER,
1203*05b00f60SXin Li * time-stamp TimeTicks,
1204*05b00f60SXin Li * varbindlist SEQUENCE OF
1205*05b00f60SXin Li * SEQUENCE {
1206*05b00f60SXin Li * name ObjectName,
1207*05b00f60SXin Li * value ObjectValue
1208*05b00f60SXin Li * }
1209*05b00f60SXin Li * }
1210*05b00f60SXin Li */
1211*05b00f60SXin Li
1212*05b00f60SXin Li /*
1213*05b00f60SXin Li * Decode SNMP varBind
1214*05b00f60SXin Li */
1215*05b00f60SXin Li static void
varbind_print(netdissect_options * ndo,u_short pduid,const u_char * np,u_int length)1216*05b00f60SXin Li varbind_print(netdissect_options *ndo,
1217*05b00f60SXin Li u_short pduid, const u_char *np, u_int length)
1218*05b00f60SXin Li {
1219*05b00f60SXin Li struct be elem;
1220*05b00f60SXin Li int count = 0;
1221*05b00f60SXin Li #ifdef USE_LIBSMI
1222*05b00f60SXin Li SmiNode *smiNode = NULL;
1223*05b00f60SXin Li #endif
1224*05b00f60SXin Li int status;
1225*05b00f60SXin Li
1226*05b00f60SXin Li /* Sequence of varBind */
1227*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1228*05b00f60SXin Li return;
1229*05b00f60SXin Li if (elem.type != BE_SEQ) {
1230*05b00f60SXin Li ND_PRINT("[!SEQ of varbind]");
1231*05b00f60SXin Li asn1_print(ndo, &elem);
1232*05b00f60SXin Li return;
1233*05b00f60SXin Li }
1234*05b00f60SXin Li if ((u_int)count < length)
1235*05b00f60SXin Li ND_PRINT("[%d extra after SEQ of varbind]", length - count);
1236*05b00f60SXin Li /* descend */
1237*05b00f60SXin Li length = elem.asnlen;
1238*05b00f60SXin Li np = (const u_char *)elem.data.raw;
1239*05b00f60SXin Li
1240*05b00f60SXin Li while (length) {
1241*05b00f60SXin Li const u_char *vbend;
1242*05b00f60SXin Li u_int vblength;
1243*05b00f60SXin Li
1244*05b00f60SXin Li ND_PRINT(" ");
1245*05b00f60SXin Li
1246*05b00f60SXin Li /* Sequence */
1247*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1248*05b00f60SXin Li return;
1249*05b00f60SXin Li if (elem.type != BE_SEQ) {
1250*05b00f60SXin Li ND_PRINT("[!varbind]");
1251*05b00f60SXin Li asn1_print(ndo, &elem);
1252*05b00f60SXin Li return;
1253*05b00f60SXin Li }
1254*05b00f60SXin Li vbend = np + count;
1255*05b00f60SXin Li vblength = length - count;
1256*05b00f60SXin Li /* descend */
1257*05b00f60SXin Li length = elem.asnlen;
1258*05b00f60SXin Li np = (const u_char *)elem.data.raw;
1259*05b00f60SXin Li
1260*05b00f60SXin Li /* objName (OID) */
1261*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1262*05b00f60SXin Li return;
1263*05b00f60SXin Li if (elem.type != BE_OID) {
1264*05b00f60SXin Li ND_PRINT("[objName!=OID]");
1265*05b00f60SXin Li asn1_print(ndo, &elem);
1266*05b00f60SXin Li return;
1267*05b00f60SXin Li }
1268*05b00f60SXin Li #ifdef USE_LIBSMI
1269*05b00f60SXin Li smiNode = smi_print_variable(ndo, &elem, &status);
1270*05b00f60SXin Li #else
1271*05b00f60SXin Li status = asn1_print(ndo, &elem);
1272*05b00f60SXin Li #endif
1273*05b00f60SXin Li if (status < 0)
1274*05b00f60SXin Li return;
1275*05b00f60SXin Li length -= count;
1276*05b00f60SXin Li np += count;
1277*05b00f60SXin Li
1278*05b00f60SXin Li if (pduid != GETREQ && pduid != GETNEXTREQ
1279*05b00f60SXin Li && pduid != GETBULKREQ)
1280*05b00f60SXin Li ND_PRINT("=");
1281*05b00f60SXin Li
1282*05b00f60SXin Li /* objVal (ANY) */
1283*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1284*05b00f60SXin Li return;
1285*05b00f60SXin Li if (pduid == GETREQ || pduid == GETNEXTREQ
1286*05b00f60SXin Li || pduid == GETBULKREQ) {
1287*05b00f60SXin Li if (elem.type != BE_NULL) {
1288*05b00f60SXin Li ND_PRINT("[objVal!=NULL]");
1289*05b00f60SXin Li if (asn1_print(ndo, &elem) < 0)
1290*05b00f60SXin Li return;
1291*05b00f60SXin Li }
1292*05b00f60SXin Li } else {
1293*05b00f60SXin Li if (elem.type != BE_NULL) {
1294*05b00f60SXin Li #ifdef USE_LIBSMI
1295*05b00f60SXin Li status = smi_print_value(ndo, smiNode, pduid, &elem);
1296*05b00f60SXin Li #else
1297*05b00f60SXin Li status = asn1_print(ndo, &elem);
1298*05b00f60SXin Li #endif
1299*05b00f60SXin Li }
1300*05b00f60SXin Li if (status < 0)
1301*05b00f60SXin Li return;
1302*05b00f60SXin Li }
1303*05b00f60SXin Li length = vblength;
1304*05b00f60SXin Li np = vbend;
1305*05b00f60SXin Li }
1306*05b00f60SXin Li }
1307*05b00f60SXin Li
1308*05b00f60SXin Li /*
1309*05b00f60SXin Li * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
1310*05b00f60SXin Li * GetBulk, Inform, V2Trap, and Report
1311*05b00f60SXin Li */
1312*05b00f60SXin Li static void
snmppdu_print(netdissect_options * ndo,u_short pduid,const u_char * np,u_int length)1313*05b00f60SXin Li snmppdu_print(netdissect_options *ndo,
1314*05b00f60SXin Li u_short pduid, const u_char *np, u_int length)
1315*05b00f60SXin Li {
1316*05b00f60SXin Li struct be elem;
1317*05b00f60SXin Li int count = 0, error_status;
1318*05b00f60SXin Li
1319*05b00f60SXin Li /* reqId (Integer) */
1320*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1321*05b00f60SXin Li return;
1322*05b00f60SXin Li if (elem.type != BE_INT) {
1323*05b00f60SXin Li ND_PRINT("[reqId!=INT]");
1324*05b00f60SXin Li asn1_print(ndo, &elem);
1325*05b00f60SXin Li return;
1326*05b00f60SXin Li }
1327*05b00f60SXin Li if (ndo->ndo_vflag)
1328*05b00f60SXin Li ND_PRINT("R=%d ", elem.data.integer);
1329*05b00f60SXin Li length -= count;
1330*05b00f60SXin Li np += count;
1331*05b00f60SXin Li
1332*05b00f60SXin Li /* errorStatus (Integer) */
1333*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1334*05b00f60SXin Li return;
1335*05b00f60SXin Li if (elem.type != BE_INT) {
1336*05b00f60SXin Li ND_PRINT("[errorStatus!=INT]");
1337*05b00f60SXin Li asn1_print(ndo, &elem);
1338*05b00f60SXin Li return;
1339*05b00f60SXin Li }
1340*05b00f60SXin Li error_status = 0;
1341*05b00f60SXin Li if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1342*05b00f60SXin Li || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1343*05b00f60SXin Li && elem.data.integer != 0) {
1344*05b00f60SXin Li char errbuf[20];
1345*05b00f60SXin Li ND_PRINT("[errorStatus(%s)!=0]",
1346*05b00f60SXin Li DECODE_ErrorStatus(elem.data.integer));
1347*05b00f60SXin Li } else if (pduid == GETBULKREQ) {
1348*05b00f60SXin Li ND_PRINT(" N=%d", elem.data.integer);
1349*05b00f60SXin Li } else if (elem.data.integer != 0) {
1350*05b00f60SXin Li char errbuf[20];
1351*05b00f60SXin Li ND_PRINT(" %s", DECODE_ErrorStatus(elem.data.integer));
1352*05b00f60SXin Li error_status = elem.data.integer;
1353*05b00f60SXin Li }
1354*05b00f60SXin Li length -= count;
1355*05b00f60SXin Li np += count;
1356*05b00f60SXin Li
1357*05b00f60SXin Li /* errorIndex (Integer) */
1358*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1359*05b00f60SXin Li return;
1360*05b00f60SXin Li if (elem.type != BE_INT) {
1361*05b00f60SXin Li ND_PRINT("[errorIndex!=INT]");
1362*05b00f60SXin Li asn1_print(ndo, &elem);
1363*05b00f60SXin Li return;
1364*05b00f60SXin Li }
1365*05b00f60SXin Li if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1366*05b00f60SXin Li || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1367*05b00f60SXin Li && elem.data.integer != 0)
1368*05b00f60SXin Li ND_PRINT("[errorIndex(%d)!=0]", elem.data.integer);
1369*05b00f60SXin Li else if (pduid == GETBULKREQ)
1370*05b00f60SXin Li ND_PRINT(" M=%d", elem.data.integer);
1371*05b00f60SXin Li else if (elem.data.integer != 0) {
1372*05b00f60SXin Li if (!error_status)
1373*05b00f60SXin Li ND_PRINT("[errorIndex(%d) w/o errorStatus]", elem.data.integer);
1374*05b00f60SXin Li else
1375*05b00f60SXin Li ND_PRINT("@%d", elem.data.integer);
1376*05b00f60SXin Li } else if (error_status) {
1377*05b00f60SXin Li ND_PRINT("[errorIndex==0]");
1378*05b00f60SXin Li }
1379*05b00f60SXin Li length -= count;
1380*05b00f60SXin Li np += count;
1381*05b00f60SXin Li
1382*05b00f60SXin Li varbind_print(ndo, pduid, np, length);
1383*05b00f60SXin Li }
1384*05b00f60SXin Li
1385*05b00f60SXin Li /*
1386*05b00f60SXin Li * Decode SNMP Trap PDU
1387*05b00f60SXin Li */
1388*05b00f60SXin Li static void
trappdu_print(netdissect_options * ndo,const u_char * np,u_int length)1389*05b00f60SXin Li trappdu_print(netdissect_options *ndo,
1390*05b00f60SXin Li const u_char *np, u_int length)
1391*05b00f60SXin Li {
1392*05b00f60SXin Li struct be elem;
1393*05b00f60SXin Li int count = 0, generic;
1394*05b00f60SXin Li
1395*05b00f60SXin Li ND_PRINT(" ");
1396*05b00f60SXin Li
1397*05b00f60SXin Li /* enterprise (oid) */
1398*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1399*05b00f60SXin Li return;
1400*05b00f60SXin Li if (elem.type != BE_OID) {
1401*05b00f60SXin Li ND_PRINT("[enterprise!=OID]");
1402*05b00f60SXin Li asn1_print(ndo, &elem);
1403*05b00f60SXin Li return;
1404*05b00f60SXin Li }
1405*05b00f60SXin Li if (asn1_print(ndo, &elem) < 0)
1406*05b00f60SXin Li return;
1407*05b00f60SXin Li length -= count;
1408*05b00f60SXin Li np += count;
1409*05b00f60SXin Li
1410*05b00f60SXin Li ND_PRINT(" ");
1411*05b00f60SXin Li
1412*05b00f60SXin Li /* agent-addr (inetaddr) */
1413*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1414*05b00f60SXin Li return;
1415*05b00f60SXin Li if (elem.type != BE_INETADDR) {
1416*05b00f60SXin Li ND_PRINT("[agent-addr!=INETADDR]");
1417*05b00f60SXin Li asn1_print(ndo, &elem);
1418*05b00f60SXin Li return;
1419*05b00f60SXin Li }
1420*05b00f60SXin Li if (asn1_print(ndo, &elem) < 0)
1421*05b00f60SXin Li return;
1422*05b00f60SXin Li length -= count;
1423*05b00f60SXin Li np += count;
1424*05b00f60SXin Li
1425*05b00f60SXin Li /* generic-trap (Integer) */
1426*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1427*05b00f60SXin Li return;
1428*05b00f60SXin Li if (elem.type != BE_INT) {
1429*05b00f60SXin Li ND_PRINT("[generic-trap!=INT]");
1430*05b00f60SXin Li asn1_print(ndo, &elem);
1431*05b00f60SXin Li return;
1432*05b00f60SXin Li }
1433*05b00f60SXin Li generic = elem.data.integer;
1434*05b00f60SXin Li {
1435*05b00f60SXin Li char buf[20];
1436*05b00f60SXin Li ND_PRINT(" %s", DECODE_GenericTrap(generic));
1437*05b00f60SXin Li }
1438*05b00f60SXin Li length -= count;
1439*05b00f60SXin Li np += count;
1440*05b00f60SXin Li
1441*05b00f60SXin Li /* specific-trap (Integer) */
1442*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1443*05b00f60SXin Li return;
1444*05b00f60SXin Li if (elem.type != BE_INT) {
1445*05b00f60SXin Li ND_PRINT("[specific-trap!=INT]");
1446*05b00f60SXin Li asn1_print(ndo, &elem);
1447*05b00f60SXin Li return;
1448*05b00f60SXin Li }
1449*05b00f60SXin Li if (generic != GT_ENTERPRISE) {
1450*05b00f60SXin Li if (elem.data.integer != 0)
1451*05b00f60SXin Li ND_PRINT("[specific-trap(%d)!=0]", elem.data.integer);
1452*05b00f60SXin Li } else
1453*05b00f60SXin Li ND_PRINT(" s=%d", elem.data.integer);
1454*05b00f60SXin Li length -= count;
1455*05b00f60SXin Li np += count;
1456*05b00f60SXin Li
1457*05b00f60SXin Li ND_PRINT(" ");
1458*05b00f60SXin Li
1459*05b00f60SXin Li /* time-stamp (TimeTicks) */
1460*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1461*05b00f60SXin Li return;
1462*05b00f60SXin Li if (elem.type != BE_UNS) { /* XXX */
1463*05b00f60SXin Li ND_PRINT("[time-stamp!=TIMETICKS]");
1464*05b00f60SXin Li asn1_print(ndo, &elem);
1465*05b00f60SXin Li return;
1466*05b00f60SXin Li }
1467*05b00f60SXin Li if (asn1_print(ndo, &elem) < 0)
1468*05b00f60SXin Li return;
1469*05b00f60SXin Li length -= count;
1470*05b00f60SXin Li np += count;
1471*05b00f60SXin Li
1472*05b00f60SXin Li varbind_print(ndo, TRAP, np, length);
1473*05b00f60SXin Li }
1474*05b00f60SXin Li
1475*05b00f60SXin Li /*
1476*05b00f60SXin Li * Decode arbitrary SNMP PDUs.
1477*05b00f60SXin Li */
1478*05b00f60SXin Li static void
pdu_print(netdissect_options * ndo,const u_char * np,u_int length,int version)1479*05b00f60SXin Li pdu_print(netdissect_options *ndo,
1480*05b00f60SXin Li const u_char *np, u_int length, int version)
1481*05b00f60SXin Li {
1482*05b00f60SXin Li struct be pdu;
1483*05b00f60SXin Li int count = 0;
1484*05b00f60SXin Li
1485*05b00f60SXin Li /* PDU (Context) */
1486*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &pdu)) < 0)
1487*05b00f60SXin Li return;
1488*05b00f60SXin Li if (pdu.type != BE_PDU) {
1489*05b00f60SXin Li ND_PRINT("[no PDU]");
1490*05b00f60SXin Li return;
1491*05b00f60SXin Li }
1492*05b00f60SXin Li if ((u_int)count < length)
1493*05b00f60SXin Li ND_PRINT("[%d extra after PDU]", length - count);
1494*05b00f60SXin Li if (ndo->ndo_vflag) {
1495*05b00f60SXin Li ND_PRINT("{ ");
1496*05b00f60SXin Li }
1497*05b00f60SXin Li if (asn1_print(ndo, &pdu) < 0)
1498*05b00f60SXin Li return;
1499*05b00f60SXin Li ND_PRINT(" ");
1500*05b00f60SXin Li /* descend into PDU */
1501*05b00f60SXin Li length = pdu.asnlen;
1502*05b00f60SXin Li np = (const u_char *)pdu.data.raw;
1503*05b00f60SXin Li
1504*05b00f60SXin Li if (version == SNMP_VERSION_1 &&
1505*05b00f60SXin Li (pdu.id == GETBULKREQ || pdu.id == INFORMREQ ||
1506*05b00f60SXin Li pdu.id == V2TRAP || pdu.id == REPORT)) {
1507*05b00f60SXin Li ND_PRINT("[v2 PDU in v1 message]");
1508*05b00f60SXin Li return;
1509*05b00f60SXin Li }
1510*05b00f60SXin Li
1511*05b00f60SXin Li if (version == SNMP_VERSION_2 && pdu.id == TRAP) {
1512*05b00f60SXin Li ND_PRINT("[v1 PDU in v2 message]");
1513*05b00f60SXin Li return;
1514*05b00f60SXin Li }
1515*05b00f60SXin Li
1516*05b00f60SXin Li switch (pdu.id) {
1517*05b00f60SXin Li case TRAP:
1518*05b00f60SXin Li trappdu_print(ndo, np, length);
1519*05b00f60SXin Li break;
1520*05b00f60SXin Li case GETREQ:
1521*05b00f60SXin Li case GETNEXTREQ:
1522*05b00f60SXin Li case GETRESP:
1523*05b00f60SXin Li case SETREQ:
1524*05b00f60SXin Li case GETBULKREQ:
1525*05b00f60SXin Li case INFORMREQ:
1526*05b00f60SXin Li case V2TRAP:
1527*05b00f60SXin Li case REPORT:
1528*05b00f60SXin Li snmppdu_print(ndo, pdu.id, np, length);
1529*05b00f60SXin Li break;
1530*05b00f60SXin Li }
1531*05b00f60SXin Li
1532*05b00f60SXin Li if (ndo->ndo_vflag) {
1533*05b00f60SXin Li ND_PRINT(" } ");
1534*05b00f60SXin Li }
1535*05b00f60SXin Li }
1536*05b00f60SXin Li
1537*05b00f60SXin Li /*
1538*05b00f60SXin Li * Decode a scoped SNMP PDU.
1539*05b00f60SXin Li */
1540*05b00f60SXin Li static void
scopedpdu_print(netdissect_options * ndo,const u_char * np,u_int length,int version)1541*05b00f60SXin Li scopedpdu_print(netdissect_options *ndo,
1542*05b00f60SXin Li const u_char *np, u_int length, int version)
1543*05b00f60SXin Li {
1544*05b00f60SXin Li struct be elem;
1545*05b00f60SXin Li int count = 0;
1546*05b00f60SXin Li
1547*05b00f60SXin Li /* Sequence */
1548*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1549*05b00f60SXin Li return;
1550*05b00f60SXin Li if (elem.type != BE_SEQ) {
1551*05b00f60SXin Li ND_PRINT("[!scoped PDU]");
1552*05b00f60SXin Li asn1_print(ndo, &elem);
1553*05b00f60SXin Li return;
1554*05b00f60SXin Li }
1555*05b00f60SXin Li length = elem.asnlen;
1556*05b00f60SXin Li np = (const u_char *)elem.data.raw;
1557*05b00f60SXin Li
1558*05b00f60SXin Li /* contextEngineID (OCTET STRING) */
1559*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1560*05b00f60SXin Li return;
1561*05b00f60SXin Li if (elem.type != BE_STR) {
1562*05b00f60SXin Li ND_PRINT("[contextEngineID!=STR]");
1563*05b00f60SXin Li asn1_print(ndo, &elem);
1564*05b00f60SXin Li return;
1565*05b00f60SXin Li }
1566*05b00f60SXin Li length -= count;
1567*05b00f60SXin Li np += count;
1568*05b00f60SXin Li
1569*05b00f60SXin Li ND_PRINT("E=");
1570*05b00f60SXin Li if (asn1_print_octets(ndo, &elem) == -1)
1571*05b00f60SXin Li return;
1572*05b00f60SXin Li ND_PRINT(" ");
1573*05b00f60SXin Li
1574*05b00f60SXin Li /* contextName (OCTET STRING) */
1575*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1576*05b00f60SXin Li return;
1577*05b00f60SXin Li if (elem.type != BE_STR) {
1578*05b00f60SXin Li ND_PRINT("[contextName!=STR]");
1579*05b00f60SXin Li asn1_print(ndo, &elem);
1580*05b00f60SXin Li return;
1581*05b00f60SXin Li }
1582*05b00f60SXin Li length -= count;
1583*05b00f60SXin Li np += count;
1584*05b00f60SXin Li
1585*05b00f60SXin Li ND_PRINT("C=");
1586*05b00f60SXin Li if (asn1_print_string(ndo, &elem) == -1)
1587*05b00f60SXin Li return;
1588*05b00f60SXin Li ND_PRINT(" ");
1589*05b00f60SXin Li
1590*05b00f60SXin Li pdu_print(ndo, np, length, version);
1591*05b00f60SXin Li }
1592*05b00f60SXin Li
1593*05b00f60SXin Li /*
1594*05b00f60SXin Li * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
1595*05b00f60SXin Li */
1596*05b00f60SXin Li static void
community_print(netdissect_options * ndo,const u_char * np,u_int length,int version)1597*05b00f60SXin Li community_print(netdissect_options *ndo,
1598*05b00f60SXin Li const u_char *np, u_int length, int version)
1599*05b00f60SXin Li {
1600*05b00f60SXin Li struct be elem;
1601*05b00f60SXin Li int count = 0;
1602*05b00f60SXin Li
1603*05b00f60SXin Li /* Community (String) */
1604*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1605*05b00f60SXin Li return;
1606*05b00f60SXin Li if (elem.type != BE_STR) {
1607*05b00f60SXin Li ND_PRINT("[comm!=STR]");
1608*05b00f60SXin Li asn1_print(ndo, &elem);
1609*05b00f60SXin Li return;
1610*05b00f60SXin Li }
1611*05b00f60SXin Li /* default community */
1612*05b00f60SXin Li if (!(elem.asnlen == sizeof(DEF_COMMUNITY) - 1 &&
1613*05b00f60SXin Li strncmp((const char *)elem.data.str, DEF_COMMUNITY,
1614*05b00f60SXin Li sizeof(DEF_COMMUNITY) - 1) == 0)) {
1615*05b00f60SXin Li /* ! "public" */
1616*05b00f60SXin Li ND_PRINT("C=");
1617*05b00f60SXin Li if (asn1_print_string(ndo, &elem) == -1)
1618*05b00f60SXin Li return;
1619*05b00f60SXin Li ND_PRINT(" ");
1620*05b00f60SXin Li }
1621*05b00f60SXin Li length -= count;
1622*05b00f60SXin Li np += count;
1623*05b00f60SXin Li
1624*05b00f60SXin Li pdu_print(ndo, np, length, version);
1625*05b00f60SXin Li }
1626*05b00f60SXin Li
1627*05b00f60SXin Li /*
1628*05b00f60SXin Li * Decode SNMPv3 User-based Security Message Header (SNMPv3)
1629*05b00f60SXin Li */
1630*05b00f60SXin Li static void
usm_print(netdissect_options * ndo,const u_char * np,u_int length)1631*05b00f60SXin Li usm_print(netdissect_options *ndo,
1632*05b00f60SXin Li const u_char *np, u_int length)
1633*05b00f60SXin Li {
1634*05b00f60SXin Li struct be elem;
1635*05b00f60SXin Li int count = 0;
1636*05b00f60SXin Li
1637*05b00f60SXin Li /* Sequence */
1638*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1639*05b00f60SXin Li return;
1640*05b00f60SXin Li if (elem.type != BE_SEQ) {
1641*05b00f60SXin Li ND_PRINT("[!usm]");
1642*05b00f60SXin Li asn1_print(ndo, &elem);
1643*05b00f60SXin Li return;
1644*05b00f60SXin Li }
1645*05b00f60SXin Li length = elem.asnlen;
1646*05b00f60SXin Li np = (const u_char *)elem.data.raw;
1647*05b00f60SXin Li
1648*05b00f60SXin Li /* msgAuthoritativeEngineID (OCTET STRING) */
1649*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1650*05b00f60SXin Li return;
1651*05b00f60SXin Li if (elem.type != BE_STR) {
1652*05b00f60SXin Li ND_PRINT("[msgAuthoritativeEngineID!=STR]");
1653*05b00f60SXin Li asn1_print(ndo, &elem);
1654*05b00f60SXin Li return;
1655*05b00f60SXin Li }
1656*05b00f60SXin Li length -= count;
1657*05b00f60SXin Li np += count;
1658*05b00f60SXin Li
1659*05b00f60SXin Li /* msgAuthoritativeEngineBoots (INTEGER) */
1660*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1661*05b00f60SXin Li return;
1662*05b00f60SXin Li if (elem.type != BE_INT) {
1663*05b00f60SXin Li ND_PRINT("[msgAuthoritativeEngineBoots!=INT]");
1664*05b00f60SXin Li asn1_print(ndo, &elem);
1665*05b00f60SXin Li return;
1666*05b00f60SXin Li }
1667*05b00f60SXin Li if (ndo->ndo_vflag)
1668*05b00f60SXin Li ND_PRINT("B=%d ", elem.data.integer);
1669*05b00f60SXin Li length -= count;
1670*05b00f60SXin Li np += count;
1671*05b00f60SXin Li
1672*05b00f60SXin Li /* msgAuthoritativeEngineTime (INTEGER) */
1673*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1674*05b00f60SXin Li return;
1675*05b00f60SXin Li if (elem.type != BE_INT) {
1676*05b00f60SXin Li ND_PRINT("[msgAuthoritativeEngineTime!=INT]");
1677*05b00f60SXin Li asn1_print(ndo, &elem);
1678*05b00f60SXin Li return;
1679*05b00f60SXin Li }
1680*05b00f60SXin Li if (ndo->ndo_vflag)
1681*05b00f60SXin Li ND_PRINT("T=%d ", elem.data.integer);
1682*05b00f60SXin Li length -= count;
1683*05b00f60SXin Li np += count;
1684*05b00f60SXin Li
1685*05b00f60SXin Li /* msgUserName (OCTET STRING) */
1686*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1687*05b00f60SXin Li return;
1688*05b00f60SXin Li if (elem.type != BE_STR) {
1689*05b00f60SXin Li ND_PRINT("[msgUserName!=STR]");
1690*05b00f60SXin Li asn1_print(ndo, &elem);
1691*05b00f60SXin Li return;
1692*05b00f60SXin Li }
1693*05b00f60SXin Li length -= count;
1694*05b00f60SXin Li np += count;
1695*05b00f60SXin Li
1696*05b00f60SXin Li ND_PRINT("U=");
1697*05b00f60SXin Li if (asn1_print_string(ndo, &elem) == -1)
1698*05b00f60SXin Li return;
1699*05b00f60SXin Li ND_PRINT(" ");
1700*05b00f60SXin Li
1701*05b00f60SXin Li /* msgAuthenticationParameters (OCTET STRING) */
1702*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1703*05b00f60SXin Li return;
1704*05b00f60SXin Li if (elem.type != BE_STR) {
1705*05b00f60SXin Li ND_PRINT("[msgAuthenticationParameters!=STR]");
1706*05b00f60SXin Li asn1_print(ndo, &elem);
1707*05b00f60SXin Li return;
1708*05b00f60SXin Li }
1709*05b00f60SXin Li length -= count;
1710*05b00f60SXin Li np += count;
1711*05b00f60SXin Li
1712*05b00f60SXin Li /* msgPrivacyParameters (OCTET STRING) */
1713*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1714*05b00f60SXin Li return;
1715*05b00f60SXin Li if (elem.type != BE_STR) {
1716*05b00f60SXin Li ND_PRINT("[msgPrivacyParameters!=STR]");
1717*05b00f60SXin Li asn1_print(ndo, &elem);
1718*05b00f60SXin Li return;
1719*05b00f60SXin Li }
1720*05b00f60SXin Li length -= count;
1721*05b00f60SXin Li np += count;
1722*05b00f60SXin Li
1723*05b00f60SXin Li if ((u_int)count < length)
1724*05b00f60SXin Li ND_PRINT("[%d extra after usm SEQ]", length - count);
1725*05b00f60SXin Li }
1726*05b00f60SXin Li
1727*05b00f60SXin Li /*
1728*05b00f60SXin Li * Decode SNMPv3 Message Header (SNMPv3)
1729*05b00f60SXin Li */
1730*05b00f60SXin Li static void
v3msg_print(netdissect_options * ndo,const u_char * np,u_int length)1731*05b00f60SXin Li v3msg_print(netdissect_options *ndo,
1732*05b00f60SXin Li const u_char *np, u_int length)
1733*05b00f60SXin Li {
1734*05b00f60SXin Li struct be elem;
1735*05b00f60SXin Li int count = 0;
1736*05b00f60SXin Li u_char flags;
1737*05b00f60SXin Li int model;
1738*05b00f60SXin Li const u_char *xnp = np;
1739*05b00f60SXin Li int xlength = length;
1740*05b00f60SXin Li
1741*05b00f60SXin Li /* Sequence */
1742*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1743*05b00f60SXin Li return;
1744*05b00f60SXin Li if (elem.type != BE_SEQ) {
1745*05b00f60SXin Li ND_PRINT("[!message]");
1746*05b00f60SXin Li asn1_print(ndo, &elem);
1747*05b00f60SXin Li return;
1748*05b00f60SXin Li }
1749*05b00f60SXin Li length = elem.asnlen;
1750*05b00f60SXin Li np = (const u_char *)elem.data.raw;
1751*05b00f60SXin Li
1752*05b00f60SXin Li if (ndo->ndo_vflag) {
1753*05b00f60SXin Li ND_PRINT("{ ");
1754*05b00f60SXin Li }
1755*05b00f60SXin Li
1756*05b00f60SXin Li /* msgID (INTEGER) */
1757*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1758*05b00f60SXin Li return;
1759*05b00f60SXin Li if (elem.type != BE_INT) {
1760*05b00f60SXin Li ND_PRINT("[msgID!=INT]");
1761*05b00f60SXin Li asn1_print(ndo, &elem);
1762*05b00f60SXin Li return;
1763*05b00f60SXin Li }
1764*05b00f60SXin Li length -= count;
1765*05b00f60SXin Li np += count;
1766*05b00f60SXin Li
1767*05b00f60SXin Li /* msgMaxSize (INTEGER) */
1768*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1769*05b00f60SXin Li return;
1770*05b00f60SXin Li if (elem.type != BE_INT) {
1771*05b00f60SXin Li ND_PRINT("[msgMaxSize!=INT]");
1772*05b00f60SXin Li asn1_print(ndo, &elem);
1773*05b00f60SXin Li return;
1774*05b00f60SXin Li }
1775*05b00f60SXin Li length -= count;
1776*05b00f60SXin Li np += count;
1777*05b00f60SXin Li
1778*05b00f60SXin Li /* msgFlags (OCTET STRING) */
1779*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1780*05b00f60SXin Li return;
1781*05b00f60SXin Li if (elem.type != BE_STR) {
1782*05b00f60SXin Li ND_PRINT("[msgFlags!=STR]");
1783*05b00f60SXin Li asn1_print(ndo, &elem);
1784*05b00f60SXin Li return;
1785*05b00f60SXin Li }
1786*05b00f60SXin Li if (elem.asnlen != 1) {
1787*05b00f60SXin Li ND_PRINT("[msgFlags size %d]", elem.asnlen);
1788*05b00f60SXin Li return;
1789*05b00f60SXin Li }
1790*05b00f60SXin Li flags = GET_U_1(elem.data.str);
1791*05b00f60SXin Li if (flags != 0x00 && flags != 0x01 && flags != 0x03
1792*05b00f60SXin Li && flags != 0x04 && flags != 0x05 && flags != 0x07) {
1793*05b00f60SXin Li ND_PRINT("[msgFlags=0x%02X]", flags);
1794*05b00f60SXin Li return;
1795*05b00f60SXin Li }
1796*05b00f60SXin Li length -= count;
1797*05b00f60SXin Li np += count;
1798*05b00f60SXin Li
1799*05b00f60SXin Li ND_PRINT("F=%s%s%s ",
1800*05b00f60SXin Li flags & 0x01 ? "a" : "",
1801*05b00f60SXin Li flags & 0x02 ? "p" : "",
1802*05b00f60SXin Li flags & 0x04 ? "r" : "");
1803*05b00f60SXin Li
1804*05b00f60SXin Li /* msgSecurityModel (INTEGER) */
1805*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1806*05b00f60SXin Li return;
1807*05b00f60SXin Li if (elem.type != BE_INT) {
1808*05b00f60SXin Li ND_PRINT("[msgSecurityModel!=INT]");
1809*05b00f60SXin Li asn1_print(ndo, &elem);
1810*05b00f60SXin Li return;
1811*05b00f60SXin Li }
1812*05b00f60SXin Li model = elem.data.integer;
1813*05b00f60SXin Li length -= count;
1814*05b00f60SXin Li np += count;
1815*05b00f60SXin Li
1816*05b00f60SXin Li if ((u_int)count < length)
1817*05b00f60SXin Li ND_PRINT("[%d extra after message SEQ]", length - count);
1818*05b00f60SXin Li
1819*05b00f60SXin Li if (ndo->ndo_vflag) {
1820*05b00f60SXin Li ND_PRINT("} ");
1821*05b00f60SXin Li }
1822*05b00f60SXin Li
1823*05b00f60SXin Li if (model == 3) {
1824*05b00f60SXin Li if (ndo->ndo_vflag) {
1825*05b00f60SXin Li ND_PRINT("{ USM ");
1826*05b00f60SXin Li }
1827*05b00f60SXin Li } else {
1828*05b00f60SXin Li ND_PRINT("[security model %d]", model);
1829*05b00f60SXin Li return;
1830*05b00f60SXin Li }
1831*05b00f60SXin Li
1832*05b00f60SXin Li np = xnp + (np - xnp);
1833*05b00f60SXin Li length = xlength - (np - xnp);
1834*05b00f60SXin Li
1835*05b00f60SXin Li /* msgSecurityParameters (OCTET STRING) */
1836*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1837*05b00f60SXin Li return;
1838*05b00f60SXin Li if (elem.type != BE_STR) {
1839*05b00f60SXin Li ND_PRINT("[msgSecurityParameters!=STR]");
1840*05b00f60SXin Li asn1_print(ndo, &elem);
1841*05b00f60SXin Li return;
1842*05b00f60SXin Li }
1843*05b00f60SXin Li length -= count;
1844*05b00f60SXin Li np += count;
1845*05b00f60SXin Li
1846*05b00f60SXin Li if (model == 3) {
1847*05b00f60SXin Li usm_print(ndo, elem.data.str, elem.asnlen);
1848*05b00f60SXin Li if (ndo->ndo_vflag) {
1849*05b00f60SXin Li ND_PRINT("} ");
1850*05b00f60SXin Li }
1851*05b00f60SXin Li }
1852*05b00f60SXin Li
1853*05b00f60SXin Li if (ndo->ndo_vflag) {
1854*05b00f60SXin Li ND_PRINT("{ ScopedPDU ");
1855*05b00f60SXin Li }
1856*05b00f60SXin Li
1857*05b00f60SXin Li scopedpdu_print(ndo, np, length, 3);
1858*05b00f60SXin Li
1859*05b00f60SXin Li if (ndo->ndo_vflag) {
1860*05b00f60SXin Li ND_PRINT("} ");
1861*05b00f60SXin Li }
1862*05b00f60SXin Li }
1863*05b00f60SXin Li
1864*05b00f60SXin Li /*
1865*05b00f60SXin Li * Decode SNMP header and pass on to PDU printing routines
1866*05b00f60SXin Li */
1867*05b00f60SXin Li void
snmp_print(netdissect_options * ndo,const u_char * np,u_int length)1868*05b00f60SXin Li snmp_print(netdissect_options *ndo,
1869*05b00f60SXin Li const u_char *np, u_int length)
1870*05b00f60SXin Li {
1871*05b00f60SXin Li struct be elem;
1872*05b00f60SXin Li int count = 0;
1873*05b00f60SXin Li int version = 0;
1874*05b00f60SXin Li
1875*05b00f60SXin Li ndo->ndo_protocol = "snmp";
1876*05b00f60SXin Li ND_PRINT(" ");
1877*05b00f60SXin Li
1878*05b00f60SXin Li /* initial Sequence */
1879*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1880*05b00f60SXin Li return;
1881*05b00f60SXin Li if (elem.type != BE_SEQ) {
1882*05b00f60SXin Li ND_PRINT("[!init SEQ]");
1883*05b00f60SXin Li asn1_print(ndo, &elem);
1884*05b00f60SXin Li return;
1885*05b00f60SXin Li }
1886*05b00f60SXin Li if ((u_int)count < length)
1887*05b00f60SXin Li ND_PRINT("[%d extra after iSEQ]", length - count);
1888*05b00f60SXin Li /* descend */
1889*05b00f60SXin Li length = elem.asnlen;
1890*05b00f60SXin Li np = (const u_char *)elem.data.raw;
1891*05b00f60SXin Li
1892*05b00f60SXin Li /* Version (INTEGER) */
1893*05b00f60SXin Li if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
1894*05b00f60SXin Li return;
1895*05b00f60SXin Li if (elem.type != BE_INT) {
1896*05b00f60SXin Li ND_PRINT("[version!=INT]");
1897*05b00f60SXin Li asn1_print(ndo, &elem);
1898*05b00f60SXin Li return;
1899*05b00f60SXin Li }
1900*05b00f60SXin Li
1901*05b00f60SXin Li switch (elem.data.integer) {
1902*05b00f60SXin Li case SNMP_VERSION_1:
1903*05b00f60SXin Li case SNMP_VERSION_2:
1904*05b00f60SXin Li case SNMP_VERSION_3:
1905*05b00f60SXin Li if (ndo->ndo_vflag)
1906*05b00f60SXin Li ND_PRINT("{ %s ", SnmpVersion[elem.data.integer]);
1907*05b00f60SXin Li break;
1908*05b00f60SXin Li default:
1909*05b00f60SXin Li ND_PRINT("SNMP [version = %d]", elem.data.integer);
1910*05b00f60SXin Li return;
1911*05b00f60SXin Li }
1912*05b00f60SXin Li version = elem.data.integer;
1913*05b00f60SXin Li length -= count;
1914*05b00f60SXin Li np += count;
1915*05b00f60SXin Li
1916*05b00f60SXin Li switch (version) {
1917*05b00f60SXin Li case SNMP_VERSION_1:
1918*05b00f60SXin Li case SNMP_VERSION_2:
1919*05b00f60SXin Li community_print(ndo, np, length, version);
1920*05b00f60SXin Li break;
1921*05b00f60SXin Li case SNMP_VERSION_3:
1922*05b00f60SXin Li v3msg_print(ndo, np, length);
1923*05b00f60SXin Li break;
1924*05b00f60SXin Li default:
1925*05b00f60SXin Li ND_PRINT("[version = %d]", elem.data.integer);
1926*05b00f60SXin Li break;
1927*05b00f60SXin Li }
1928*05b00f60SXin Li
1929*05b00f60SXin Li if (ndo->ndo_vflag) {
1930*05b00f60SXin Li ND_PRINT("} ");
1931*05b00f60SXin Li }
1932*05b00f60SXin Li }
1933