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