blob: f5501582ba7a3b8aec3455ec7f55a4857ab013fd [file] [log] [blame]
The Android Open Source Project2949f582009-03-03 19:30:46 -08001/*
2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3 * John Robert LoVerso. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
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.
15 *
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.
26 *
27 *
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
35 * to this file.
36 *
37 * Support for SNMPv2c/SNMPv3 and the ability to link the module against
38 * the libsmi was added by J. Schoenwaelder, Copyright (c) 1999.
39 *
40 * This started out as a very simple program, but the incremental decoding
41 * (into the BE structure) complicated things.
42 *
43 # Los Alamos National Laboratory
44 #
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
57 */
58
Elliott Hughes892a68b2015-10-19 14:43:53 -070059#define NETDISSECT_REWORKED
The Android Open Source Project2949f582009-03-03 19:30:46 -080060#ifdef HAVE_CONFIG_H
61#include "config.h"
62#endif
63
64#include <tcpdump-stdinc.h>
65
66#include <stdio.h>
67#include <string.h>
68
Elliott Hughes892a68b2015-10-19 14:43:53 -070069#ifdef USE_LIBSMI
The Android Open Source Project2949f582009-03-03 19:30:46 -080070#include <smi.h>
71#endif
72
73#include "interface.h"
The Android Open Source Project2949f582009-03-03 19:30:46 -080074
75#undef OPAQUE /* defined in <wingdi.h> */
76
Elliott Hughes892a68b2015-10-19 14:43:53 -070077static const char tstr[] = "[|snmp]";
78
The Android Open Source Project2949f582009-03-03 19:30:46 -080079/*
80 * Universal ASN.1 types
81 * (we only care about the tag values for those allowed in the Internet SMI)
82 */
Elliott Hughes892a68b2015-10-19 14:43:53 -070083static const char *Universal[] = {
The Android Open Source Project2949f582009-03-03 19:30:46 -080084 "U-0",
85 "Boolean",
86 "Integer",
87#define INTEGER 2
88 "Bitstring",
89 "String",
90#define STRING 4
91 "Null",
92#define ASN_NULL 5
93 "ObjID",
94#define OBJECTID 6
95 "ObjectDes",
96 "U-8","U-9","U-10","U-11", /* 8-11 */
97 "U-12","U-13","U-14","U-15", /* 12-15 */
98 "Sequence",
99#define SEQUENCE 16
100 "Set"
101};
102
103/*
104 * Application-wide ASN.1 types from the Internet SMI and their tags
105 */
Elliott Hughes892a68b2015-10-19 14:43:53 -0700106static const char *Application[] = {
The Android Open Source Project2949f582009-03-03 19:30:46 -0800107 "IpAddress",
108#define IPADDR 0
109 "Counter",
110#define COUNTER 1
111 "Gauge",
112#define GAUGE 2
113 "TimeTicks",
114#define TIMETICKS 3
115 "Opaque",
116#define OPAQUE 4
117 "C-5",
118 "Counter64"
119#define COUNTER64 6
120};
121
122/*
123 * Context-specific ASN.1 types for the SNMP PDUs and their tags
124 */
Elliott Hughes892a68b2015-10-19 14:43:53 -0700125static const char *Context[] = {
The Android Open Source Project2949f582009-03-03 19:30:46 -0800126 "GetRequest",
127#define GETREQ 0
128 "GetNextRequest",
129#define GETNEXTREQ 1
130 "GetResponse",
131#define GETRESP 2
132 "SetRequest",
133#define SETREQ 3
134 "Trap",
135#define TRAP 4
136 "GetBulk",
137#define GETBULKREQ 5
138 "Inform",
139#define INFORMREQ 6
140 "V2Trap",
141#define V2TRAP 7
142 "Report"
143#define REPORT 8
144};
145
146#define NOTIFY_CLASS(x) (x == TRAP || x == V2TRAP || x == INFORMREQ)
147#define READ_CLASS(x) (x == GETREQ || x == GETNEXTREQ || x == GETBULKREQ)
148#define WRITE_CLASS(x) (x == SETREQ)
149#define RESPONSE_CLASS(x) (x == GETRESP)
150#define INTERNAL_CLASS(x) (x == REPORT)
151
152/*
153 * Context-specific ASN.1 types for the SNMP Exceptions and their tags
154 */
Elliott Hughes892a68b2015-10-19 14:43:53 -0700155static const char *Exceptions[] = {
The Android Open Source Project2949f582009-03-03 19:30:46 -0800156 "noSuchObject",
157#define NOSUCHOBJECT 0
158 "noSuchInstance",
159#define NOSUCHINSTANCE 1
160 "endOfMibView",
161#define ENDOFMIBVIEW 2
162};
163
164/*
165 * Private ASN.1 types
166 * The Internet SMI does not specify any
167 */
Elliott Hughes892a68b2015-10-19 14:43:53 -0700168static const char *Private[] = {
The Android Open Source Project2949f582009-03-03 19:30:46 -0800169 "P-0"
170};
171
172/*
173 * error-status values for any SNMP PDU
174 */
Elliott Hughes892a68b2015-10-19 14:43:53 -0700175static const char *ErrorStatus[] = {
The Android Open Source Project2949f582009-03-03 19:30:46 -0800176 "noError",
177 "tooBig",
178 "noSuchName",
179 "badValue",
180 "readOnly",
181 "genErr",
182 "noAccess",
183 "wrongType",
184 "wrongLength",
185 "wrongEncoding",
186 "wrongValue",
187 "noCreation",
188 "inconsistentValue",
189 "resourceUnavailable",
190 "commitFailed",
191 "undoFailed",
192 "authorizationError",
193 "notWritable",
194 "inconsistentName"
195};
196#define DECODE_ErrorStatus(e) \
197 ( e >= 0 && (size_t)e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
198 ? ErrorStatus[e] \
199 : (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf))
200
201/*
202 * generic-trap values in the SNMP Trap-PDU
203 */
Elliott Hughes892a68b2015-10-19 14:43:53 -0700204static const char *GenericTrap[] = {
The Android Open Source Project2949f582009-03-03 19:30:46 -0800205 "coldStart",
206 "warmStart",
207 "linkDown",
208 "linkUp",
209 "authenticationFailure",
210 "egpNeighborLoss",
211 "enterpriseSpecific"
212#define GT_ENTERPRISE 6
213};
214#define DECODE_GenericTrap(t) \
215 ( t >= 0 && (size_t)t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
216 ? GenericTrap[t] \
217 : (snprintf(buf, sizeof(buf), "gt=%d", t), buf))
218
219/*
220 * ASN.1 type class table
221 * Ties together the preceding Universal, Application, Context, and Private
222 * type definitions.
223 */
224#define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
Elliott Hughes892a68b2015-10-19 14:43:53 -0700225static const struct {
The Android Open Source Project2949f582009-03-03 19:30:46 -0800226 const char *name;
227 const char **Id;
228 int numIDs;
229 } Class[] = {
230 defineCLASS(Universal),
231#define UNIVERSAL 0
232 defineCLASS(Application),
233#define APPLICATION 1
234 defineCLASS(Context),
235#define CONTEXT 2
236 defineCLASS(Private),
237#define PRIVATE 3
238 defineCLASS(Exceptions),
239#define EXCEPTIONS 4
240};
241
242/*
243 * defined forms for ASN.1 types
244 */
Elliott Hughes892a68b2015-10-19 14:43:53 -0700245static const char *Form[] = {
The Android Open Source Project2949f582009-03-03 19:30:46 -0800246 "Primitive",
247#define PRIMITIVE 0
248 "Constructed",
249#define CONSTRUCTED 1
250};
251
252/*
253 * A structure for the OID tree for the compiled-in MIB.
254 * This is stored as a general-order tree.
255 */
256struct obj {
257 const char *desc; /* name of object */
258 u_char oid; /* sub-id following parent */
259 u_char type; /* object type (unused) */
260 struct obj *child, *next; /* child and next sibling pointers */
261} *objp = NULL;
262
263/*
264 * Include the compiled in SNMP MIB. "mib.h" is produced by feeding
265 * RFC-1156 format files into "makemib". "mib.h" MUST define at least
266 * a value for `mibroot'.
267 *
268 * In particular, this is gross, as this is including initialized structures,
269 * and by right shouldn't be an "include" file.
270 */
271#include "mib.h"
272
273/*
274 * This defines a list of OIDs which will be abbreviated on output.
275 * Currently, this includes the prefixes for the Internet MIB, the
276 * private enterprises tree, and the experimental tree.
277 */
Elliott Hughes892a68b2015-10-19 14:43:53 -0700278static const struct obj_abrev {
The Android Open Source Project2949f582009-03-03 19:30:46 -0800279 const char *prefix; /* prefix for this abrev */
280 struct obj *node; /* pointer into object table */
281 const char *oid; /* ASN.1 encoded OID */
282} obj_abrev_list[] = {
283#ifndef NO_ABREV_MIB
284 /* .iso.org.dod.internet.mgmt.mib */
285 { "", &_mib_obj, "\53\6\1\2\1" },
286#endif
287#ifndef NO_ABREV_ENTER
288 /* .iso.org.dod.internet.private.enterprises */
289 { "E:", &_enterprises_obj, "\53\6\1\4\1" },
290#endif
291#ifndef NO_ABREV_EXPERI
292 /* .iso.org.dod.internet.experimental */
293 { "X:", &_experimental_obj, "\53\6\1\3" },
294#endif
295#ifndef NO_ABBREV_SNMPMODS
296 /* .iso.org.dod.internet.snmpV2.snmpModules */
297 { "S:", &_snmpModules_obj, "\53\6\1\6\3" },
298#endif
299 { 0,0,0 }
300};
301
302/*
303 * This is used in the OID print routine to walk down the object tree
304 * rooted at `mibroot'.
305 */
306#define OBJ_PRINT(o, suppressdot) \
307{ \
308 if (objp) { \
309 do { \
310 if ((o) == objp->oid) \
311 break; \
312 } while ((objp = objp->next) != NULL); \
313 } \
314 if (objp) { \
Elliott Hughes892a68b2015-10-19 14:43:53 -0700315 ND_PRINT((ndo, suppressdot?"%s":".%s", objp->desc)); \
The Android Open Source Project2949f582009-03-03 19:30:46 -0800316 objp = objp->child; \
317 } else \
Elliott Hughes892a68b2015-10-19 14:43:53 -0700318 ND_PRINT((ndo, suppressdot?"%u":".%u", (o))); \
The Android Open Source Project2949f582009-03-03 19:30:46 -0800319}
320
321/*
322 * This is the definition for the Any-Data-Type storage used purely for
323 * temporary internal representation while decoding an ASN.1 data stream.
324 */
325struct be {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700326 uint32_t asnlen;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800327 union {
328 caddr_t raw;
329 int32_t integer;
Elliott Hughes892a68b2015-10-19 14:43:53 -0700330 uint32_t uns;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800331 const u_char *str;
332 struct {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700333 uint32_t high;
334 uint32_t low;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800335 } uns64;
336 } data;
337 u_short id;
338 u_char form, class; /* tag info */
339 u_char type;
340#define BE_ANY 255
341#define BE_NONE 0
342#define BE_NULL 1
343#define BE_OCTET 2
344#define BE_OID 3
345#define BE_INT 4
346#define BE_UNS 5
347#define BE_STR 6
348#define BE_SEQ 7
349#define BE_INETADDR 8
350#define BE_PDU 9
351#define BE_UNS64 10
352#define BE_NOSUCHOBJECT 128
353#define BE_NOSUCHINST 129
354#define BE_ENDOFMIBVIEW 130
355};
356
357/*
358 * SNMP versions recognized by this module
359 */
Elliott Hughes892a68b2015-10-19 14:43:53 -0700360static const char *SnmpVersion[] = {
The Android Open Source Project2949f582009-03-03 19:30:46 -0800361 "SNMPv1",
362#define SNMP_VERSION_1 0
363 "SNMPv2c",
364#define SNMP_VERSION_2 1
365 "SNMPv2u",
366#define SNMP_VERSION_2U 2
367 "SNMPv3"
368#define SNMP_VERSION_3 3
369};
370
371/*
372 * Defaults for SNMP PDU components
373 */
374#define DEF_COMMUNITY "public"
375
376/*
377 * constants for ASN.1 decoding
378 */
379#define OIDMUX 40
380#define ASNLEN_INETADDR 4
381#define ASN_SHIFT7 7
382#define ASN_SHIFT8 8
383#define ASN_BIT8 0x80
384#define ASN_LONGLEN 0x80
385
386#define ASN_ID_BITS 0x1f
387#define ASN_FORM_BITS 0x20
388#define ASN_FORM_SHIFT 5
389#define ASN_CLASS_BITS 0xc0
390#define ASN_CLASS_SHIFT 6
391
392#define ASN_ID_EXT 0x1f /* extension ID in tag field */
393
394/*
395 * This decodes the next ASN.1 object in the stream pointed to by "p"
396 * (and of real-length "len") and stores the intermediate data in the
397 * provided BE object.
398 *
399 * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
400 * O/w, this returns the number of bytes parsed from "p".
401 */
402static int
Elliott Hughes892a68b2015-10-19 14:43:53 -0700403asn1_parse(netdissect_options *ndo,
404 register const u_char *p, u_int len, struct be *elem)
The Android Open Source Project2949f582009-03-03 19:30:46 -0800405{
406 u_char form, class, id;
407 int i, hdr;
408
409 elem->asnlen = 0;
410 elem->type = BE_ANY;
411 if (len < 1) {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700412 ND_PRINT((ndo, "[nothing to parse]"));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800413 return -1;
414 }
Elliott Hughes892a68b2015-10-19 14:43:53 -0700415 ND_TCHECK(*p);
The Android Open Source Project2949f582009-03-03 19:30:46 -0800416
417 /*
418 * it would be nice to use a bit field, but you can't depend on them.
419 * +---+---+---+---+---+---+---+---+
420 * + class |frm| id |
421 * +---+---+---+---+---+---+---+---+
422 * 7 6 5 4 3 2 1 0
423 */
424 id = *p & ASN_ID_BITS; /* lower 5 bits, range 00-1f */
425#ifdef notdef
426 form = (*p & 0xe0) >> 5; /* move upper 3 bits to lower 3 */
427 class = form >> 1; /* bits 7&6 -> bits 1&0, range 0-3 */
428 form &= 0x1; /* bit 5 -> bit 0, range 0-1 */
429#else
430 form = (u_char)(*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
431 class = (u_char)(*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
432#endif
433 elem->form = form;
434 elem->class = class;
435 elem->id = id;
436 p++; len--; hdr = 1;
437 /* extended tag field */
438 if (id == ASN_ID_EXT) {
439 /*
440 * The ID follows, as a sequence of octets with the
441 * 8th bit set and the remaining 7 bits being
442 * the next 7 bits of the value, terminated with
443 * an octet with the 8th bit not set.
444 *
445 * First, assemble all the octets with the 8th
446 * bit set. XXX - this doesn't handle a value
447 * that won't fit in 32 bits.
448 */
449 for (id = 0; *p & ASN_BIT8; len--, hdr++, p++) {
450 if (len < 1) {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700451 ND_PRINT((ndo, "[Xtagfield?]"));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800452 return -1;
453 }
Elliott Hughes892a68b2015-10-19 14:43:53 -0700454 ND_TCHECK(*p);
The Android Open Source Project2949f582009-03-03 19:30:46 -0800455 id = (id << 7) | (*p & ~ASN_BIT8);
456 }
457 if (len < 1) {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700458 ND_PRINT((ndo, "[Xtagfield?]"));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800459 return -1;
460 }
Elliott Hughes892a68b2015-10-19 14:43:53 -0700461 ND_TCHECK(*p);
The Android Open Source Project2949f582009-03-03 19:30:46 -0800462 elem->id = id = (id << 7) | *p;
463 --len;
464 ++hdr;
465 ++p;
466 }
467 if (len < 1) {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700468 ND_PRINT((ndo, "[no asnlen]"));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800469 return -1;
470 }
Elliott Hughes892a68b2015-10-19 14:43:53 -0700471 ND_TCHECK(*p);
The Android Open Source Project2949f582009-03-03 19:30:46 -0800472 elem->asnlen = *p;
473 p++; len--; hdr++;
474 if (elem->asnlen & ASN_BIT8) {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700475 uint32_t noct = elem->asnlen % ASN_BIT8;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800476 elem->asnlen = 0;
477 if (len < noct) {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700478 ND_PRINT((ndo, "[asnlen? %d<%d]", len, noct));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800479 return -1;
480 }
Elliott Hughes892a68b2015-10-19 14:43:53 -0700481 ND_TCHECK2(*p, noct);
The Android Open Source Project2949f582009-03-03 19:30:46 -0800482 for (; noct-- > 0; len--, hdr++)
483 elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++;
484 }
485 if (len < elem->asnlen) {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700486 ND_PRINT((ndo, "[len%d<asnlen%u]", len, elem->asnlen));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800487 return -1;
488 }
489 if (form >= sizeof(Form)/sizeof(Form[0])) {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700490 ND_PRINT((ndo, "[form?%d]", form));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800491 return -1;
492 }
493 if (class >= sizeof(Class)/sizeof(Class[0])) {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700494 ND_PRINT((ndo, "[class?%c/%d]", *Form[form], class));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800495 return -1;
496 }
497 if ((int)id >= Class[class].numIDs) {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700498 ND_PRINT((ndo, "[id?%c/%s/%d]", *Form[form], Class[class].name, id));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800499 return -1;
500 }
501
502 switch (form) {
503 case PRIMITIVE:
504 switch (class) {
505 case UNIVERSAL:
506 switch (id) {
507 case STRING:
508 elem->type = BE_STR;
509 elem->data.str = p;
510 break;
511
512 case INTEGER: {
513 register int32_t data;
514 elem->type = BE_INT;
515 data = 0;
516
Elliott Hughes892a68b2015-10-19 14:43:53 -0700517 ND_TCHECK2(*p, elem->asnlen);
The Android Open Source Project2949f582009-03-03 19:30:46 -0800518 if (*p & ASN_BIT8) /* negative */
519 data = -1;
520 for (i = elem->asnlen; i-- > 0; p++)
521 data = (data << ASN_SHIFT8) | *p;
522 elem->data.integer = data;
523 break;
524 }
525
526 case OBJECTID:
527 elem->type = BE_OID;
528 elem->data.raw = (caddr_t)p;
529 break;
530
531 case ASN_NULL:
532 elem->type = BE_NULL;
533 elem->data.raw = NULL;
534 break;
535
536 default:
537 elem->type = BE_OCTET;
538 elem->data.raw = (caddr_t)p;
Elliott Hughes892a68b2015-10-19 14:43:53 -0700539 ND_PRINT((ndo, "[P/U/%s]", Class[class].Id[id]));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800540 break;
541 }
542 break;
543
544 case APPLICATION:
545 switch (id) {
546 case IPADDR:
547 elem->type = BE_INETADDR;
548 elem->data.raw = (caddr_t)p;
549 break;
550
551 case COUNTER:
552 case GAUGE:
553 case TIMETICKS: {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700554 register uint32_t data;
555 ND_TCHECK2(*p, elem->asnlen);
The Android Open Source Project2949f582009-03-03 19:30:46 -0800556 elem->type = BE_UNS;
557 data = 0;
558 for (i = elem->asnlen; i-- > 0; p++)
559 data = (data << 8) + *p;
560 elem->data.uns = data;
561 break;
562 }
563
564 case COUNTER64: {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700565 register uint32_t high, low;
566 ND_TCHECK2(*p, elem->asnlen);
The Android Open Source Project2949f582009-03-03 19:30:46 -0800567 elem->type = BE_UNS64;
568 high = 0, low = 0;
569 for (i = elem->asnlen; i-- > 0; p++) {
570 high = (high << 8) |
571 ((low & 0xFF000000) >> 24);
572 low = (low << 8) | *p;
573 }
574 elem->data.uns64.high = high;
575 elem->data.uns64.low = low;
576 break;
577 }
578
579 default:
580 elem->type = BE_OCTET;
581 elem->data.raw = (caddr_t)p;
Elliott Hughes892a68b2015-10-19 14:43:53 -0700582 ND_PRINT((ndo, "[P/A/%s]",
583 Class[class].Id[id]));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800584 break;
585 }
586 break;
587
588 case CONTEXT:
589 switch (id) {
590 case NOSUCHOBJECT:
591 elem->type = BE_NOSUCHOBJECT;
592 elem->data.raw = NULL;
593 break;
594
595 case NOSUCHINSTANCE:
596 elem->type = BE_NOSUCHINST;
597 elem->data.raw = NULL;
598 break;
599
600 case ENDOFMIBVIEW:
601 elem->type = BE_ENDOFMIBVIEW;
602 elem->data.raw = NULL;
603 break;
604 }
605 break;
606
607 default:
Elliott Hughes892a68b2015-10-19 14:43:53 -0700608 ND_PRINT((ndo, "[P/%s/%s]", Class[class].name, Class[class].Id[id]));
609 ND_TCHECK2(*p, elem->asnlen);
The Android Open Source Project2949f582009-03-03 19:30:46 -0800610 elem->type = BE_OCTET;
611 elem->data.raw = (caddr_t)p;
612 break;
613 }
614 break;
615
616 case CONSTRUCTED:
617 switch (class) {
618 case UNIVERSAL:
619 switch (id) {
620 case SEQUENCE:
621 elem->type = BE_SEQ;
622 elem->data.raw = (caddr_t)p;
623 break;
624
625 default:
626 elem->type = BE_OCTET;
627 elem->data.raw = (caddr_t)p;
Elliott Hughes892a68b2015-10-19 14:43:53 -0700628 ND_PRINT((ndo, "C/U/%s", Class[class].Id[id]));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800629 break;
630 }
631 break;
632
633 case CONTEXT:
634 elem->type = BE_PDU;
635 elem->data.raw = (caddr_t)p;
636 break;
637
638 default:
639 elem->type = BE_OCTET;
640 elem->data.raw = (caddr_t)p;
Elliott Hughes892a68b2015-10-19 14:43:53 -0700641 ND_PRINT((ndo, "C/%s/%s", Class[class].name, Class[class].Id[id]));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800642 break;
643 }
644 break;
645 }
646 p += elem->asnlen;
647 len -= elem->asnlen;
648 return elem->asnlen + hdr;
649
650trunc:
Elliott Hughes892a68b2015-10-19 14:43:53 -0700651 ND_PRINT((ndo, "%s", tstr));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800652 return -1;
653}
654
655/*
656 * Display the ASN.1 object represented by the BE object.
657 * This used to be an integral part of asn1_parse() before the intermediate
658 * BE form was added.
659 */
660static int
Elliott Hughes892a68b2015-10-19 14:43:53 -0700661asn1_print(netdissect_options *ndo,
662 struct be *elem)
The Android Open Source Project2949f582009-03-03 19:30:46 -0800663{
664 u_char *p = (u_char *)elem->data.raw;
Elliott Hughes892a68b2015-10-19 14:43:53 -0700665 uint32_t asnlen = elem->asnlen;
666 uint32_t i;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800667
668 switch (elem->type) {
669
670 case BE_OCTET:
Elliott Hughes892a68b2015-10-19 14:43:53 -0700671 ND_TCHECK2(*p, asnlen);
The Android Open Source Project2949f582009-03-03 19:30:46 -0800672 for (i = asnlen; i-- > 0; p++)
Elliott Hughes892a68b2015-10-19 14:43:53 -0700673 ND_PRINT((ndo, "_%.2x", *p));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800674 break;
675
676 case BE_NULL:
677 break;
678
679 case BE_OID: {
680 int o = 0, first = -1, i = asnlen;
681
Elliott Hughes892a68b2015-10-19 14:43:53 -0700682 if (!ndo->ndo_sflag && !ndo->ndo_nflag && asnlen > 2) {
683 const struct obj_abrev *a = &obj_abrev_list[0];
The Android Open Source Project2949f582009-03-03 19:30:46 -0800684 size_t a_len = strlen(a->oid);
685 for (; a->node; a++) {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700686 ND_TCHECK2(*p, a_len);
The Android Open Source Project2949f582009-03-03 19:30:46 -0800687 if (memcmp(a->oid, (char *)p, a_len) == 0) {
688 objp = a->node->child;
689 i -= strlen(a->oid);
690 p += strlen(a->oid);
Elliott Hughes892a68b2015-10-19 14:43:53 -0700691 ND_PRINT((ndo, "%s", a->prefix));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800692 first = 1;
693 break;
694 }
695 }
696 }
697
Elliott Hughes892a68b2015-10-19 14:43:53 -0700698 for (; !ndo->ndo_sflag && i-- > 0; p++) {
699 ND_TCHECK(*p);
The Android Open Source Project2949f582009-03-03 19:30:46 -0800700 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
701 if (*p & ASN_LONGLEN)
702 continue;
703
704 /*
705 * first subitem encodes two items with 1st*OIDMUX+2nd
706 * (see X.690:1997 clause 8.19 for the details)
707 */
708 if (first < 0) {
709 int s;
Elliott Hughes892a68b2015-10-19 14:43:53 -0700710 if (!ndo->ndo_nflag)
The Android Open Source Project2949f582009-03-03 19:30:46 -0800711 objp = mibroot;
712 first = 0;
713 s = o / OIDMUX;
714 if (s > 2) s = 2;
715 OBJ_PRINT(s, first);
716 o -= s * OIDMUX;
717 }
718 OBJ_PRINT(o, first);
719 if (--first < 0)
720 first = 0;
721 o = 0;
722 }
723 break;
724 }
725
726 case BE_INT:
Elliott Hughes892a68b2015-10-19 14:43:53 -0700727 ND_PRINT((ndo, "%d", elem->data.integer));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800728 break;
729
730 case BE_UNS:
Elliott Hughes892a68b2015-10-19 14:43:53 -0700731 ND_PRINT((ndo, "%u", elem->data.uns));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800732 break;
733
734 case BE_UNS64: { /* idea borrowed from by Marshall Rose */
735 double d;
736 int j, carry;
737 char *cpf, *cpl, last[6], first[30];
738 if (elem->data.uns64.high == 0) {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700739 ND_PRINT((ndo, "%u", elem->data.uns64.low));
740 break;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800741 }
742 d = elem->data.uns64.high * 4294967296.0; /* 2^32 */
743 if (elem->data.uns64.high <= 0x1fffff) {
744 d += elem->data.uns64.low;
745#if 0 /*is looks illegal, but what is the intention?*/
Elliott Hughes892a68b2015-10-19 14:43:53 -0700746 ND_PRINT((ndo, "%.f", d));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800747#else
Elliott Hughes892a68b2015-10-19 14:43:53 -0700748 ND_PRINT((ndo, "%f", d));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800749#endif
750 break;
751 }
752 d += (elem->data.uns64.low & 0xfffff000);
753#if 0 /*is looks illegal, but what is the intention?*/
754 snprintf(first, sizeof(first), "%.f", d);
755#else
756 snprintf(first, sizeof(first), "%f", d);
757#endif
758 snprintf(last, sizeof(last), "%5.5d",
759 elem->data.uns64.low & 0xfff);
760 for (carry = 0, cpf = first+strlen(first)-1, cpl = last+4;
761 cpl >= last;
762 cpf--, cpl--) {
763 j = carry + (*cpf - '0') + (*cpl - '0');
764 if (j > 9) {
765 j -= 10;
766 carry = 1;
767 } else {
768 carry = 0;
769 }
770 *cpf = j + '0';
771 }
Elliott Hughes892a68b2015-10-19 14:43:53 -0700772 ND_PRINT((ndo, "%s", first));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800773 break;
774 }
775
776 case BE_STR: {
777 register int printable = 1, first = 1;
778 const u_char *p = elem->data.str;
Elliott Hughes892a68b2015-10-19 14:43:53 -0700779 ND_TCHECK2(*p, asnlen);
The Android Open Source Project2949f582009-03-03 19:30:46 -0800780 for (i = asnlen; printable && i-- > 0; p++)
JP Abgrall53f17a92014-02-12 14:02:41 -0800781 printable = ND_ISPRINT(*p);
The Android Open Source Project2949f582009-03-03 19:30:46 -0800782 p = elem->data.str;
783 if (printable) {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700784 ND_PRINT((ndo, "\""));
785 if (fn_printn(ndo, p, asnlen, ndo->ndo_snapend)) {
786 ND_PRINT((ndo, "\""));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800787 goto trunc;
788 }
Elliott Hughes892a68b2015-10-19 14:43:53 -0700789 ND_PRINT((ndo, "\""));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800790 } else
791 for (i = asnlen; i-- > 0; p++) {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700792 ND_PRINT((ndo, first ? "%.2x" : "_%.2x", *p));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800793 first = 0;
794 }
795 break;
796 }
797
798 case BE_SEQ:
Elliott Hughes892a68b2015-10-19 14:43:53 -0700799 ND_PRINT((ndo, "Seq(%u)", elem->asnlen));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800800 break;
801
802 case BE_INETADDR:
803 if (asnlen != ASNLEN_INETADDR)
Elliott Hughes892a68b2015-10-19 14:43:53 -0700804 ND_PRINT((ndo, "[inetaddr len!=%d]", ASNLEN_INETADDR));
805 ND_TCHECK2(*p, asnlen);
The Android Open Source Project2949f582009-03-03 19:30:46 -0800806 for (i = asnlen; i-- != 0; p++) {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700807 ND_PRINT((ndo, (i == asnlen-1) ? "%u" : ".%u", *p));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800808 }
809 break;
810
811 case BE_NOSUCHOBJECT:
812 case BE_NOSUCHINST:
813 case BE_ENDOFMIBVIEW:
Elliott Hughes892a68b2015-10-19 14:43:53 -0700814 ND_PRINT((ndo, "[%s]", Class[EXCEPTIONS].Id[elem->id]));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800815 break;
816
817 case BE_PDU:
Elliott Hughes892a68b2015-10-19 14:43:53 -0700818 ND_PRINT((ndo, "%s(%u)", Class[CONTEXT].Id[elem->id], elem->asnlen));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800819 break;
820
821 case BE_ANY:
Elliott Hughes892a68b2015-10-19 14:43:53 -0700822 ND_PRINT((ndo, "[BE_ANY!?]"));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800823 break;
824
825 default:
Elliott Hughes892a68b2015-10-19 14:43:53 -0700826 ND_PRINT((ndo, "[be!?]"));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800827 break;
828 }
829 return 0;
830
831trunc:
Elliott Hughes892a68b2015-10-19 14:43:53 -0700832 ND_PRINT((ndo, "%s", tstr));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800833 return -1;
834}
835
836#ifdef notdef
837/*
838 * This is a brute force ASN.1 printer: recurses to dump an entire structure.
839 * This will work for any ASN.1 stream, not just an SNMP PDU.
840 *
841 * By adding newlines and spaces at the correct places, this would print in
842 * Rose-Normal-Form.
843 *
844 * This is not currently used.
845 */
846static void
847asn1_decode(u_char *p, u_int length)
848{
849 struct be elem;
850 int i = 0;
851
852 while (i >= 0 && length > 0) {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700853 i = asn1_parse(ndo, p, length, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -0800854 if (i >= 0) {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700855 ND_PRINT((ndo, " "));
856 if (asn1_print(ndo, &elem) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -0800857 return;
858 if (elem.type == BE_SEQ || elem.type == BE_PDU) {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700859 ND_PRINT((ndo, " {"));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800860 asn1_decode(elem.data.raw, elem.asnlen);
Elliott Hughes892a68b2015-10-19 14:43:53 -0700861 ND_PRINT((ndo, " }"));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800862 }
863 length -= i;
864 p += i;
865 }
866 }
867}
868#endif
869
Elliott Hughes892a68b2015-10-19 14:43:53 -0700870#ifdef USE_LIBSMI
The Android Open Source Project2949f582009-03-03 19:30:46 -0800871
872struct smi2be {
873 SmiBasetype basetype;
874 int be;
875};
876
Elliott Hughes892a68b2015-10-19 14:43:53 -0700877static const struct smi2be smi2betab[] = {
The Android Open Source Project2949f582009-03-03 19:30:46 -0800878 { SMI_BASETYPE_INTEGER32, BE_INT },
879 { SMI_BASETYPE_OCTETSTRING, BE_STR },
880 { SMI_BASETYPE_OCTETSTRING, BE_INETADDR },
881 { SMI_BASETYPE_OBJECTIDENTIFIER, BE_OID },
882 { SMI_BASETYPE_UNSIGNED32, BE_UNS },
883 { SMI_BASETYPE_INTEGER64, BE_NONE },
884 { SMI_BASETYPE_UNSIGNED64, BE_UNS64 },
885 { SMI_BASETYPE_FLOAT32, BE_NONE },
886 { SMI_BASETYPE_FLOAT64, BE_NONE },
887 { SMI_BASETYPE_FLOAT128, BE_NONE },
888 { SMI_BASETYPE_ENUM, BE_INT },
889 { SMI_BASETYPE_BITS, BE_STR },
890 { SMI_BASETYPE_UNKNOWN, BE_NONE }
891};
892
893static int
Elliott Hughes892a68b2015-10-19 14:43:53 -0700894smi_decode_oid(netdissect_options *ndo,
895 struct be *elem, unsigned int *oid,
896 unsigned int oidsize, unsigned int *oidlen)
The Android Open Source Project2949f582009-03-03 19:30:46 -0800897{
898 u_char *p = (u_char *)elem->data.raw;
Elliott Hughes892a68b2015-10-19 14:43:53 -0700899 uint32_t asnlen = elem->asnlen;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800900 int o = 0, first = -1, i = asnlen;
Elliott Hughes892a68b2015-10-19 14:43:53 -0700901 unsigned int firstval;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800902
Elliott Hughes892a68b2015-10-19 14:43:53 -0700903 for (*oidlen = 0; ndo->ndo_sflag && i-- > 0; p++) {
904 ND_TCHECK(*p);
The Android Open Source Project2949f582009-03-03 19:30:46 -0800905 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
906 if (*p & ASN_LONGLEN)
907 continue;
908
909 /*
910 * first subitem encodes two items with 1st*OIDMUX+2nd
911 * (see X.690:1997 clause 8.19 for the details)
912 */
913 if (first < 0) {
914 first = 0;
Elliott Hughes892a68b2015-10-19 14:43:53 -0700915 firstval = o / OIDMUX;
916 if (firstval > 2) firstval = 2;
917 o -= firstval * OIDMUX;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800918 if (*oidlen < oidsize) {
Elliott Hughes892a68b2015-10-19 14:43:53 -0700919 oid[(*oidlen)++] = firstval;
The Android Open Source Project2949f582009-03-03 19:30:46 -0800920 }
The Android Open Source Project2949f582009-03-03 19:30:46 -0800921 }
922 if (*oidlen < oidsize) {
923 oid[(*oidlen)++] = o;
924 }
925 o = 0;
926 }
927 return 0;
928
929trunc:
Elliott Hughes892a68b2015-10-19 14:43:53 -0700930 ND_PRINT((ndo, "%s", tstr));
The Android Open Source Project2949f582009-03-03 19:30:46 -0800931 return -1;
932}
933
934static int smi_check_type(SmiBasetype basetype, int be)
935{
936 int i;
937
938 for (i = 0; smi2betab[i].basetype != SMI_BASETYPE_UNKNOWN; i++) {
939 if (smi2betab[i].basetype == basetype && smi2betab[i].be == be) {
940 return 1;
941 }
942 }
943
944 return 0;
945}
946
947static int smi_check_a_range(SmiType *smiType, SmiRange *smiRange,
948 struct be *elem)
949{
950 int ok = 1;
951
952 switch (smiType->basetype) {
953 case SMI_BASETYPE_OBJECTIDENTIFIER:
954 case SMI_BASETYPE_OCTETSTRING:
955 if (smiRange->minValue.value.unsigned32
956 == smiRange->maxValue.value.unsigned32) {
957 ok = (elem->asnlen == smiRange->minValue.value.unsigned32);
958 } else {
959 ok = (elem->asnlen >= smiRange->minValue.value.unsigned32
960 && elem->asnlen <= smiRange->maxValue.value.unsigned32);
961 }
962 break;
963
964 case SMI_BASETYPE_INTEGER32:
965 ok = (elem->data.integer >= smiRange->minValue.value.integer32
966 && elem->data.integer <= smiRange->maxValue.value.integer32);
967 break;
968
969 case SMI_BASETYPE_UNSIGNED32:
970 ok = (elem->data.uns >= smiRange->minValue.value.unsigned32
971 && elem->data.uns <= smiRange->maxValue.value.unsigned32);
972 break;
973
974 case SMI_BASETYPE_UNSIGNED64:
975 /* XXX */
976 break;
977
978 /* case SMI_BASETYPE_INTEGER64: SMIng */
979 /* case SMI_BASETYPE_FLOAT32: SMIng */
980 /* case SMI_BASETYPE_FLOAT64: SMIng */
981 /* case SMI_BASETYPE_FLOAT128: SMIng */
982
983 case SMI_BASETYPE_ENUM:
984 case SMI_BASETYPE_BITS:
985 case SMI_BASETYPE_UNKNOWN:
986 ok = 1;
987 break;
988
989 default:
990 ok = 0;
991 break;
992 }
993
994 return ok;
995}
996
997static int smi_check_range(SmiType *smiType, struct be *elem)
998{
999 SmiRange *smiRange;
1000 int ok = 1;
1001
1002 for (smiRange = smiGetFirstRange(smiType);
1003 smiRange;
1004 smiRange = smiGetNextRange(smiRange)) {
1005
1006 ok = smi_check_a_range(smiType, smiRange, elem);
1007
1008 if (ok) {
1009 break;
1010 }
1011 }
1012
1013 if (ok) {
1014 SmiType *parentType;
1015 parentType = smiGetParentType(smiType);
1016 if (parentType) {
1017 ok = smi_check_range(parentType, elem);
1018 }
1019 }
1020
1021 return ok;
1022}
1023
Elliott Hughes892a68b2015-10-19 14:43:53 -07001024static SmiNode *
1025smi_print_variable(netdissect_options *ndo,
1026 struct be *elem, int *status)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001027{
1028 unsigned int oid[128], oidlen;
1029 SmiNode *smiNode = NULL;
1030 unsigned int i;
1031
Elliott Hughes892a68b2015-10-19 14:43:53 -07001032 *status = smi_decode_oid(ndo, elem, oid, sizeof(oid) / sizeof(unsigned int),
The Android Open Source Project2949f582009-03-03 19:30:46 -08001033 &oidlen);
1034 if (*status < 0)
1035 return NULL;
1036 smiNode = smiGetNodeByOID(oidlen, oid);
1037 if (! smiNode) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001038 *status = asn1_print(ndo, elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001039 return NULL;
1040 }
Elliott Hughes892a68b2015-10-19 14:43:53 -07001041 if (ndo->ndo_vflag) {
1042 ND_PRINT((ndo, "%s::", smiGetNodeModule(smiNode)->name));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001043 }
Elliott Hughes892a68b2015-10-19 14:43:53 -07001044 ND_PRINT((ndo, "%s", smiNode->name));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001045 if (smiNode->oidlen < oidlen) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001046 for (i = smiNode->oidlen; i < oidlen; i++) {
1047 ND_PRINT((ndo, ".%u", oid[i]));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001048 }
1049 }
1050 *status = 0;
1051 return smiNode;
1052}
1053
1054static int
Elliott Hughes892a68b2015-10-19 14:43:53 -07001055smi_print_value(netdissect_options *ndo,
1056 SmiNode *smiNode, u_char pduid, struct be *elem)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001057{
1058 unsigned int i, oid[128], oidlen;
1059 SmiType *smiType;
1060 SmiNamedNumber *nn;
1061 int done = 0;
1062
1063 if (! smiNode || ! (smiNode->nodekind
1064 & (SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN))) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001065 return asn1_print(ndo, elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001066 }
1067
1068 if (elem->type == BE_NOSUCHOBJECT
1069 || elem->type == BE_NOSUCHINST
1070 || elem->type == BE_ENDOFMIBVIEW) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001071 return asn1_print(ndo, elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001072 }
1073
1074 if (NOTIFY_CLASS(pduid) && smiNode->access < SMI_ACCESS_NOTIFY) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001075 ND_PRINT((ndo, "[notNotifyable]"));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001076 }
1077
1078 if (READ_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_ONLY) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001079 ND_PRINT((ndo, "[notReadable]"));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001080 }
1081
1082 if (WRITE_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_WRITE) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001083 ND_PRINT((ndo, "[notWritable]"));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001084 }
1085
1086 if (RESPONSE_CLASS(pduid)
1087 && smiNode->access == SMI_ACCESS_NOT_ACCESSIBLE) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001088 ND_PRINT((ndo, "[noAccess]"));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001089 }
1090
1091 smiType = smiGetNodeType(smiNode);
1092 if (! smiType) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001093 return asn1_print(ndo, elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001094 }
1095
1096 if (! smi_check_type(smiType->basetype, elem->type)) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001097 ND_PRINT((ndo, "[wrongType]"));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001098 }
1099
1100 if (! smi_check_range(smiType, elem)) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001101 ND_PRINT((ndo, "[outOfRange]"));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001102 }
1103
1104 /* resolve bits to named bits */
1105
1106 /* check whether instance identifier is valid */
1107
1108 /* apply display hints (integer, octetstring) */
1109
1110 /* convert instance identifier to index type values */
1111
1112 switch (elem->type) {
1113 case BE_OID:
1114 if (smiType->basetype == SMI_BASETYPE_BITS) {
1115 /* print bit labels */
1116 } else {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001117 smi_decode_oid(ndo, elem, oid,
The Android Open Source Project2949f582009-03-03 19:30:46 -08001118 sizeof(oid)/sizeof(unsigned int),
1119 &oidlen);
1120 smiNode = smiGetNodeByOID(oidlen, oid);
1121 if (smiNode) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001122 if (ndo->ndo_vflag) {
1123 ND_PRINT((ndo, "%s::", smiGetNodeModule(smiNode)->name));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001124 }
Elliott Hughes892a68b2015-10-19 14:43:53 -07001125 ND_PRINT((ndo, "%s", smiNode->name));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001126 if (smiNode->oidlen < oidlen) {
1127 for (i = smiNode->oidlen;
1128 i < oidlen; i++) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001129 ND_PRINT((ndo, ".%u", oid[i]));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001130 }
1131 }
1132 done++;
1133 }
1134 }
1135 break;
1136
1137 case BE_INT:
1138 if (smiType->basetype == SMI_BASETYPE_ENUM) {
1139 for (nn = smiGetFirstNamedNumber(smiType);
1140 nn;
1141 nn = smiGetNextNamedNumber(nn)) {
1142 if (nn->value.value.integer32
1143 == elem->data.integer) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001144 ND_PRINT((ndo, "%s", nn->name));
1145 ND_PRINT((ndo, "(%d)", elem->data.integer));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001146 done++;
1147 break;
1148 }
1149 }
1150 }
1151 break;
1152 }
1153
1154 if (! done) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001155 return asn1_print(ndo, elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001156 }
1157 return 0;
1158}
1159#endif
1160
1161/*
1162 * General SNMP header
1163 * SEQUENCE {
1164 * version INTEGER {version-1(0)},
1165 * community OCTET STRING,
1166 * data ANY -- PDUs
1167 * }
1168 * PDUs for all but Trap: (see rfc1157 from page 15 on)
1169 * SEQUENCE {
1170 * request-id INTEGER,
1171 * error-status INTEGER,
1172 * error-index INTEGER,
1173 * varbindlist SEQUENCE OF
1174 * SEQUENCE {
1175 * name ObjectName,
1176 * value ObjectValue
1177 * }
1178 * }
1179 * PDU for Trap:
1180 * SEQUENCE {
1181 * enterprise OBJECT IDENTIFIER,
1182 * agent-addr NetworkAddress,
1183 * generic-trap INTEGER,
1184 * specific-trap INTEGER,
1185 * time-stamp TimeTicks,
1186 * varbindlist SEQUENCE OF
1187 * SEQUENCE {
1188 * name ObjectName,
1189 * value ObjectValue
1190 * }
1191 * }
1192 */
1193
1194/*
1195 * Decode SNMP varBind
1196 */
1197static void
Elliott Hughes892a68b2015-10-19 14:43:53 -07001198varbind_print(netdissect_options *ndo,
1199 u_char pduid, const u_char *np, u_int length)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001200{
1201 struct be elem;
1202 int count = 0, ind;
Elliott Hughes892a68b2015-10-19 14:43:53 -07001203#ifdef USE_LIBSMI
The Android Open Source Project2949f582009-03-03 19:30:46 -08001204 SmiNode *smiNode = NULL;
1205#endif
1206 int status;
1207
1208 /* Sequence of varBind */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001209 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001210 return;
1211 if (elem.type != BE_SEQ) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001212 ND_PRINT((ndo, "[!SEQ of varbind]"));
1213 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001214 return;
1215 }
1216 if ((u_int)count < length)
Elliott Hughes892a68b2015-10-19 14:43:53 -07001217 ND_PRINT((ndo, "[%d extra after SEQ of varbind]", length - count));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001218 /* descend */
1219 length = elem.asnlen;
1220 np = (u_char *)elem.data.raw;
1221
1222 for (ind = 1; length > 0; ind++) {
1223 const u_char *vbend;
1224 u_int vblength;
1225
Elliott Hughes892a68b2015-10-19 14:43:53 -07001226 ND_PRINT((ndo, " "));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001227
1228 /* Sequence */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001229 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001230 return;
1231 if (elem.type != BE_SEQ) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001232 ND_PRINT((ndo, "[!varbind]"));
1233 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001234 return;
1235 }
1236 vbend = np + count;
1237 vblength = length - count;
1238 /* descend */
1239 length = elem.asnlen;
1240 np = (u_char *)elem.data.raw;
1241
1242 /* objName (OID) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001243 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001244 return;
1245 if (elem.type != BE_OID) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001246 ND_PRINT((ndo, "[objName!=OID]"));
1247 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001248 return;
1249 }
Elliott Hughes892a68b2015-10-19 14:43:53 -07001250#ifdef USE_LIBSMI
1251 smiNode = smi_print_variable(ndo, &elem, &status);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001252#else
Elliott Hughes892a68b2015-10-19 14:43:53 -07001253 status = asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001254#endif
1255 if (status < 0)
1256 return;
1257 length -= count;
1258 np += count;
1259
1260 if (pduid != GETREQ && pduid != GETNEXTREQ
1261 && pduid != GETBULKREQ)
Elliott Hughes892a68b2015-10-19 14:43:53 -07001262 ND_PRINT((ndo, "="));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001263
1264 /* objVal (ANY) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001265 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001266 return;
1267 if (pduid == GETREQ || pduid == GETNEXTREQ
1268 || pduid == GETBULKREQ) {
1269 if (elem.type != BE_NULL) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001270 ND_PRINT((ndo, "[objVal!=NULL]"));
1271 if (asn1_print(ndo, &elem) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001272 return;
1273 }
1274 } else {
1275 if (elem.type != BE_NULL) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001276#ifdef USE_LIBSMI
1277 status = smi_print_value(ndo, smiNode, pduid, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001278#else
Elliott Hughes892a68b2015-10-19 14:43:53 -07001279 status = asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001280#endif
1281 }
1282 if (status < 0)
1283 return;
1284 }
1285 length = vblength;
1286 np = vbend;
1287 }
1288}
1289
1290/*
1291 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
1292 * GetBulk, Inform, V2Trap, and Report
1293 */
1294static void
Elliott Hughes892a68b2015-10-19 14:43:53 -07001295snmppdu_print(netdissect_options *ndo,
1296 u_short pduid, const u_char *np, u_int length)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001297{
1298 struct be elem;
1299 int count = 0, error;
1300
1301 /* reqId (Integer) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001302 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001303 return;
1304 if (elem.type != BE_INT) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001305 ND_PRINT((ndo, "[reqId!=INT]"));
1306 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001307 return;
1308 }
Elliott Hughes892a68b2015-10-19 14:43:53 -07001309 if (ndo->ndo_vflag)
1310 ND_PRINT((ndo, "R=%d ", elem.data.integer));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001311 length -= count;
1312 np += count;
1313
1314 /* errorStatus (Integer) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001315 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001316 return;
1317 if (elem.type != BE_INT) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001318 ND_PRINT((ndo, "[errorStatus!=INT]"));
1319 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001320 return;
1321 }
1322 error = 0;
1323 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1324 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1325 && elem.data.integer != 0) {
1326 char errbuf[20];
Elliott Hughes892a68b2015-10-19 14:43:53 -07001327 ND_PRINT((ndo, "[errorStatus(%s)!=0]",
1328 DECODE_ErrorStatus(elem.data.integer)));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001329 } else if (pduid == GETBULKREQ) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001330 ND_PRINT((ndo, " N=%d", elem.data.integer));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001331 } else if (elem.data.integer != 0) {
1332 char errbuf[20];
Elliott Hughes892a68b2015-10-19 14:43:53 -07001333 ND_PRINT((ndo, " %s", DECODE_ErrorStatus(elem.data.integer)));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001334 error = elem.data.integer;
1335 }
1336 length -= count;
1337 np += count;
1338
1339 /* errorIndex (Integer) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001340 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001341 return;
1342 if (elem.type != BE_INT) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001343 ND_PRINT((ndo, "[errorIndex!=INT]"));
1344 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001345 return;
1346 }
1347 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1348 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1349 && elem.data.integer != 0)
Elliott Hughes892a68b2015-10-19 14:43:53 -07001350 ND_PRINT((ndo, "[errorIndex(%d)!=0]", elem.data.integer));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001351 else if (pduid == GETBULKREQ)
Elliott Hughes892a68b2015-10-19 14:43:53 -07001352 ND_PRINT((ndo, " M=%d", elem.data.integer));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001353 else if (elem.data.integer != 0) {
1354 if (!error)
Elliott Hughes892a68b2015-10-19 14:43:53 -07001355 ND_PRINT((ndo, "[errorIndex(%d) w/o errorStatus]", elem.data.integer));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001356 else {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001357 ND_PRINT((ndo, "@%d", elem.data.integer));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001358 error = elem.data.integer;
1359 }
1360 } else if (error) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001361 ND_PRINT((ndo, "[errorIndex==0]"));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001362 error = 0;
1363 }
1364 length -= count;
1365 np += count;
1366
Elliott Hughes892a68b2015-10-19 14:43:53 -07001367 varbind_print(ndo, pduid, np, length);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001368 return;
1369}
1370
1371/*
1372 * Decode SNMP Trap PDU
1373 */
1374static void
Elliott Hughes892a68b2015-10-19 14:43:53 -07001375trappdu_print(netdissect_options *ndo,
1376 const u_char *np, u_int length)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001377{
1378 struct be elem;
1379 int count = 0, generic;
1380
Elliott Hughes892a68b2015-10-19 14:43:53 -07001381 ND_PRINT((ndo, " "));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001382
1383 /* enterprise (oid) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001384 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001385 return;
1386 if (elem.type != BE_OID) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001387 ND_PRINT((ndo, "[enterprise!=OID]"));
1388 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001389 return;
1390 }
Elliott Hughes892a68b2015-10-19 14:43:53 -07001391 if (asn1_print(ndo, &elem) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001392 return;
1393 length -= count;
1394 np += count;
1395
Elliott Hughes892a68b2015-10-19 14:43:53 -07001396 ND_PRINT((ndo, " "));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001397
1398 /* agent-addr (inetaddr) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001399 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001400 return;
1401 if (elem.type != BE_INETADDR) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001402 ND_PRINT((ndo, "[agent-addr!=INETADDR]"));
1403 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001404 return;
1405 }
Elliott Hughes892a68b2015-10-19 14:43:53 -07001406 if (asn1_print(ndo, &elem) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001407 return;
1408 length -= count;
1409 np += count;
1410
1411 /* generic-trap (Integer) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001412 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001413 return;
1414 if (elem.type != BE_INT) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001415 ND_PRINT((ndo, "[generic-trap!=INT]"));
1416 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001417 return;
1418 }
1419 generic = elem.data.integer;
1420 {
1421 char buf[20];
Elliott Hughes892a68b2015-10-19 14:43:53 -07001422 ND_PRINT((ndo, " %s", DECODE_GenericTrap(generic)));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001423 }
1424 length -= count;
1425 np += count;
1426
1427 /* specific-trap (Integer) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001428 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001429 return;
1430 if (elem.type != BE_INT) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001431 ND_PRINT((ndo, "[specific-trap!=INT]"));
1432 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001433 return;
1434 }
1435 if (generic != GT_ENTERPRISE) {
1436 if (elem.data.integer != 0)
Elliott Hughes892a68b2015-10-19 14:43:53 -07001437 ND_PRINT((ndo, "[specific-trap(%d)!=0]", elem.data.integer));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001438 } else
Elliott Hughes892a68b2015-10-19 14:43:53 -07001439 ND_PRINT((ndo, " s=%d", elem.data.integer));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001440 length -= count;
1441 np += count;
1442
Elliott Hughes892a68b2015-10-19 14:43:53 -07001443 ND_PRINT((ndo, " "));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001444
1445 /* time-stamp (TimeTicks) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001446 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001447 return;
1448 if (elem.type != BE_UNS) { /* XXX */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001449 ND_PRINT((ndo, "[time-stamp!=TIMETICKS]"));
1450 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001451 return;
1452 }
Elliott Hughes892a68b2015-10-19 14:43:53 -07001453 if (asn1_print(ndo, &elem) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001454 return;
1455 length -= count;
1456 np += count;
1457
Elliott Hughes892a68b2015-10-19 14:43:53 -07001458 varbind_print(ndo, TRAP, np, length);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001459 return;
1460}
1461
1462/*
1463 * Decode arbitrary SNMP PDUs.
1464 */
1465static void
Elliott Hughes892a68b2015-10-19 14:43:53 -07001466pdu_print(netdissect_options *ndo,
1467 const u_char *np, u_int length, int version)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001468{
1469 struct be pdu;
1470 int count = 0;
1471
1472 /* PDU (Context) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001473 if ((count = asn1_parse(ndo, np, length, &pdu)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001474 return;
1475 if (pdu.type != BE_PDU) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001476 ND_PRINT((ndo, "[no PDU]"));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001477 return;
1478 }
1479 if ((u_int)count < length)
Elliott Hughes892a68b2015-10-19 14:43:53 -07001480 ND_PRINT((ndo, "[%d extra after PDU]", length - count));
1481 if (ndo->ndo_vflag) {
1482 ND_PRINT((ndo, "{ "));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001483 }
Elliott Hughes892a68b2015-10-19 14:43:53 -07001484 if (asn1_print(ndo, &pdu) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001485 return;
Elliott Hughes892a68b2015-10-19 14:43:53 -07001486 ND_PRINT((ndo, " "));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001487 /* descend into PDU */
1488 length = pdu.asnlen;
1489 np = (u_char *)pdu.data.raw;
1490
1491 if (version == SNMP_VERSION_1 &&
1492 (pdu.id == GETBULKREQ || pdu.id == INFORMREQ ||
1493 pdu.id == V2TRAP || pdu.id == REPORT)) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001494 ND_PRINT((ndo, "[v2 PDU in v1 message]"));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001495 return;
1496 }
1497
1498 if (version == SNMP_VERSION_2 && pdu.id == TRAP) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001499 ND_PRINT((ndo, "[v1 PDU in v2 message]"));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001500 return;
1501 }
1502
1503 switch (pdu.id) {
1504 case TRAP:
Elliott Hughes892a68b2015-10-19 14:43:53 -07001505 trappdu_print(ndo, np, length);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001506 break;
1507 case GETREQ:
1508 case GETNEXTREQ:
1509 case GETRESP:
1510 case SETREQ:
1511 case GETBULKREQ:
1512 case INFORMREQ:
1513 case V2TRAP:
1514 case REPORT:
Elliott Hughes892a68b2015-10-19 14:43:53 -07001515 snmppdu_print(ndo, pdu.id, np, length);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001516 break;
1517 }
1518
Elliott Hughes892a68b2015-10-19 14:43:53 -07001519 if (ndo->ndo_vflag) {
1520 ND_PRINT((ndo, " } "));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001521 }
1522}
1523
1524/*
1525 * Decode a scoped SNMP PDU.
1526 */
1527static void
Elliott Hughes892a68b2015-10-19 14:43:53 -07001528scopedpdu_print(netdissect_options *ndo,
1529 const u_char *np, u_int length, int version)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001530{
1531 struct be elem;
1532 int i, count = 0;
1533
1534 /* Sequence */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001535 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001536 return;
1537 if (elem.type != BE_SEQ) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001538 ND_PRINT((ndo, "[!scoped PDU]"));
1539 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001540 return;
1541 }
1542 length = elem.asnlen;
1543 np = (u_char *)elem.data.raw;
1544
1545 /* contextEngineID (OCTET STRING) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001546 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001547 return;
1548 if (elem.type != BE_STR) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001549 ND_PRINT((ndo, "[contextEngineID!=STR]"));
1550 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001551 return;
1552 }
1553 length -= count;
1554 np += count;
1555
Elliott Hughes892a68b2015-10-19 14:43:53 -07001556 ND_PRINT((ndo, "E= "));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001557 for (i = 0; i < (int)elem.asnlen; i++) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001558 ND_PRINT((ndo, "0x%02X", elem.data.str[i]));
1559 }
1560 ND_PRINT((ndo, " "));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001561
1562 /* contextName (OCTET STRING) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001563 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001564 return;
1565 if (elem.type != BE_STR) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001566 ND_PRINT((ndo, "[contextName!=STR]"));
1567 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001568 return;
1569 }
1570 length -= count;
1571 np += count;
1572
Elliott Hughes892a68b2015-10-19 14:43:53 -07001573 ND_PRINT((ndo, "C=%.*s ", (int)elem.asnlen, elem.data.str));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001574
Elliott Hughes892a68b2015-10-19 14:43:53 -07001575 pdu_print(ndo, np, length, version);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001576}
1577
1578/*
1579 * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
1580 */
1581static void
Elliott Hughes892a68b2015-10-19 14:43:53 -07001582community_print(netdissect_options *ndo,
1583 const u_char *np, u_int length, int version)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001584{
1585 struct be elem;
1586 int count = 0;
1587
1588 /* Community (String) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001589 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001590 return;
1591 if (elem.type != BE_STR) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001592 ND_PRINT((ndo, "[comm!=STR]"));
1593 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001594 return;
1595 }
1596 /* default community */
1597 if (!(elem.asnlen == sizeof(DEF_COMMUNITY) - 1 &&
1598 strncmp((char *)elem.data.str, DEF_COMMUNITY,
1599 sizeof(DEF_COMMUNITY) - 1) == 0))
1600 /* ! "public" */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001601 ND_PRINT((ndo, "C=%.*s ", (int)elem.asnlen, elem.data.str));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001602 length -= count;
1603 np += count;
1604
Elliott Hughes892a68b2015-10-19 14:43:53 -07001605 pdu_print(ndo, np, length, version);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001606}
1607
1608/*
1609 * Decode SNMPv3 User-based Security Message Header (SNMPv3)
1610 */
1611static void
Elliott Hughes892a68b2015-10-19 14:43:53 -07001612usm_print(netdissect_options *ndo,
1613 const u_char *np, u_int length)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001614{
1615 struct be elem;
1616 int count = 0;
1617
1618 /* Sequence */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001619 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001620 return;
1621 if (elem.type != BE_SEQ) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001622 ND_PRINT((ndo, "[!usm]"));
1623 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001624 return;
1625 }
1626 length = elem.asnlen;
1627 np = (u_char *)elem.data.raw;
1628
1629 /* msgAuthoritativeEngineID (OCTET STRING) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001630 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001631 return;
1632 if (elem.type != BE_STR) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001633 ND_PRINT((ndo, "[msgAuthoritativeEngineID!=STR]"));
1634 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001635 return;
1636 }
1637 length -= count;
1638 np += count;
1639
1640 /* msgAuthoritativeEngineBoots (INTEGER) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001641 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001642 return;
1643 if (elem.type != BE_INT) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001644 ND_PRINT((ndo, "[msgAuthoritativeEngineBoots!=INT]"));
1645 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001646 return;
1647 }
Elliott Hughes892a68b2015-10-19 14:43:53 -07001648 if (ndo->ndo_vflag)
1649 ND_PRINT((ndo, "B=%d ", elem.data.integer));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001650 length -= count;
1651 np += count;
1652
1653 /* msgAuthoritativeEngineTime (INTEGER) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001654 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001655 return;
1656 if (elem.type != BE_INT) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001657 ND_PRINT((ndo, "[msgAuthoritativeEngineTime!=INT]"));
1658 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001659 return;
1660 }
Elliott Hughes892a68b2015-10-19 14:43:53 -07001661 if (ndo->ndo_vflag)
1662 ND_PRINT((ndo, "T=%d ", elem.data.integer));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001663 length -= count;
1664 np += count;
1665
1666 /* msgUserName (OCTET STRING) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001667 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001668 return;
1669 if (elem.type != BE_STR) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001670 ND_PRINT((ndo, "[msgUserName!=STR]"));
1671 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001672 return;
1673 }
1674 length -= count;
1675 np += count;
1676
Elliott Hughes892a68b2015-10-19 14:43:53 -07001677 ND_PRINT((ndo, "U=%.*s ", (int)elem.asnlen, elem.data.str));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001678
1679 /* msgAuthenticationParameters (OCTET STRING) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001680 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001681 return;
1682 if (elem.type != BE_STR) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001683 ND_PRINT((ndo, "[msgAuthenticationParameters!=STR]"));
1684 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001685 return;
1686 }
1687 length -= count;
1688 np += count;
1689
1690 /* msgPrivacyParameters (OCTET STRING) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001691 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001692 return;
1693 if (elem.type != BE_STR) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001694 ND_PRINT((ndo, "[msgPrivacyParameters!=STR]"));
1695 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001696 return;
1697 }
1698 length -= count;
1699 np += count;
1700
1701 if ((u_int)count < length)
Elliott Hughes892a68b2015-10-19 14:43:53 -07001702 ND_PRINT((ndo, "[%d extra after usm SEQ]", length - count));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001703}
1704
1705/*
1706 * Decode SNMPv3 Message Header (SNMPv3)
1707 */
1708static void
Elliott Hughes892a68b2015-10-19 14:43:53 -07001709v3msg_print(netdissect_options *ndo,
1710 const u_char *np, u_int length)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001711{
1712 struct be elem;
1713 int count = 0;
1714 u_char flags;
1715 int model;
1716 const u_char *xnp = np;
1717 int xlength = length;
1718
1719 /* Sequence */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001720 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001721 return;
1722 if (elem.type != BE_SEQ) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001723 ND_PRINT((ndo, "[!message]"));
1724 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001725 return;
1726 }
1727 length = elem.asnlen;
1728 np = (u_char *)elem.data.raw;
1729
Elliott Hughes892a68b2015-10-19 14:43:53 -07001730 if (ndo->ndo_vflag) {
1731 ND_PRINT((ndo, "{ "));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001732 }
1733
1734 /* msgID (INTEGER) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001735 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001736 return;
1737 if (elem.type != BE_INT) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001738 ND_PRINT((ndo, "[msgID!=INT]"));
1739 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001740 return;
1741 }
1742 length -= count;
1743 np += count;
1744
1745 /* msgMaxSize (INTEGER) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001746 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001747 return;
1748 if (elem.type != BE_INT) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001749 ND_PRINT((ndo, "[msgMaxSize!=INT]"));
1750 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001751 return;
1752 }
1753 length -= count;
1754 np += count;
1755
1756 /* msgFlags (OCTET STRING) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001757 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001758 return;
1759 if (elem.type != BE_STR) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001760 ND_PRINT((ndo, "[msgFlags!=STR]"));
1761 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001762 return;
1763 }
1764 if (elem.asnlen != 1) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001765 ND_PRINT((ndo, "[msgFlags size %d]", elem.asnlen));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001766 return;
1767 }
1768 flags = elem.data.str[0];
1769 if (flags != 0x00 && flags != 0x01 && flags != 0x03
1770 && flags != 0x04 && flags != 0x05 && flags != 0x07) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001771 ND_PRINT((ndo, "[msgFlags=0x%02X]", flags));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001772 return;
1773 }
1774 length -= count;
1775 np += count;
1776
Elliott Hughes892a68b2015-10-19 14:43:53 -07001777 ND_PRINT((ndo, "F=%s%s%s ",
1778 flags & 0x01 ? "a" : "",
1779 flags & 0x02 ? "p" : "",
1780 flags & 0x04 ? "r" : ""));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001781
1782 /* msgSecurityModel (INTEGER) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001783 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001784 return;
1785 if (elem.type != BE_INT) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001786 ND_PRINT((ndo, "[msgSecurityModel!=INT]"));
1787 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001788 return;
1789 }
1790 model = elem.data.integer;
1791 length -= count;
1792 np += count;
1793
1794 if ((u_int)count < length)
Elliott Hughes892a68b2015-10-19 14:43:53 -07001795 ND_PRINT((ndo, "[%d extra after message SEQ]", length - count));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001796
Elliott Hughes892a68b2015-10-19 14:43:53 -07001797 if (ndo->ndo_vflag) {
1798 ND_PRINT((ndo, "} "));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001799 }
1800
1801 if (model == 3) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001802 if (ndo->ndo_vflag) {
1803 ND_PRINT((ndo, "{ USM "));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001804 }
1805 } else {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001806 ND_PRINT((ndo, "[security model %d]", model));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001807 return;
1808 }
1809
1810 np = xnp + (np - xnp);
1811 length = xlength - (np - xnp);
1812
1813 /* msgSecurityParameters (OCTET STRING) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001814 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001815 return;
1816 if (elem.type != BE_STR) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001817 ND_PRINT((ndo, "[msgSecurityParameters!=STR]"));
1818 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001819 return;
1820 }
1821 length -= count;
1822 np += count;
1823
1824 if (model == 3) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001825 usm_print(ndo, elem.data.str, elem.asnlen);
1826 if (ndo->ndo_vflag) {
1827 ND_PRINT((ndo, "} "));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001828 }
1829 }
1830
Elliott Hughes892a68b2015-10-19 14:43:53 -07001831 if (ndo->ndo_vflag) {
1832 ND_PRINT((ndo, "{ ScopedPDU "));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001833 }
1834
Elliott Hughes892a68b2015-10-19 14:43:53 -07001835 scopedpdu_print(ndo, np, length, 3);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001836
Elliott Hughes892a68b2015-10-19 14:43:53 -07001837 if (ndo->ndo_vflag) {
1838 ND_PRINT((ndo, "} "));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001839 }
1840}
1841
1842/*
1843 * Decode SNMP header and pass on to PDU printing routines
1844 */
1845void
Elliott Hughes892a68b2015-10-19 14:43:53 -07001846snmp_print(netdissect_options *ndo,
1847 const u_char *np, u_int length)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001848{
1849 struct be elem;
1850 int count = 0;
1851 int version = 0;
1852
Elliott Hughes892a68b2015-10-19 14:43:53 -07001853 ND_PRINT((ndo, " "));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001854
1855 /* initial Sequence */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001856 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001857 return;
1858 if (elem.type != BE_SEQ) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001859 ND_PRINT((ndo, "[!init SEQ]"));
1860 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001861 return;
1862 }
1863 if ((u_int)count < length)
Elliott Hughes892a68b2015-10-19 14:43:53 -07001864 ND_PRINT((ndo, "[%d extra after iSEQ]", length - count));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001865 /* descend */
1866 length = elem.asnlen;
1867 np = (u_char *)elem.data.raw;
1868
1869 /* Version (INTEGER) */
Elliott Hughes892a68b2015-10-19 14:43:53 -07001870 if ((count = asn1_parse(ndo, np, length, &elem)) < 0)
The Android Open Source Project2949f582009-03-03 19:30:46 -08001871 return;
1872 if (elem.type != BE_INT) {
Elliott Hughes892a68b2015-10-19 14:43:53 -07001873 ND_PRINT((ndo, "[version!=INT]"));
1874 asn1_print(ndo, &elem);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001875 return;
1876 }
1877
1878 switch (elem.data.integer) {
1879 case SNMP_VERSION_1:
1880 case SNMP_VERSION_2:
1881 case SNMP_VERSION_3:
Elliott Hughes892a68b2015-10-19 14:43:53 -07001882 if (ndo->ndo_vflag)
1883 ND_PRINT((ndo, "{ %s ", SnmpVersion[elem.data.integer]));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001884 break;
1885 default:
Elliott Hughes892a68b2015-10-19 14:43:53 -07001886 ND_PRINT((ndo, "[version = %d]", elem.data.integer));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001887 return;
1888 }
1889 version = elem.data.integer;
1890 length -= count;
1891 np += count;
1892
1893 switch (version) {
1894 case SNMP_VERSION_1:
1895 case SNMP_VERSION_2:
Elliott Hughes892a68b2015-10-19 14:43:53 -07001896 community_print(ndo, np, length, version);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001897 break;
1898 case SNMP_VERSION_3:
Elliott Hughes892a68b2015-10-19 14:43:53 -07001899 v3msg_print(ndo, np, length);
The Android Open Source Project2949f582009-03-03 19:30:46 -08001900 break;
1901 default:
Elliott Hughes892a68b2015-10-19 14:43:53 -07001902 ND_PRINT((ndo, "[version = %d]", elem.data.integer));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001903 break;
1904 }
1905
Elliott Hughes892a68b2015-10-19 14:43:53 -07001906 if (ndo->ndo_vflag) {
1907 ND_PRINT((ndo, "} "));
The Android Open Source Project2949f582009-03-03 19:30:46 -08001908 }
1909}