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