]> The Tcpdump Group git mirrors - tcpdump/blob - print-snmp.c
NDOize the rest of util.c
[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 #define NETDISSECT_REWORKED
60 #ifdef HAVE_CONFIG_H
61 #include "config.h"
62 #endif
63
64 #include <tcpdump-stdinc.h>
65
66 #include <stdio.h>
67 #include <string.h>
68
69 #ifdef HAVE_SMI_H
70 #include <smi.h>
71 #endif
72
73 #include "interface.h"
74
75 #undef OPAQUE /* defined in <wingdi.h> */
76
77 static const char tstr[] = "[|snmp]";
78
79 /*
80 * Universal ASN.1 types
81 * (we only care about the tag values for those allowed in the Internet SMI)
82 */
83 static const char *Universal[] = {
84 "U-0",
85 "Boolean",
86 "Integer",
87 #define INTEGER 2
88 "Bitstring",
89 "String",
90 #define STRING 4
91 "Null",
92 #define ASN_NULL 5
93 "ObjID",
94 #define OBJECTID 6
95 "ObjectDes",
96 "U-8","U-9","U-10","U-11", /* 8-11 */
97 "U-12","U-13","U-14","U-15", /* 12-15 */
98 "Sequence",
99 #define SEQUENCE 16
100 "Set"
101 };
102
103 /*
104 * Application-wide ASN.1 types from the Internet SMI and their tags
105 */
106 static const char *Application[] = {
107 "IpAddress",
108 #define IPADDR 0
109 "Counter",
110 #define COUNTER 1
111 "Gauge",
112 #define GAUGE 2
113 "TimeTicks",
114 #define TIMETICKS 3
115 "Opaque",
116 #define OPAQUE 4
117 "C-5",
118 "Counter64"
119 #define COUNTER64 6
120 };
121
122 /*
123 * Context-specific ASN.1 types for the SNMP PDUs and their tags
124 */
125 static const char *Context[] = {
126 "GetRequest",
127 #define GETREQ 0
128 "GetNextRequest",
129 #define GETNEXTREQ 1
130 "GetResponse",
131 #define GETRESP 2
132 "SetRequest",
133 #define SETREQ 3
134 "Trap",
135 #define TRAP 4
136 "GetBulk",
137 #define GETBULKREQ 5
138 "Inform",
139 #define INFORMREQ 6
140 "V2Trap",
141 #define V2TRAP 7
142 "Report"
143 #define REPORT 8
144 };
145
146 #define NOTIFY_CLASS(x) (x == TRAP || x == V2TRAP || x == INFORMREQ)
147 #define READ_CLASS(x) (x == GETREQ || x == GETNEXTREQ || x == GETBULKREQ)
148 #define WRITE_CLASS(x) (x == SETREQ)
149 #define RESPONSE_CLASS(x) (x == GETRESP)
150 #define INTERNAL_CLASS(x) (x == REPORT)
151
152 /*
153 * Context-specific ASN.1 types for the SNMP Exceptions and their tags
154 */
155 static const char *Exceptions[] = {
156 "noSuchObject",
157 #define NOSUCHOBJECT 0
158 "noSuchInstance",
159 #define NOSUCHINSTANCE 1
160 "endOfMibView",
161 #define ENDOFMIBVIEW 2
162 };
163
164 /*
165 * Private ASN.1 types
166 * The Internet SMI does not specify any
167 */
168 static const char *Private[] = {
169 "P-0"
170 };
171
172 /*
173 * error-status values for any SNMP PDU
174 */
175 static const char *ErrorStatus[] = {
176 "noError",
177 "tooBig",
178 "noSuchName",
179 "badValue",
180 "readOnly",
181 "genErr",
182 "noAccess",
183 "wrongType",
184 "wrongLength",
185 "wrongEncoding",
186 "wrongValue",
187 "noCreation",
188 "inconsistentValue",
189 "resourceUnavailable",
190 "commitFailed",
191 "undoFailed",
192 "authorizationError",
193 "notWritable",
194 "inconsistentName"
195 };
196 #define DECODE_ErrorStatus(e) \
197 ( e >= 0 && (size_t)e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
198 ? ErrorStatus[e] \
199 : (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf))
200
201 /*
202 * generic-trap values in the SNMP Trap-PDU
203 */
204 static const char *GenericTrap[] = {
205 "coldStart",
206 "warmStart",
207 "linkDown",
208 "linkUp",
209 "authenticationFailure",
210 "egpNeighborLoss",
211 "enterpriseSpecific"
212 #define GT_ENTERPRISE 6
213 };
214 #define DECODE_GenericTrap(t) \
215 ( t >= 0 && (size_t)t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
216 ? GenericTrap[t] \
217 : (snprintf(buf, sizeof(buf), "gt=%d", t), buf))
218
219 /*
220 * ASN.1 type class table
221 * Ties together the preceding Universal, Application, Context, and Private
222 * type definitions.
223 */
224 #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
225 static const struct {
226 const char *name;
227 const char **Id;
228 int numIDs;
229 } Class[] = {
230 defineCLASS(Universal),
231 #define UNIVERSAL 0
232 defineCLASS(Application),
233 #define APPLICATION 1
234 defineCLASS(Context),
235 #define CONTEXT 2
236 defineCLASS(Private),
237 #define PRIVATE 3
238 defineCLASS(Exceptions),
239 #define EXCEPTIONS 4
240 };
241
242 /*
243 * defined forms for ASN.1 types
244 */
245 static const char *Form[] = {
246 "Primitive",
247 #define PRIMITIVE 0
248 "Constructed",
249 #define CONSTRUCTED 1
250 };
251
252 /*
253 * A structure for the OID tree for the compiled-in MIB.
254 * This is stored as a general-order tree.
255 */
256 struct obj {
257 const char *desc; /* name of object */
258 u_char oid; /* sub-id following parent */
259 u_char type; /* object type (unused) */
260 struct obj *child, *next; /* child and next sibling pointers */
261 } *objp = NULL;
262
263 /*
264 * Include the compiled in SNMP MIB. "mib.h" is produced by feeding
265 * RFC-1156 format files into "makemib". "mib.h" MUST define at least
266 * a value for `mibroot'.
267 *
268 * In particular, this is gross, as this is including initialized structures,
269 * and by right shouldn't be an "include" file.
270 */
271 #include "mib.h"
272
273 /*
274 * This defines a list of OIDs which will be abbreviated on output.
275 * Currently, this includes the prefixes for the Internet MIB, the
276 * private enterprises tree, and the experimental tree.
277 */
278 static const struct obj_abrev {
279 const char *prefix; /* prefix for this abrev */
280 struct obj *node; /* pointer into object table */
281 const char *oid; /* ASN.1 encoded OID */
282 } obj_abrev_list[] = {
283 #ifndef NO_ABREV_MIB
284 /* .iso.org.dod.internet.mgmt.mib */
285 { "", &_mib_obj, "\53\6\1\2\1" },
286 #endif
287 #ifndef NO_ABREV_ENTER
288 /* .iso.org.dod.internet.private.enterprises */
289 { "E:", &_enterprises_obj, "\53\6\1\4\1" },
290 #endif
291 #ifndef NO_ABREV_EXPERI
292 /* .iso.org.dod.internet.experimental */
293 { "X:", &_experimental_obj, "\53\6\1\3" },
294 #endif
295 #ifndef NO_ABBREV_SNMPMODS
296 /* .iso.org.dod.internet.snmpV2.snmpModules */
297 { "S:", &_snmpModules_obj, "\53\6\1\6\3" },
298 #endif
299 { 0,0,0 }
300 };
301
302 /*
303 * This is used in the OID print routine to walk down the object tree
304 * rooted at `mibroot'.
305 */
306 #define OBJ_PRINT(o, suppressdot) \
307 { \
308 if (objp) { \
309 do { \
310 if ((o) == objp->oid) \
311 break; \
312 } while ((objp = objp->next) != NULL); \
313 } \
314 if (objp) { \
315 ND_PRINT((ndo, suppressdot?"%s":".%s", objp->desc)); \
316 objp = objp->child; \
317 } else \
318 ND_PRINT((ndo, suppressdot?"%u":".%u", (o))); \
319 }
320
321 /*
322 * This is the definition for the Any-Data-Type storage used purely for
323 * temporary internal representation while decoding an ASN.1 data stream.
324 */
325 struct be {
326 u_int32_t asnlen;
327 union {
328 caddr_t raw;
329 int32_t integer;
330 u_int32_t uns;
331 const u_char *str;
332 struct {
333 u_int32_t high;
334 u_int32_t low;
335 } uns64;
336 } data;
337 u_short id;
338 u_char form, class; /* tag info */
339 u_char type;
340 #define BE_ANY 255
341 #define BE_NONE 0
342 #define BE_NULL 1
343 #define BE_OCTET 2
344 #define BE_OID 3
345 #define BE_INT 4
346 #define BE_UNS 5
347 #define BE_STR 6
348 #define BE_SEQ 7
349 #define BE_INETADDR 8
350 #define BE_PDU 9
351 #define BE_UNS64 10
352 #define BE_NOSUCHOBJECT 128
353 #define BE_NOSUCHINST 129
354 #define BE_ENDOFMIBVIEW 130
355 };
356
357 /*
358 * SNMP versions recognized by this module
359 */
360 static const char *SnmpVersion[] = {
361 "SNMPv1",
362 #define SNMP_VERSION_1 0
363 "SNMPv2c",
364 #define SNMP_VERSION_2 1
365 "SNMPv2u",
366 #define SNMP_VERSION_2U 2
367 "SNMPv3"
368 #define SNMP_VERSION_3 3
369 };
370
371 /*
372 * Defaults for SNMP PDU components
373 */
374 #define DEF_COMMUNITY "public"
375
376 /*
377 * constants for ASN.1 decoding
378 */
379 #define OIDMUX 40
380 #define ASNLEN_INETADDR 4
381 #define ASN_SHIFT7 7
382 #define ASN_SHIFT8 8
383 #define ASN_BIT8 0x80
384 #define ASN_LONGLEN 0x80
385
386 #define ASN_ID_BITS 0x1f
387 #define ASN_FORM_BITS 0x20
388 #define ASN_FORM_SHIFT 5
389 #define ASN_CLASS_BITS 0xc0
390 #define ASN_CLASS_SHIFT 6
391
392 #define ASN_ID_EXT 0x1f /* extension ID in tag field */
393
394 /*
395 * This decodes the next ASN.1 object in the stream pointed to by "p"
396 * (and of real-length "len") and stores the intermediate data in the
397 * provided BE object.
398 *
399 * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
400 * O/w, this returns the number of bytes parsed from "p".
401 */
402 static int
403 asn1_parse(netdissect_options *ndo,
404 register const u_char *p, u_int len, struct be *elem)
405 {
406 u_char form, class, id;
407 int i, hdr;
408
409 elem->asnlen = 0;
410 elem->type = BE_ANY;
411 if (len < 1) {
412 ND_PRINT((ndo, "[nothing to parse]"));
413 return -1;
414 }
415 ND_TCHECK(*p);
416
417 /*
418 * it would be nice to use a bit field, but you can't depend on them.
419 * +---+---+---+---+---+---+---+---+
420 * + class |frm| id |
421 * +---+---+---+---+---+---+---+---+
422 * 7 6 5 4 3 2 1 0
423 */
424 id = *p & ASN_ID_BITS; /* lower 5 bits, range 00-1f */
425 #ifdef notdef
426 form = (*p & 0xe0) >> 5; /* move upper 3 bits to lower 3 */
427 class = form >> 1; /* bits 7&6 -> bits 1&0, range 0-3 */
428 form &= 0x1; /* bit 5 -> bit 0, range 0-1 */
429 #else
430 form = (u_char)(*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
431 class = (u_char)(*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
432 #endif
433 elem->form = form;
434 elem->class = class;
435 elem->id = id;
436 p++; len--; hdr = 1;
437 /* extended tag field */
438 if (id == ASN_ID_EXT) {
439 /*
440 * The ID follows, as a sequence of octets with the
441 * 8th bit set and the remaining 7 bits being
442 * the next 7 bits of the value, terminated with
443 * an octet with the 8th bit not set.
444 *
445 * First, assemble all the octets with the 8th
446 * bit set. XXX - this doesn't handle a value
447 * that won't fit in 32 bits.
448 */
449 for (id = 0; *p & ASN_BIT8; len--, hdr++, p++) {
450 if (len < 1) {
451 ND_PRINT((ndo, "[Xtagfield?]"));
452 return -1;
453 }
454 ND_TCHECK(*p);
455 id = (id << 7) | (*p & ~ASN_BIT8);
456 }
457 if (len < 1) {
458 ND_PRINT((ndo, "[Xtagfield?]"));
459 return -1;
460 }
461 ND_TCHECK(*p);
462 elem->id = id = (id << 7) | *p;
463 --len;
464 ++hdr;
465 ++p;
466 }
467 if (len < 1) {
468 ND_PRINT((ndo, "[no asnlen]"));
469 return -1;
470 }
471 ND_TCHECK(*p);
472 elem->asnlen = *p;
473 p++; len--; hdr++;
474 if (elem->asnlen & ASN_BIT8) {
475 u_int32_t noct = elem->asnlen % ASN_BIT8;
476 elem->asnlen = 0;
477 if (len < noct) {
478 ND_PRINT((ndo, "[asnlen? %d<%d]", len, noct));
479 return -1;
480 }
481 ND_TCHECK2(*p, noct);
482 for (; noct-- > 0; len--, hdr++)
483 elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++;
484 }
485 if (len < elem->asnlen) {
486 ND_PRINT((ndo, "[len%d<asnlen%u]", len, elem->asnlen));
487 return -1;
488 }
489 if (form >= sizeof(Form)/sizeof(Form[0])) {
490 ND_PRINT((ndo, "[form?%d]", form));
491 return -1;
492 }
493 if (class >= sizeof(Class)/sizeof(Class[0])) {
494 ND_PRINT((ndo, "[class?%c/%d]", *Form[form], class));
495 return -1;
496 }
497 if ((int)id >= Class[class].numIDs) {
498 ND_PRINT((ndo, "[id?%c/%s/%d]", *Form[form], Class[class].name, id));
499 return -1;
500 }
501
502 switch (form) {
503 case PRIMITIVE:
504 switch (class) {
505 case UNIVERSAL:
506 switch (id) {
507 case STRING:
508 elem->type = BE_STR;
509 elem->data.str = p;
510 break;
511
512 case INTEGER: {
513 register int32_t data;
514 elem->type = BE_INT;
515 data = 0;
516
517 ND_TCHECK2(*p, elem->asnlen);
518 if (*p & ASN_BIT8) /* negative */
519 data = -1;
520 for (i = elem->asnlen; i-- > 0; p++)
521 data = (data << ASN_SHIFT8) | *p;
522 elem->data.integer = data;
523 break;
524 }
525
526 case OBJECTID:
527 elem->type = BE_OID;
528 elem->data.raw = (caddr_t)p;
529 break;
530
531 case ASN_NULL:
532 elem->type = BE_NULL;
533 elem->data.raw = NULL;
534 break;
535
536 default:
537 elem->type = BE_OCTET;
538 elem->data.raw = (caddr_t)p;
539 ND_PRINT((ndo, "[P/U/%s]", Class[class].Id[id]));
540 break;
541 }
542 break;
543
544 case APPLICATION:
545 switch (id) {
546 case IPADDR:
547 elem->type = BE_INETADDR;
548 elem->data.raw = (caddr_t)p;
549 break;
550
551 case COUNTER:
552 case GAUGE:
553 case TIMETICKS: {
554 register u_int32_t data;
555 ND_TCHECK2(*p, elem->asnlen);
556 elem->type = BE_UNS;
557 data = 0;
558 for (i = elem->asnlen; i-- > 0; p++)
559 data = (data << 8) + *p;
560 elem->data.uns = data;
561 break;
562 }
563
564 case COUNTER64: {
565 register u_int32_t high, low;
566 ND_TCHECK2(*p, elem->asnlen);
567 elem->type = BE_UNS64;
568 high = 0, low = 0;
569 for (i = elem->asnlen; i-- > 0; p++) {
570 high = (high << 8) |
571 ((low & 0xFF000000) >> 24);
572 low = (low << 8) | *p;
573 }
574 elem->data.uns64.high = high;
575 elem->data.uns64.low = low;
576 break;
577 }
578
579 default:
580 elem->type = BE_OCTET;
581 elem->data.raw = (caddr_t)p;
582 ND_PRINT((ndo, "[P/A/%s]",
583 Class[class].Id[id]));
584 break;
585 }
586 break;
587
588 case CONTEXT:
589 switch (id) {
590 case NOSUCHOBJECT:
591 elem->type = BE_NOSUCHOBJECT;
592 elem->data.raw = NULL;
593 break;
594
595 case NOSUCHINSTANCE:
596 elem->type = BE_NOSUCHINST;
597 elem->data.raw = NULL;
598 break;
599
600 case ENDOFMIBVIEW:
601 elem->type = BE_ENDOFMIBVIEW;
602 elem->data.raw = NULL;
603 break;
604 }
605 break;
606
607 default:
608 ND_PRINT((ndo, "[P/%s/%s]", Class[class].name, Class[class].Id[id]));
609 ND_TCHECK2(*p, elem->asnlen);
610 elem->type = BE_OCTET;
611 elem->data.raw = (caddr_t)p;
612 break;
613 }
614 break;
615
616 case CONSTRUCTED:
617 switch (class) {
618 case UNIVERSAL:
619 switch (id) {
620 case SEQUENCE:
621 elem->type = BE_SEQ;
622 elem->data.raw = (caddr_t)p;
623 break;
624
625 default:
626 elem->type = BE_OCTET;
627 elem->data.raw = (caddr_t)p;
628 ND_PRINT((ndo, "C/U/%s", Class[class].Id[id]));
629 break;
630 }
631 break;
632
633 case CONTEXT:
634 elem->type = BE_PDU;
635 elem->data.raw = (caddr_t)p;
636 break;
637
638 default:
639 elem->type = BE_OCTET;
640 elem->data.raw = (caddr_t)p;
641 ND_PRINT((ndo, "C/%s/%s", Class[class].name, Class[class].Id[id]));
642 break;
643 }
644 break;
645 }
646 p += elem->asnlen;
647 len -= elem->asnlen;
648 return elem->asnlen + hdr;
649
650 trunc:
651 ND_PRINT((ndo, "%s", tstr));
652 return -1;
653 }
654
655 /*
656 * Display the ASN.1 object represented by the BE object.
657 * This used to be an integral part of asn1_parse() before the intermediate
658 * BE form was added.
659 */
660 static int
661 asn1_print(netdissect_options *ndo,
662 struct be *elem)
663 {
664 u_char *p = (u_char *)elem->data.raw;
665 u_int32_t asnlen = elem->asnlen;
666 u_int32_t i;
667
668 switch (elem->type) {
669
670 case BE_OCTET:
671 ND_TCHECK2(*p, asnlen);
672 for (i = asnlen; i-- > 0; p++)
673 ND_PRINT((ndo, "_%.2x", *p));
674 break;
675
676 case BE_NULL:
677 break;
678
679 case BE_OID: {
680 int o = 0, first = -1, i = asnlen;
681
682 if (!ndo->ndo_sflag && !ndo->ndo_nflag && asnlen > 2) {
683 const struct obj_abrev *a = &obj_abrev_list[0];
684 size_t a_len = strlen(a->oid);
685 for (; a->node; a++) {
686 ND_TCHECK2(*p, a_len);
687 if (memcmp(a->oid, (char *)p, a_len) == 0) {
688 objp = a->node->child;
689 i -= strlen(a->oid);
690 p += strlen(a->oid);
691 ND_PRINT((ndo, "%s", a->prefix));
692 first = 1;
693 break;
694 }
695 }
696 }
697
698 for (; !ndo->ndo_sflag && i-- > 0; p++) {
699 ND_TCHECK(*p);
700 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
701 if (*p & ASN_LONGLEN)
702 continue;
703
704 /*
705 * first subitem encodes two items with 1st*OIDMUX+2nd
706 * (see X.690:1997 clause 8.19 for the details)
707 */
708 if (first < 0) {
709 int s;
710 if (!ndo->ndo_nflag)
711 objp = mibroot;
712 first = 0;
713 s = o / OIDMUX;
714 if (s > 2) s = 2;
715 OBJ_PRINT(s, first);
716 o -= s * OIDMUX;
717 }
718 OBJ_PRINT(o, first);
719 if (--first < 0)
720 first = 0;
721 o = 0;
722 }
723 break;
724 }
725
726 case BE_INT:
727 ND_PRINT((ndo, "%d", elem->data.integer));
728 break;
729
730 case BE_UNS:
731 ND_PRINT((ndo, "%u", elem->data.uns));
732 break;
733
734 case BE_UNS64: { /* idea borrowed from by Marshall Rose */
735 double d;
736 int j, carry;
737 char *cpf, *cpl, last[6], first[30];
738 if (elem->data.uns64.high == 0) {
739 ND_PRINT((ndo, "%u", elem->data.uns64.low));
740 break;
741 }
742 d = elem->data.uns64.high * 4294967296.0; /* 2^32 */
743 if (elem->data.uns64.high <= 0x1fffff) {
744 d += elem->data.uns64.low;
745 #if 0 /*is looks illegal, but what is the intention?*/
746 ND_PRINT((ndo, "%.f", d));
747 #else
748 ND_PRINT((ndo, "%f", d));
749 #endif
750 break;
751 }
752 d += (elem->data.uns64.low & 0xfffff000);
753 #if 0 /*is looks illegal, but what is the intention?*/
754 snprintf(first, sizeof(first), "%.f", d);
755 #else
756 snprintf(first, sizeof(first), "%f", d);
757 #endif
758 snprintf(last, sizeof(last), "%5.5d",
759 elem->data.uns64.low & 0xfff);
760 for (carry = 0, cpf = first+strlen(first)-1, cpl = last+4;
761 cpl >= last;
762 cpf--, cpl--) {
763 j = carry + (*cpf - '0') + (*cpl - '0');
764 if (j > 9) {
765 j -= 10;
766 carry = 1;
767 } else {
768 carry = 0;
769 }
770 *cpf = j + '0';
771 }
772 ND_PRINT((ndo, "%s", first));
773 break;
774 }
775
776 case BE_STR: {
777 register int printable = 1, first = 1;
778 const u_char *p = elem->data.str;
779 ND_TCHECK2(*p, asnlen);
780 for (i = asnlen; printable && i-- > 0; p++)
781 printable = ND_ISPRINT(*p);
782 p = elem->data.str;
783 if (printable) {
784 ND_PRINT((ndo, "\""));
785 if (fn_printn(ndo, p, asnlen, ndo->ndo_snapend)) {
786 ND_PRINT((ndo, "\""));
787 goto trunc;
788 }
789 ND_PRINT((ndo, "\""));
790 } else
791 for (i = asnlen; i-- > 0; p++) {
792 ND_PRINT((ndo, first ? "%.2x" : "_%.2x", *p));
793 first = 0;
794 }
795 break;
796 }
797
798 case BE_SEQ:
799 ND_PRINT((ndo, "Seq(%u)", elem->asnlen));
800 break;
801
802 case BE_INETADDR:
803 if (asnlen != ASNLEN_INETADDR)
804 ND_PRINT((ndo, "[inetaddr len!=%d]", ASNLEN_INETADDR));
805 ND_TCHECK2(*p, asnlen);
806 for (i = asnlen; i-- != 0; p++) {
807 ND_PRINT((ndo, (i == asnlen-1) ? "%u" : ".%u", *p));
808 }
809 break;
810
811 case BE_NOSUCHOBJECT:
812 case BE_NOSUCHINST:
813 case BE_ENDOFMIBVIEW:
814 ND_PRINT((ndo, "[%s]", Class[EXCEPTIONS].Id[elem->id]));
815 break;
816
817 case BE_PDU:
818 ND_PRINT((ndo, "%s(%u)", Class[CONTEXT].Id[elem->id], elem->asnlen));
819 break;
820
821 case BE_ANY:
822 ND_PRINT((ndo, "[BE_ANY!?]"));
823 break;
824
825 default:
826 ND_PRINT((ndo, "[be!?]"));
827 break;
828 }
829 return 0;
830
831 trunc:
832 ND_PRINT((ndo, "%s", tstr));
833 return -1;
834 }
835
836 #ifdef notdef
837 /*
838 * This is a brute force ASN.1 printer: recurses to dump an entire structure.
839 * This will work for any ASN.1 stream, not just an SNMP PDU.
840 *
841 * By adding newlines and spaces at the correct places, this would print in
842 * Rose-Normal-Form.
843 *
844 * This is not currently used.
845 */
846 static void
847 asn1_decode(u_char *p, u_int length)
848 {
849 struct be elem;
850 int i = 0;
851
852 while (i >= 0 && length > 0) {
853 i = asn1_parse(ndo, p, length, &elem);
854 if (i >= 0) {
855 ND_PRINT((ndo, " "));
856 if (asn1_print(ndo, &elem) < 0)
857 return;
858 if (elem.type == BE_SEQ || elem.type == BE_PDU) {
859 ND_PRINT((ndo, " {"));
860 asn1_decode(elem.data.raw, elem.asnlen);
861 ND_PRINT((ndo, " }"));
862 }
863 length -= i;
864 p += i;
865 }
866 }
867 }
868 #endif
869
870 #ifdef LIBSMI
871
872 struct smi2be {
873 SmiBasetype basetype;
874 int be;
875 };
876
877 static const struct smi2be smi2betab[] = {
878 { SMI_BASETYPE_INTEGER32, BE_INT },
879 { SMI_BASETYPE_OCTETSTRING, BE_STR },
880 { SMI_BASETYPE_OCTETSTRING, BE_INETADDR },
881 { SMI_BASETYPE_OBJECTIDENTIFIER, BE_OID },
882 { SMI_BASETYPE_UNSIGNED32, BE_UNS },
883 { SMI_BASETYPE_INTEGER64, BE_NONE },
884 { SMI_BASETYPE_UNSIGNED64, BE_UNS64 },
885 { SMI_BASETYPE_FLOAT32, BE_NONE },
886 { SMI_BASETYPE_FLOAT64, BE_NONE },
887 { SMI_BASETYPE_FLOAT128, BE_NONE },
888 { SMI_BASETYPE_ENUM, BE_INT },
889 { SMI_BASETYPE_BITS, BE_STR },
890 { SMI_BASETYPE_UNKNOWN, BE_NONE }
891 };
892
893 static int
894 smi_decode_oid(netdissect_options *ndo,
895 struct be *elem, unsigned int *oid,
896 unsigned int oidsize, unsigned int *oidlen)
897 {
898 u_char *p = (u_char *)elem->data.raw;
899 u_int32_t asnlen = elem->asnlen;
900 int o = 0, first = -1, i = asnlen;
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 if (*oidlen < oidsize) {
915 oid[*oidlen] = o / OIDMUX;
916 if (oid[*oidlen] > 2) oid[*oidlen] = 2;
917 }
918 o -= oid[*oidlen] * OIDMUX;
919 if (*oidlen < oidsize) (*oidlen)++;
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 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 = (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 = (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 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 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 = (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 = (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((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 = (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 = (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 = (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 }