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