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